使用Go进行CPU id的位掩码转换

huangapple go评论147阅读模式
英文:

Bitmasking conversion of CPU ids with Go

问题

我有一个包含cpu_ids的二进制计数的掩码(对于3个CPU,为0xA00000800000),我想将其转换为逗号分隔的cpu_ids字符串:"0,2,24"

我使用了以下Go实现(我是一个Go初学者)。这是最好的方法吗?特别是字节缓冲区的处理似乎效率低下!

package main

import (
	"fmt"
	"os"
	"os/exec"
)

func main(){
    cpuMap     := "0xA00000800000"
    cpuIds     = getCpuIds(cpuMap)
    fmt.Println(cpuIds)
}

func getCpuIds(cpuMap string) string {
	// 获取cpu ids
	cpu_ids_i, _ := strconv.ParseInt(cpuMap, 0, 64) // 将字符串转换为整数
	cpu_ids_b := strconv.FormatInt(cpu_ids_i, 2)    // 转换为二进制字符串

	var buff bytes.Buffer
	for i, runeValue := range cpu_ids_b {
		// 注意!Go返回的是码点而不是字符串
		if runeValue == '1' {
			buff.WriteString(fmt.Sprintf("%d", i))
		}
		if (i+1 < len(cpu_ids_b)) && (runeValue == '1') {
			buff.WriteString(string(","))
		}

	}
	cpuIds := buff.String()
	// 移除最后一个逗号
	cpuIds = cpuIds[:len(cpuIds)-1]
	return cpuIds
}

返回结果:

"0,2,24"

英文:

I have a mask that contains a binary counting of cpu_ids (0xA00000800000 for 3 CPUs) which I want to convert into a string of comma separated cpu_ids: &quot;0,2,24&quot;.

I did the following Go implementation (I am a Go starter). Is it the best way to do it? Especially the handling of byte buffers seems to be inefficient!

package main

import (
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;os/exec&quot;
)

func main(){
    cpuMap     := &quot;0xA00000800000&quot;
    cpuIds     = getCpuIds(cpuMap)
    fmt.Println(cpuIds)
}

func getCpuIds(cpuMap string) string {
	// getting the cpu ids
	cpu_ids_i, _ := strconv.ParseInt(cpuMap, 0, 64) // int from string
	cpu_ids_b := strconv.FormatInt(cpu_ids_i, 2)    // binary as string

	var buff bytes.Buffer
	for i, runeValue := range cpu_ids_b {
		// take care! go returns code points and not the string    
		if runeValue == &#39;1&#39; {
			//fmt.Println(bitString, i)
			buff.WriteString(fmt.Sprintf(&quot;%d&quot;, i))
		}
		if (i+1 &lt; len(cpu_ids_b)) &amp;&amp; (runeValue == &#39;1&#39;) {
			//fmt.Println(bitString)
			buff.WriteString(string(&quot;,&quot;))
		}

	}
	cpuIds := buff.String()
	// remove last comma
	cpuIds = cpuIds[:len(cpuIds)-1]
	//fmt.Println(cpuIds)
	return cpuIds
}

Returns:

> "0,2,24"

答案1

得分: 3

你正在做的事情实际上是从左到右输出二进制表示中"1"的索引,并从左侧开始计数索引(不寻常)。

你可以使用位掩码和位运算符实现相同的功能,而无需将其转换为二进制字符串。我会返回索引的切片,而不是格式化的字符串,这样更容易处理。

要测试最低(最右边)的位是否为1,可以使用x&0x01 == 1,要将一个整数按位右移:x >>= 1。移位后,最右边的位"消失",之前的第二位变为第一位,因此可以使用相同的逻辑再次进行测试。可以循环直到数字大于0(这意味着它仍然有1位)。

请参阅此问题以获取更多位运算的示例:https://stackoverflow.com/questions/28432398/difference-between-some-operators-golang/28433370#28433370

当然,如果我们测试最右边的位并向右移位,我们会得到_相反顺序_的位(与您想要的相比),并且索引是从右边计数的,因此在返回结果之前我们必须进行修正。

因此,解决方案如下:

func getCpuIds(cpuMap string) (r []int) {
	ci, err := strconv.ParseInt(cpuMap, 0, 64)
	if err != nil {
		panic(err)
	}

	count := 0
	for ; ci > 0; count, ci = count+1, ci>>1 {
		if ci&0x01 == 1 {
			r = append(r, count)
		}
	}

	// 索引是从右边计数的,进行修正:
	for i, v := range r {
		r[i] = count - v - 1
	}
	// 结果是相反顺序的:
	for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
		r[i], r[j] = r[j], r[i]
	}

	return
}

输出(在Go Playground上尝试):

[0 2 24]

如果由于某种原因你需要将结果作为逗号分隔的string,可以按如下方式获取:

buf := &bytes.Buffer{}
for i, v := range cpuIds {
	if i > 0 {
		buf.WriteString(",")
	}
	buf.WriteString(strconv.Itoa(v))
}
cpuIdsStr := buf.String()
fmt.Println(cpuIdsStr)

输出(在Go Playground上尝试):

0,2,24
英文:

What you're doing is essentially outputting the indices of the &quot;1&quot;'s in the binary representation from left-to-right, and starting index counting from the left (unusal).

You can achieve the same using bitmasks and bitwise operators, without converting it to a binary string. And I would return a slice of indices instead of its formatted string, easier to work with.

To test if the lowest (rightmost) bit is 1, you can do it like x&amp;0x01 == 1, and to shift a whole number bitwise to the right: x &gt;&gt;= 1. After a shift, the rightmost bit "disappears", and the previously 2nd bit becomes the 1st, so you can test again with the same logic. You may loop until the number is greater than 0 (which means it sill has 1-bits).

See this question for more examples of bitwise operations: https://stackoverflow.com/questions/28432398/difference-between-some-operators-golang/28433370#28433370

Of course if we test the rightmost bit and shift right, we get the bits (indices) in reverse order (compared to what you want), and the indices are counted from right, so we have to correct this before returning the result.

So the solution looks like this:

func getCpuIds(cpuMap string) (r []int) {
	ci, err := strconv.ParseInt(cpuMap, 0, 64)
	if err != nil {
		panic(err)
	}

	count := 0
	for ; ci &gt; 0; count, ci = count+1, ci&gt;&gt;1 {
		if ci&amp;0x01 == 1 {
			r = append(r, count)
		}
	}

	// Indices are from the right, correct it:
	for i, v := range r {
		r[i] = count - v - 1
	}
	// Result is in reverse order:
	for i, j := 0, len(r)-1; i &lt; j; i, j = i+1, j-1 {
		r[i], r[j] = r[j], r[i]
	}

	return
}

Output (try it on the Go Playground):

[0 2 24]

If for some reason you need the result as a comma separated string, this is how you can obtain that:

buf := &amp;bytes.Buffer{}
for i, v := range cpuIds {
	if i &gt; 0 {
		buf.WriteString(&quot;,&quot;)
	}
	buf.WriteString(strconv.Itoa(v))
}
cpuIdsStr := buf.String()
fmt.Println(cpuIdsStr)

Output (try it on the Go Playground):

0,2,24

huangapple
  • 本文由 发表于 2016年10月25日 16:50:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/40235464.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定