diff --git a/centos_pkg_dirs b/centos_pkg_dirs index 4054e84..6a074ee 100644 --- a/centos_pkg_dirs +++ b/centos_pkg_dirs @@ -1,5 +1,4 @@ middleware/io-monitor/recipes-common/io-monitor middleware/recipes-common/build-info middleware/patching/recipes-common/enable-dev-patch -middleware/util/recipes-common/monitor-tools middleware/util/recipes-common/engtools/hostdata-collectors diff --git a/middleware/util/recipes-common/monitor-tools/LICENSE b/middleware/util/recipes-common/monitor-tools/LICENSE deleted file mode 100644 index d645695..0000000 --- a/middleware/util/recipes-common/monitor-tools/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/middleware/util/recipes-common/monitor-tools/centos/build_srpm.data b/middleware/util/recipes-common/monitor-tools/centos/build_srpm.data deleted file mode 100644 index acaff65..0000000 --- a/middleware/util/recipes-common/monitor-tools/centos/build_srpm.data +++ /dev/null @@ -1,2 +0,0 @@ -SRC_DIR=scripts -TIS_PATCH_VER=0 diff --git a/middleware/util/recipes-common/monitor-tools/centos/monitor-tools.spec b/middleware/util/recipes-common/monitor-tools/centos/monitor-tools.spec deleted file mode 100644 index a282ca3..0000000 --- a/middleware/util/recipes-common/monitor-tools/centos/monitor-tools.spec +++ /dev/null @@ -1,41 +0,0 @@ -Summary: Monitor tools package -Name: monitor-tools -Version: 1.0 -Release: %{tis_patch_ver}%{?_tis_dist} -License: Apache-2.0 -Group: base -Packager: Wind River -URL: unknown -BuildArch: noarch -Source: %name-%version.tar.gz -#Requires: /usr/bin/perl - -%description -This package contains data collection tools to monitor host performance. -Tools are general purpose engineering and debugging related. Includes -overall memory, cpu occupancy, per-task cpu, per-task scheduling, per-task -io. - -%prep -%autosetup - -%install -rm -rf $RPM_BUILD_ROOT -%global _buildsubdir %{_builddir}/%{name}-%{version} -install -d %{buildroot}/usr/bin -install %{_buildsubdir}/memtop %{buildroot}/usr/bin -install %{_buildsubdir}/schedtop %{buildroot}/usr/bin -install %{_buildsubdir}/occtop %{buildroot}/usr/bin - -%files -%license LICENSE -%defattr(-,root,root,-) -/usr/bin/* - -%post -grep schedstats /etc/sysctl.conf -if [ $? -ne 0 ]; then - echo -e "\nkernel.sched_schedstats=1" >> /etc/sysctl.conf - sysctl -p &>/dev/null -fi -exit 0 diff --git a/middleware/util/recipes-common/monitor-tools/scripts/LICENSE b/middleware/util/recipes-common/monitor-tools/scripts/LICENSE deleted file mode 100644 index d645695..0000000 --- a/middleware/util/recipes-common/monitor-tools/scripts/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/middleware/util/recipes-common/monitor-tools/scripts/memtop b/middleware/util/recipes-common/monitor-tools/scripts/memtop deleted file mode 100755 index 9bcaf64..0000000 --- a/middleware/util/recipes-common/monitor-tools/scripts/memtop +++ /dev/null @@ -1,344 +0,0 @@ -#!/usr/bin/perl -######################################################################## -# -# Copyright (c) 2015 Wind River Systems, Inc. -# -# SPDX-License-Identifier: Apache-2.0 -# -# -######################################################################## -# -# Description: -# This displays overall memory information per sample period. -# Output includes total, used, avail, per-numa node breakdown of avail -# and free hugepages memory. -# -# Usage: memtop OPTIONS -# memtop [--delay=] [--repeat=] [--period=] [--help] -# - -# Summarize high-level memory usage. -use 5.10.0; -use warnings; -use strict; -use Benchmark ':hireswallclock'; -use POSIX qw(strftime); -use Data::Dumper; -use File::Basename; -use File::Spec (); -use Time::HiRes qw(time usleep); -use Carp qw(croak carp); - -# IEC and SI constants -use constant SI_k => 1.0E3; -use constant SI_M => 1.0E6; -use constant SI_G => 1.0E9; -use constant Ki => 1024.0; -use constant Mi => 1024.0*1024.0; -use constant Gi => 1024.0*1024.0*1024.0; - -# Name of this program -our $TOOLNAME = basename($0); -our $VERSION = "0.1"; - -# Argument list parameters -our ($arg_debug, - $arg_delay, - $arg_repeat, - $arg_period) = (); - -# Globals -our $t_0 = (); -our $t_1 = (); -our $t_elapsed = (); -our $t_final = (); -our $is_strict = (); -our $num_nodes = (); - -#------------------------------------------------------------------------------- -# MAIN Program -#------------------------------------------------------------------------------- -# benchmark variables -my ($bd, $b0, $b1); - -# Autoflush output -select(STDERR); -$| = 1; -select(STDOUT); # default -$| = 1; - -# Parse input arguments and print tool usage if necessary -&parse_memtop_args( - \$::arg_debug, - \$::arg_delay, - \$::arg_repeat, - \$::arg_period, -); - -# Print out some debugging information -if (defined $::arg_debug) { - $Data::Dumper::Indent = 1; -} - -# Strict vs non-strict memory accounting -$::is_strict = &is_strict(); - -# Number of numa nodes -$::num_nodes = &num_numa_nodes(); - -# Print tool header and selected options -printf "%s %s -- ". - "selected options: delay = %.3fs, repeat = %d, period = %.3fs, %s, unit = %s\n", - $::TOOLNAME, $::VERSION, - $::arg_delay, $::arg_repeat, $::arg_period, - $::is_strict ? 'strict' : 'non-strict', - 'MiB'; - -# Capture timestamp -$b0 = new Benchmark; - -# Get current hires epoc timestamp -$::t_1 = time(); -$::t_final = $::t_1 + $::arg_period; - -# Set initial delay -$::t_elapsed = $::arg_delay; - -# Main loop -my $delay = SI_M*$::arg_delay - 600.0; -REPEAT_LOOP: for (my $rep=1; $rep <= $::arg_repeat; $rep++) { - # Copy all state variables - $::t_0 = $::t_1; - - # Sleep for desired interarrival time - usleep( $delay ); - - # Current hires epoc timestamp - $::t_1 = time(); - - # Delta calculation - $::t_elapsed = $::t_1 - $::t_0; - - # Print summary - &print_memory(\$::t_1); - - # Exit if we have reached period - last if ((defined $::t_final) && ($::t_1 > $::t_final)); -} - -# Print that tool has finished -print "done\n"; - -# Capture timestamp and report delta -if (defined $::arg_debug) { - $b1 = new Benchmark; $bd = Benchmark::timediff($b1, $b0); - printf "processing time: %s\n", timestr($bd); -} -exit 0; - - -################################################################################ - -# Parse input option arguments -sub parse_memtop_args { - (local *::arg_debug, - local *::arg_delay, - local *::arg_repeat, - local *::arg_period, - ) = @_; - - # Local variables - my ($fail, $arg_help); - - # Use the Argument processing module - use Getopt::Long; - - # Process input arguments - $fail = 0; - GetOptions( - "debug:i", \$::arg_debug, - "delay=f", \$::arg_delay, - "repeat=i", \$::arg_repeat, - "period=i", \$::arg_period, - "help|h", \$arg_help - ) || GetOptionsMessage(); - - # Print help documentation if user has selected --help - &ListHelp() if (defined $arg_help); - - # Validate options - if ((defined $::arg_repeat) && (defined $::arg_period)) { - $fail = 1; - warn "$::TOOLNAME: Input error: cannot specify both --repeat and --period options.\n"; - } - if ((defined $::arg_delay) && ($::arg_delay < 0.01)) { - $fail = 1; - warn "$::TOOLNAME: Input error: --delay %f is less than 0.01.\n", - $::arg_delay; - } - if (@::ARGV) { - $fail = 1; - warn "$::TOOLNAME: Input error: not expecting these options: '@::ARGV'.\n"; - } - - # Set reasonable defaults - $::arg_delay ||= 1.0; - $::arg_repeat ||= 1; - if ($::arg_period) { - $::arg_repeat = $::arg_period / $::arg_delay; - } else { - $::arg_period = $::arg_delay * $::arg_repeat; - } - - # Upon missing or invalid options, print usage - if ($fail == 1) { - &Usage(); - exit 1; - } -} - -# Print out a warning message and usage -sub GetOptionsMessage { - warn "$::TOOLNAME: Error processing input arguments.\n"; - &Usage(); - exit 1; -} - -# Print out program usage -sub Usage { - printf "Usage: $::TOOLNAME OPTIONS\n"; - printf " [--delay=] [--repeat=] [--period=]\n"; - printf " [--help]\n"; - printf "\n"; -} - -# Print tool help -sub ListHelp { - printf "$::TOOLNAME -- displays high memory usage at high level\n"; - &Usage(); - printf " --delay= : output interval (seconds): default: 1.0\n"; - printf " --repeat= : number of repeat samples: default: 1\n"; - printf " --period= : overall tool duration (seconds): default: --\n"; - printf " --help : this help\n"; - printf "\n"; - exit 0; -} - -# Print memory summary -sub print_memory { - (local *::t_1) = @_; - - # counter - our $count; - $::count++; $::count %= 15; - - my ($file, $n); - my %mem = (); - my %node = (); - - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst); - ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($::t_1); - my $msec = 1000.0*($::t_1 - int($::t_1)); - - # Process all entries of MEMINFO - $file = '/proc/meminfo'; - open(FILE, $file) || die "Cannot open file: $file ($!)"; - while($_ = ) { - s/[\0\e\f\r\a]//g; chomp; # strip control characters if any - if (/^(\S+):\s+(\d+)\b/) { - $mem{$1} = $2; - } - } - close(FILE); - - # Process all entries of per-Node MEMINFO - for ($n=0; $n < $::num_nodes; $n++) { - $file = sprintf('/sys/devices/system/node/node%d/meminfo', $n); - open(FILE, $file) || die "Cannot open file: $file ($!)"; - while($_ = ) { - s/[\0\e\f\r\a]//g; chomp; # strip control characters if any - if (/^Node\s+(\d+)\s+(\S+):\s+(\d+)\b/) { - $node{$1}{$2} = $3; - } - } - close(FILE); - } - - # Calculate available memory - if ($::is_strict) { - $mem{'Avail'} = $mem{'CommitLimit'} - $mem{'Committed_AS'}; - } else { - $mem{'Avail'} = $mem{'MemFree'} + - $mem{'Cached'} + - $mem{'Buffers'} + - $mem{'SReclaimable'}; - } - $mem{'Used'} = $mem{'MemTotal'} - $mem{'Avail'}; - $mem{'Anon'} = $mem{'AnonPages'}; - for ($n=0; $n < $::num_nodes; $n++) { - $node{$n}{'Avail'} = $node{$n}{'MemFree'} + - $node{$n}{'FilePages'} + - $node{$n}{'SReclaimable'}; - $node{$n}{'HFree'} = $node{$n}{'HugePages_Free'} * $mem{'Hugepagesize'}; - } - - # Print heading every so often - if ($::count == 1) { - printf "%s ". - "%8s %8s %8s %7s %6s %6s %8s %8s %7s %7s %8s %8s", - 'yyyy-mm-dd hh:mm:ss.fff', - 'Tot', 'Used', 'Free', 'Ca', 'Buf', 'Slab', 'CAS', 'CLim', 'Dirty', 'WBack', 'Anon', 'Avail'; - for ($n=0; $n < $::num_nodes; $n++) { - printf " %8s %8s", sprintf('%d:Avail', $n), sprintf('%d:HFree', $n); - } - printf "\n"; - } - - # Print one line memory summary - printf "%4d-%02d-%02d %02d:%02d:%02d.%03d ". - "%8.1f %8.1f %8.1f %7.1f %6.1f %6.1f %8.1f %8.1f %7.1f %7.1f %8.1f %8.1f", - 1900+$year, 1+$mon, $mday, $hour, $min, $sec, $msec, - $mem{'MemTotal'}/Ki, - $mem{'Used'}/Ki, - $mem{'MemFree'}/Ki, - $mem{'Cached'}/Ki, - $mem{'Buffers'}/Ki, - $mem{'Slab'}/Ki, - $mem{'Committed_AS'}/Ki, - $mem{'CommitLimit'}/Ki, - $mem{'Dirty'}/Ki, - $mem{'Writeback'}/Ki, - $mem{'Anon'}/Ki, - $mem{'Avail'}/Ki; - for ($n=0; $n < $::num_nodes; $n++) { - printf " %8.1f %8.1f", $node{$n}{'Avail'}/Ki, $node{$n}{'HFree'}/Ki; - } - printf "\n"; - -} - -sub num_numa_nodes { - my $file = '/proc/cpuinfo'; - my %nodes = (); - open(FILE, $file) || die "Cannot open file: $file ($!)"; - while($_ = ) { - s/[\0\e\f\r\a]//g; chomp; # strip control characters if any - if (/^physical\s+id\s+:\s+(\d+)\b/) { - $nodes{$1} = 1; - } - } - close(FILE); - return scalar keys %nodes; -} - -sub is_strict { - my $value = 0; - my $file = '/proc/sys/vm/overcommit_memory'; - open(FILE, $file) || die "Cannot open file: $file ($!)"; - $_ = ; - $value = /(\d+)/; - close(FILE); - return ($value == 2) ? 1 : 0; -} - -1; diff --git a/middleware/util/recipes-common/monitor-tools/scripts/occtop b/middleware/util/recipes-common/monitor-tools/scripts/occtop deleted file mode 100755 index d4178a1..0000000 --- a/middleware/util/recipes-common/monitor-tools/scripts/occtop +++ /dev/null @@ -1,592 +0,0 @@ -#!/usr/bin/perl -######################################################################## -# -# Copyright (c) 2015-2016 Wind River Systems, Inc. -# -# SPDX-License-Identifier: Apache-2.0 -# -# -######################################################################## -# -# Description: -# This displays per-core occupancy information per sample period. -# Output includes total occupancy, and per-core occupancy based on -# hi-resolution timings. -# -# Usage: occtop OPTIONS -# [--delay=] [--repeat=] [--period=] -# [--header=] -# [--help] - -use strict; -use warnings; -use Data::Dumper; -use POSIX qw(uname strftime); -use Time::HiRes qw(clock_gettime usleep CLOCK_MONOTONIC CLOCK_REALTIME); - -use Benchmark ':hireswallclock'; -use Carp qw(croak carp); - -# Define toolname -our $TOOLNAME = "occtop"; -our $VERSION = "0.1"; - -# Constants -use constant SI_k => 1.0E3; -use constant SI_M => 1.0E6; -use constant SI_G => 1.0E9; -use constant Ki => 1024.0; -use constant Mi => 1024.0*1024.0; -use constant Gi => 1024.0*1024.0*1024.0; - -# Globals -our %percpu_0 = (); -our %percpu_1 = (); -our %D_percpu = (); -our %loadavg = (); -our $D_total = 0.0; -our $tm_0 = 0.0; -our $tm_1 = 0.0; -our $tr_0 = 0.0; -our $tr_1 = 0.0; -our $tm_elapsed = 0.0; -our $tm_final = 0.0; -our $uptime = 0.0; -our $num_cpus = 1; -our $num_tasks = 0; -our $num_blk = 0; -our $print_host = 1; -our $is_schedstat = 1; -our $USER_HZ = 100; # no easy way to get this -our $CLOCK_NS = SI_G / $USER_HZ; - -# Argument list parameters -our ($arg_debug, - $arg_delay, - $arg_repeat, - $arg_period, - $arg_header, - ) = (); - -#------------------------------------------------------------------------------- -# MAIN Program -#------------------------------------------------------------------------------- -my $MIN_DELAY = 0.001; -my $MAX_DELAY = 0.001; - -# benchmark variables -my ($bd, $b0, $b1); - -# Autoflush output -select(STDERR); -$| = 1; -select(STDOUT); # default -$| = 1; - -# Parse input arguments and print tool usage if necessary -&parse_occtop_args( - \$::arg_debug, - \$::arg_delay, - \$::arg_repeat, - \$::arg_period, - \$::arg_header, -); - -# Print out some debugging information -if (defined $::arg_debug) { - $Data::Dumper::Indent = 1; -} - -# Check for schedstat support; fallback to stats -$is_schedstat = -e '/proc/schedstat' ? 1 : 0; - -# Print out selected options -printf "selected options: delay = %.3fs, repeat = %d, header = %d, source = %s\n", - $::arg_delay, $::arg_repeat, $::arg_header, $is_schedstat ? 'schedstat' : 'jiffie'; - -# Capture timestamp -$b0 = new Benchmark; - -# Get number of logical cpus -&get_num_logical_cpus(\$::num_cpus); - - -# Get current hires epoc timestamp -$::tm_1 = clock_gettime(CLOCK_MONOTONIC); -$::tr_1 = clock_gettime(CLOCK_REALTIME); -$::tm_final = $::tm_1 + $::arg_delay*$::arg_repeat; - -# Set initial delay -$::tm_elapsed = $::arg_delay; -$MAX_DELAY = $::arg_delay + $MIN_DELAY; - -# Get overall per-cpu stats -if ($is_schedstat) { - &read_schedstat(\%::percpu_1); -} else { - &read_stat(\%::percpu_1); -} - -# Main loop -REPEAT_LOOP: for (my $repeat=1; $repeat <= $::arg_repeat; $repeat++) { - - # copy all state variables - %::tm_0 = (); %::tr_0 = (); %::percpu_0 = (); - $::tm_0 = $::tm_1; $::tr_0 = $::tr_1; - foreach my $cpu (keys %::percpu_1) { $::percpu_0{$cpu} = $::percpu_1{$cpu}; } - - # estimate sleep delay to achieve desired interarrival by subtracting out - # the measured cpu runtime of the tool. - my $delay = $::arg_delay; - $delay = $MIN_DELAY if ($delay < $MIN_DELAY); - $delay = $MAX_DELAY if ($delay > $MAX_DELAY); - usleep( SI_M*$delay ); - - # Collect current state - $::tm_1 = (); $::tr_1 = (); %::percpu_1 = (); - # Get current hires epoc timestamp - $::tm_1 = clock_gettime(CLOCK_MONOTONIC); - $::tr_1 = clock_gettime(CLOCK_REALTIME); - # Get overall per-cpu stats - if ($is_schedstat) { - &read_schedstat(\%::percpu_1); - } else { - &read_stat(\%::percpu_1); - } - - # Get current uptime - &get_uptime(\$::uptime); - # Get current loadavg - &get_loadavg(\%::loadavg, \$::runq, \$::num_tasks); - # Get current processes blocked - &get_blocked(\$::num_blk); - - # Delta calculation - %::D_percpu = (); - $::tm_elapsed = $tm_1 - $tm_0; - foreach my $cpu (keys %::percpu_1) { - $::D_percpu{$cpu}{'runtime'} = ($::percpu_1{$cpu} - $::percpu_0{$cpu})/1.0E6; - if ($::tm_elapsed > 0.0) { - $::D_percpu{$cpu}{'occ'} = 100.0*$D_percpu{$cpu}{'runtime'}/1.0E3/$::tm_elapsed; - } else { - $::D_percpu{$cpu}{'occ'} = 0.0; - } - } - - # Print tool header - if ($repeat == 1) { - &occtop_header( - \$::tr_1, - \$::uptime, - \%::loadavg, - \$::runq, - \$::num_blk, - \$::num_tasks, - \$::print_host, - ); - } - - # Print one-liner summary - &print_occtop( - \$::tr_1, - \$::num_cpus, - \%::D_percpu, - \$::arg_header, - ); - - # exit repeat loop if we have exceeded overall time - last if ($::tm_1 > $::tm_final); - -} # REPEAT LOOP - -# Print that tool has finished -print "done\n"; - -# Capture timestamp and report delta -$b1 = new Benchmark; $bd = Benchmark::timediff($b1, $b0); -printf "processing time: %s\n", timestr($bd); -exit 0; - - -#------------------------------------------------------------------------------- - -# Parse per-cpu hi-resolution scheduling stats -sub read_schedstat -{ - (local *::percpu) = @_; - my ($version, $timestamp); - my ($cpu, $cputime); - my ($fh, $file); - - %::percpu = (); - - # parse /proc/schedstat - $file = '/proc/schedstat'; - open($fh, $file) || croak "Cannot open file: $file ($!)"; - $_ = <$fh>; ($version) = /^version\s+(\d+)/; - $_ = <$fh>; ($timestamp) = /^timestamp\s+(\d+)/; - - if ($version == 15) { - LOOP_SCHEDSTAT: while (<$fh>) { - # version 15: cputime is 7th field - if (/^cpu(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+(\d+)\s+/) { - $cpu = $1; $cputime = $2; - $::percpu{$cpu} = $cputime; - } - } - } else { - croak "schedstat version: $version method not implemented."; - } - close($fh); -} - -# Parse per-cpu jiffie stats; cputime excludes iowait. -sub read_stat -{ - (local *::percpu) = @_; - my ($cpu, $cputime); - my ($user, $sys, $nice, $idle, $iowt, $hirq, $sirq); - my ($fh, $file); - - %::percpu = (); - - # parse /proc/stat - $file = '/proc/stat'; - open($fh, $file) || croak "Cannot open file: $file ($!)"; - LOOP_STAT: while (<$fh>) { - if (/^cpu(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+/) { - $cpu =$1; $user = $2; $sys = $3; $nice = $4; $idle = $5; $iowt = $6; $hirq = $7; $sirq = $8; - $cputime = $CLOCK_NS * ($user + $sys + $nice + $iowt + $hirq + $sirq); - $::percpu{$cpu} = $cputime; - } - } - close($fh); -} - -# Parse load-average from /proc/loadavg -sub get_loadavg -{ - (local *::loadavg, local *::runq, *::num_tasks) = @_; - - $::loadavg{'1'} = 0.0; - $::loadavg{'5'} = 0.0; - $::loadavg{'15'} = 0.0; - $::runq = 0; - $::num_tasks = 0; - - my $file = '/proc/loadavg'; - open(my $fh, $file) || croak "Cannot open file: $file ($!)"; - $_ = <$fh>; - if (/^(\S+)\s+(\S+)\s+(\S+)\s+(\d+)\/(\d+)\s+\d+/) { - $::loadavg{'1'} = $1; - $::loadavg{'5'} = $2; - $::loadavg{'15'} = $3; - $::runq = $4; - $::num_tasks = $5; - } - close($fh); -} - -# Parse blocked from /proc/stat -sub get_blocked -{ - (local *::num_blk) = @_; - - $::num_blk = 0; - - my $file = '/proc/stat'; - open(my $fh, $file) || croak "Cannot open file: $file ($!)"; - while ($_ = <$fh>) { - if (/^procs_blocked\s+(\d+)/) { - $::num_blk = $1; - } - } - close($fh); -} - -# Parse uptime from /proc/uptime -sub get_uptime -{ - (local *::uptime) = @_; - $::uptime = 0.0; - - my $file = '/proc/uptime'; - open(my $fh, $file) || croak "Cannot open file: $file ($!)"; - $_ = <$fh>; - if (/^(\S+)\s+\S+/) { - $::uptime = $1; - } - close($fh); -} - -# Get number of online logical cpus -sub get_num_logical_cpus { - (local *::num_cpus) = @_; - $::num_cpus = 0; - - my $file = "/proc/cpuinfo"; - open(my $fh, $file) || croak "Cannot open file: $file ($!)"; - LOOP_CPUINFO: while (<$fh>) { - if (/^[Pp]rocessor\s+:\s\d+/) { - $::num_cpus++; - } - } - close($fh); -} - -# Print occupancy summary -sub print_occtop { - (local *::tr_1, - local *::num_cpus, - local *::D_percpu, - local *::arg_header, - ) = @_; - - # counter - our $count; - $::count++; $::count %= $::arg_header; - $::count = 1 if ($::arg_header == 1); - - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst); - ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($::tr_1); - my $msec = 1000.0*($::tr_1 - int($::tr_1)); - - # Print heading every so often - if ($::count == 1) { - printf "%s ". - "%7s ", - 'yyyy-mm-dd hh:mm:ss.fff', - 'total'; - for (my $cpu=0; $cpu < $::num_cpus; $cpu++) { - printf "%5s ", $cpu; - } - print "\n"; - } - - # Print one summary - my $occ_total = 0.0; - for (my $cpu=0; $cpu < $::num_cpus; $cpu++) { - $occ_total += $::D_percpu{$cpu}{'occ'}; - } - printf "%4d-%02d-%02d %02d:%02d:%02d.%03d ". - "%7.1f ", - 1900+$year, 1+$mon, $mday, $hour, $min, $sec, $msec, - $occ_total; - for (my $cpu=0; $cpu < $::num_cpus; $cpu++) { - printf "%5.1f ", $::D_percpu{$cpu}{'occ'}; - } - print "\n"; -} - -# Print header -sub occtop_header { - (local *::tr_1, - local *::uptime, - local *::loadavg, - local *::runq, - local *::num_blk, - local *::num_tasks, - local *::print_host, - ) = @_; - - # process epoch to get current timestamp - my $mm_in_s = 60; - my $hh_in_s = 60*60; - my $dd_in_s = 24*60*60; - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst); - ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($::tr_1); - my $msec = 1000.0*($::tr_1 - int($::tr_1)); - - # convert uptime to elapsed ::: - my ($up, $up_dd, $up_hh, $up_mm, $up_ss); - $up = int($::uptime); - $up_dd = int($up/$dd_in_s); - $up -= $dd_in_s*$up_dd; - $up_hh = int($up/$hh_in_s); - $up -= $hh_in_s*$up_hh; - $up_mm = int($up/$mm_in_s); - $up -= $mm_in_s*$up_mm; - $up_ss = $up; - - #occtop -- 2014/03/03 02:00:21.357 ldavg:0.07, 0.09, 0.08 runq:1 nproc:440 up:6:13:00:56 - printf "%s %s -- ". - "%4d-%02d-%02d %02d:%02d:%02d.%03d ". - "ldavg:%.2f, %.2f, %.2f runq:%d blk:%d nproc:%d ". - "up:%d:%02d:%02d:%02d\n", - $::TOOLNAME, $::VERSION, - 1900+$year, 1+$mon, $mday, $hour, $min, $sec, $msec, - $::loadavg{'1'}, $::loadavg{'5'}, $::loadavg{'15'}, - $::runq, $::num_blk, $::num_tasks, - $up_dd, $up_hh, $up_mm, $up_ss; - - return if (!($::print_host)); - - # After first print, disable print host information - $::print_host = 0; - - # Get host specific information - my ($OSTYPE, $NODENAME, $OSRELEASE, $version, $MACHINE); - ($OSTYPE, $NODENAME, $OSRELEASE, $version, $MACHINE) = POSIX::uname(); - my ($NODETYPE, $SUBFUNCTION, $BUILDINFO) = ('-', '-', '-'); - my ($SW_VERSION, $BUILD_ID) = ('-', '-'); - - # Get platform nodetype and subfunction - PLATFORM: { - my $file = "/etc/platform/platform.conf"; - open(FILE, $file) || next; - while($_ = ) { - s/[\0\e\f\r\a]//g; chomp; # strip control characters if any - if (/^nodetype=(\S+)/) { - $NODETYPE = $1; - } - if (/^subfunction=(\S+)/) { - $SUBFUNCTION = $1; - } - } - close(FILE); - } - - # Get loadbuild info - BUILD: { - my $file = "/etc/build.info"; - open(FILE, $file) || next; - while($_ = ) { - s/[\0\e\f\r\a]//g; chomp; # strip control characters if any - if (/^SW_VERSION=\"([^"]+)\"/) { - $SW_VERSION = $1; - } - if (/^BUILD_ID=\"([^"]+)\"/) { - $BUILD_ID = $1; - } - } - close(FILE); - } - $BUILDINFO = join(' ', $SW_VERSION, $BUILD_ID); - - # Parse /proc/cpuinfo to get specific processor info - my ($n_cpu, $model_name, $cpu_MHz) = (0, '-', 0); - CPUINFO: { - my $file = "/proc/cpuinfo"; - open(FILE, $file) || croak "Cannot open file: $file ($!)"; - while($_ = ) { - s/[\0\e\f\r\a]//g; chomp; # strip control characters if any - if (/^[Pp]rocessor\s+:\s+\d+/) { - $n_cpu++; - } elsif (/^model name\s+:\s+(.*)$/) { - $_ = $1; s/\s+/ /g; - $model_name = $_; - } elsif (/^cpu MHz\s+:\s+(\S+)/) { - $cpu_MHz = $1; - } elsif (/^bogomips\s+:\s+(\S+)/) { - $cpu_MHz = $1 if ($cpu_MHz == 0); - } - } - close(FILE); - } - - printf " host:%s nodetype:%s subfunction:%s\n", - $NODENAME, $NODETYPE, $SUBFUNCTION; - printf " arch:%s processor:%s speed:%.0f #CPUs:%d\n", - $MACHINE, $model_name, $cpu_MHz, $n_cpu; - printf " %s %s build:%s\n", $OSTYPE, $OSRELEASE, $BUILDINFO; - -} - -# Parse and validate command line arguments -sub parse_occtop_args { - (local *::arg_debug, - local *::arg_delay, - local *::arg_repeat, - local *::arg_period, - local *::arg_header, - ) = @_; - - # Local variables - my ($fail, $arg_help); - - # Use the Argument processing module - use Getopt::Long; - - # Print usage if no arguments - if (!@::ARGV) { - &Usage(); - exit 0; - } - - # Process input arguments - $fail = 0; - GetOptions( - "debug:i", \$::arg_debug, - "delay=f", \$::arg_delay, - "period=i", \$::arg_period, - "repeat=i", \$::arg_repeat, - "header:i", \$::arg_header, - "help|h", \$arg_help - ) || GetOptionsMessage(); - - # Print help documentation if user has selected --help - &ListHelp() if (defined $arg_help); - - # Validate options - if ((defined $::arg_repeat) && (defined $::arg_period)) { - $fail = 1; - warn "$::TOOLNAME: Input error: cannot specify both --repeat and --period options.\n"; - } - if ((defined $::arg_delay) && ($::arg_delay < 0.01)) { - $fail = 1; - warn "$::TOOLNAME: Input error: --delay %f is less than 0.01.\n", - $::arg_delay; - } - if (@::ARGV) { - $fail = 1; - warn "$::TOOLNAME: Input error: not expecting these options: '@::ARGV'.\n"; - } - - # Set reasonable defaults - $::arg_header ||= 15; - $::arg_delay ||= 1.0; - $::arg_repeat ||= 1; - if ($::arg_period) { - $::arg_repeat = $::arg_period / $::arg_delay; - } else { - $::arg_period = $::arg_delay * $::arg_repeat; - } - - # Upon missing or invalid options, print usage - if ($fail == 1) { - &Usage(); - exit 1; - } -} - -# Print out a warning message and usage -sub GetOptionsMessage { - warn "$::TOOLNAME: Error processing input arguments.\n"; - &Usage(); - exit 1; -} - -# Print out program usage -sub Usage { - printf "Usage: $::TOOLNAME OPTIONS\n"; - printf " [--delay=] [--repeat=] [--period=]\n"; - printf " [--header=]\n"; - printf " [--help]\n"; - - printf "\n"; -} - -# Print tool help -sub ListHelp { - printf "$::TOOLNAME -- display hi-resolution per-cpu occupancy\n"; - &Usage(); - printf "Options: miscellaneous\n"; - printf " --delay= : output interval (seconds): default: 1.0\n"; - printf " --repeat= : number of repeat samples: default: 1\n"; - printf " --period= : overall tool duration (seconds): default: --\n"; - printf " --header= : print header every num samples: default: 15\n"; - printf " --help : this help\n"; - exit 0; -} - -1; diff --git a/middleware/util/recipes-common/monitor-tools/scripts/schedtop b/middleware/util/recipes-common/monitor-tools/scripts/schedtop deleted file mode 100755 index a170040..0000000 --- a/middleware/util/recipes-common/monitor-tools/scripts/schedtop +++ /dev/null @@ -1,1312 +0,0 @@ -#!/usr/bin/perl -######################################################################## -# -# Copyright (c) 2015-2016 Wind River Systems, Inc. -# -# SPDX-License-Identifier: Apache-2.0 -# -# -######################################################################## -# -# Description: -# This displays occupancy and scheduling information per sample period. -# Output includes total occupancy, per-core occupancy, loadavg, per-task cpu, -# per-task scheduling, per-task io-wait. -# -# Usage: schedtop OPTIONS -# [--delay=] [--repeat=] [--period=] -# [--reset-hwm] [--idle] [--sort=] -# [--help] - -use strict; -use warnings; -use Data::Dumper; -use POSIX qw(uname strftime); -use Time::HiRes qw(clock_gettime usleep CLOCK_MONOTONIC CLOCK_REALTIME); -use Benchmark ':hireswallclock'; -use Carp qw(croak carp); -use Math::BigInt; - -# Define toolname -our $TOOLNAME = "schedtop"; -our $VERSION = "0.1"; - -# Constants -use constant SI_k => 1.0E3; -use constant SI_M => 1.0E6; -use constant SI_G => 1.0E9; -use constant Ki => 1024.0; -use constant Mi => 1024.0*1024.0; -use constant Gi => 1024.0*1024.0*1024.0; - -# Globals -our %opt_V = (); -our %opt_P = (); -our %percpu_0 = (); -our %percpu_1 = (); -our %task_0 = (); -our %task_1 = (); -our %tids_0 = (); -our %tids_1 = (); -our %D_task = (); -our %D_percpu = (); -our %loadavg = (); -our $tm_0 = (); -our $tm_1 = (); -our $tr_0 = (); -our $tr_1 = (); -our $tm_elapsed = (); -our $tr_elapsed = (); -our $tm_final = (); -our $uptime = (); -our $num_cpus = 1; -our $affinity_mask = Math::BigInt->new('0'); -our $w_aff = 10; -our $num_tasks = 0; -our $num_blk = 0; -our $is_schedstat = 1; -our $USER_HZ = 100; # no easy way to get this -our $CLOCK_NS = SI_G / $USER_HZ; -our $print_host = 1; - -# Print options -our ($P_none, $P_lite, $P_brief, $P_full) = (0, 1, 2, 3); -our ($P_ps, $P_cpu, $P_del, $P_io, $P_id, $P_cmd) = (0, 1, 2, 3, 4, 5); -our @P_list = ($::P_ps, $::P_cpu, $::P_del, $::P_io, $::P_id, $::P_cmd); - -# Argument list parameters -our ($arg_debug, - $arg_delay, - $arg_repeat, - $arg_period, - $arg_reset_hwm, - $arg_idle, - $arg_sort, - $arg_print) = (); - -#------------------------------------------------------------------------------- -# MAIN Program -#------------------------------------------------------------------------------- -my $ONE_BILLION = 1.0E9; -my $MIN_DELAY = 0.001; -my $MAX_DELAY = 0.001; - -# benchmark variables -my ($bd, $b0, $b1); -my @policies = ('OT', 'FF', 'RR', 'BA', 'ID', 'UN', 'UN'); -my @delta_list = ( - 'nr_switches', - 'nr_migrations', - 'exec_runtime', - 'wait_sum', - 'wait_count', - 'iowait_sum', - 'iowait_count', - 'syscr', - 'syscw', - 'read_bytes', - 'write_bytes', - 'cancelled_write_bytes', -); - -my @state_list = ( - 'exec_max', 'wait_max', - 'pid', 'ppid', 'state', 'comm', 'cmdline', 'wchan', 'affinity', - 'VmSize', 'VmRSS', 'start_time', - 'nice', 'policy', 'priority', 'rt_priority', 'task_cpu' -); - -# Autoflush output -select(STDERR); -$| = 1; -select(STDOUT); # default -$| = 1; - -# Parse input arguments and print tool usage if necessary -&parse_schedtop_args( - \$::arg_debug, - \$::arg_delay, - \$::arg_repeat, - \$::arg_period, - \$::arg_reset_hwm, - \$::arg_idle, - \$::arg_sort, - \$::arg_print, -); - -# Set default print options -if ($::arg_print eq 'full') { - for my $P (@::P_list) { $::opt_P{$P} = $::P_full; } -} elsif ($::arg_print eq 'brief') { - for my $P (@::P_list) { $::opt_P{$P} = $::P_brief; } -} else { - for my $P (@::P_list) { $::opt_P{$P} = $::P_none; } -} -# Disable some options if data not present -$::opt_V{'sched'} = &is_sched(); -$::opt_V{'io'} = &is_io(); -if ($::opt_V{'sched'} == 0) { - $::opt_P{$::P_cpu} = $::P_none; - $::opt_P{$::P_del} = $::P_none; - $::opt_P{$::P_io} = $::P_none; - undef $::arg_reset_hwm; -} -if ($::opt_V{'io'} == 0) { - if ($::opt_V{'sched'} == 0) { - $::opt_P{$::P_io} = $::P_none; - $::arg_sort = 'cpu'; - } else { - if ($::opt_P{$::P_io} != $::P_none) { - $::opt_P{$::P_io} = $::P_lite; - } - } -} - -# Check for root user -if ($>) { - warn "$::TOOLNAME: requires root/sudo.\n"; - exit 1; -} - -# Print out some debugging information -if (defined $::arg_debug) { - $Data::Dumper::Indent = 1; -} - -# Check for schedstat support; fallback to stats -$is_schedstat = -e '/proc/schedstat' ? 1 : 0; - -# Print out selected options -printf "selected options: ". - "delay = %.3fs, repeat = %d, idle=%s, hwm=%s, sort=%s, print=%s\n", - $::arg_delay, $::arg_repeat, - (defined $::arg_idle ? 'idle_tasks' : 'no_idle_tasks'), - (defined $::arg_reset_hwm ? 'reset-hwm' : 'unchanged'), - $::arg_sort, $::arg_print; - -# Capture timestamp -$b0 = new Benchmark; - -# Get number of logical cpus -&get_num_logical_cpus(\$::num_cpus); -$::affinity_mask = Math::BigInt->new('0'); -for (my $i=0; $i < $::num_cpus; $i++) { - my $y = Math::BigInt->new('1'); - $y->blsft($i); - $::affinity_mask->bior($y); -} -$w_aff = &max(length 'AFF', length $::affinity_mask->as_hex()); - -# Reset scheduling hi-water marks -if (defined $::arg_reset_hwm) { - &get_tids(\%::tids_1); - &reset_sched_hwm(\%::tids_1); - sleep(0.001); -} - -# Get current hires epoc timestamp -$::tm_1 = clock_gettime(CLOCK_MONOTONIC); -$::tr_1 = clock_gettime(CLOCK_REALTIME); -$::tm_final = $::tm_1 + $::arg_delay*$::arg_repeat; - -# Set initial delay -$::tm_elapsed = $::arg_delay; -$MAX_DELAY = $::arg_delay + $MIN_DELAY; - - -# Get overall per-cpu stats -if ($is_schedstat) { - &read_schedstat(\%::percpu_1); -} else { - &read_stat(\%::percpu_1); -} -# Get list of pids and tids -&get_tids(\%::tids_1); -# Get current scheduling and io info for all tids -&read_sched(\%::tids_1, \%::task_1); - -# determine column sort order -my ($s_key1, $s_key2, $s_key3) = (); -if ($::arg_sort eq 'cpu') { - ($s_key1, $s_key2, $s_key3) = ('exec_runtime', 'nr_switches', 'pid'); -} elsif ($::arg_sort eq 'io') { - ($s_key1, $s_key2, $s_key3) = ('io', 'ios', 'exec_runtime'); -} else { - ($s_key1, $s_key2, $s_key3) = ('exec_runtime', 'nr_switches', , 'pid'); -} - -# Main loop -REPEAT_LOOP: for (my $repeat=1; $repeat <= $::arg_repeat; $repeat++) { - - # copy all state variables - $::tm_0 = (); $::tr_0 = (); %::percpu_0 = (); %::tids_0 = (); %::task_0 = (); - $::tm_0 = $::tm_1; $::tr_0 = $::tr_1; - foreach my $cpu (keys %::percpu_1) { $::percpu_0{$cpu} = $::percpu_1{$cpu}; } - foreach my $tid (keys %::tids_1) { $::tids_0{$tid} = $::tids_1{$tid}; } - foreach my $tid (keys %::task_1) { - foreach my $var (keys $::task_1{$tid}) { - $::task_0{$tid}{$var} = $::task_1{$tid}{$var}; - } - } - - # estimate sleep delay to achieve desired interarrival by subtracting out - # the measured cpu runtime of the tool. - my $delay = $::arg_delay; - if (defined $::D_task{$$}{'exec_runtime'}) { - $delay -= ($::D_task{$$}{'exec_runtime'}/SI_k); - } - $delay = $MIN_DELAY if ($delay < $MIN_DELAY); - $delay = $MAX_DELAY if ($delay > $MAX_DELAY); - usleep( SI_M*$delay ); - - # Collect current state - $::tm_1 = (); $::tr_1 = (); %::percpu_1 = (); %::tids_1 = (); %::task_1 = (); - # Get current hires epoc timestamp - $::tm_1 = clock_gettime(CLOCK_MONOTONIC); - $::tr_1 = clock_gettime(CLOCK_REALTIME); - # Get overall per-cpu stats - if ($is_schedstat) { - &read_schedstat(\%::percpu_1); - } else { - &read_stat(\%::percpu_1); - } - # Get list of pids and tids - &get_tids(\%::tids_1); - # Get current scheduling and io info for all tids - &read_sched(\%::tids_1, \%::task_1); - # Get current uptime - &get_uptime(\$::uptime); - # Get current loadavg - &get_loadavg(\%::loadavg, \$::runq, \$::num_tasks); - # Get current processes blocked - &get_blocked(\$::num_blk); - - # Delta calculation - %::D_task = (); %::D_percpu = (); - $::tm_elapsed = $::tm_1 - $::tm_0; - $::tr_elapsed = $::tr_1 - $::tr_0; - foreach my $tid (keys %::task_1) { - next if ( !(exists $::task_0{$tid}) ); - - # simple delta - foreach my $var (@delta_list) { - $::D_task{$tid}{$var} = ($::task_1{$tid}{$var} - $::task_0{$tid}{$var}); - } - # state information - foreach my $state (@state_list) { - $::D_task{$tid}{$state} = $::task_1{$tid}{$state}; - } - - # derived calculations - my $exec_runtime = $::D_task{$tid}{'exec_runtime'}; - my $nr_switches = $::D_task{$tid}{'nr_switches'}; - my $iowait_sum = $::D_task{$tid}{'iowait_sum'}; - if ($nr_switches > 0.0) { - $::D_task{$tid}{'tlen'} = $exec_runtime / $nr_switches; - } else { - $::D_task{$tid}{'tlen'} = 0.0; - } - if ($::tm_elapsed > 0.0) { - $::D_task{$tid}{'occ'} = 100.0*$exec_runtime/1.0E3/$::tm_elapsed; - $::D_task{$tid}{'iowait'} = 100.0*$iowait_sum/1.0E3/$::tm_elapsed; - } else { - $::D_task{$tid}{'occ'} = 0.0; - $::D_task{$tid}{'iowait'} = 0.0; - } - $::D_task{$tid}{'io'} = $::D_task{$tid}{'read_bytes'} - + $::D_task{$tid}{'write_bytes'} - + $::D_task{$tid}{'cancelled_write_bytes'}; - $::D_task{$tid}{'ios'} = $::D_task{$tid}{'syscw'} - + $::D_task{$tid}{'iowait_count'}; - } - - foreach my $cpu (keys %::percpu_1) { - $::D_percpu{$cpu}{'runtime'} = ($::percpu_1{$cpu} - $::percpu_0{$cpu})/1.0E6; - if ($::tm_elapsed > 0.0) { - $::D_percpu{$cpu}{'occ'} = 100.0*$D_percpu{$cpu}{'runtime'}/1.0E3/$::tm_elapsed; - } else { - $::D_percpu{$cpu}{'occ'} = 0.0; - } - } - my $occ_total = 0.0; - for (my $cpu=0; $cpu < $::num_cpus; $cpu++) { - $occ_total += $::D_percpu{$cpu}{'occ'}; - } - - # Print summary - &schedtop_header( - \$::tr_1, - \$::tm_elapsed, - \$::tr_elapsed, - \$::uptime, - \$::loadavg, - \$::runq, - \$::num_blk, - \$::num_tasks, - \$::print_host - ); - - printf "%-5s %7s ", 'core:', 'total'; - for (my $cpu=0; $cpu < $::num_cpus; $cpu++) { - printf "%5s ", $cpu; - } - print "\n"; - printf "%-5s %7.1f ", 'occ:', $occ_total; - for (my $cpu=0; $cpu < $::num_cpus; $cpu++) { - printf "%5.1f ", $::D_percpu{$cpu}{'occ'}; - } - print "\n"; - print "\n"; - - # Build up output line by specific area - my $L = (); - $L = ''; - $L .= sprintf "%6s %6s %6s ", "TID", "PID", "PPID"; - if ($::opt_P{$::P_ps} != $::P_none) { - $L .= sprintf "%1s %2s %*s %2s %3s %4s ", - "S", "P", $w_aff, "AFF", "PO", "NI", "PR"; - } - if ($::opt_P{$::P_cpu} == $::P_brief) { - $L .= sprintf "%6s %7s ", "ctxt", "occ"; - } elsif ($::opt_P{$::P_cpu} == $::P_full) { - $L .= sprintf "%6s %6s %7s ", "ctxt", "migr", "occ"; - } - if ($::opt_P{$::P_del} != $::P_none) { - $L .= sprintf "%7s %7s %7s %7s ", "tlen", "tmax", "delay", "dmax"; - } - if ($::opt_P{$::P_io} == $::P_lite) { - $L .= sprintf "%7s %6s ", "iowt", "iocnt"; - } elsif ($::opt_P{$::P_io} == $::P_brief) { - $L .= sprintf "%7s %8s %8s ", "iowt", "read", "write"; - } elsif ($::opt_P{$::P_io} == $::P_full) { - $L .= sprintf "%7s %8s %8s %8s %8s %8s ", - "iowt", "read", "write", "wcncl", "rsysc", "wsysc"; - } - if ($::opt_P{$::P_id} != $::P_none) { - $L .= sprintf "%-22s ", "wchan"; - } - if ($::opt_P{$::P_cmd} == $::P_brief) { - $L .= sprintf "%s", "cmdline"; - } elsif ($::opt_P{$::P_cmd} == $::P_full) { - $L .= sprintf "%-15s %s", "comm", "cmdline"; - } - print $L, "\n"; - - foreach my $tid (sort {($D_task{$b}{$s_key1} <=> $D_task{$a}{$s_key1}) or - ($D_task{$b}{$s_key2} <=> $D_task{$a}{$s_key2}) or - ($D_task{$b}{$s_key3} <=> $D_task{$a}{$s_key3})} keys %D_task) { - my $exec_runtime = $::D_task{$tid}{'exec_runtime'}; - my $nr_switches = $::D_task{$tid}{'nr_switches'}; - my $aff = $::D_task{$tid}{'affinity'}->as_hex(); - - # skip printing if there is no actual delta - if ( !(defined $::arg_idle) ) { - next if (($exec_runtime == 0.0) && ($nr_switches == 0)); - } - - # Build up output line by specific area - $L = ''; - $L .= sprintf "%6d %6d %6d ", - $tid, $::D_task{$tid}{'pid'}, $::D_task{$tid}{'ppid'}; - if ($::opt_P{$::P_ps} != $::P_none) { - $L .= sprintf "%1s %2d %*s %2s %3d %4d ", - $::D_task{$tid}{'state'}, $::D_task{$tid}{'task_cpu'}, $w_aff, $aff, - $policies[$::D_task{$tid}{'policy'}], $::D_task{$tid}{'nice'}, - $::D_task{$tid}{'priority'}; - } - if ($::opt_P{$::P_cpu} == $::P_brief) { - $L .= sprintf "%6d %7.2f ", - $::D_task{$tid}{'nr_switches'}, $::D_task{$tid}{'occ'}; - } elsif ($::opt_P{$::P_cpu} == $::P_full) { - $L .= sprintf "%6d %6d %7.2f ", - $::D_task{$tid}{'nr_switches'}, $::D_task{$tid}{'nr_migrations'}, - $::D_task{$tid}{'occ'}, - } - if ($::opt_P{$::P_del} != $::P_none) { - $L .= sprintf "%7.3f %7.1f %7.3f %7.1f ", - $::D_task{$tid}{'tlen'}, $::D_task{$tid}{'exec_max'}, - $::D_task{$tid}{'wait_sum'}, $::D_task{$tid}{'wait_max'}; - } - if ($::opt_P{$::P_io} == $::P_lite) { - $L .= sprintf "%7.2f %6d ", - $::D_task{$tid}{'iowait'}, $::D_task{$tid}{'iowait_count'}; - } elsif ($::opt_P{$::P_io} == $::P_brief) { - $L .= sprintf "%7.2f %8s %8s ", - $::D_task{$tid}{'iowait'}, - &format_SI($::D_task{$tid}{'read_bytes'}), - &format_SI($::D_task{$tid}{'write_bytes'}); - } elsif ($::opt_P{$::P_io} == $::P_full) { - $L .= sprintf "%7.2f %8s %8s %8s %8s %8s ", - $::D_task{$tid}{'iowait'}, - &format_SI($::D_task{$tid}{'read_bytes'}), - &format_SI($::D_task{$tid}{'write_bytes'}), - &format_SI($::D_task{$tid}{'cancelled_write_bytes'}), - &format_SI($::D_task{$tid}{'syscr'}), - &format_SI($::D_task{$tid}{'syscw'}); - } - if ($::opt_P{$::P_id} != $::P_none) { - $L .= sprintf "%-22s ", substr($::D_task{$tid}{'wchan'}, 0, 22); - } - if ($::opt_P{$::P_cmd} == $::P_brief) { - $L .= sprintf "%s", $::D_task{$tid}{'cmdline'}; - } elsif ($::opt_P{$::P_cmd} == $::P_full) { - $L .= sprintf "%-15s %s", - $::D_task{$tid}{'comm'}, $::D_task{$tid}{'cmdline'}; - } - print $L, "\n"; - } - print "\n"; - - # exit repeat loop if we have exceeded overall time - last if ($::tm_1 > $::tm_final); - -} # REPEAT LOOP - -# Print that tool has finished -print "done\n"; - -# Capture timestamp and report delta -$b1 = new Benchmark; $bd = Benchmark::timediff($b1, $b0); -printf "processing time: %s\n", timestr($bd); -exit 0; - - -#------------------------------------------------------------------------------- -# Convert a number to SI unit xxx.yyyG -sub format_SI -{ - (my $value) = @_; - if ($value >= SI_G) { - return sprintf("%.3fG", $value/SI_G); - } elsif ($value >= SI_M) { - return sprintf("%.3fM", $value/SI_M); - } elsif ($value >= SI_k) { - return sprintf("%.3fk", $value/SI_k); - } else { - return sprintf("%.0f", $value); - } -} - -# Convert to IEC binary unit xxx.yyyGi -# Since underlying memory units are in pages, don't need decimals for Ki -sub format_IEC -{ - (my $value) = @_; - if ($value >= Gi) { - return sprintf("%.3fGi", $value/Gi); - } elsif ($value >= Mi) { - return sprintf("%.3fMi", $value/Mi); - } elsif ($value >= Ki) { - return sprintf("%.0fKi", $value/Ki); - } else { - return sprintf("%.0f", $value); - } -} - -# Determine whether scheduler stats are available -sub is_sched -{ - return (-e '/proc/1/task/1/sched') ? 1 : 0; -} - -# Determine whether IO stats are available -sub is_io -{ - return (-e '/proc/1/task/1/io') ? 1 : 0; -} - -# Determine max of array -sub max { - my ($max, @vars) = @_; - for (@vars) { - $max = $_ if $_ > $max; - } - return $max; -} - -# Determine tids and pid mapping by walking /proc//task/ -sub get_tids -{ - (local *::tids) = @_; - my (@pids_, @tids_) = (); - my ($dh, $pid, $tid); - - # get pid list - my $dir = '/proc'; - opendir($dh, $dir) || croak "Cannot open directory: $dir ($!)"; - @pids_ = grep { /^\d+$/ && -d "$dir/$_" } readdir($dh); - closedir $dh; - - # get tid list - foreach $pid (@pids_) { - $dir = '/proc/' . $pid . '/task'; - opendir(my $dh, $dir) || next; - @tids_ = grep { /^\d+$/ && -d "$dir/$_" } readdir($dh); - closedir $dh; - foreach $tid (@tids_) { $::tids{$tid} = $pid; } - } -} - -# Reset scheduling hi-water-marks -sub reset_sched_hwm -{ - (local *::tids) = @_; - - # reset scheduling hi-water-marks by writing '0' to each task - foreach my $tid (keys %::tids) { - my $file = '/proc/' . $tid . '/sched'; - open(my $fh, "> $file") || next; - print $fh "0\n"; - close($fh); - } -} - -# Parse cpu and scheduling info for each tid -# - ignore the specific tid if there is incomplete data, -# (i.e., cannot obtain info because task has died, -# eg. missing ./stat, ./status, ./cmdline, ./wchan) -# -sub read_sched -{ - (local *::tids, local *::task) = @_; - - %::task = (); - foreach my $tid (keys %::tids) { - my ($fh, $file, $pid, $comm, $cmdline, $wchan, $id) = (); - my ($tpid, $tcomm, $state, $ppid, $pgrp, $sid, - $tty_nr, $tty_pgrp, $flags, - $min_flt, $cmin_flt, $maj_flt, $cmaj_flt, - $utime, $stime, $cutime, $cstime, - $priority, $nice, $num_threads, - $it_real_value, $start_time, - $vsize, $rss, $rsslim, - $start_code, $end_code, $start_stack, $esp, $eip, - $pending, $blocked, $sigign, $sigcatch, $wchan_addr, - $dum1, $dum2, $exit_signal, $task_cpu, - $rt_priority, $policy, $blkio_ticks, - $gtime, $cgtime, - $start_data, $end_data, $start_brk, $arg_start, $arg_end, - $env_start, $env_end, $exit_code) = (); - - my ($nr_switches, $nr_migrations) = (0,0); - my ($exec_runtime, $exec_max) = (0.0, 0.0); - my ($wait_max, $wait_sum, $wait_count) = (0.0, 0.0, 0); - my ($iowait_sum, $iowait_count) = (0.0, 0); - my ($VmSize, $VmRSS) = (); - my $Cpus_allowed = Math::BigInt->new('0'); - my $affinity = Math::BigInt->new('0'); - my ($rchar, $wchar, $syscr, $syscw, $read_bytes, $write_bytes, - $cancelled_write_bytes) = (0,0,0,0,0,0,0); - - my ($sched_valid, $io_valid, $status_valid, $cmdline_valid, - $wchan_valid, $stat_valid) = (); - - $pid = $::tids{$tid}; - - # NOTE: Format change over time: OLD: se.statistics.X, NEW: se.statistics->X - #cat /proc/1/sched - #systemd (1, #threads: 1) - #------------------------------------------------------------------- - #se.exec_start : 33792676.285222 - #se.vruntime : 28019997.693224 - #se.sum_exec_runtime : 21918.207287 - #se.nr_migrations : 5413 - #se.statistics->sum_sleep_runtime : 1166561.198533 - #se.statistics->wait_start : 0.000000 - #se.statistics->sleep_start : 33792676.285222 - #se.statistics->block_start : 0.000000 - #se.statistics->sleep_max : 18951.679990 - #se.statistics->block_max : 0.000000 - #se.statistics->exec_max : 0.909747 - #se.statistics->slice_max : 1.790123 - #se.statistics->wait_max : 4.026544 - #se.statistics->wait_sum : 507.245963 - #se.statistics->wait_count : 2540 - #se.statistics->iowait_sum : 0.000000 - #se.statistics->iowait_count : 0 - #se.statistics->nr_migrations_cold : 0 - #se.statistics->nr_failed_migrations_affine : 67 - #se.statistics->nr_failed_migrations_running : 1 - #se.statistics->nr_failed_migrations_hot : 1 - #se.statistics->nr_forced_migrations : 0 - #se.statistics->nr_wakeups : 2472 - #se.statistics->nr_wakeups_sync : 34 - #se.statistics->nr_wakeups_migrate : 176 - #se.statistics->nr_wakeups_local : 1442 - #se.statistics->nr_wakeups_remote : 1030 - #se.statistics->nr_wakeups_affine : 155 - #se.statistics->nr_wakeups_affine_attempts : 969 - #se.statistics->nr_wakeups_passive : 0 - #se.statistics->nr_wakeups_idle : 0 - #avg_atom : 0.286970 - #avg_per_cpu : 4.049179 - #nr_switches : 76378 - #nr_voluntary_switches : 72308 - #nr_involuntary_switches : 4070 - #se.load.weight : 1024 - #policy : 0 - #prio : 120 - #clock-delta : 28 - - # parse /proc//task//sched - $file = '/proc/' . $pid . '/task/' . $tid . '/sched'; - open($fh, $file) || goto SKIP_SCHED; - $_ = <$fh>; - if (/^(.*)\s+\((\d+),\s+#threads:/) { - $comm = $1; $id = $2; - } - my ($k, $v, $c0); - LOOP_SCHED: while (<$fh>) { - if (/^se\.statistics.{1,2}wait_max\s+:\s+(\S+)/) { - $wait_max = $1; - } elsif (/^se\.statistics.{1,2}wait_sum\s+:\s+(\S+)/) { - $wait_sum = $1; - } elsif (/^se\.statistics.{1,2}wait_count\s+:\s+(\S+)/) { - $wait_count = $1; - } elsif (/^se\.statistics.{1,2}exec_max\s+:\s+(\S+)/) { - $exec_max = $1; - } elsif (/^se\.statistics.{1,2}iowait_sum\s+:\s+(\S+)/) { - $iowait_sum = $1; - } elsif (/^se\.statistics.{1,2}iowait_count\s+:\s+(\S+)/) { - $iowait_count = $1; - } elsif (/^se\.sum_exec_runtime\s+:\s+(\S+)/) { - $exec_runtime = $1; - } elsif (/^se\.nr_migrations\s+:\s+(\S+)/) { - $nr_migrations = $1; - } elsif (/^nr_switches\s+:\s+(\S+)/) { - $nr_switches = $1; - $sched_valid = 1; - last LOOP_SCHED; - } - } - close($fh); - SKIP_SCHED:; - - #cat /proc/1/io - #rchar: 3432590242 - #wchar: 438665986 - #syscr: 316595 - #syscw: 104722 - #read_bytes: 1586438144 - #write_bytes: 246829056 - #cancelled_write_bytes: 7798784 - - # parse /proc//task//io - $file = '/proc/' . $pid . '/task/' . $tid . '/io'; - open($fh, $file) || goto SKIP_IO; - LOOP_IO: while (<$fh>) { - if (/^rchar:\s+(\S+)/) { - $rchar = $1; - } elsif (/^wchar:\s+(\S+)/) { - $wchar = $1; - } elsif (/^syscr:\s+(\S+)/) { - $syscr = $1; - } elsif (/^syscw:\s+(\S+)/) { - $syscw = $1; - } elsif (/^read_bytes:\s+(\S+)/) { - $read_bytes = $1; - } elsif (/^write_bytes:\s+(\S+)/) { - $write_bytes = $1; - } elsif (/^cancelled_write_bytes:\s+(\S+)/) { - $cancelled_write_bytes = $1; - $io_valid = 1; - last LOOP_IO; - } - } - close($fh); - SKIP_IO:; - - # parse /proc//task//status - $file = '/proc/' . $pid . '/task/' . $tid . '/status'; - open($fh, $file) || next; - LOOP_STATUS: while (<$fh>) { - if (/^Name:\s+(.*)/) { - $comm = $1; - } elsif (/^State:\s+(\S+)/) { - $state = $1; - } elsif (/^PPid:\s+(\S+)/) { - $ppid = $1; - } elsif (/^VmSize:\s+(\S+)/) { - $VmSize = $1; - } elsif (/^VmRSS:\s+(\S+)/) { - $VmRSS = $1; - } elsif (/^Cpus_allowed:\s+([0]+,)*(\S+)/) { - my $h = $2; $h =~ tr/,/_/; - $Cpus_allowed = Math::BigInt->from_hex($h); - $affinity = $Cpus_allowed->band($::affinity_mask); - $status_valid = 1; - last LOOP_STATUS; - } - } - close($fh); - - # parse /proc//task//cmdline - $file = '/proc/' . $pid . '/task/' . $tid . '/cmdline'; - open($fh, $file) || next; - LOOP_CMDLINE: while (<$fh>) { - if (/^(.*)$/) { - $cmdline = $1; - $cmdline =~ s/\000/ /g; - $cmdline_valid = 1; - last LOOP_CMDLINE; - } - } - if (!$cmdline_valid) { - $cmdline_valid = 1; - $cmdline = $comm; - } - close($fh); - - # parse /proc//task//wchan - $file = '/proc/' . $pid . '/task/' . $tid . '/wchan'; - open($fh, $file) || next; - LOOP_WCHAN: while (<$fh>) { - if (/^(.*)$/) { - $wchan = $1; - $wchan_valid = 1; - last LOOP_WCHAN; - } - } - close($fh); - - #Table 1-4: Contents of the stat files (as of 2.6.30-rc7) - #.............................................................................. - # Field Content - # tpid process id (or tid, if /proc//task//stat) - # tcomm filename of the executable - # state state (R is running, S is sleeping, D is sleeping in an - # uninterruptible wait, Z is zombie, T is traced or stopped) - # ppid process id of the parent process - # pgrp pgrp of the process - # sid session id - # tty_nr tty the process uses - # tty_pgrp pgrp of the tty - # flags task flags - # min_flt number of minor faults - # cmin_flt number of minor faults with child's - # maj_flt number of major faults - # cmaj_flt number of major faults with child's - # utime user mode jiffies - # stime kernel mode jiffies - # cutime user mode jiffies with child's - # cstime kernel mode jiffies with child's - # priority priority level - # nice nice level - # num_threads number of threads - # it_real_value (obsolete, always 0) - # start_time time the process started after system boot - # vsize virtual memory size - # rss resident set memory size - # rsslim current limit in bytes on the rss - # start_code address above which program text can run - # end_code address below which program text can run - # start_stack address of the start of the main process stack - # esp current value of ESP - # eip current value of EIP - # pending bitmap of pending signals - # blocked bitmap of blocked signals - # sigign bitmap of ignored signals - # sigcatch bitmap of catched signals - # wchan address where process went to sleep - # 0 (place holder) - # 0 (place holder) - # exit_signal signal to send to parent thread on exit - # task_cpu which CPU the task is scheduled on - # rt_priority realtime priority - # policy scheduling policy (man sched_setscheduler) - # blkio_ticks time spent waiting for block IO - # gtime guest time of the task in jiffies - # cgtime guest time of the task children in jiffies - # start_data address above which program data+bss is placed - # end_data address below which program data+bss is placed - # start_brk address above which program heap can be expanded with brk() - # arg_start address above which program command line is placed - # arg_end address below which program command line is placed - # env_start address above which program environment is placed - # env_end address below which program environment is placed - # exit_code the thread's exit_code in the form reported by the waitpid system call - - # parse /proc//task//stat - $file = '/proc/' . $pid . '/task/' . $tid . '/stat'; - my $dummy; - open($fh, $file) || next; - $_ = <$fh>; - ($tpid, $tcomm, $dummy) = /^(\d+)\s+\((.*)\)\s+(.*)/; - ($state, $ppid, $pgrp, $sid, - $tty_nr, $tty_pgrp, $flags, - $min_flt, $cmin_flt, $maj_flt, $cmaj_flt, - $utime, $stime, $cutime, $cstime, - $priority, $nice, $num_threads, - $it_real_value, $start_time, - $vsize, $rss, $rsslim, - $start_code, $end_code, $start_stack, $esp, $eip, - $pending, $blocked, $sigign, $sigcatch, $wchan_addr, - $dum1, $dum2, $exit_signal, $task_cpu, - $rt_priority, $policy, $blkio_ticks, $gtime, $cgtime, - $start_data, $end_data, $start_brk, $arg_start, $arg_end, - $env_start, $env_end, $exit_code) = split(/\s+/, $dummy); - $stat_valid = 1; - close($fh); - - # sched - if (defined $sched_valid) { - $::task{$tid}{'exec_runtime'} = $exec_runtime; - $::task{$tid}{'exec_max'} = $exec_max; - $::task{$tid}{'wait_max'} = $wait_max; - $::task{$tid}{'wait_sum'} = $wait_sum; - $::task{$tid}{'wait_count'} = $wait_count; - $::task{$tid}{'iowait_sum'} = $iowait_sum; - $::task{$tid}{'iowait_count'} = $iowait_count; - $::task{$tid}{'nr_migrations'} = $nr_migrations; - $::task{$tid}{'nr_switches'} = $nr_switches; - } else { - $::task{$tid}{'exec_runtime'} = 0; - $::task{$tid}{'exec_max'} = 0; - $::task{$tid}{'wait_max'} = 0; - $::task{$tid}{'wait_sum'} = 0; - $::task{$tid}{'wait_count'} = 0; - $::task{$tid}{'iowait_sum'} = 0; - $::task{$tid}{'iowait_count'} = 0; - $::task{$tid}{'nr_migrations'} = 0; - $::task{$tid}{'nr_switches'} = 0; - } - - # io - if (defined $io_valid) { - $::task{$tid}{'rchar'} = $rchar; - $::task{$tid}{'wchar'} = $wchar; - $::task{$tid}{'syscr'} = $syscr; - $::task{$tid}{'syscw'} = $syscw; - $::task{$tid}{'read_bytes'} = $read_bytes; - $::task{$tid}{'write_bytes'} = $write_bytes; - $::task{$tid}{'cancelled_write_bytes'} = $cancelled_write_bytes; - } else { - $::task{$tid}{'rchar'} = 0; - $::task{$tid}{'wchar'} = 0; - $::task{$tid}{'syscr'} = 0; - $::task{$tid}{'syscw'} = 0; - $::task{$tid}{'read_bytes'} = 0; - $::task{$tid}{'write_bytes'} = 0; - $::task{$tid}{'cancelled_write_bytes'} = 0; - } - - # status - if (defined $status_valid) { - $::task{$tid}{'pid'} = $pid; - $::task{$tid}{'comm'} = $comm; - $::task{$tid}{'state'} = $state; - $::task{$tid}{'ppid'} = $ppid; - $::task{$tid}{'VmSize'} = $VmSize; - $::task{$tid}{'VmRSS'} = $VmRSS; - $::task{$tid}{'affinity'} = $affinity; - } else { - $::task{$tid}{'pid'} = 0; - $::task{$tid}{'comm'} = '-'; - $::task{$tid}{'state'} = '-'; - $::task{$tid}{'ppid'} = 0; - $::task{$tid}{'VmSize'} = 0; - $::task{$tid}{'VmRSS'} = 0; - $::task{$tid}{'affinity'} = Math::BigInt->new('0'); - } - - # cmdline - if (defined $cmdline_valid) { - $::task{$tid}{'cmdline'} = $cmdline; - } else { - $::task{$tid}{'cmdline'} = $comm; - } - - # wchan - if (defined $cmdline_valid) { - $::task{$tid}{'wchan'} = $wchan; - } else { - $::task{$tid}{'wchan'} = '-'; - } - - # stat - if (defined $stat_valid) { - $::task{$tid}{'nice'} = $nice; - $::task{$tid}{'policy'} = $policy; - $::task{$tid}{'priority'} = $priority; - $::task{$tid}{'rt_priority'} = $rt_priority; - $::task{$tid}{'start_time'} = $start_time; - $::task{$tid}{'task_cpu'} = $task_cpu; - } else { - $::task{$tid}{'nice'} = 0; - $::task{$tid}{'policy'} = '-'; - $::task{$tid}{'priority'} = 0; - $::task{$tid}{'rt_priority'} = 0; - $::task{$tid}{'start_time'} = ''; - $::task{$tid}{'task_cpu'} = 0; - } - } -} - -# Parse per-cpu hi-resolution scheduling stats -sub read_schedstat -{ - (local *::percpu) = @_; - my ($version, $timestamp); - my ($cpu, $cputime); - my ($fh, $file); - - %::percpu = (); - - # parse /proc/schedstat - $file = '/proc/schedstat'; - open($fh, $file) || croak "Cannot open file: $file ($!)"; - $_ = <$fh>; ($version) = /^version\s+(\d+)/; - $_ = <$fh>; ($timestamp) = /^timestamp\s+(\d+)/; - - if ($version == 15) { - LOOP_SCHEDSTAT: while (<$fh>) { - # version 15: cputime is 7th field - if (/^cpu(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+(\d+)\s+/) { - $cpu = $1; $cputime = $2; - $::percpu{$cpu} = $cputime; - } - } - } else { - croak "schedstat version: $version method not implemented."; - } - close($fh); - SKIP_SCHED:; -} - -# Parse per-cpu jiffie stats; cputime excludes iowait. -sub read_stat -{ - (local *::percpu) = @_; - my ($cpu, $cputime); - my ($user, $sys, $nice, $idle, $iowt, $hirq, $sirq); - my ($fh, $file); - - %::percpu = (); - - # parse /proc/stat - $file = '/proc/stat'; - open($fh, $file) || croak "Cannot open file: $file ($!)"; - LOOP_STAT: while (<$fh>) { - if (/^cpu(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+/) { - $cpu =$1; $user = $2; $sys = $3; $nice = $4; $idle = $5; $iowt = $6; $hirq = $7; $sirq = $8; - $cputime = $CLOCK_NS * ($user + $sys + $nice + $iowt + $hirq + $sirq); - $::percpu{$cpu} = $cputime; - } - } - close($fh); -} - -# Parse load-average from /proc/loadavg -sub get_loadavg -{ - (local *::loadavg, local *::runq, local *::num_tasks) = @_; - - $::loadavg{'1'} = 0.0; - $::loadavg{'5'} = 0.0; - $::loadavg{'15'} = 0.0; - $::runq = 0; - $::num_tasks = 0; - - my $file = '/proc/loadavg'; - open(my $fh, $file) || croak "Cannot open file: $file ($!)"; - $_ = <$fh>; - if (/^(\S+)\s+(\S+)\s+(\S+)\s+(\d+)\/(\d+)\s+\d+/) { - $::loadavg{'1'} = $1; - $::loadavg{'5'} = $2; - $::loadavg{'15'} = $3; - $::runq = $4; - $::num_tasks = $5; - } - close($fh); -} - -# Parse blocked from /proc/stat -sub get_blocked -{ - (local *::num_blk) = @_; - - $::num_blk = 0; - - my $file = '/proc/stat'; - open(my $fh, $file) || croak "Cannot open file: $file ($!)"; - while ($_ = <$fh>) { - if (/^procs_blocked\s+(\d+)/) { - $::num_blk = $1; - } - } - close($fh); -} - -# Parse uptime from /proc/uptime -sub get_uptime -{ - (local *::uptime) = @_; - $::uptime = 0.0; - - my $file = '/proc/uptime'; - open(my $fh, $file) || croak "Cannot open file: $file ($!)"; - $_ = <$fh>; - if (/^(\S+)\s+\S+/) { - $::uptime = $1; - } - close($fh); -} - -# Get number of online logical cpus -sub get_num_logical_cpus { - (local *::num_cpus) = @_; - $::num_cpus = 0; - - my $file = "/proc/cpuinfo"; - open(my $fh, $file) || croak "Cannot open file: $file ($!)"; - LOOP_CPUINFO: while (<$fh>) { - if (/^[Pp]rocessor\s+:\s\d+/) { - $::num_cpus++; - } - } - close($fh); -} - -# Print header -sub schedtop_header { - (local *::tr_1, - local *::tm_elapsed, - local *::tr_elapsed, - local *::uptime, - local *::loadavg, - local *::runq, - local *::num_blk, - local *::num_tasks, - local *::print_host, - ) = @_; - - # process epoch to get current timestamp - my $mm_in_s = 60; - my $hh_in_s = 60*60; - my $dd_in_s = 24*60*60; - my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst); - ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($::tr_1); - my $msec = 1000.0*($::tr_1 - int($::tr_1)); - - # convert uptime to elapsed ::: - my ($up, $up_dd, $up_hh, $up_mm, $up_ss); - $up = int($::uptime); - $up_dd = int($up/$dd_in_s); - $up -= $dd_in_s*$up_dd; - $up_hh = int($up/$hh_in_s); - $up -= $hh_in_s*$up_hh; - $up_mm = int($up/$mm_in_s); - $up -= $mm_in_s*$up_mm; - $up_ss = $up; - - # Calculate skew of CLOCK_REALTIME vs CLOCK_MONOTONIC, - # and display skew if > 5% relative difference. - my $skew_ms = ($::tr_elapsed - $::tm_elapsed)*1000.0; - my $skew = ""; - if (abs($skew_ms)/$::tm_elapsed > 50.0) { - $skew = sprintf " skew:%.3f ms", $skew_ms; - } - - #schedtop -- 2014/03/03 02:00:21.357 dt:2050.003 ms ldavg:0.07, 0.09, 0.08 runq:1 blk:0 nproc:440 up:6:13:00:56 skew:0.001 ms - printf "%s %s -- ". - "%4d-%02d-%02d %02d:%02d:%02d.%03d ". - "dt:%.3f ms ". - "ldavg:%.2f, %.2f, %.2f runq:%d blk:%d nproc:%d ". - "up:%d:%02d:%02d:%02d %s\n", - $::TOOLNAME, $::VERSION, - 1900+$year, 1+$mon, $mday, $hour, $min, $sec, $msec, - $::tm_elapsed*1000.0, - $::loadavg{'1'}, $::loadavg{'5'}, $::loadavg{'15'}, - $::runq, $::num_blk, $::num_tasks, - $up_dd, $up_hh, $up_mm, $up_ss, - $skew; - - return if (!($::print_host)); - - # After first print, disable print host information - $::print_host = 0; - - # Get host specific information - my ($OSTYPE, $NODENAME, $OSRELEASE, $version, $MACHINE); - ($OSTYPE, $NODENAME, $OSRELEASE, $version, $MACHINE) = POSIX::uname(); - my ($NODETYPE, $SUBFUNCTION, $BUILDINFO) = ('-', '-', '-'); - my ($SW_VERSION, $BUILD_ID) = ('-', '-'); - - # Get platform nodetype and subfunction - PLATFORM: { - my $file = "/etc/platform/platform.conf"; - open(FILE, $file) || next; - while($_ = ) { - s/[\0\e\f\r\a]//g; chomp; # strip control characters if any - if (/^nodetype=(\S+)/) { - $NODETYPE = $1; - } - if (/^subfunction=(\S+)/) { - $SUBFUNCTION = $1; - } - } - close(FILE); - } - - # Get loadbuild info - BUILD: { - my $file = "/etc/build.info"; - open(FILE, $file) || next; - while($_ = ) { - s/[\0\e\f\r\a]//g; chomp; # strip control characters if any - if (/^SW_VERSION=\"([^"]+)\"/) { - $SW_VERSION = $1; - } - if (/^BUILD_ID=\"([^"]+)\"/) { - $BUILD_ID = $1; - } - } - close(FILE); - } - $BUILDINFO = join(' ', $SW_VERSION, $BUILD_ID); - - # Parse /proc/cpuinfo to get specific processor info - my ($n_cpu, $model_name, $cpu_MHz) = (0, '-', 0); - CPUINFO: { - my $file = "/proc/cpuinfo"; - open(FILE, $file) || croak "Cannot open file: $file ($!)"; - while($_ = ) { - s/[\0\e\f\r\a]//g; chomp; # strip control characters if any - if (/^[Pp]rocessor\s+:\s+\d+/) { - $n_cpu++; - } elsif (/^model name\s+:\s+(.*)$/) { - $_ = $1; s/\s+/ /g; - $model_name = $_; - } elsif (/^cpu MHz\s+:\s+(\S+)/) { - $cpu_MHz = $1; - } elsif (/^bogomips\s+:\s+(\S+)/) { - $cpu_MHz = $1 if ($cpu_MHz == 0); - } - } - close(FILE); - } - - printf " host:%s nodetype:%s subfunction:%s\n", - $NODENAME, $NODETYPE, $SUBFUNCTION; - printf " arch:%s processor:%s speed:%.0f #CPUs:%d\n", - $MACHINE, $model_name, $cpu_MHz, $n_cpu; - printf " %s %s build:%s\n", $OSTYPE, $OSRELEASE, $BUILDINFO; - -} - -# Parse and validate command line arguments -sub parse_schedtop_args { - (local *::arg_debug, - local *::arg_delay, - local *::arg_repeat, - local *::arg_period, - local *::arg_reset_hwm, - local *::arg_idle, - local *::arg_sort, - local *::arg_print, - ) = @_; - - # Local variables - my ($fail, $arg_help); - - # Use the Argument processing module - use Getopt::Long; - - # Print usage if no arguments - if (!@::ARGV) { - &Usage(); - exit 0; - } - - # Process input arguments - $fail = 0; - GetOptions( - "debug:i", \$::arg_debug, - "delay=f", \$::arg_delay, - "period=i", \$::arg_period, - "repeat=i", \$::arg_repeat, - "reset-hwm", \$::arg_reset_hwm, - "idle", \$::arg_idle, - "sort=s", \$::arg_sort, - "print=s", \$::arg_print, - "help|h", \$arg_help - ) || GetOptionsMessage(); - - # Print help documentation if user has selected --help - &ListHelp() if (defined $arg_help); - - # Validate options - if ((defined $::arg_repeat) && (defined $::arg_period)) { - $fail = 1; - warn "$::TOOLNAME: Input error: cannot specify both --repeat and --period options.\n"; - } - if ((defined $::arg_delay) && ($::arg_delay < 0.01)) { - $fail = 1; - warn "$::TOOLNAME: Input error: --delay %f is less than 0.01.\n", - $::arg_delay; - } - if ((defined $::arg_sort) && !(($::arg_sort eq 'cpu') || ($::arg_sort eq 'io'))) { - $fail = 1; - warn "$::TOOLNAME: Input error: --sort=$::arg_sort invalid; valid options are: cpu, io.\n"; - } - if ((defined $::arg_print) && !(($::arg_print eq 'brief') || ($::arg_print eq 'full'))) { - $fail = 1; - warn "$::TOOLNAME: Input error: --print=$::arg_print invalid; valid options are: brief, full\n"; - } - if (@::ARGV) { - $fail = 1; - warn "$::TOOLNAME: Input error: not expecting these options: '@::ARGV'.\n"; - } - - # Set reasonable defaults - $::arg_delay ||= 1.0; - $::arg_repeat ||= 1; - if ($::arg_period) { - $::arg_repeat = $::arg_period / $::arg_delay; - } else { - $::arg_period = $::arg_delay * $::arg_repeat; - } - $::arg_sort ||= 'cpu'; - $::arg_print ||= 'full'; - - # Upon missing or invalid options, print usage - if ($fail == 1) { - &Usage(); - exit 1; - } -} - -# Print out a warning message and usage -sub GetOptionsMessage { - warn "$::TOOLNAME: Error processing input arguments.\n"; - &Usage(); - exit 1; -} - -# Print out program usage -sub Usage { - printf "Usage: $::TOOLNAME OPTIONS\n"; - printf " [--delay=] [--repeat=] [--period=]\n"; - printf " [--reset-hwm] [--idle] [--sort=] [--print=]\n"; - printf " [--help]\n"; - - printf "\n"; -} - -# Print tool help -sub ListHelp { - printf "$::TOOLNAME -- display per-task scheduling occupancy\n"; - &Usage(); - printf "Options: miscellaneous\n"; - printf " --delay= : output interval (seconds): default: 1.0\n"; - printf " --repeat= : number of repeat samples: default: 1\n"; - printf " --period= : overall tool duration (seconds): default: --\n"; - printf " --reset-hwm : reset scheduling delay hi-water marks\n"; - printf " --idle : specify printing of idle tasks\n"; - printf " --sort= : sort order, select from 'cpu' or 'io'\n"; - printf " --print= : select 'brief' or 'full' fields to display\n"; - printf " --help : this help\n"; - exit 0; -} - -1;