题 'real','user'和'sys'在time(1)的输出中是什么意思?


$ time foo
real        0m0.003s
user        0m0.000s
sys         0m0.004s
$

“真实”,“用户”和“系统”在时间输出中意味着什么?

在对我的应用进行基准测试时哪一个有意义?


1345
2018-02-17 11:33


起源


我怎样才能访问其中一个?比如只是实时的? - Mojtaba Ahmadi
@ConcernedOfTunbridgeWells - Mojtaba Ahmadi
@Casillass Real - stackoverflow.com/questions/2408981/... - ConcernedOfTunbridgeWells
如果你的程序退出那么快,它们都没有意义,那只是启动开销。如果你想测量整个程序 time,让它做一些至少需要一秒钟的事情。 - Peter Cordes


答案:


Real,User和Sys处理时间统计信息

其中一件事与另一件事情不同。实际是指实际经过的时间; User和Sys指的是使用的CPU时间 只有这个过程。

  • 真实 是挂钟时间 - 从通话开始到结束的时间。这是所有经过的时间,包括其他进程使用的时间片和进程花费的时间(例如,如果它等待I / O完成)。

  • 用户 是用户模式代码(内核之外)花费的CPU时间量  这个过程。这只是执行过程时使用的实际CPU时间。流程花费的其他流程和时间不计入此数字。

  • SYS 是进程内核中花费的CPU时间量。这意味着执行系统调用所花费的CPU时间 在内核中, 而库代码仍然在用户空间中运行。与'user'一样,这只是进程使用的CPU时间。有关内核模式(也称为“管理程序”模式)和系统调用机制的简要说明,请参见下文。

User+Sys 将告诉您进程使用的实际CPU时间。请注意,这是跨所有CPU的,因此如果进程有多个线程(并且此进程在具有多个处理器的计算机上运行),则可能会超过所报告的挂钟时间。 Real (通常发生)。请注意,在输出中这些数字包括 User 和 Sys 所有子进程(及其后代)的时间以及它们可以被收集的时间,例如通过 wait(2) 要么 waitpid(2)虽然底层系统调用会分别返回进程及其子进程的统计信息。

报告统计数据的起源 time (1)

报告的统计数据 time 从各种系统调用中收集。 '用户'和'系统'来自 wait (2) 要么 times (2),取决于特定的系统。 '真实'是从收集的开始和结束时间计算出来的 gettimeofday (2) 呼叫。根据系统的版本,还可以收集各种其他统计信息,例如上下文切换的数量 time

在多处理器计算机上,多线程进程或分叉子进程可能会比CPU总时间小 - 因为不同的线程或进程可能并行运行。此外,报告的时间统计来自不同的来源,因此对于非常短的运行任务记录的时间可能受到舍入误差的影响,如原始海报给出的示例所示。

关于内核与用户模式的简要介绍 

在Unix或任何受保护的内存操作系统上, '内核'或'主管' 模式是指a 特权模式 CPU可以运行。某些可能影响安全性或稳定性的特权操作只能在CPU以此模式运行时才能完成。这些操作不适用于应用程序代码。这种行为的一个例子可能是操纵 MMU 获得对另一个进程的地址空间的访问权限。一般, 用户模式 代码不能这样做(有充分的理由),虽然它可以请求 共享内存 来自内核,哪个 可以 由多个进程读取或写入。在这种情况下,通过安全机制从内核显式请求共享内存,并且两个进程必须显式附加到它才能使用它。

特权模式通常称为“内核”模式,因为内核由在此模式下运行的CPU执行。为了切换到内核模式,你必须发出一个特定的指令(通常称为 陷阱)将CPU切换到以内核模式运行 并从跳转表中保存的特定位置运行代码。  出于安全原因,您无法切换到内核模式并执行任意代码 - 陷阱通过无法写入的地址表进行管理,除非CPU以管理员模式运行。使用显式陷阱编号进行陷阱,并在跳转表中查找地址;内核具有有限数量的受控入口点。

C库中的“系统”调用(特别是手册页第2节中描述的那些)具有用户模式组件,这是您实际从C程序调用的组件。在幕后,他们可能会向内核发出一个或多个系统调用来执行特定服务(如I / O),但它们仍然可以在用户模式下运行代码。如果需要,也可以从任何用户空间代码直接向内核模式发出陷阱,尽管您可能需要编写汇编语言片段来为调用正确设置寄存器。可以找到描述Linux内核提供的系统调用的页面以及设置寄存器的约定 这里。

更多关于'sys'的信息 

您的代码无法通过用户模式执行某些操作 - 例如分配内存或访问硬件(HDD,网络等)。这些都在内核的监督下,只有它才能做到。你做的一些操作(比如 malloc 要么fread/fwrite)将调用这些内核函数,然后将计为'sys'时间。不幸的是,它并不像“每次调用malloc都将计入'sys'时间”那么简单。打电话给 malloc 将自己做一些处理(仍然计入'用户'时间)然后在它可能调用内核中的函数的某个地方(在'sys'时间内计算)。从内核调用返回后,'user'中会有更多时间 malloc 将返回您的代码。至于何时发生切换,以及在内核模式下花费了多少......你不能说。这取决于库的实现。此外,其他看似无辜的功能也可能使用 malloc 等等在后台,然后在'sys'中再次有一些时间。


1613
2018-04-29 05:29



子进程花费的时间是否计入real / sys? - ron
@ron - 根据Linux手册页,它将'c'时间与进程时间聚合在一起,所以我认为确实如此。但是,父时间和子时间可以与时间(2)呼叫分开提供。我想时间(1)的Solaris / SysV版本做了类似的事情。 - ConcernedOfTunbridgeWells
User + Sys允许您测量进程的CPU使用情况。您可以使用它来衡量性能。这对于多线程代码特别有用,其中多个CPU核心可能正在进行计算。 - ConcernedOfTunbridgeWells
尽管如此,运行“\ time <cmd>”很有意思 - 它提供了更多细节:(原谅评论中的格式不佳):$ time ps PID TTY TIME CMD 9437 pts / 19 00:00:00 bash 11459 pts / 19 00:00:00 ps real 0m0.025s user 0m0.004s sys 0m0.018s $ \ time ps PID TTY TIME CMD 9437 pts / 19 00:00:00 bash 11461 pts / 19 00:00:00 time 11462 pts / 19 00:00:00 ps 0.00user 0.01system 0:00.02elapsed 95%CPU(0avgtext + 0avgdata 2160maxresident)k 0inputs + 0outputs(0major + 103minor)pagefaults 0swaps $ - kaiwan
(在上一篇评论中超出了字号):更多细节?使用perf [1],[2]。 [1] perf.wiki.kernel.org/index.php/Main_Page [2] brendangregg.com/perf.html - kaiwan


扩大 接受了答案,我只是想提供另一个原因 real ≠ user + sys

请记住 real 代表实际经过的时间,而 user 和 sys 值表示CPU执行时间。因此,在多核系统上, user 和/或 sys 时间(以及他们的总和)实际上可以 超过 实时。例如,在我正在为类运行的Java应用程序中,我得到以下值:

real    1m47.363s
user    2m41.318s
sys     0m4.013s

214
2017-11-05 04:34



我总是想知道这件事。既然我知道我的程序是单线程的,那么用户和实时之间的区别必须是VM开销,对吗? - Quantum7
不必要; Solaris机器上的Sun JVM以及Mac OS X上的Apple JVM甚至在单线程应用程序中也使用了多个核心。如果你做一个java进程的样本,你会发现像垃圾收集这样的东西在不同的线程上运行(还有一些其他东西,我不记得了我的头脑)。我不知道你是否真的想要称之为“VM开销”。 - lensovet
我想现在投票的数量给了你足够的声望:D。那你觉得怎么样? real 超额 user 和 sys 总计?诸如线程上下文切换的操作系统开销可能是? - Muhammad Gelbana
另一个潜在的问题可能是I / O:如果您的应用程序花费大量时间等待接收文件或流,那么显然实时将大大超过用户/系统时间,因为在等待访问时没有使用CPU时间到一个文件或类似的东西。 - lensovet
@MuhammadGelbana - 如果因任何原因阻止执行应用程序,就会发生这种情况。例如,如果它正在等待I / O,IPC或套接字连接,它将处于空闲状态,在阻塞调用返回之前不会累积CPU时间。 - ConcernedOfTunbridgeWells


Real表示流程的总周转时间; 用户显示用户定义指令的执行时间 和Sys是时候执行系统调用!

实时包括等待时间(I / O的等待时间等)


14
2017-11-24 19:05





真实:从开始到结束运行过程所花费的实际时间,就好像是由带有秒表的人测量的

用户:计算期间所有CPU花费的累计时间

SYS:所有CPU在系统相关任务(如内存分配)期间所花费的累计时间。

请注意,有时user + sys可能比real更大,因为   多个处理器可以并行工作。


6



sys 系统调用(和页面错误处理程序?)花费的CPU时间是多少? - Peter Cordes
real 通常被描述为“挂钟”时间。 - Peter Cordes


热门问题

如何将ISO8601 TimeSpan转换为C#如何停止和恢复Observable.interval发递归是一个如何在数组中找到特定值并返回Fluent Nhibernate使用额外列进行多null类型的参数应该显式地转换为Class []以调用vaphp数组 | landcareweb.com landcareweb.com Toggle navigation 问题 题 php数组 我有以下数组 Array ( [0] => Array ( [id] => 96 [shipping_no] => 212755-1 [part_no] => reterty [description] => tyrfyt [packaging_type] => PC ) [1] => Array ( [id] => 96 [shipping_no] => 212755-1 [part_no] => dftgtryh [description] => dfhgfyh [packaging_type] => PC ) [2] => Array ( [id] => 97 [shipping_no] => 212755-2 [part_no] => ZeoDark [description] => s%c%s%c%s [packaging_type] => PC ) ) 我该如何对数组进行分组 id?有没有任何本机PHP功能可以做到这一点? 如果我 foreach 以上我会得到一个重复的,我怎么能避免这个? 在上面的例子中 id 有两个项目,所以它需要在里面 id。 编辑:一切工作精细:但有一种方式可以用一个前进的方式实现相同的目标吗? 39 2017-10-03 10:14 起源 你还想删除重复??? - Baba@Baba没有........ - Red大多数解决方案使用一个FOREACH。 - Justin John@JustinJohn大多数解决方案都使用ONE FOREACH进行数组创建,最终结果不是数组。我正在寻找更好的解决方案。 - Red你的意思是最终结果不是一维数组。 - Justin John答案: 没有原生的,只需使用循环。 $result = array(); foreach ($data as $element) { $result[$element['id']][] = $element; } 90 2017-10-03 10:20 +1,它给了我很多帮助。谢谢... - CJ Ramki好的.... :) - Pragnesh Rupapara你不需要 if  - 真实的部分适用于这两种情况。 - Nicholas Shanks这里不需要if条件。这与...相同 $result[$id][] = $data。尝试一下。 - Ejaz Karim 您可以尝试以下方法: $group = array(); foreach ( $array as $value ) { $group[$value['id']][] = $value; } var_dump($group); 输出: array 96 => array 0 => array 'id' => int 96 'shipping_no' => string '212755-1' (length=8) 'part_no' => string 'reterty' (length=7) 'description' => string 'tyrfyt' (length=6) 'packaging_type' => string 'PC' (length=2) 1 => array 'id' => int 96 'shipping_no' => string '212755-1' (length=8) 'part_no' => string 'dftgtryh' (length=8) 'description' => string 'dfhgfyh' (length=7) 'packaging_type' => string 'PC' (length=2) 97 => array 0 => array 'id' => int 97 'shipping_no' => string '212755-2' (length=8) 'part_no' => string 'ZeoDark' (length=7) 'description' => string 's%c%s%c%s' (length=9) 'packaging_type' => string 'PC' (length=2) 26 2017-10-03 10:19 我只是把它扔到了一起,受.NET LINQ的启发 <?php // callable type hint may be "closure" type hint instead, depending on php version function array_group_by(array $arr, callable $key_selector) { $result = array(); foreach ($arr as $i) { $key = call_user_func($key_selector, $i); $result[$key][] = $i; } return $result; } $data = array( array(1, "Andy", "PHP"), array(1, "Andy", "C#"), array(2, "Josh", "C#"), array(2, "Josh", "ASP"), array(1, "Andy", "SQL"), array(3, "Steve", "SQL"), ); $grouped = array_group_by($data, function($i){ return $i[0]; }); var_dump($grouped); ?> 瞧,你得到了 array(3) { [1]=> array(3) { [0]=> array(3) { [0]=> int(1) [1]=> string(4) "Andy" [2]=> string(3) "PHP" } [1]=> array(3) { [0]=> int(1) [1]=> string(4) "Andy" [2]=> string(2) "C#" } [2]=> array(3) { [0]=> int(1) [1]=> string(4) "Andy" [2]=> string(3) "SQL" } } [2]=> array(2) { [0]=> array(3) { [0]=> int(2) [1]=> string(4) "Josh" [2]=> string(2) "C#" } [1]=> array(3) { [0]=> int(2) [1]=> string(4) "Josh" [2]=> string(3) "ASP" } } [3]=> array(1) { [0]=> array(3) { [0]=> int(3) [1]=> string(5) "Steve" [2]=> string(3) "SQL" } } } 15 2018-03-14 17:29 在更具功能性的编程风格中,您可以使用 array_reduce $groupedById = array_reduce($data, function (array $accumulator, array $element) { $accumulator[$element['id']][] = $element; return $accumulator; }, []); 4 2018-06-14 10:12 我也需要这样的功能。我创建了这个,你传递了你要分组的列: function array_group(array $data, $by_column) { $result = []; foreach ($data as $item) { $column = $item[$by_column]; unset($item[$by_column]); if (isset($result[$column])) { $result[$column][] = $item; } else { $result[$column] = array($item); } } return $result; } 3 2017-08-29 13:58 for($i = 0 ; $i < count($arr) ; $i++ ) { $tmpArr[$arr[$i]['id']] = $arr[$i]['id']; } $vmpArr = array_keys($tmpArr); print_r($vmpArr); 2 2017-10-03 10:23 这个 array_group_by 功能达到你想要的: $grouped = array_group_by($arr, 'id'); 它甚至支持多级分组: $grouped = array_group_by($arr, 'id', 'part_no'); 2 2017-08-30 06:15 警告:此方法 array_group_by 介绍变量 $key 作为方法参数并在中重写 foreach - DannyFeliz 扩展@ baba的答案,我喜欢,但创建了一个更复杂的三级深度多维(数组(数组(数组))): $group = array(); foreach ( $array as $value ) { $group[$value['id']][] = $value; } // output only data from id 96 foreach ($group as $key=>$value) { //outer loop foreach ($value as $k=>$v){ //inner loop if($key==96){ //if outer loop is equal to 96 (could be variable) for ($i=0;$i<count($k);$i++){ //iterate over the inner loop printf($key.' has a part no. of '.$v['part_no'].' and shipping no. of '.$v['shipping_no'].'<br>'); } } } } 将输出: 96有一个零件号。的遗产和运输号码212755-1 96有一个零件号。 dftgtryh和发货号码212755-1 1 2017-10-03 12:13 使用LINQ是很简单的,LINQ是在几个库中用PHP实现的,包括 YaLinqo*。它允许对数组和对象执行类似SQL的查询。该 groubBy function专为分组而设计,您只需指定要分组的字段: $grouped_array = from($array)->groupBy('$v["id"]')->toArray(); 哪里 '$v["id"]' 是一个简写 function ($v) { return $v["id"]; } 这个库支持哪个。 结果将与接受的答案完全相同,只需少量代码即可。 *由我开发 1 2018-06-04 15:58 你能给我一个如何按多个字段分组的提示吗?在我的用例中,我有一个带有日期字段的对象,需要按年,月和日对它进行分组。像{2016 => {09 => {15 => $ object}}}之类的东西 - fnagel@fnagel嵌套分组有点复杂。见 支持有关嵌套groupBy的问题。它包括一个辅助函数 group_by_multiple,以及嵌套分组如何工作的长篇解释。使用此功能,您的查询将如下所示 group_by_multiple($objects, [ '$v->date->format("Y")', '$v->date->format("n")', '$v->date->format("j")' ])。 - Athari 1。 GROUP BY 一把钥匙 此功能可用作 GROUP BY 对于数组,但有一个重要的限制:只有一个分组“列”($identifier)是可能的。 function arrayUniqueByIdentifier(array $array, string $identifier) { $ids = array_column($array, $identifier); $ids = array_unique($ids); $array = array_filter($array, function ($key, $value) use($ids) { return in_array($value, array_keys($ids)); }, ARRAY_FILTER_USE_BOTH); return $array; } 2.检测表的唯一行(二维数组) 此功能用于过滤“行”。如果我们说,一个二维数组是一个表,那么它的每个元素都是一行。因此,我们可以使用此功能删除重复的行。如果所有列(第二维的元素)相等,则两行(第一维的元素)相等。对“列”值的比较适用:如果值很简单 类型,价值本身将用于比较;否则其类型(array, object, resource, unknown type) 将会被使用。 策略很简单:从原始数组中创建一个浅数组,其中元素是 imploded原始数组的“列”;然后申请 array_unique(...) 在上面;并且最后使用检测到的ID来过滤原始数组。 function arrayUniqueByRow(array $table = [], string $implodeSeparator) { $elementStrings = []; foreach ($table as $row) { // To avoid notices like "Array to string conversion". $elementPreparedForImplode = array_map( function ($field) { $valueType = gettype($field); $simpleTypes = ['boolean', 'integer', 'double', 'float', 'string', 'NULL']; $field = in_array($valueType, $simpleTypes) ? $field : $valueType; return $field; }, $row ); $elementStrings[] = implode($implodeSeparator, $elementPreparedForImplode); } $elementStringsUnique = array_unique($elementStrings); $table = array_intersect_key($table, $elementStringsUnique); return $table; } 如果它的类型是,那么也可以改进比较,检测“列”值的类 object。 该 $implodeSeparator 应该或多或少复杂,z.B。 spl_object_hash($this)。 3.检测具有表的唯一标识符列的行(二维数组) 该解决方案依赖于第二个解决方案。现在,完整的“行”不需要是唯一的。如果全部,两个“行”(第一维的元素)现在相等 相应 一个“行”的“字段”(第二维的元素)等于相应的“字段”(具有相同键的元素)。 “相关”“字段”是具有键的“字段”(第二维的元素),其等于传递的“标识符”的元素之一。 function arrayUniqueByMultipleIdentifiers(array $table, array $identifiers, string $implodeSeparator = null) { $arrayForMakingUniqueByRow = $removeArrayColumns($table, $identifiers, true); $arrayUniqueByRow = $arrayUniqueByRow($arrayForMakingUniqueByRow, $implodeSeparator); $arrayUniqueByMultipleIdentifiers = array_intersect_key($table, $arrayUniqueByRow); return $arrayUniqueByMultipleIdentifiers; } function removeArrayColumns(array $table, array $columnNames, bool $isWhitelist = false) { foreach ($table as $rowKey => $row) { if (is_array($row)) { if ($isWhitelist) { foreach ($row as $fieldName => $fieldValue) { if (!in_array($fieldName, $columnNames)) { unset($table[$rowKey][$fieldName]); } } } else { foreach ($row as $fieldName => $fieldValue) { if (in_array($fieldName, $columnNames)) { unset($table[$rowKey][$fieldName]); } } } } } return $table; } 1 2018-05-23 14:00 热门问题