parallel-processing - 获取进程/线程的上下文切换次数

标签 parallel-processing context-switch

出于好奇,我想知道我的程序被操作系统切换了多少次上下文。就像所有寄存器都被保存并且控制权被传递给另一个进程或线程一样,然后一段时间后一切都恢复了,我们继续,因为它从未发生过。

系统是否在某处维护这样的数字,或者是否存在某种黑客行为或其他什么?

我特别喜欢 Linux,但我对其他系统也很感兴趣。

最佳答案

好吧,让我们来看看这个案例。 Linux类型的O/S系统地保存这些细节,并且可以使用Python的舒适性,既可以检查状态,也可以轻松设计一个监控系统,可以报告任何过多的情况(前者与出于好奇的情况非常匹配) ,后者对于系统工作的任何返工/重用非常方便):


两者的“监控”示例{ volunteer |非自愿}-Ctx 切换:

Python 在这里既起到教育作用,又方便和舒适地进一步扩展功能范围:

分配了 signal.signal( signal.SIGALRM, SIG_ALRM_handler_A ) 和时间后,系统准备好报告自愿和非自愿(强制)上下文切换,其中“FAT”-使用了阻塞计算,由于历史原因,它求助于非 GIL Numpy/C/FORTRAN 代码,因此会受到非自愿 CtxSwitched 情况的干扰,如下所示:

len(str([np.math.factorial(2**f) for f in range(20)][-1]))

但通过使用基本上任何其他 PID 数字,这种微不足道的监视机制可以用于任何其他目的:

########################################################################
### SIGALRM_handler_          
###

import psutil, resource, os, time
        
SIG_ALRM_last_ctx_switch_VOLUNTARY = -1
SIG_ALRM_last_ctx_switch_FORCED    = -1

def SIG_ALRM_handler_A( aSigNUM, aFrame ):                              # SIG_ALRM fired evenly even during [ np.math.factorial( 2**f ) for f in range( 20 ) ] C-based processing =======================================
    # onEntry_ROTATE_SigHandlers() -- MAY set another sub-sampled SIG_ALRM_handler_B() ... { last: 0, 0: handler_A, 1: handler_B, 2: handler_C }
    #
    # onEntry_SEQ of calls of regular, hierarchically timed MONITORS ( just the SNAPSHOT-DATA ACQUISITION Code-SPRINTs, handle later due to possible TimeDOMAIN overlaps )
    # 
    #
    # print( time.ctime() )
    # print( formatExtMemoryUsed( getExtMemoryUsed() ) )
    # print( 60 * "=", psutil.Process( os.getpid() ).num_ctx_switches(), "~~~", aProcess.cpu_percent( interval = 0 ) )
    #                                        ???                        # WHY CPU 0.0%
    aProcess         =   psutil.Process( os.getpid() )
    aProcessCpuPCT   =         aProcess.cpu_percent( interval = 0 )     # EVENLY-TIME-STEPPED
    aCtxSwitchNUMs   =         aProcess.num_ctx_switches()              # THIS PROCESS ( may inspect other per-incident later ... on anomaly )
    
    aVolCtxSwitchCNT = aCtxSwitchNUMs.voluntary
    aForcedSwitchCNT = aCtxSwitchNUMs.involuntary
    
    global SIG_ALRM_last_ctx_switch_VOLUNTARY
    global SIG_ALRM_last_ctx_switch_FORCED
    
    if (     SIG_ALRM_last_ctx_switch_VOLUNTARY != -1 ):                # .INIT VALUE STILL UNCHANGED
        #----------
        # .ON_TICK: must process delta(s)
        if ( SIG_ALRM_last_ctx_switch_VOLUNTARY == aVolCtxSwitchCNT ):
            #
            # AN INDIRECT INDICATION OF A LONG-RUNNING WORKLOAD OUTSIDE GIL-STEPPING ( regex / C-lib / FORTRAN / numpy-block et al )
            #                                                                                 |||||              vvv
            # SIG_:  Wed Oct 19 12:24:32 2016 ------------------------------ pctxsw(voluntary=48714, involuntary=315)  ~~~  0.0
            # SIG_:  Wed Oct 19 12:24:37 2016 ------------------------------ pctxsw(voluntary=48714, involuntary=323)  ~~~  0.0
            # SIG_:  Wed Oct 19 12:24:42 2016 ------------------------------ pctxsw(voluntary=48714, involuntary=331)  ~~~  0.0
            # SIG_:  Wed Oct 19 12:24:47 2016 ------------------------------ pctxsw(voluntary=48714, involuntary=338)  ~~~  0.0
            # SIG_:  Wed Oct 19 12:24:52 2016 ------------------------------ pctxsw(voluntary=48714, involuntary=346)  ~~~  0.0
            # SIG_:  Wed Oct 19 12:24:57 2016 ------------------------------ pctxsw(voluntary=48714, involuntary=353)  ~~~  0.0
            # ...                                                                             |||||              ^^^
            # 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000]
            # >>>                                                                             |||||              |||
            #                                                                                 vvvvv              |||
            # SIG_:  Wed Oct 19 12:26:17 2016 ------------------------------ pctxsw(voluntary=49983, involuntary=502)  ~~~  0.0
            # SIG_:  Wed Oct 19 12:26:22 2016 ------------------------------ pctxsw(voluntary=49984, involuntary=502)  ~~~  0.0
            # SIG_:  Wed Oct 19 12:26:27 2016 ------------------------------ pctxsw(voluntary=49985, involuntary=502)  ~~~  0.0
            # SIG_:  Wed Oct 19 12:26:32 2016 ------------------------------ pctxsw(voluntary=49986, involuntary=502)  ~~~  0.0
            # SIG_:  Wed Oct 19 12:26:37 2016 ------------------------------ pctxsw(voluntary=49987, involuntary=502)  ~~~  0.0
            # SIG_:  Wed Oct 19 12:26:42 2016 ------------------------------ pctxsw(voluntary=49988, involuntary=502)  ~~~  0.0
            
            #rint(   "SIG_ALRM_handler_A(): A SUSPECT CPU-LOAD:: ", time.ctime(), 10 * "-",  aProcess.num_ctx_switches(), "{0: > 8.2f} CPU_CORE_LOAD [%]".format( aProcessCpuPCT ), " INSPECT processes ... ev. add a Stateful-self-Introspection" )
            print(   "SIG_ALRM_handler_A(): A SUSPECT CPU-LOAD:: ", time.ctime(), 10 * "-",  aProcess.num_ctx_switches(), "{0:_>60s}".format( str( aProcess.threads() ) ), " INSPECT processes ... ev. add a Stateful-self-Introspection" )
            #rint(   "SIG_ALRM_handler_A(): A SUSPECT CPU-LOAD:: ", str( resource.getrusage( resource.RUSAGE_SELF ) )[22:] )
    else:
        #----------
        # .ON_INIT: may report .INIT()
        #rint(   "SIG_ALRM_handler_A(): A SUSPECT CPU-LOAD:: ", time.ctime(), ...
        print(   "SIG_ALRM_handler_A(): activated            ", time.ctime(), 30 * "-",  aProcess.num_ctx_switches() )
    
    ##########
    # FINALLY:
    
    SIG_ALRM_last_ctx_switch_VOLUNTARY = aVolCtxSwitchCNT               # .STO ACTUALs
    SIG_ALRM_last_ctx_switch_FORCED    = aForcedSwitchCNT               # .STO ACTUALs
    
    #rint(   "SIG_: ", time.ctime(), 30 * "-",  aProcess.num_ctx_switches(), " ~~~ ", aProcess.cpu_percent( interval = 0 ), " % -?- ", aProcess.threads() )

#____________________________________________________________________
# SIG_ALRM_handler_A( aSigNUM, aFrame ):                      DEFINED
#####################################################################

##########
# FINALLY:
# 
# > signal.signal(    signal.SIGALRM, SIG_ALRM_handler_A )          # .ASSOC { SIGALRM: thisHandler }
# > signal.setitimer( signal.ITIMER_REAL, 10, 5 )                   # .SET   @5 [sec] interval, after first run, starting after 10[sec] initial-delay
# > signal.setitimer( signal.ITIMER_REAL,  0, 5 )                   # .UNSET
# > SIG_ALRM_last_ctx_switch_VOLUNTARY = -1                         # .RESET .INIT() the global { signalling | state }-variable
# > len(str([np.math.factorial(2**f) for f in range(20)][-1]))      # .RUN   A "FAT"-BLOCKING CHUNK OF A regex/numpy/C/FORTRAN-calculus
    

还有线程级 CtxSwitch 详细信息

虽然没有详细阐述到类似的深度,但与上述相同适用于:

>>> psutil.Process( 18263 ).cpu_percent()                           0.0
>>> psutil.Process( 18263 ).ppid()                                  18054

>>> psutil.Process( 18054 ).cpu_percent()                           0.0
=== ( 18054 ).threads(): [ 17679, 17680, 17681, 18054, 18265, 18266, 18267, ]
                                                                                                ==4 -------------vvv-------------------=4--------------vvvv-------------------=4--------------vvv
>>> [ psutil.Process( p ).num_ctx_switches() for p in ( 18259, 18260, 18261 ) ] [pctxsw(voluntary=4, involuntary=267), pctxsw(voluntary=4, involuntary=1909), pctxsw(voluntary=4, involuntary=444)]
>>> [ psutil.Process( p ).num_ctx_switches() for p in ( 18259, 18260, 18261 ) ] [pctxsw(voluntary=4, involuntary=273), pctxsw(voluntary=4, involuntary=1915), pctxsw(voluntary=4, involuntary=445)]
>>> [ psutil.Process( p ).num_ctx_switches() for p in ( 18259, 18260, 18261 ) ] [pctxsw(voluntary=4, involuntary=275), pctxsw(voluntary=4, involuntary=1917), pctxsw(voluntary=4, involuntary=445)]

关于parallel-processing - 获取进程/线程的上下文切换次数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48048784/

相关文章:

c++ - 如何使 perf_event_open() 中的 PERF_COUNT_SW_CONTEXT_SWITCHES 配置起作用?

windows - 在 Windows 中强制上下文切换

C#:在 ASP.NET 中向 Parallel.ForEach() 添加上下文

multithreading - 通过 Akka 应用程序中的上下文切换导致 CPU 使用率高

java - 并行深度优先搜索

c - 如何在 OS X 上编译 OpenMP 和 MPI 混合 C 程序

c - kernel/sched.c/context_switch() 是否保证每次进程切换时都会被调用?

c - 如何更精确地衡量上下文切换的成本

parallel-processing - GNU parallel 有两个参数

c# - 如何等待后台 worker 完成处理?