2016-11-23 39 views
3

我正在研究如何在专用CPU上运行进程以避免上下文切换。在我的Ubuntu上,我使用内核参数“isolcpus = 3,7”和“irqaffinity = 0-2,4-6”隔离了两个CPU。我相信这是正确的考虑到:单独在CPU上启动的进程无法避免上下文切换

$ cat /proc/cmdline 
BOOT_IMAGE=/boot/vmlinuz-4.8.0-27-generic root=UUID=58c66f12-0588-442b-9bb8-1d2dd833efe2 ro quiet splash isolcpus=3,7 irqaffinity=0-2,4-6 vt.handoff=7 

重新启动后,我可以检查一切正常如预期。在第一个控制台我跑

$ stress -c 24 
stress: info: [31717] dispatching hogs: 24 cpu, 0 io, 0 vm, 0 hdd 

并在第二之一,采用“顶”我可以检查我的CPU的使用情况:

top - 18:39:07 up 2 days, 20:48, 18 users, load average: 23,15, 10,46, 4,53 
Tasks: 457 total, 26 running, 431 sleeping, 0 stopped, 0 zombie 
%Cpu0 :100,0 us, 0,0 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st 
%Cpu1 : 98,7 us, 1,3 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st 
%Cpu2 : 99,3 us, 0,7 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st 
%Cpu3 : 0,0 us, 0,0 sy, 0,0 ni,100,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st 
%Cpu4 : 95,7 us, 4,3 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st 
%Cpu5 : 98,0 us, 2,0 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st 
%Cpu6 : 98,7 us, 1,3 sy, 0,0 ni, 0,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st 
%Cpu7 : 0,0 us, 0,0 sy, 0,0 ni,100,0 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st 
KiB Mem : 7855176 total, 385736 free, 5891280 used, 1578160 buff/cache 
KiB Swap: 15624188 total, 10414520 free, 5209668 used. 626872 avail Mem 

CPU的3和7是免费的,而6点其他的都很忙。精细。


对于我试验的其余时间,我会用一个小应用程序,确实几乎是纯加工

  1. 它同样采用了尺寸
  2. 的两个int缓冲区它读取一个接 - 第一个缓冲区的所有值
    • 每个值都是第二个缓冲区中的随机索引
  3. 它的索引在所述第二缓冲器读出的值
  4. 它总结从第二缓冲器
  5. 它全部为越来越大
  6. 前面的步骤最后,我打印所采取的所有值自愿和非自愿CPU上下文切换数

我现在正在研究我的应用程序,当我启动它:

  1. 分离的CPU

我通过下面的命令行做它非隔离CPU

  • 上:

    $ ./TestCpuset    ### launch on any non-isolated CPU 
    $ taskset -c 7 ./TestCpuset ### launch on isolated CPU 7 
    

    当任何CPU上启动,上下文的数量切换从变化20 to ... thousands

    在隔离CPU上启动时,即使并行启动“压力-c 24”,上下文切换的数量也几乎不变(介于10和20之间)。 (看起来很正常)

    但是我的问题是:为什么不是0绝对0?当一个进程完成交换时,它是为了用另一个进程来替换它?但在我的情况下,没有其他过程可以替代!

    我有一个假说是,“isolcpus”选项,将隔离 CPU形成任何处理(除非该进程的CPU亲和力是 给出,比如什么与“taskset的”一起做),但不能从内核任务。 不过,我没有发现任何文档它

    我希望得到任何帮助,以达到0上下文切换

    FYI,这个问题被关闭,另外一个我以前打开:Cannot allocate exclusively a CPU for my process

    这里是我使用的程序代码:

    #include <limits.h> 
    #include <iostream> 
    #include <unistd.h> 
    #include <sys/time.h> 
    #include <sys/resource.h> 
    
    const unsigned int BUFFER_SIZE = 4096; 
    
    using namespace std; 
    
    
    class TimedSumComputer 
    { 
    
    public: 
        TimedSumComputer() : 
        sum(0), 
        bufferSize(0), 
        valueBuffer(0), 
        indexBuffer(0) 
        {} 
    
    
    public: 
        virtual ~TimedSumComputer() 
        { 
        resetBuffers(); 
        } 
    
    
    public: 
        void init(unsigned int bufferSize) 
        { 
        this->bufferSize = bufferSize; 
        resetBuffers(); 
        initValueBuffer(); 
        initIndexBuffer(); 
        } 
    
    
    private: 
        void resetBuffers() 
        { 
        delete [] valueBuffer; 
        delete [] indexBuffer; 
        valueBuffer = 0; 
        indexBuffer = 0; 
        } 
    
    
        void initValueBuffer() 
        { 
        valueBuffer = new unsigned int[bufferSize]; 
        for (unsigned int i = 0 ; i < bufferSize ; i++) 
        { 
         valueBuffer[i] = randomUint(); 
        } 
        } 
    
    
        static unsigned int randomUint() 
        { 
        int value = rand() % UINT_MAX; 
        return value; 
        } 
    
    
    protected: 
        void initIndexBuffer() 
        { 
        indexBuffer = new unsigned int[bufferSize]; 
        for (unsigned int i = 0 ; i < bufferSize ; i++) 
        { 
         indexBuffer[i] = rand() % bufferSize; 
        } 
        } 
    
    
    public: 
        unsigned int getSum() const 
        { 
        return sum; 
        } 
    
    
        unsigned int computeTimeInMicroSeconds() 
        { 
        struct timeval startTime, endTime; 
    
        gettimeofday(&startTime, NULL); 
        unsigned int sum = computeSum(); 
        gettimeofday(&endTime, NULL); 
    
        return ((endTime.tv_sec - startTime.tv_sec) * 1000 * 1000) + (endTime.tv_usec - startTime.tv_usec); 
        } 
    
    
        unsigned int computeSum() 
        { 
        sum = 0; 
    
        for (unsigned int i = 0 ; i < bufferSize ; i++) 
        { 
         unsigned int index = indexBuffer[i]; 
         sum += valueBuffer[index]; 
        } 
    
        return sum; 
        } 
    
    
    protected: 
        unsigned int sum; 
        unsigned int bufferSize; 
        unsigned int * valueBuffer; 
        unsigned int * indexBuffer; 
    
    }; 
    
    
    
    unsigned int runTestForBufferSize(TimedSumComputer & timedComputer, unsigned int bufferSize) 
    { 
        timedComputer.init(bufferSize); 
    
        unsigned int timeInMicroSec = timedComputer.computeTimeInMicroSeconds(); 
        cout << "bufferSize = " << bufferSize << " - time (in micro-sec) = " << timeInMicroSec << endl; 
        return timedComputer.getSum(); 
    } 
    
    
    
    void runTest(TimedSumComputer & timedComputer) 
    { 
        unsigned int result = 0; 
    
        for (unsigned int i = 1 ; i < 10 ; i++) 
        { 
        result += runTestForBufferSize(timedComputer, BUFFER_SIZE * i); 
        } 
    
        unsigned int factor = 1; 
        for (unsigned int i = 2 ; i <= 6 ; i++) 
        { 
        factor *= 10; 
        result += runTestForBufferSize(timedComputer, BUFFER_SIZE * factor); 
        } 
    
        cout << "result = " << result << endl; 
    } 
    
    
    
    void printPid() 
    { 
        cout << "###############################" << endl; 
        cout << "Pid = " << getpid() << endl; 
        cout << "###############################" << endl; 
    } 
    
    
    
    void printNbContextSwitch() 
    { 
        struct rusage usage; 
        getrusage(RUSAGE_THREAD, &usage); 
        cout << "Number of voluntary context switch: " << usage.ru_nvcsw << endl; 
        cout << "Number of involuntary context switch: " << usage.ru_nivcsw << endl; 
    } 
    
    
    
    int main() 
    { 
        printPid(); 
    
        TimedSumComputer timedComputer; 
        runTest(timedComputer); 
    
        printNbContextSwitch(); 
    
        return 0; 
    } 
    
  • +0

    您的数据来自哪里?你使用的内存是否比你的机器物理上有更多?我期望在等待分页操作时暂停进程时,访问内存的分页部分将强制增加上下文切换计数器。 –

    +0

    我正在使用的程序只是一个简单的测试程序,它只访问用随机值初始化的缓冲区(参考rand()函数) –

    回答

    1

    潜在的任何系统调用ç应该涉及上下文切换。当你访问分页出内存时,它也可能增加上下文切换次数。要达到0上下文切换,您需要强制内核来保持程序使用的所有内存映射到其地址空间,并且您需要确保您调用的任何系统调用都不需要上下文切换。我相信它可能在RT补丁的内核上,但在标准的发行版内核上很难实现。

    +0

    非常感谢您的回答。我几乎可以肯定,在我的简单例子中(其代码在上面提供),我的程序使用的所有内存都保持映射=>没有页面。 –

    +0

    此外,我自愿地几乎没有系统调用,除了: 1)新增/删除 2)getrusage()??? 3)cout 我可能是错的,但系统调用引起的上下文切换记录在“自愿上下文切换”中,但在我身边,主要问题是“非自愿” –

    1

    今天,我获得了关于我的问题的更多线索 我意识到我必须深入研究内核调度程序中发生了什么。我发现这两个页面:

    我启用调度跟踪,而我的应用程序正在运行这样的:

    # sudo bash 
    # cd /sys/kernel/debug/tracing 
    # echo 1 > options/function-trace ; echo function_graph > current_tracer ; echo 1 > tracing_on ; echo 0 > tracing_max_latency ; taskset -c 7 [path-to-my-program]/TestCpuset ; echo 0 > tracing_on 
    # cat trace 
    

    由于我的计划是在CPU 7启动(taskset -c 7),我必须过滤“跟踪”输出

    # grep " 7)" trace 
    

    然后我就可以搜索的过渡,从一个过程到另一个问题:

    # grep " 7)" trace | grep "=>" 
    ... 
    7) TestCpu-4753 => kworker-5866 
    7) kworker-5866 => TestCpu-4753 
    7) TestCpu-4753 => watchdo-26 
    7) watchdo-26 => TestCpu-4753 
    7) TestCpu-4753 => kworker-5866 
    7) kworker-5866 => TestCpu-4753 
    7) TestCpu-4753 => kworker-5866 
    7) kworker-5866 => TestCpu-4753 
    7) TestCpu-4753 => kworker-5866 
    7) kworker-5866 => TestCpu-4753 
    ... 
    

    宾果!看来,上下文切换,我跟踪被转换为:

    • kworker
    • 看门狗

    我现在必须找到:

    • 什么是完全相同这些进程/线程? (看起来它们是由内核处理的)
    • 我可以避免它们在我的专用CPU上运行吗?

    对于过程,我再次感谢所有帮助:-P

    +0

    我发现这个非常有趣的页面:[避免守护进程运行在专用CPU核心](http://stackoverflow.com/questions/40081780/avoid-daemon-running-in-dedicated-cpu-cores/40082778) –

    +1

    看来,可以禁用看门狗使用Linux内核选项'nowatchdog ' –

    0

    对于那些通过谷歌(像我一样),找到这个的缘故/sys/devices/virtual/workqueue/cpumask控制,内核可排队的作品排队以WORK_CPU_UNBOUND(唐不在乎哪个CPU)。在写这个答案时,它没有被设置为默认操作的掩码。

    一旦我将其更改为不包括我的独立cpus,我看到一个显着更小(但不是零)的上下文切换量到我的关键线程。我认为在我独立的cpus上运行过的作品必须特别要求它,例如使用schedule_on_each_cpu

    相关问题