Multithreading 如何在多任务环境中测量多线程进程时间?

Multithreading 如何在多任务环境中测量多线程进程时间?,multithreading,language-agnostic,multicore,time-measurement,Multithreading,Language Agnostic,Multicore,Time Measurement,由于我正在(抢占式)多任务、多核环境中运行多线程程序的性能评估测试,因此进程可以定期交换。我想计算延迟,即仅计算进程处于活动状态时的持续时间。这将允许我推断在非多任务环境下的性能如何,即只有一个程序在运行(大部分时间)或在不同的工作负载上 通常测量两种时间: 挂钟时间(即进程启动后的时间),但这包括进程被调出的时间 处理器时间(即所有线程使用的CPU时间的总和),但这对计算进程的延迟不有用 我相信我需要的是单个线程的makespan时间,由于线程之间的任务依赖结构,这可能不同于任何线程使用的

由于我正在(抢占式)多任务、多核环境中运行多线程程序的性能评估测试,因此进程可以定期交换。我想计算延迟,即仅计算进程处于活动状态时的持续时间。这将允许我推断在非多任务环境下的性能如何,即只有一个程序在运行(大部分时间)或在不同的工作负载上

通常测量两种时间:

  • 挂钟时间(即进程启动后的时间),但这包括进程被调出的时间
  • 处理器时间(即所有线程使用的CPU时间的总和),但这对计算进程的延迟不有用
我相信我需要的是单个线程的makespan时间,由于线程之间的任务依赖结构,这可能不同于任何线程使用的最大CPU时间。例如,在一个有两个线程的进程中,线程1在运行时间的前三分之二(对于CPU时间t)中被重载,而线程2在进程运行时间的后三分之二(同样,对于CPU时间t)中被重载。在这种情况下:

  • 挂钟时间将返回3t/2+上下文切换时间+其间其他进程使用的时间
  • 所有线程的最大CPU时间将返回一个接近t的值,并且
  • 总CPU时间接近2t
  • 我希望收到的度量输出是makespan,即3t/2
此外,多线程本身带来了不确定性。这个问题可能需要多次运行测试并总结结果

此外,延迟还取决于操作系统如何调度线程;如果进程中的一些线程等待CPU,而另一些线程运行,事情就会变得更加复杂。但是让我们忘记这一点

有没有一种有效的方法来计算/近似这个最大完工时间?为了提供代码示例,请使用任何编程语言,但最好在Linux上使用C或C++。 PS:我理解最大完工时间的定义不同于调度问题中使用的定义。调度问题中使用的定义类似于挂钟时间

问题的重新表述 我已经编写了一个多线程应用程序,它在我的K-core机器上执行需要X秒

我如何估计程序在单核计算机上运行需要多长时间

经验性 显而易见的解决方案是让一台只有一个内核的计算机运行应用程序,并根据需要使用挂钟时间和/或CPU时间

…哦,等等,你的电脑已经有一个核心了(它也有一些其他的,但我们不需要使用它们)

如何做到这一点将取决于操作系统,但我从谷歌找到的第一个结果之一解释了WindowsXP和Vista的几种方法

接下来你可以:

  • 将应用程序的进程分配给单个核心的关联。(您也可以在代码中执行此操作)
  • 启动操作系统时,只需知道其中一个核心。(然后再切换回来)
独立并行 从分析角度估计这一点需要了解有关程序、并行方法等的知识

作为一个简单的例子,假设我编写了一个多线程程序来计算pi的第100亿位小数和e的第100亿位小数

我的代码如下所示:

public static int main()
{
    Task t1 = new Task( calculatePiDigit );
    Task t2 = new Task( calculateEDigit );
    t1.Start();
    t2.Start();
    Task.waitall( t1, t2 );
}
“先发生后发生”图如下所示:

public static int main()
{
    Task t1 = new Task( calculatePiDigit );
    Task t2 = new Task( calculateEDigit );
    t1.Start();
    t2.Start();
    Task.waitall( t1, t2 );
}

显然,这些是独立的

在这种情况下

  • 时间自动计算epidigit()
  • 时间会自动计算出数字()
  • 把时间加在一起
二级管道 当任务不是独立的时,您将无法将各个时间相加

在下一个示例中,我创建了一个多线程应用程序:拍摄10幅图像,将其转换为灰度,然后运行线条检测算法。由于某些外部原因,不允许对每个图像进行无序处理。因此,我创建了一个管道模式

我的代码如下所示:

ConcurrentQueue<Image> originalImages = new ConcurrentQueue<Image>();
ConcurrentQueue<Image> grayscaledImages = new ConcurrentQueue<Image>();
ConcurrentQueue<Image> completedImages = new ConcurrentQueue<Image>();

public static int main()
{
     PipeLineStage p1 = new PipeLineStage(originalImages, grayScale, grayscaledImages);
     PipeLineStage p2 = new PipeLineStage(grayscaledImages, lineDetect, completedImages);

     p1.Start();
     p2.Start();

     originalImages.add( image1 );
     originalImages.add( image2 );
     //... 
     originalImages.add( image10 );

     originalImages.add( CancellationToken );

     Task.WaitAll( p1, p2 );
}
ConcurrentQueue originalImages=新的ConcurrentQueue();
ConcurrentQueue GrayscaleImage=新ConcurrentQueue();
ConcurrentQueue completedImages=新建ConcurrentQueue();
公共静态int main()
{
PipeLineStage p1=新的PipeLineStage(原始图像、灰度、灰度图像);
PipeLineStage p2=新的PipeLineStage(灰度图像、线条检测、完成图像);
p1.开始();
p2.Start();
原始图像。添加(图像1);
原始图像。添加(图像2);
//... 
原始图像。添加(图像10);
添加(取消令牌);
Task.WaitAll(p1,p2);
}
以数据为中心发生在图形之前:

如果该程序最初设计为一个顺序程序,出于缓存原因,在移动到下一个图像之前,一次获取一个图像并将其移动到“已完成”将更有效

不管怎样,我们知道GrayScale()将被调用10次,LineDetection()将被调用10次,所以我们可以分别计时,然后将它们乘以10

但推送/弹出/轮询ConcurrentQueue的成本如何

假设图像很大,那么时间可以忽略不计

如果有数百万个小映像,每个阶段都有许多使用者,那么当程序按顺序运行时,您可能会发现等待锁、互斥锁等的开销非常小(假设在关键部分执行的工作量很小,例如在并发队列内)

语境转换的成本? 看看这个问题:

基本上,您将在多核环境和单核环境中使用上下文切换