首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >bash打印线程亲和性解析

bash打印线程亲和性解析
EN

Stack Overflow用户
提问于 2014-08-26 21:51:42
回答 3查看 1.1K关注 0票数 3

我有以下功能:

代码语言:javascript
复制
affinity ()
{
     local tid TASKSET CORE;
     for tid in $(ps -efL | awk '/foo.*d/ {print $4}');
     do
         TASKSET=($( taskset -pc $tid | awk -F"[' ]" '{print $2,$NF}' ));
         CORE[${TASKSET[1]}]="${CORE["${TASKSET[1]}"]} ${TASKSET[0]}";
     done;
     for i in "${!CORE[@]}";
     do
         printf "Core %-2s:%2s\n" "$i" "${CORE[$i]}";
     done
}

它通常会打印如下内容:

代码语言:javascript
复制
$ affinity
Core 5 : 2545
Core 9 : 14621 14640
Core 10: 1056
Core 11: 1081

我注意到它工作得很好,直到我遇到一个服务器,它的每个线程有超过1个CPU由taskset返回,这破坏了这个脚本/函数:

代码语言:javascript
复制
$ taskset -pc 14471
pid 14471's current affinity list: 0-3
$ taskset -pc 14621
pid 14621's current affinity list: 4,5
$ affinity
-bash: CORE: bad array subscript
-bash: CORE[${TASKSET[1]}]: bad array subscript

你建议我如何改进这个脚本来处理这种情况?

更多详细信息:

代码语言:javascript
复制
$ taskset
taskset (util-linux-ng 2.17.2)
usage: taskset [options] [mask | cpu-list] [pid | cmd [args...]]
set or get the affinity of a process

  -p, --pid                  operate on existing given pid
  -c, --cpu-list             display and specify cpus in list format
  -h, --help                 display this help
  -V, --version              output version information

The default behavior is to run a new command:
  taskset 03 sshd -b 1024
You can retrieve the mask of an existing task:
  taskset -p 700
Or set it:
  taskset -p 03 700
List format uses a comma-separated list instead of a mask:
  taskset -pc 0,3,7-11 700
Ranges in list format can take a stride argument:
  e.g. 0-31:2 is equivalent to mask 0x55555555

至于linux的类型,它是一个自定义的dist:

代码语言:javascript
复制
$ uname -a
Linux MySrv 2.6.32-358.23.2.61.foo.x86_64 #1 SMP PREEMPT Wed Jun 18 06:59:23 CDT 2014 x86_64 x86_64 x86_64 GNU/Linux

谢谢

解决方案:在汇总了下面所有优秀的线索和答案后,我得出了以下结论:这也处理了初始问题遗漏的0,1,4-6输出。

代码语言:javascript
复制
affinity ()
{
    local ii tid CORE CORES_STR CORES_ARR;
    for tid in $(ps -Leo tid,command | awk '/[f]oo.*d/ {print $1}');
    do
        CORES_STR=($(taskset -pc $tid | awk '{gsub(/,/," ",$NF);print $NF}'));
        CORES_ARR=();
        for ii in ${CORES_STR[@]};
        do
            [[ $ii =~ - ]] && CORES_ARR+=($(eval echo {${ii/-/..}})) || CORES_ARR+=($ii);
        done;
        for ii in ${CORES_ARR[@]};
        do
            CORE[${ii}]="${CORE[${ii}]} $tid";
        done;
    done;
    for ii in "${!CORE[@]}";
    do
        printf "Core %-2d:%2s\n" "$ii" "${CORE[$ii]}";
    done
}
EN

回答 3

Stack Overflow用户

发布于 2014-08-27 00:28:13

在您的函数中包含一个范围解析器,以识别某个范围内的所有核心。下面是一个获取某个范围内数组中所有核心的示例。然后循环该进程以将该进程添加到所有内核。

代码语言:javascript
复制
#!/bin/bash

range=0,3,7-11
cores=()
while read part; do
    if [[ $part =~ - ]]; then
        cores+=($(seq ${part/-/ }))
    else
        cores+=($part)
    fi
done < <( echo $range | tr ',' '\n' )

for core in ${cores[*]}; do
    echo $core
done

从@bishop得到提示,这可以通过eval和bash扩展得到一定程度的简化,例如:

代码语言:javascript
复制
range=0,3,7-11
cores=()
IFS=',' read -ra parts <<<$range
for part in "${parts[@]}"; do
    [[ $part =~ - ]] && cores+=($(eval echo {${part/-/..}})) || cores+=($part)
done
票数 2
EN

Stack Overflow用户

发布于 2014-08-27 01:56:06

代码语言:javascript
复制
$ tasklist -pc 2420 14370 17654
pid 2420's current affinity list: 0-1
pid 14370's current affinity list: 0,2-4
pid 17654's current affinity list: 2-5,9,11,13-15

$ affinity_for_tid 2420 14370 17654
Core 0 : 2420 14370
Core 1 : 2420
Core 2 : 17654 14370
Core 3 : 17654 14370
Core 4 : 17654 14370
Core 5 : 17654
Core 9 : 17654
Core 11: 17654
Core 13: 17654
Core 14: 17654
Core 15: 17654

function affinity_for_tid() {
    declare -A map

    # give me every line from tasklist
    while read -r line; do
        # break it up into an array
        # array[0] === the tid, as a number; array[1] === the stripe
        IFS=' '
        local array=( $(awk '{print strtonum($2) " " $6}' <<<"$line") )

        # convert the stripe of form like "0,2-4" to "{0,{2..4}}"
        # so that shell brace expansion can deal with it
        local parts=(), stripe=()
        IFS=',' read -ra parts <<<"${array[1]}"
        for part in "${parts[@]}"; do
            if [[ $part == *-* ]]; then
                stripe+=("{${part//-/..}}")
            else
                stripe+=("$part")
            fi
        done

        # expand
        local expansion=$(IFS=,; echo "${stripe[*]}")
        if [[ $expansion == *,* ]]; then
            expansion="{$expansion}"
        fi
        local expanded=$(eval echo "${expansion}")

        # put the expansion into the map
        for cpu in $expanded; do
            map[$cpu]="${map[$cpu]} ${array[0]}"
        done
    done < <(tasklist -pc "@")

    # output as desired
    for cpu in "${!map[@]}"; do
        printf 'Core %-2d:%s\n' "$cpu" "${map[$cpu]}"
    done | sort -t ' ' -k 2n
}

从本质上讲,这会将taskset的条带化输出转换为bash括号扩展。所以"0,2-4“变成了"{0,{2..4}}”。剩下的只是用来移动数据的胶水,这可能是可以简化的。

票数 1
EN

Stack Overflow用户

发布于 2014-08-27 00:52:18

我可以使用范围解析器扩展我的代码。(在看到+zerodiff的答案之前:)

代码语言:javascript
复制
affinity ()
{
    CORE=()
    for tid in $(ps -efL | awk '/[f]oo.*d/ {print $4}');
    do
        CPU=$(taskset -pc $tid | awk -F"[' ]" '{print $NF}' );
        if [[ $CPU =~ "-" ]]; then
            for ii in $(seq ${CPU/-/ });
            do
                CORE[${ii}]="${CORE[${ii}]} $tid";
            done;
        else
            if [[ $CPU =~ "," ]]; then
                for ii in ${CPU/,/ };
                do
                    CORE[${ii}]="${CORE[${ii}]} $tid";
                done;
            else
                CORE[${CPU}]="${CORE[${CPU}]} $tid";
            fi;
        fi;
    done;
    for i in "${!CORE[@]}";
    do
        printf "Core %-2s:%2s\n" "$i" "${CORE[$i]}";
    done
}

+zerodiff的代码看起来更干净。明天我将尝试合并它:)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25507535

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档