pcp-3.8.12ubuntu1/0000775000000000000000000000000012272262617010612 5ustar pcp-3.8.12ubuntu1/man/0000775000000000000000000000000012272262617011365 5ustar pcp-3.8.12ubuntu1/man/man5/0000775000000000000000000000000012272262617012225 5ustar pcp-3.8.12ubuntu1/man/man5/mmv.50000664000000000000000000001072712272262501013111 0ustar '\"! tbl | nroff \-man '\"macro stdmacro .\" .\" Copyright (c) 2009 Max Matveev .\" Copyright (c) 2009 Aconex. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH MMV 5 "" "Performance Co-Pilot" .SH NAME \f3mmv\f1 \- Memory Mapped Values for Performance Co-Pilot .SH SYNOPSIS .I $PCP_TMP_DIR/mmv/ .SH DESCRIPTION The files in \f2$PCP_TMP_DIR/mmv\f1 are generated by \f2mmv_stats_init\f1() function from \f3libpcp_mmv\f1 library. There could be multiple files in this directory, each file representing a single source of the performance metrics. The metrics are harvested by the \f2mmv\f1 PMDA which exports them to the rest of the Performance Co-Pilot infrastructure. .SH FILE FORMAT Each file starts with the following header: .TS box,center; c | c | c n | n | l. Offset Length Name _ 0 4 tag == "MMV\\0" _ 4 4 Version _ 8 8 Generation 1 _ 16 8 Generation 2 _ 24 4 Number of TOC entries _ 28 4 Flags _ 32 4 Process identifier (PID) _ 36 4 Cluster identifier .TE .PP .PP The generation numbers are timestamps at the time of file creation, and must match for the file to be considered by the MMV PMDA. .PP The flags can specify ways in which the client would like the MMV PMDA to behave - e.g. the MMV_FLAG_PROCESS flag specifies that only if the process identified by PID is currently running should those values be exported. .PP Finally, if set, the cluster identifier is a hint to the MMV PMDA as to what cluster should be used with this application when forming the individual metric identifiers. A performance metric identifier (see \f2PMDA\f1(3)) consists of the PMDA domain number, the cluster number, and the individual item numbers described in the Metrics section. .PP The header is followed by at least 2 TOC sections: one section for metrics and another for values. The TOC section has the following format: .TS box,center; c | c | c n | n | l. Offset Length Value _ 0 4 Section Type (see \f2mmv_stats.h\f1) _ 4 4 Number of entries in the section _ 8 8 Section's offset from the start of the file .TE .PP .PP The section types are: .IP 1: Indoms (instance domain definitions) .IP 2: Instances .IP 3: Metrics (metric definitions) .IP 4: Values .IP 5: String .PP The only mandatory sections are Metrics and Values. Indoms and Instances sections only appear if there are metrics with multiple instances. String sections only appear if there are metrics with string values, or when Metrics or Indoms are defined with help text. .PP The entries in the Indoms section have the following format: .TS box,center; c | c | c n | n | l. Offset Length Value _ 0 4 Unique serial number for this domain _ 4 4 Number of entries in the domain _ 8 8 Offset to first instance _ 16 8 Short help text offset _ 24 8 Long help text offset .TE .PP .PP The entries in the Instances section have the following format: .TS box,center; c | c | c n | n | l. Offset Length Value _ 0 8 Offset into the indom section _ 8 4 Unused padding (zero filled) _ 12 4 Internal instance identifier _ 16 64 External instance identifier .TE .PP .PP The entries in the Metrics section have the following format: .TS box,center; c | c | c n | n | l. Offset Length Value _ 0 64 Metric Name _ 64 4 Metric Item (see \f2PMDA\f1(3)) _ 68 4 Metric Type (see \f2mmv_stats.h\f1) _ 72 4 Semantics (see \f2PMAPI\f1(3)) _ 76 4 Dimensions (see \f2PMAPI\f1(3)) _ 80 4 Instance Domain ID _ 84 4 Unused padding (zero filled) _ 88 8 Short help text offset _ 96 8 Long help text offset .TE .PP .PP The entries in the Values section have the following format: .TS box,center; c | c | c n | n | l. Offset Length Value _ 0 8 \f3pmAtomValue\f1 (see \f2PMAPI\f1(3)) _ 8 8 Extra space for STRING and ELAPSED _ 16 8 Offset into the Metrics section _ 24 8 Offset into the Instances section .TE .PP .PP Each entry in the strings section is a 256 byte character array, containing a single NULL-terminated character string. So each string has a maximum length of 256 bytes, which includes the terminating NULL. .PP .SH SEE ALSO .BR PCPIntro (1), .BR PMAPI (3), .BR mmv_stats_init (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man5/pmns.50000664000000000000000000001462112272262501013264 0ustar '\"! tbl | mmdoc '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNS 5 "PCP" "Performance Co-Pilot" .SH NAME \f3pmns\f1 \- the performance metrics name space .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS .I $PCP_VAR_DIR/pmns .SH DESCRIPTION When using the Performance Metrics Programming Interface (PMAPI) of the Performance Co-Pilot (PCP), performance metrics are identified by an external name in a hierarchic Performance Metrics Name Space (PMNS), and an internal identifier, the Performance Metric Identifier (PMID). .PP A PMNS specifies the association between a metric's name and its PMID. .PP A PMNS is defined on one or more ASCII source files. .PP Loading of a PMNS is done by calling .BR pmLoadNameSpace (3) or .BR pmLoadASCIINameSpace (3). .PP By default duplicate PMIDs are not allowed in the PMNS, although .BR pmLoadASCIINameSpace (3) provides an alternative interface with user-defined control over the processing of duplicate PMIDs in the PMNS. The external format for a PMNS conforms to the syntax and semantics described in the following sections. .PP There is one default PMNS in the files below .IR $PCP_VAR_DIR/pmns , although users and application developers are free to create and use alternate PMNS's. For an example of this, see the PCP Tutorial in .IR $PCP_DEMOS_DIR/Tutorial . .PP Although an application can call .BR pmLoadNameSpace (3), normally this is only done directly for the .B \-n command line option where an explicit root PMNS file is specified. Since PCP version 2 uses a distributed PMNS (see below), an application can extract PMNS information from a host's PMCD or an archive. If the PMNS source is a version 1 archive (see .BR PCPIntro (1)), however, then the local PMNS will be loaded using the path specified by the environment variable .BR PMNS_DEFAULT . .SH DISTRIBUTED PMNS In PCP version 1, the PMNS functions in the API all operated on a PMNS loaded locally from a file. Since PCP version 2, however, PMNS functions may get the PMNS information remotely from a PMCD or directly from the meta data of an archive. .SH PROCESSING FRAMEWORK .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. The PMNS specification is initially passed through .BR pmcpp (1). This means the following facilities may be used in the specification .IP + 3n C-style comments .IP + 3n .CW #include directives .IP + 3n .CW #define directives and macro substitution .IP + 3n conditional processing via .CW #ifdef \&... .CW #endif , etc. .PP When .BR pmcpp (1) is executed, the ``standard'' include directories are the current directory and .IR $PCP_VAR_DIR/pmns . .SH SYNTAX The general syntax for a non-leaf node in the PMNS is as follows .PP .ft CW .nf pathname { name [pmid] ... } .fi .ft R .PP Where .CW pathname is the full pathname from the root of the PMNS to this non-leaf node, with each component in the pathname separated by a ``.''. The root node for the PMNS must have the special name ``root'', but the common prefix ``root.'' must be omitted from all pathnames. Each component in the pathname must begin with an alphabetic character, and be followed by zero or more characters drawn from the alphabetics, the digits and the underscore ``_'') character. For alphabetic characters in a pathname component, upper and lower case are distinguished. .PP Non-leaf nodes in the PMNS may be defined in any order. .PP The descendent nodes are defined by the set of .CW names , relative to the .CW pathname of their parent non-leaf node. For the descendent nodes, leaf nodes have a .CW pmid specification, non-leaf nodes do not. The syntax for the .CW pmid specification has been chosen to help manage the allocation of PMIDs across disjoint and autonomous domains of administration and implementation. Each .CW pmid consists of 3 integer parts, separated by colons, e.g. 14:27:11. This hierarchic numbering scheme is intended to mirror the implementation hierarchy of performance metric domain, metrics cluster (data structure or operational similarity) and individual metric. In practice, the two leading components are likely to be macros in the PMNS specification source, and .BR pmcpp (1) will convert the macros to integers. These macros for the initial components of the .CW pmid are likely to be defined either in a standard include file, e.g. \c .IR $PCP_VAR_DIR/pmns/stdpmid , or in the current source file. .PP To support dynamic metrics, where the existence of a metric is known to a PMDA, but not visible in the PMNS, a variant syntax for the .CW pmid is supported, namely a domain number followed by asterisks for the other components of the .CW pmid , e.g. 14:*:*. The corresponding metric name forms the root of a subtree of dynamic metric names defined in the corresponding PMDA as identified by the domain number. .PP The current allocation of the high-order (PMD or domain) component of PMIDs is as follows. .TS box,center; c | c n | l. Range Allocation _ 0 reserved _ 1-31 PMDAs from the PCP base product _ 32-39 Oracle _ 40-47 Sybase _ 48-55 Informix _ 56-58 SNMP Gateway PMDA _ 59-63 Linux PMDAs _ 64-69 ISV PMDAs _ 70-128 more PMDAs from the PCP base product _ 129-510 End-user PMDAs and demo PMDAs _ 511 RESERVED .TE .SH EXAMPLE .ft CW .nf #define KERNEL 1 #define FOO 317 root { network cpu dynamic FOO:*:* } #define NETWORK 26 network { intrate KERNEL:NETWORK:1 packetrate } network.packetrate { in KERNEL:NETWORK:35 out KERNEL:NETWORK:36 } #define CPU 10 cpu { syscallrate KERNEL:CPU:10 util } #define USER 20 #define SYSTEM 21 #define IDLE 22 cpu.util { user KERNEL:CPU:USER sys KERNEL:CPU:SYSTEM idle KERNEL:CPU:IDLE } .fi .ft R .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmcpp (1), .BR PCPIntro (3), .BR PMAPI (3), .BR pmErrStr (3), .BR pmGetConfig (3), .BR pmLoadASCIINameSpace (3), .BR pmLoadNameSpace (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man5/pcp.conf.50000664000000000000000000000601512272262501014013 0ustar '\"! tbl | mmdoc '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PCP.CONF 5 "PCP" "Performance Co-Pilot" .SH NAME \f3pcp.conf\f1 \- the Performance Co-Pilot configuration and environment file .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS .I /etc/pcp.conf .SH DESCRIPTION When using Performance Co-Pilot (PCP) tools and utilities and when calling PCP library functions, a standard set of environment variables are defined in .IR /etc/pcp.conf . These variables are generally used to specify the location of various PCP pieces in the file system and may be loaded into shell scripts by sourcing the .IR /etc/pcp.env (5) shell script and queried by C/C++ programs using the .IR pmGetConfig (3) library function. If a variable is already defined in the environment, the values in .I pcp.conf do .B not override those values, i.e. the values in .I pcp.conf serve as installation defaults only. .PP Both the .I pcp.env and .I pcp.conf files are expected to be found in .I /etc by default. If required, the .I pcp.conf file may be relocated and .B PCP_CONF set in the environment to specify the full path to the new location. The .I pcp.env file can not be relocated (this is the only hard coded path required by PCP). .PP The syntax rules for .I pcp.conf are as follows : .IP 1. 4 the general syntax is .br .ce 1 .B "PCP_VARIABLE_NAME=variable value to end of line" .IP 2. 4 lines that begin with .B # and all blank lines are ignored. .IP 3. 4 all variables must be prefixed with .BR PCP_ . This is a security issue - variables that do not have this prefix will be silently ignored. .IP 4. 4 there should be no space between the variable name and the literal .B = and no space between the .B = and the variable value (unless the value actually starts with a space). This is required because the .I pcp.conf file may be sourced directly by Makefiles as well as interpreted by the .I pcp.env script and the .I "pmGetConfig" function. .IP 5. 4 variable values may contain spaces and should .B not be quoted. The .I pcp.env script automatically quotes all variable values from the character immediately following the .B = through to the end of the line. .PP For further details and an explanation of the use of each variable, see the comments in the .I /etc/pcp.conf file itself. .SH ENVIRONMENT The .B PCP_CONF environment variable specifies an alternative path to the .I pcp.conf file. .SH SEE ALSO .BR PCPIntro (1), .BR PCPIntro (3), .BR PMAPI (3), .BR pmGetConfig (3) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man5/GNUmakefile0000664000000000000000000000161012272262521014267 0ustar # # Copyright (c) 2014 Red Hat. # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs MAN_SECTION = 5 MAN_PAGES = $(shell echo *.5) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) LSRCFILES = $(MAN_PAGES) default_pcp default : $(MAN_PAGES) include $(BUILDRULES) install install_pcp : default @$(INSTALL_MAN) pcp-3.8.12ubuntu1/man/man5/pcp.env.50000664000000000000000000000314512272262501013657 0ustar '\"! tbl | mmdoc '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PCP.ENV 5 "PCP" "Performance Co-Pilot" .SH NAME \f3pcp.env\f1 \- script to set Performance Co-Pilot run-time environment variables .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS .I /etc/pcp.env .SH DESCRIPTION The .I pcp.env script is sourced by assorted Performance Co-Pilot (PCP) scripts and utilities to define the PCP operating environment variables. The conjugate for executable programs using the PCP libraries is the .IR __pmGetConfig (3) function. .PP Typical usage of .I pcp.env in a script is as follows : .IP #! /bin/sh # source the PCP environment variables . /etc/pcp.env rest of script ... .PP The full syntax and semantics of the .I pcp.conf file and the .I __pmGetConfig function are described in their respective reference pages. .SH ENVIRONMENT The .B PCP_CONF environment variable specifies an alternative path to the .I pcp.conf file. .SH SEE ALSO .BR PCPIntro (1), .BR PCPIntro (3), .BR PMAPI (3), .BR __pmGetConfig (3) and .BR pcp.conf (5). pcp-3.8.12ubuntu1/man/man5/pmieconf.50000664000000000000000000002352412272262501014111 0ustar '\"macro stdmacro .ie \(.g \{\ .\" ... groff (hack for khelpcenter, man2html, etc.) .TH PMIECONF 5 "PCP" "Performance Co-Pilot" \} .el \{\ .if \nX=0 .ds x} PMIECONF 5 "PCP" "Performance Co-Pilot" .if \nX=1 .ds x} PMIECONF 5 "Performance Co-Pilot" .if \nX=2 .ds x} PMIECONF 5 "" "\&" .if \nX=3 .ds x} PMIECONF "" "" "\&" .TH \*(x} .rr X \} .SH NAME pmieconf \- generalized pmie rules and customizations .SH DESCRIPTION The pmieconf file formats are used by the .BR pmieconf (1) tool as a way to generalize .BR pmie (1) rule sets such that they can be easily configured for different systems and different environments. There are two completely different (although closely related) file formats discussed here, namely ``pmieconf-rules'' and ``pmieconf-pmie''. .PP The directory .B $PCP_VAR_DIR/config/pmieconf contains information about all the default system .B pmie generalized rules and variables, including default values for all variables. These files are in the pmieconf-rules format. Although new pmieconf-rules files can be added, the files in this directory should never be changed. Instead, use the .B pmieconf utility to change variable values in the .B pmie configuration file. .PP The pmieconf-pmie format allows site specific customizations of the rules contained in pmieconf-rules files and their associated variables. The pmieconf-pmie format is generated by .B pmieconf and should not be edited by hand. This generated file is in the .B pmie format, with some additional information held at the head of the file \- thus, the pmieconf-pmie format is a superset of the .B pmie file format (extended to hold customizations to the generalized rules, but also containing the actual performance rules for .B pmie to evaluate) which can also be parsed by .B pmie (all extensions are hidden within comments, and are thus meaningless to .B pmie itself). .PP The file .B $PCP_VAR_DIR/config/pmieconf/config.pmie contains local system settings for .B pmieconf configurable variables. The variable settings in this file replace the default values specified in .BR $PCP_VAR_DIR/config/pmieconf/*/* . .SH PMIECONF-PMIE SYNTAX All rule customization lines in a valid pmieconf-pmie specification are prefixed by ``//'' and are located at the head of the file \- this allows files containing a pmieconf-pmie specification to be successfully parsed by .BR pmie . A pmieconf-pmie must always have the first line in the form: .sp .nf // pmieconf-pmie \f2version\f1 \f2pmieconf_path\f1 .fi .sp The .I version specifies which version of the pmieconf-pmie syntax should be used to parse this file. Currently the only supported version is 1. The .I pmieconf_path specifies the path to the pmieconf-rules files which were used, by .BR pmieconf , to generate this file. This is discussed in the .BR pmieconf (1) man page (see the .B \-r option). .PP The remainder of the specification consists of one line entries for each of the modified variables. The syntax for each line is: .sp .nf // \f2rule_version\f1 \f2rule_name\f1 \f2rule_variable\f1 = \f2value\f1 .fi .sp The .I rule_version and .I rule_name are used to identify the rule with which to associate the customization. These are followed by the .I rule_variable name (i.e. the variable of rule .I rule_name which has been changed) for which the new .I value is to be used. .PP A pmieconf-pmie specification must be terminated with the ``end'' keyword. This is used by .B pmieconf to distinguish where the customizations ends, and the actual .B pmie rule component begins. .SH PMIECONF-PMIE EXAMPLE The following example is a valid pmieconf-pmie format file, as generated by .BR pmieconf . In order to make changes by hand which are preserved by .BR pmieconf , see the comments contained in the generated file (below) as to where such changes should be made. .sp .nf // pmieconf-pmie 1 $PCP_VAR_DIR/config/pmieconf // 1 memory.exhausted delta = "4 minutes" // 1 memory.exhausted enabled = yes // 1 memory.exhausted pcplog_action = yes // end // // --- START GENERATED SECTION (do not change this section) --- // generated by pmieconf on: [DATESTAMP] // // 1 memory.exhausted delta = 4 minutes; some_host ( ( avg_sample (swap.pagesout @0..9 ) ) > 0 && 30 %_sample swap.pagesout >= 5 ) -> shell 10 min "$PCP_BINADM_DIR/pmpost Severe demand for real memory" \\ " %vpgsout/s@%h"; // --- END GENERATED SECTION (changes below will be preserved) --- .fi .sp .PP To see how this all works, you can generate this file as follows: .sp .nf # cat \- | pmieconf \-f /tmp/pmieconf.out \\ \-r $PCP_VAR_DIR/config/pmieconf/memory:$PCP_VAR_DIR/config/pmieconf/global modify memory.exhausted delta "4 minutes" modify memory.exhausted enabled yes modify memory.exhausted pcplog_action yes ^D # .fi .sp Then verify that the generated file is a valid .B pmie configuration file using: .sp .nf # pmie \-C /tmp/pmieconf.out .fi .sp This parses the file, and then exits after reporting any syntax errors. Now replace \-C with \-v (above), and watch .B pmie do its work! .SH PMIECONF-RULES SYNTAX A pmieconf-rules specification consists of a number of separate data objects which together form a complete rule specification (note that a specification may span multiple files and even multiple subdirectories). Each object must have an .I identifier string and a data .IR type , followed by an (optional) list of .IR attribute s. .PP The generic specification of a pmieconf-rules object is thus: .sp .nf \f2type\f1 \f2identifier\f1 [ \f2attribute\f1 = \f2value\f1 ]* ; .fi .sp The set of valid .IR type s is: "rule" (rule definition), "string" (arbitrary, double-quote enclosed string), "double", "integer", "unsigned", "percent" (real number between 0 and 100), "hostlist" (space separated list of host names), "instlist" (space separated list of metric instance names), and the four .B pmie action types, namely "print", "shell", "alarm", and "syslog". .PP Rule names use the ``.'' character to introduce the concept of a rule group, e.g. "memory.exhausted" associates this rule with the "memory" group. .B pmieconf can operate at either the level of rule groups or individual rules. The group name "global" is reserved and may not be used with any rule. .PP Usually when an object is created it is associated with the current rule. However, if an object's name is preceded by the reserved group name "global", then that object is visible to all rules. .PP The set of valid .IR attribute s is: "help" (descriptive text about this object), "modify" (\f2value\f1 is yes/no, flags whether .B pmieconf should allow changes), "enabled" (\f2value\f1 is yes/no, flags whether this is on or off - only meaningful for rules and actions), "display" (yes/no - flags whether .B pmieconf should show this object), "default" (\f2value\f1 determined by \f2type\f1, and is the default value for this object), and specific to objects of rule type are the "version", "predicate", and "enumerate" attributes. "version" and "predicate" are fairly self explanatory ("predicate" must equate to a valid .B pmie rule when expanded), but "enumerate" requires further discussion. .PP The "enumerate" clause is useful when you wish to generate multiple, similar .B pmie rules from a single predicate. This is most useful for rule definitions wishing to use the "some_inst" clause in the .B pmie language across multiple hosts. For a rule to use these together, it must be certain that the instance list is the same on all of the monitored hosts. This is rarely true, so the "enumerate" attribute allows us to generate multiple rules, expanded over variables of either type "instlist" or "hostlist". These variables make up the value for the "enumerate" attribute \- which is a space-separated list of "instlist" or "hostlist" variable names. .PP Objects can be incorporated into other object definitions using the $\f2identifier\f1$ syntax. See the example later for more insight into how this is useful. .PP When .B pmieconf is generating the .B pmie configuration file, it looks at each enabled rule with N enabled actions (where N > 0) and expands the string: .sp .nf // "version" \f2identifier\f1 delta = $delta$; "predicate" -> $threshold$ $action1$ & ... & $actionN$ ; .fi .sp The delta, threshold, and action variables are defined globally (using the "global" keyword) for all rules, but can, of course, be changed at the level of an individual rule or rule group. .SH PMIECONF-RULES EXAMPLE The following is an example of a single pmieconf-rules specification, showing a number of different aspects of the language discussed above. The example defines a rule ("memory.exhausted") and a string ("rule"). .sp .nf rule memory.exhausted default = "$rule$" predicate = "some_host ( ( avg_sample (swap.pagesout $hosts$ @0..9 ) ) > 0 && $pct$ %_sample swap.pagesout $hosts$ @0..9 >= $threshold$ )" enabled = yes version = 1 help = "The system is swapping modified pages out of main memory to the swap partitions, and has been doing this on at least pct of the last 10 evaluations of this rule. There appears to be insufficient main memory to meet the resident demands of the current workload."; string rule default = "Severe demand for real memory" modify = no display = no; .fi .sp Note that for the above rule to be complete, "threshold" and "pct" would also need to be defined - for the full expression of this rule, refer to .IR $PCP_VAR_DIR/config/pmieconf/memory/exhausted . .PP .SH FILES .PD 0 .TP 10 .IR $PCP_VAR_DIR/config/pmieconf/ */* generalized system resource monitoring rules .TP 10 .I $PCP_VAR_DIR/config/pmieconf/config.pmie default super-user settings for system resource monitoring rules .TP 10 .I $HOME/.pcp/pmie/config.pmie default user settings for system resource monitoring rules .PD .SH SEE ALSO .BR pmie (1) and .BR pmieconf (1). pcp-3.8.12ubuntu1/man/GNUmakefile0000664000000000000000000000205012272262501013424 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = .. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs SUBDIRS = man1 man3 man5 default :: default_pcp default_pcp : $(SUBDIRS) $(SUBDIRS_MAKERULE) install :: default_pcp install_pcp install_pcp : $(SUBDIRS) $(SUBDIRS_MAKERULE) include $(BUILDRULES) pcp-3.8.12ubuntu1/man/man1/0000775000000000000000000000000012272262617012221 5ustar pcp-3.8.12ubuntu1/man/man1/pmcollectl.10000664000000000000000000002240212272262501014431 0ustar '\"macro stdmacro .\" .\" Copyright 2012, Red Hat. .\" Copyright 2003-2011, Hewlett-Packard Development Company, LP .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMCOLLECTL 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmcollectl\f1 \- collect data that describes the current system status .SH SYNOPSIS \f3pmcollectl\f1 [\f3\-f\f1 \f2file\f1 | \f3\-p\f1 \f2file\f1 ...] \f2[options\f1 ...] .SH DESCRIPTION .B pmcollectl is a system-level performance monitoring utility that records or displays specific operating system data for one or more sets of subsystems. Any of the subsystems (such as CPU, Disks, Memory or Sockets) can be included or excluded from data collection. Data can either be displayed immediately to a terminal, or stored in files for retrospective analysis. .PP .B pmcollectl is a .BR python (1) script providing much of the functionality available from the .BR collectl (1) Linux utility (which happens to be written in .BR perl (1)). .PP It makes use of the Performance Co-Pilot (PCP) toolkit to simplify its implementation, as well as provide more of the .B collectl functionality on platforms other than Linux. .PP .B pmcollectl has two primary modes of operation: .IP 1. 0.3i Record Mode (\f3\-f\f1 or \f3\-\-filename\f1 option) which reads data from a live system and writes output to a file or displays it on a terminal. .IP 2. 0.3i Playback Mode (\f3\-p\f1 or \f3\-\-playback\f1 option) which reads data from one or more PCP archive files and displays output on a terminal. Note that these files are .I not raw .B collectl format data, rather they are archives created by the .BR pmlogger (1) utility (possibly indirectly, through use of the \f3\-f\f1 option to .BR pmcollectl ). .PP .SH "RECORD MODE OPTIONS" In this mode data is taken from a .BR live system and either displayed on the terminal or written to a PCP archive. .PP .B "\-h host" .RS Display metrics from .I host instead of displaying metrics from the local host. .RE .PP .\" .B "--align" .\" .RS .\" .BR pmcollectl .\" sample monitoring will be aligned such that a sample will always be taken at the .\" top of a minute (this does NOT mean the first sample will occur then) so that all .\" instances of .\" .BR .\" pmcollect .\" running on any systems which have their clocks synchronized .\" will all take samples at the same time. .\" .RE .\" .\" .B "--all" .\" .RS .\" Collect summary data for ALL subsystems except slabs, since slab monitoring requires .\" a different monitoring interval. .\" You can use this switch anywhere \f3\-s\f1 can be used but not both together. .\" .RE .\" .B "\-c, --count samples" .RS The number of samples to record. .RE .PP .\" .\" .B "\-D, --daemon" .\" .RS .\" Run .\" .BR pmcollectl .\" as a daemon, primarily used when starting as a service. .\" This option sets the sampling interval to once every 10 seconds by default. .\" .RE .\" .B "\-f, --filename filename" .RS This is the name of a PCP archive to write the output to. .RE .PP .\" .\" .B "\-F, --flush seconds" .\" .RS .\" Flush output buffers after this number of seconds. This is equivalent to .\" issuing .\" .B kill \-s USR1 .\" to .\" .B pmlogger .\" at the same frequency (but a lot easier!). If 0, a flush will occur every .\" data collection interval. .\" .RE .\" .\" .B --home .\" .RS .\" Always start the display for the current interval at the top of the screen .\" also known as the home position (non-plot format only). This generates a .\" real-time, continuously refreshing display when the data fits on a single screen. .\" .RE .\" .B "\-i, --interval interval" .RS This is the sampling interval in seconds. The default is 1 second. .\" The default is 10 seconds when run as a daemon and 1 second otherwise. .RE .\" .\" .B --nohup .\" .RS .\" Whenever collectl finishes a data collection interval, it checks to see if the starting parent .\" has exited. This is to prevent the case in which someone might start a copy of collectl .\" and then the process dies and collectl keeps running. If that is the behavior someone .\" actually intends, they should start collectl with --nohup. .\" .\" NOTE - when running as a daemon, --nohup is implied. .\" .RE .\" .B "\-R, --runtime duration" .RS Specify the duration of data collection where the duration is a number followed by one of .BR wdhms, indicating how many weeks, days, hours, minutes or seconds the collection is to be taken for. .RE .\" .PP .SH "PLAYBACK MODE OPTIONS" In this mode, data is read from one or more PCP data files that were generated with the recording option, or indirectly via the .B pmlogger utility. .PP .B "\-f, --filename filename" .RS If specified, this is the name of a PCP archive to write the output to (rather than the terminal). .RE .PP .\" .B "--from timerange" .\" .RS .\" Play back data starting with this time, which may optionally include the ending .\" time as well, which is of the format of [date:]time[-[date:]time]. .\" The leading 0 of the hour is optional and if the seconds field is not specified .\" is assumed to be 0. If no dates specified the time(s) apply to each file specified .\" by \-P. Otherwise the time(s) only apply to the first/last dates and any files .\" between those dates will have all their data reported. .\" .RE .\" .B "\-p, --playback filename" .RS Read data from the specified PCP archive files(s). .RE .PP .\" .B "--thru time" .\" .RS .\" Time thru which to play back a raw file. See --from for more .\" .RE .SH "COMMON OPTIONS" The following options are supported in both record and playback modes. .PP .B \--help .RS Display standard help message. .RE .PP .\" .\" .B --hr, --headerrepeat num .\" .RS .\" Sets the number of intervals to display data for before repeating the header. .\" A value \-1 will prevent any headers from being displayed and a value of 0 .\" will cause only a single header to be displayed and never repeated. .\" .RE .\" .\" .B \-N, --nice .\" .RS .\" Set priority to a .\" .BR nicer .\" one of 10. .RE .B "\-s, --subsys subsystem" .RS This field controls which subsystem data is to be collected or played back for. The rules for displaying results vary depending on the type of data to be displayed. If you write data for CPUs and DISKs to a raw file and play it back with \-sc, you will only see CPU data. If you play it back with \f3\-scm\f1 you will still only see CPU data since memory data was not collected. .\" However, when used with \f3\-P\f1, .\" .B pmcollectl .\" will always honor the subsystems specified with .\" this switch so in the previous example you will see CPU .\" data plus memory data of all 0s. To see the current set of default subsystems, which are a subset of this full list, use \f3\-h\f1. .PP .\" You can also use + or \- to add or subtract subsystems to/from the default values. .\" For example, "\-s\-cdn+N"< will remove cpu, disk and network monitoring from the .\" defaults while adding network detail. .PP The default is "cdn", which stands for CPU, Disk and Network summary data. .TP .B "SUMMARY SUBSYSTEMS" .PP .\" .br .\" b \- buddy info (memory fragmentation) .br c \- CPU .br d \- Disk .br f \- NFS V3 Data .br .\" i \- Inode and File System .\" .br j \- Interrupts .br .\" l \- Lustre .\" .br m \- Memory .br n \- Networks .br .\" s \- Sockets .\" .br .\" t \- TCP .\" .br .\" x \- Interconnect .br y \- Slabs (system object caches) .RS .RE .PP .TP .B "DETAIL SUBSYSTEMS" .PP This is the set of .BR detail data from which in most cases the corresponding summary data is derived. So, if one has 3 disks and chooses .B \-sd, one will only see a single total taken across all 3 disks. If one chooses .B \-sD, individual disk totals will be reported but no totals. .\" Choosing .B \-sdD will get you both. .PP .br C \- CPU .br D \- Disk .br F \- NFS Data .br J \- Interrupts .br .\" L \- Lustre OST detail OR client Filesystem detail .\" .br M \- Memory node data, which is also known as NUMA data .br N \- Networks .br .\" T \- 65 TCP counters only available in plot format .\" .br .\" X \- Interconnect .br Y \- Slabs (system object caches) .br Z \- Processes .RE .PP .\" .B \-w .\" .RS .\" Disply data in .\" .BR wide .\" mode. When displaying data on the terminal, some data is formatted followed .\" by a K, M or G as appropriate. Selecting this switch will cause the .\" full field to be displayed. Note that there is no attempt .\" to align data with the column headings in this mode. .\" .RE .PD .B --verbose .RS Display output in verbose mode. This often displays more data than in the default mode. When displaying detail data, verbose mode is forced. Furthermore, if summary data for a single subsystem is to be displayed in verbose mode, the headers are only repeated occasionally whereas if multiple subsystems are involved each needs their own header. .RE .PP .SH "SEE ALSO" .BR PCPIntro (1), .BR collectl (1), .BR perl (1), .BR python (1), .BR pmlogger (1), .BR pmcd (1), .BR pmprobe (1), .BR pmval (1), .BR PMAPI (3), and .BR pcp.conf (5). pcp-3.8.12ubuntu1/man/man1/pmtrace.10000664000000000000000000000656712272262501013744 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMTRACE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmtrace\f1 \- command line performance instrumentation .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS \f3pmtrace\f1 [\f3-q\f1] [\f3\-c\f1 \f2value\f1 | \f3\-e\f1 \f2command\f1 | \f3\-v\f1 \f2value\f1] [\f3\-h\f1 \f2host\f1] [\f3\-S\f1 \f2state\f1] \f2tag\f1 .SH DESCRIPTION .B pmtrace provides a simple command line interface to the trace Performance Metrics Domain Agent (PMDA) and the associated \f2pcp_trace\f1 library. .PP The default .B pmtrace behavior is to provide point trace data to the trace PMDA, using the .I tag argument as the identifying name associated with each trace point. The .I tag then becomes an instance identifier within the set of trace.point metrics. .PP The .B \-e option allows an arbitrary \f2command\f1 to be executed. This \f2command\f1 will be measured as a transaction since it has well defined start and end points. The information is made available through the trace.transact metrics. .PP Trace data can be sent to the trace PMDA running on .IR host , rather than the localhost, using the .B \-h option. This overrides use of the environment variable .BR PCP_TRACE_HOST . .PP The .B \-q option suppresses messages from a successful trace, so that .B pmtrace runs quietly. .PP The .B \-c option allows an arbitrary counter \f2value\f1 to be exported through the trace.count metrics, while the .B \-v option allows an arbitrary floating point \f2value\f1 to be exported through the trace.observe metrics .PP The .B \-S option enables internal debugging and tracing. The value of .I state is a bit-wise combination of debug flags as defined in .BR pmtracestate (3), and may be specified using the decimal or hexadecimal syntax prescribed by .BR strtol (3). .PP .SH ENVIRONMENT Since .B pmtrace uses the \f2libpcp_trace\f1 library routines, the environment variables \f3PCP_TRACE_HOST\f1, \f3PCP_TRACE_PORT\f1, and \f3PCP_TRACE_TIMEOUT\f1 are all honored. Refer to .BR pmdatrace (3) for a detailed description of the semantics of each. .SH FILES .PD 0 .TP 10 .BI $PCP_DEMOS_DIR/trace/pmtrace.c source code for .B pmtrace .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmcd (1), .BR pmdatrace (1), .BR pmprobe (1), .BR PMAPI (3), and .BR pmdatrace (3). .SH DIAGNOSTICS All are generated on standard error and are intended to be self-explanatory. .PP The .B pmtrace exit status is always zero except when the .B \-e option is in use, in which case the exit status of \f2command\f1 is returned. pcp-3.8.12ubuntu1/man/man1/pmcd.10000664000000000000000000010712612272262501013225 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012-2013 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMCD 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmcd\f1 \- performance metrics collector daemon .SH SYNOPSIS \f3pmcd\f1 [\f3\-AfS\f1] [\f3\-c\f1 \f2config\f1] [\f3\-C\f1 \f2dirname\f1] [\f3\-H\f1 \f2hostname\f1] [\f3\-i\f1 \f2ipaddress\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-L\f1 \f2bytes\f1] [\f3\-\f1[\f3n\f1|\f3N\f1] \f2pmnsfile\f1] [\f3\-p\f1 \f2port\f1[,\f2port\f1 ...] [\f3\-P\f1 \f2passfile\f1] [\f3\-q\f1 \f2timeout\f1] [\f3\-s\f1 \f2sockname\f1] [\f3\-T\f1 \f2traceflag\f1] [\f3\-t\f1 \f2timeout\f1] [\f3\-U\f1 \f2username\f1] [\f3\-x\f1 \f2file\f1] .SH DESCRIPTION .B pmcd is the collector used by the Performance Co-Pilot (see .BR PCPIntro (1)) to gather performance metrics on a system. As a rule, there must be an instance of .B pmcd running on a system for any performance metrics to be available to the PCP. .PP .B pmcd accepts connections from client applications running either on the same machine or remotely and provides them with metrics and other related information from the machine that .B pmcd is executing on. .B pmcd delegates most of this request servicing to a collection of Performance Metrics Domain Agents (or just agents), where each agent is responsible for a particular group of metrics, known as the domain of the agent. For example the .B postgresql agent is responsible for reporting information relating to the PostgreSQL database, such as the transaction and query counts, indexing and replication statistics, and so on. .PP The agents may be processes started by .BR pmcd , independent processes or Dynamic Shared Objects (DSOs, see .BR dlopen (3)) attached to .BR pmcd 's address space. The configuration section below describes how connections to agents are specified. .PP The options to .B pmcd are as follows. .TP .B \-A Disable service advertisement. By default, .B pmcd will advertise its presence on the network using any available mechanisms (such as Avahi/DNS-SD), assisting remote monitoring tools with finding it. These mechanisms are disabled with this option. .TP \f3\-c\f1 \f2config\f1 On startup .B pmcd uses a configuration file from either the .IR $PCP_PMCDCONF_PATH , configuration variable in .IR /etc/pcp.conf , or an environment variable of the same name. However, these values may be overridden with .I config using this option. The format of this configuration file is described below. .TP \f3\-C\f1 \f2dirname\f1 Specify the path to the Network Security Services certificate database, for (optional) secure connections. The default is .BR /etc/pki/nssdb . Refer also to the \f3\-P\f1 option. If it does not already exist, this database can be created using the .B certutil utility. This process and other certificate database maintenance information is provided in the .BR PCPIntro (1) manual page and the online PCP tutorials. .TP .B \-f By default .B pmcd is started as a daemon. The .B \-f option indicates that it should run in the foreground. This is most useful when trying to diagnose problems with misbehaving agents. .TP \f3\-H\f1 \f2hostname\f1 This option can be used to set the hostname that .B pmcd will use to represent this instance of itself. This is used by client tools like .BR pmlogger (1) when reporting on the (possibly remote) host. If this option is not set, the pmcd.hostname metric will match that returned by .BR pmhostname (1). Refer to the manual page for that tool for full details on how the hostname is evaluated. .TP \f3\-i\f1 \f2ipaddress\f1 This option is usually only used on hosts with more than one network interface. If no .B \-i options are specified .B pmcd accepts connections made to any of its host's IP (Internet Protocol) addresses. The .B \-i option is used to specify explicitly an IP address that connections should be accepted on. .I ipaddress should be in the standard dotted form (e.g. 100.23.45.6). The .B \-i option may be used multiple times to define a list of IP addresses. Connections made to any other IP addresses the host has will be refused. This can be used to limit connections to one network interface if the host is a network gateway. It is also useful if the host takes over the IP address of another host that has failed. In such a situation only the standard IP addresses of the host should be given (not the ones inherited from the failed host). This allows PCP applications to determine that a host has failed, rather than connecting to the host that has assumed the identity of the failed host. .TP \f3\-l\f1 \f2logfile\f1 By default a log file named .I pmcd.log is written in the directory .BR $PCP_LOG_DIR/pmcd . The .B \-l option causes the log file to be written to .I logfile instead of the default. If the log file cannot be created or is not writable, output is written to the standard error instead. .TP \f3\-L\f1 \f2bytes\f1 .IR PDU s received by .B pmcd from monitoring clients are restricted to a maximum size of 65536 bytes by default to defend against Denial of Service attacks. The .B \-L option may be used to change the maximum incoming .I PDU size. .TP \f3\-n\f1 \f2pmnsfile\f1 Normally .B pmcd loads the default Performance Metrics Name Space (PMNS) from .BR $PCP_VAR_DIR/pmns/root , however if the .B \-n option is specified an alternative namespace is loaded from the file .IR pmnsfile . .TP \f3\-N\f1 \f2pmnsfile\f1 Same function as .BR \-n , except for the handling of duplicate Performance Metric Identifiers (PMIDs) in .I pmnsfile \- duplicates are allowed with .B \-N they are not allowed with .BR \-n . .TP \f3\-P\f1 \f2passfile\f1 Specify the path to a file containing the Network Security Services certificate database password for (optional) secure connections, and for databases that are password protected. Refer also to the \f3\-C\f1 option. When using this option, great care should be exercised to ensure appropriate ownership ("pcp" user, typically) and permissions on this file (0400, so as to be unreadable by any user other than the user running the .B pmcd process). .TP \f3\-q\f1 \f2timeout\f1 The pmcd to agent version exchange protocol (new in PCP 2.0 - introduced to provide backward compatibility) uses this timeout to specify how long pmcd should wait before assuming that no version response is coming from an agent. If this timeout is reached, the agent is assumed to be an agent which does not understand the PCP 2.0 protocol. The default timeout interval is five seconds, but the .B \-q option allows an alternative timeout interval (which must be greater than zero) to be specified. The unit of time is seconds. .TP .B \-S Require that all client connections provide user credentials. This means that only unix domain sockets, or authenticated connections are permitted (requires secure sockets support). If any user or group access control requirements are specified in the pmcd configuration file, then this mode of operation is automatically entered, whether the \f3\-S\f1 flag is specified or not. .TP \f3\-s\f1 \f2sockname\f1 Specify the path to a local unix domain socket (for platforms supporting this socket family only). The default value is .IR $PCP_RUN_DIR/pmcd.socket . .TP \f3\-t\f1 \f2timeout\f1 To prevent misbehaving clients or agents from hanging the entire Performance Metrics Collection System (PMCS), .B pmcd uses timeouts on PDU exchanges with clients and agents running as processes. By default the timeout interval is five seconds. The .B \-t option allows an alternative timeout interval in seconds to be specified. If .I timeout is zero, timeouts are turned off. It is almost impossible to use the debugger interactively on an agent unless timeouts have been turned off for its "parent" .BR pmcd . .RS .PP Once .B pmcd is running, the timeout may be dynamically modified by storing an integer value (the timeout in seconds) into the metric .B pmcd.control.timeout via .BR pmstore (1). .RE .TP \f3\-T\f1 \f2traceflag\f1 To assist with error diagnosis for agents and/or clients of .B pmcd that are not behaving correctly, an internal event tracing mechanism is supported within .BR pmcd . The value of .I traceflag is interpreted as a bit field with the following control functions: .RS .TP 4n .PD 0 .B 1 enable client connection tracing .TP .B 2 enable PDU tracing .TP .B 256 unbuffered event tracing .PD .PP By default, event tracing is buffered using a circular buffer that is over-written as new events are recorded. The default buffer size holds the last 20 events, although this number may be over-ridden by using .BR pmstore (1) to modify the metric .BR "pmcd.control.tracebufs" . .PP Similarly once .B pmcd is running, the event tracing control may be dynamically modified by storing 1 (enable) or 0 (disable) into the metrics .BR pmcd.control.traceconn , .B pmcd.control.tracepdu and .BR pmcd.control.tracenobuf . These metrics map to the bit fields associated with the .I traceflag argument for the .B \-T option. .PP When operating in buffered mode, the event trace buffer will be dumped whenever an agent connection is terminated by .BR pmcd , or when any value is stored into the metric .B pmcd.control.dumptrace via .BR pmstore (1). .PP In unbuffered mode, .B every event will be reported when it occurs. .RE .TP \f3\-U\f1 \f2username\f1 User account under which to run .BR pmcd . The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .TP \f3\-x\f1 \f2file\f1 Before the .B pmcd .I logfile can be opened, .B pmcd may encounter a fatal error which prevents it from starting. By default, the output describing this error is sent to .B /dev/tty but it may redirected to .IR file . .PP If a PDU exchange with an agent times out, the agent has violated the requirement that it delivers metrics with little or no delay. This is deemed a protocol failure and the agent is disconnected from .BR pmcd . Any subsequent requests for information from the agent will fail with a status indicating that there is no agent to provide it. .PP It is possible to specify access control to .B pmcd based on users, groups and hosts. This allows one to prevent users, groups of users, and certain hosts from accessing the metrics provided by .B pmcd and is described in more detail in the Section on ACCESS CONTROL below. .SH CONFIGURATION On startup .B pmcd looks for a configuration file named .IR $PCP_PMCDCONF_PATH . This file specifies which agents cover which performance metrics domains and how .B pmcd should make contact with the agents. An optional section specifying access controls may follow the agent configuration data. .PP \f3Warning\f1: .B pmcd is usually started as part of the boot sequence and runs initially as root. The configuration file may contain shell commands to create agents, which will be executed by root. To prevent security breaches the configuration file should be writable only by root. The use of absolute path names is also recommended. .PP The case of the reserved words in the configuration file is unimportant, but elsewhere, the case is preserved. .PP Blank lines and comments are permitted (even encouraged) in the configuration file. A comment begins with a ``#'' character and finishes at the end of the line. A line may be continued by ensuring that the last character on the line is a ``\\'' (backslash). A comment on a continued line ends at the end of the continued line. Spaces may be included in lexical elements by enclosing the entire element in double quotes. A double quote preceded by a backslash is always a literal double quote. A ``#'' in double quotes or preceded by a backslash is treated literally rather than as a comment delimiter. Lexical elements and separators are described further in the following sections. .SH "AGENT CONFIGURATION" Each line of the agent configuration section of the configuration file contains details of how to connect .B pmcd to one of its agents and specifies which metrics domain the agent deals with. An agent may be attached as a DSO, or via a socket, or a pair of pipes. .PP Each line of the agent configuration section of the configuration file must be either an agent specification, a comment, or a blank line. Lexical elements are separated by whitespace characters, however a single agent specification may not be broken across lines unless a .B \\\\\& (backslash) is used to continue the line. .PP Each agent specification must start with a textual label (string) followed by an integer in the range 1 to 510. The label is a tag used to refer to the agent and the integer specifies the domain for which the agent supplies data. This domain identifier corresponds to the domain portion of the PMIDs handled by the agent. Each agent must have a unique label and domain identifier. .PP For DSO agents a line of the form: .TP \& \f2label\f1 \f2domain-no\f1 \f3dso\f1 \f2entry-point\f1 \f2path\f1 .PP should appear. Where, .TP 14 .PD 0 .I label is a string identifying the agent .TP 14 .I domain-no is an unsigned integer specifying the agent's domain in the range 1 to 510 .TP 14 .I entry-point is the name of an initialization function which will be called when the DSO is loaded .TP 14 .I path designates the location of the DSO and this is expected to be an absolute pathname. .B pmcd is only able to load DSO agents that have the same .I simabi (Subprogram Interface Model ABI, or calling conventions) as it does (i.e. only one of the .I simabi versions will be applicable). The .I simabi version of a running .B pmcd may be determined by fetching .BR pmcd.simabi . Alternatively, the .BR file (1) command may be used to determine the .I simabi version from the .B pmcd executable. .PD .IP "" 14 For a relative .I path the environment variable .B PMCD_PATH defines a colon (:) separated list of directories to search when trying to locate the agent DSO. The default search path is .BR "$PCP_SHARE_DIR/lib:/usr/pcp/lib" . .PP For agents providing socket connections, a line of the form .TP \& \f2label\f1 \f2domain-no\f1 \f3socket\f1 \f2addr-family\f1 \f2address\f1 [ \f2command\f1 ] .PP should appear. Where, .TP 14 .PD 0 .I label is a string identifying the agent .TP 14 .I domain-no is an unsigned integer specifying the agent's domain in the range 1 to 510 .TP 14 .I addr-family designates whether the socket is in the .B AF_INET, .B AF_INET6 or .B AF_UNIX domain, and the corresponding values for this parameter are .B inet, .B ipv6 and .B unix respectively. .TP 14 .I address specifies the address of the socket within the previously specified .I addr-family. For .B unix sockets, the address should be the name of an agent's socket on the local host (a valid address for the UNIX domain). For .B inet and .B ipv6 sockets, the address may be either a port number or a port name which may be used to connect to an agent on the local host. There is no syntax for specifying an agent on a remote host as a .B pmcd deals only with agents on the same machine. .TP 14 .I command is an optional parameter used to specify a command line to start the agent when .B pmcd initializes. If .I command is not present, .B pmcd assumes that the specified agent has already been created. The .I command is considered to start from the first non-white character after the socket address and finish at the next newline that isn't preceded by a backslash. After a .BR fork (2) the .I command is passed unmodified to .BR execve (2) to instantiate the agent. .PD .PP For agents interacting with the .B pmcd via stdin/stdout, a line of the form: .TP \& \f2label\f1 \f2domain-no\f1 \f3pipe\f1 \f2protocol\f1 \f2command\f1 .PP should appear. Where, .TP 14 .PD 0 .I label is a string identifying the agent .TP 14 .I domain-no is an unsigned integer specifying the agent's domain .TP 14 .I protocol The value for this parameter should be .BR binary . .sp .IP Additionally, the \f2protocol\fP can include the \f3notready\fP keyword to indicate that the agent must be marked as not being ready to process requests from \f3pmcd\f1. The agent will explicitly notify the \f3pmcd\fP when it is ready to process the requests by sending \f3PM_ERR_PMDAREADY\fP PDU. .PD .TP 14 .I command specifies a command line to start the agent when .B pmcd initializes. Note that .I command is mandatory for pipe-based agents. The .I command is considered to start from the first non-white character after the .I protocol parameter and finish at the next newline that isn't preceded by a backslash. After a .BR fork (2) the .I command is passed unmodified to .BR execve (2) to instantiate the agent. .SH "ACCESS CONTROL CONFIGURATION" The access control section of the configuration file is optional, but if present it must follow the agent configuration data. The case of reserved words is ignored, but elsewhere case is preserved. Lexical elements in the access control section are separated by whitespace or the special delimiter characters: square brackets (``['' and ``]''), braces (``{'' and ``}''), colon (``:''), semicolon (``;'') and comma (``,''). The special characters are not treated as special in the agent configuration section. Lexical elements may be quoted (double quotes) as necessary. .PP The access control section of the file must start with a line of the form: .TP .B [access] .PP Leading and trailing whitespace may appear around and within the brackets and the case of the .B access keyword is ignored. No other text may appear on the line except a trailing comment. .PP Following this line, the remainder of the configuration file should contain lines that allow or disallow operations from particular hosts or groups of hosts. .PP There are two kinds of operations that occur via .BR pmcd : .TP 15 .B fetch allows retrieval of information from .BR pmcd . This may be information about a metric (e.g. its description, instance domain or help text) or a value for a metric. .TP 15 .B store allows .B pmcd to be used to store metric values in agents that permit store operations. This may be the actual value of the metric (e.g. resetting a counter to zero). Alternatively, it may be a value used by the PMDA to introduce a change to some aspect of monitoring of that metric (e.g. server side event filtering) \- possibly even only for the active client tool performing the store operation, and not others. .PP Access to .B pmcd can be granted in three ways - by user, group of users, or at a host level. In the latter, all users on a host are granted the same level of access, unless the user or group access control mechanism is also in use. .PP User names and group names will be verified using the local .B /etc/passwd and .B /etc/groups files (or an alternative directory service), using the .BR getpwent (3) and .BR getgrent (3) routines. .PP Hosts may be identified by name, IP address, IPv6 address or by the special host specifications ``"unix:"'' or ``"local:"''. ``"unix:"'' refers to .B pmcd's unix domain socket, on supported platforms. ``"local:"'' is equivalent to specifying ``"unix:"'' and ``localhost``. .PP Wildcards may also be specified by ending the host identifier with the single wildcard character ``*'' as the last-given component of an address. The wildcard ``".*"'' refers to all inet (IPv4) addresses. The wildcard ``":*"'' refers to all IPv6 addresses. If an IPv6 wildcard contains a ``::'' component, then the final ``*'' refers to the final 16 bits of the address only, otherwise it refers to the remaining unspecified bits of the address. .PP The wildcard ``*'' refers to all users, groups or host addresses, including ``"unix:"''. Names of users, groups or hosts may not be wildcarded. .PP The following are all valid host identifiers: .de CS .in +0.5i .ft CW .nf .. .de CE .fi .ft 1 .in .. .PP .CS boing localhost giggle.melbourne.sgi.com 129.127.112.2 129.127.114.* 129.* \&.* fe80::223:14ff:feaf:b62c fe80::223:14ff:feaf:* fe80:* :* "unix:" "local:" * .CE .PP The following are not valid host identifiers: .PP .CS *.melbourne 129.127.*.* 129.*.114.9 129.127* fe80::223:14ff:*:* fe80::223:14ff:*:b62c fe80* .CE .PP The first example is not allowed because only (numeric) IP addresses may contain a wildcard. The second and fifth examples are not valid because there is more than one wildcard character. The third and sixth contain an embedded wildcard, the fourth and seventh have a wildcard character that is not the last component of the address (the last components are \f(CW127*\f1 and \f(CWfe80*\f1 respectively). .PP The name .B localhost is given special treatment to make the behavior of host wildcarding consistent. Rather than being 127.0.0.1 and ::1, it is mapped to the primary inet and IPv6 addresses associated with the name of the host on which .B pmcd is running. Beware of this when running .B pmcd on multi-homed hosts. .PP Access for users, groups or hosts are allowed or disallowed by specifying statements of the form: .TP \& \f3allow users\f1 \f2userlist\f1 \f3:\f1 \f2operations\f1 \f3;\f1 .br \f3disallow users\f1 \f2userlist\f1 \f3:\f1 \f2operations\f1 \f3;\f1 .br \f3allow groups\f1 \f2grouplist\f1 \f3:\f1 \f2operations\f1 \f3;\f1 .br \f3disallow groups\f1 \f2grouplist\f1 \f3:\f1 \f2operations\f1 \f3;\f1 .br \f3allow hosts\f1 \f2hostlist\f1 \f3:\f1 \f2operations\f1 \f3;\f1 .br \f3disallow hosts\f1 \f2hostlist\f1 \f3:\f1 \f2operations\f1 \f3;\f1 .PP .TP 14 .IR list .IR userlist , .I grouplist and .I hostlist are comma separated lists of one or more users, groups or host identifiers. .TP 14 .I operations is a comma separated list of the operation types described above, .B all (which allows/disallows all operations), or .B all except .I operations (which allows/disallows all operations except those listed). .PP Either plural or singular forms of .BR users , .BR groups , and .B hosts keywords are allowed. If this keyword is omitted, a default of .B hosts will be used. This behaviour is for backward-compatibility only, it is preferable to be explicit. .PP Where no specific .B allow or .B disallow statement applies to an operation, the default is to allow the operation from all users, groups and hosts. In the trivial case when there is no access control section in the configuration file, all operations from all users, groups, and hosts are permitted. .PP If a new connection to .B pmcd is attempted by a user, group or host that is not permitted to perform any operations, the connection will be closed immediately after an error response .B PM_ERR_PERMISSION has been sent to the client attempting the connection. .PP Statements with the same level of wildcarding specifying identical hosts may not contradict each other. For example if a host named .B clank had an IP address of 129.127.112.2, specifying the following two rules would be erroneous: .PP .CS allow host clank : fetch, store; disallow host 129.127.112.2 : all except fetch; .CE .PP because they both refer to the same host, but disagree as to whether the .B fetch operation is permitted from that host. .PP Statements containing more specific host specifications override less specific ones according to the level of wildcarding. For example a rule of the form .PP .CS allow host clank : all; .CE .PP overrides .PP .CS disallow host 129.127.112.* : all except fetch; .CE .PP because the former contains a specific host name (equivalent to a fully specified IP address), whereas the latter has a wildcard. In turn, the latter would override .PP .CS disallow host * : all; .CE .PP It is possible to limit the number of connections from a user, group or host to .BR pmcd . This may be done by adding a clause of the form .TP \& \f3maximum\f1 \f2n\f1 \f3connections\f1 .PP to the .I operations list of an .B allow statement. Such a clause may not be used in a .B disallow statement. Here, .I n is the maximum number of connections that will be accepted from the user, group or host matching the identifier(s) used in the statement. .PP An access control statement with a list of user, group or host identifiers is equivalent to a set of access control statements, with each specifying one of the identifiers in the list and all with the same access controls (both permissions and connection limits). A group should be used if you want users to contribute to a shared connection limit. A wildcard should be used if you want hosts to contribute to a shared connection limit. .PP When a new client requests a connection, and .B pmcd has determined that the client has permission to connect, it searches the matching list of access control statements for the most specific match containing a connection limit. For brevity, this will be called the limiting statement. If there is no limiting statement, the client is granted a connection. If there is a limiting statement and the number of .B pmcd clients with user ID, group ID, or IP addresses that match the identifier in the limiting statement is less than the connection limit in the statement, the connection is allowed. Otherwise the connection limit has been reached and the client is refused a connection. .PP Group access controls and the wildcarding in host identifiers means that once .B pmcd actually accepts a connection from a client, the connection may contribute to the current connection count of more than one access control statement \- the client's host may match more than one access control statement, and similarly the user ID may be in more than one group. This may be significant for subsequent connection requests. .PP Note that .B pmcd enters a mode where it runs effectively with a higher-level of security as soon as a user or group access control section is added to the configuration. In this mode only authenticated connections are allowed \- either from a SASL authenticated connection, or a Unix domain socket (which implicitly passes client credentials). This is the same mode that is entered explicitly using the \f3\-S\f1 option. Assuming permission is allowed, one can determine whether .B pmcd is running in this mode by querying the value of the .I pmcd.feature.creds_required metric. .PP Note also that because most specific match semantics are used when checking the connection limit, for the host-based access control case, priority is given to clients with more specific host identifiers. It is also possible to exceed connection limits in some situations. Consider the following: .IP allow host clank : all, maximum 5 connections; .br allow host * : all except store, maximum 2 connections; .PP This says that only 2 client connections at a time are permitted for all hosts other than "clank", which is permitted 5. If a client from host "boing" is the first to connect to .BR pmcd , its connection is checked against the second statement (that is the most specific match with a connection limit). As there are no other clients, the connection is accepted and contributes towards the limit for only the second statement above. If the next client connects from "clank", its connection is checked against the limit for the first statement. There are no other connections from "clank", so the connection is accepted. Once this connection is accepted, it counts towards .B both statements' limits because "clank" matches the host identifier in both statements. Remember that the decision to accept a new connection is made using only the most specific matching access control statement with a connection limit. Now, the connection limit for the second statement has been reached. Any connections from hosts other than "clank" will be refused. .PP If instead, .B pmcd with no clients saw three successive connections arrived from "boing", the first two would be accepted and the third refused. After that, if a connection was requested from "clank" it would be accepted. It matches the first statement, which is more specific than the second, so the connection limit in the first is used to determine that the client has the right to connect. Now there are 3 connections contributing to the second statement's connection limit. Even though the connection limit for the second statement has been exceeded, the earlier connections from "boing" are maintained. The connection limit is only checked at the time a client attempts a connection rather than being re-evaluated every time a new client connects to .BR pmcd . .PP This gentle scheme is designed to allow reasonable limits to be imposed on a first come first served basis, with specific exceptions. .PP As illustrated by the example above, a client's connection is honored once it has been accepted. However, .B pmcd reconfiguration (see the next section) re-evaluates all the connection counts and will cause client connections to be dropped where connection limits have been exceeded. .SH "RECONFIGURING PMCD" If the configuration file has been changed or if an agent is not responding because it has terminated or the PMNS has been changed, .B pmcd may be reconfigured by sending it a SIGHUP, as in .PP .CS # pmsignal \-a \-s HUP pmcd .CE .PP When .B pmcd receives a SIGHUP, it checks the configuration file for changes. If the file has been modified, it is reparsed and the contents become the new configuration. If there are errors in the configuration file, the existing configuration is retained and the contents of the file are ignored. Errors are reported in the .B pmcd log file. .PP It also checks the PMNS file for changes. If the PMNS file has been modified, then it is reloaded. Use of .BR tail (1) on the log file is recommended while reconfiguring .BR pmcd . .PP If the configuration for an agent has changed (any parameter except the agent's label is different), the agent is restarted. Agents whose configurations do not change are not restarted. Any existing agents not present in the new configuration are terminated. Any deceased agents are that are still listed are restarted. .PP Sometimes it is necessary to restart an agent that is still running, but malfunctioning. Simply stop the agent (e.g. using SIGTERM from .BR pmsignal (1)), then send .B pmcd a SIGHUP, which will cause the agent to be restarted. .SH "STARTING AND STOPPING PMCD" Normally, .B pmcd is started automatically at boot time and stopped when the system is being brought down (see .BR rc2 (1M) and .BR rc0 (1M)). Under certain circumstances it is necessary to start or stop .B pmcd manually. To do this one must become superuser and type .PP .CS # $PCP_RC_DIR/pcp start .CE .PP to start .BR pmcd , or .PP .CS # $PCP_RC_DIR/pcp stop .CE .PP to stop .BR pmcd . Starting .B pmcd when it is already running is the same as stopping it and then starting it again. .PP Sometimes it may be necessary to restart .B pmcd during another phase of the boot process. Time-consuming parts of the boot process are often put into the background to allow the system to become available sooner (e.g. mounting huge databases). If an agent run by .B pmcd requires such a task to complete before it can run properly, it is necessary to restart or reconfigure .B pmcd after the task completes. Consider, for example, the case of mounting a database in the background while booting. If the PMDA which provides the metrics about the database cannot function until the database is mounted and available but .B pmcd is started before the database is ready, the PMDA will fail (however .B pmcd will still service requests for metrics from other domains). If the database is initialized by running a shell script, adding a line to the end of the script to reconfigure .B pmcd (by sending it a SIGHUP) will restart the PMDA (if it exited because it couldn't connect to the database). If the PMDA didn't exit in such a situation it would be necessary to restart .B pmcd because if the PMDA was still running .B pmcd would not restart it. .P Normally .B pmcd listens for client connections on TCP/IP port number 44321 (registered at .IR http://www.iana.org/ ). Either the environment variable .B PMCD_PORT or the .B \-p command line option may be used to specify alternative port number(s) when .B pmcd is started; in each case, the specification is a comma-separated list of one or more numerical port numbers. Should both methods be used or multiple .B \-p options appear on the command line, .B pmcd will listen on the union of the set of ports specified via all .B \-p options and the .B PMCD_PORT environment variable. If non-default ports are used with .B pmcd care should be taken to ensure that .B PMCD_PORT is also set in the environment of any client application that will connect to .BR pmcd , or that the extended host specification syntax is used (see .BR PCPIntro (1) for details). .SH FILES .PD 0 .TP 10 .I $PCP_PMCDCONF_PATH default configuration file .TP .I $PCP_PMCDOPTIONS_PATH command line options to .B pmcd when launched from .B $PCP_RC_DIR/pcp All the command line option lines should start with a hyphen as the first character. This file can also contain environment variable settings of the form "VARIABLE=value". .TP .B \&./pmcd.log (or .B $PCP_LOG_DIR/pmcd/pmcd.log when started automatically) .TP .B $PCP_RUN_DIR/pmcd.pid contains an ascii decimal representation of the process ID of .B pmcd , when it's running. .br All messages and diagnostics are directed here .TP .B /etc/pki/nssdb default Network Security Services (NSS) certificate database directory, used for optional Secure Socket Layer connections. This database can be created and queried using the NSS .B certutil tool, amongst others. .TP .B /etc/passwd user names, user identifiers and primary group identifiers, used for access control specifications .TP .B /etc/groups group names, group identifiers and group members, used for access control specifications .PD .SH ENVIRONMENT In addition to the PCP environment variables described in the .B "PCP ENVIRONMENT" section below, the .B PMCD_PORT variable is also recognised as the TCP/IP port for incoming connections (default .IR 44321 ), and the .B PMCD_SOCKET variable is also recognised as the path to be used for the Unix domain socket. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH DIAGNOSTICS If .B pmcd is already running the message "Error: OpenRequestSocket bind: Address may already be in use" will appear. This may also appear if .B pmcd was shutdown with an outstanding request from a client. In this case, a request socket has been left in the TIME_WAIT state and until the system closes it down (after some timeout period) it will not be possible to run .BR pmcd . .PP In addition to the standard .B PCP debugging flags, see .BR pmdbg (1), .B pmcd currently uses .B DBG_TRACE_APPL0 for tracing I/O and termination of agents, .B DBG_TRACE_APPL1 for tracing access control and .B DBG_TRACE_APPL2 for tracing the configuration file scanner and parser. .SH CAVEATS .B pmcd does not explicitly terminate its children (agents), it only closes their pipes. If an agent never checks for a closed pipe it may not terminate. .PP The configuration file parser will only read lines of less than 1200 characters. This is intended to prevent accidents with binary files. .PP The timeouts controlled by the .B \-t option apply to IPC between .B pmcd and the PMDAs it spawns. This is independent of settings of the environment variables .B PMCD_CONNECT_TIMEOUT and .B PMCD_REQUEST_TIMEOUT (see .BR PCPIntro (1)) which may be used respectively to control timeouts for client applications trying to connect to .B pmcd and trying to receive information from .BR pmcd . .SH SEE ALSO .BR PCPIntro (1), .BR pmdbg (1), .BR pmerr (1), .BR pmgenmap (1), .BR pminfo (1), .BR pmstat (1), .BR pmstore (1), .BR pmval (1), .BR getpwent (3), .BR getgrent (3), .BR pcp.conf (5), and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmfind.10000664000000000000000000000425612272262501013557 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMFIND 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmfind\f1 \- find PCP services on the network .SH SYNOPSIS \f3pmfind\f1 [\f3\-q\f1] [\f3\-m\f1 \f2mechanism\f1] [\f3\-s\f1 \f2service\f1] .SH DESCRIPTION .B pmfind searches for instances of the specified PCP service being advertised on the network and prints a list of URLs corresponding to the services discovered. .PP By default .B pmfind will search for servers advertising the .BR pmcd (1) service, however an alternate PCP .I service to discover can be specified using the .B \-s option. .PP The .B \-m option sets the .I mechanism that .B pmfind uses when performing service discovery. By default, or if the keyword "all" is specified, every available mechanism will be used (iteratively). Currently, "avahi" is the only supported discovery mechanism. .PP The .B \-q option suppresses all output on the standard output stream. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH DIAGNOSTICS The value of the exit status from the command is zero when services were successfully located, one if no services were found, and two if an error occurred. .PP In the event of an error, a message will be generated on standard error that is intended to be self-explanatory. .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR PMAPI (3), .BR pmDiscoverServices (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmdashping.10000664000000000000000000001306512272262501014432 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDASHPING 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdashping\f1 \- "shell-ping" performance metrics domain agent .SH SYNOPSIS \f3$PCP_PMDAS_DIR/shping/pmdashping\f1 [\f3\-C\f1] [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-I\f1 \f2interval\f1] [\f3\-t\f1 \f2timeout\f1] [\f3\-U\f1 \f2username\f1] \f2configfile\f1 .br .SH DESCRIPTION .B pmdashping is a Performance Metrics Domain Agent (PMDA) which exports quality of service and response time measurements for arbitrary commands as might be run from a shell such as .BR sh (1). .PP These measurements are intended to be used to quantify service quality and service availability for those services that are either mission critical or act as early indicators of adverse system performance. .PP The sample configuration monitors simple shell commands (\c .B exit and .BR date (1)), a short computationally intensive task using .BR sum (1), a short C compilation, DNS lookup via .BR nslookup (1), YP lookup via .BR ypcat (1), bind/portmapper service using .BR rpcbind (1), SMTP by connecting to telnet port 25 and sending an ``expn root'' request, and NNTP by connecting to telnet port 119 and running a ``listgroup'' command. .PP It is expected that other commands would follow the examples in the sample configuration file, and most deployments of the .B pmdashping PMDA are expected to use a customized configuration file. .PP A brief description of the .B pmdashping command line options follows: .TP 5 .B \-C Parse .IR configfile , reporting any errors and exiting with non-zero status if the file contains syntactical errors. .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP 5 .B \-l Location of the log file. By default, a log file named .I shping.log is written in the current directory of .BR pmcd (1) when .B pmdashping is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP 5 .B \-I Amount of time (in seconds) between subsequent executions of the list of commands provided via the configuration file .IR configfile . The default is 2 minutes. .TP 5 .B \-t Amount of time (in seconds) to wait before timing out awaiting a response for a command from .IR configfile . The default is 20 seconds. .TP 5 .B \-U User account under which to run the agent and all commands. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .PP The required .IR configfile specifies ``tag'' and ``command'' pairs, each on a separate line. All of the commands are run one after another, with the whole group rescheduled to be run once per .IR interval . For each command that is run, .B pmdashping records information related to the success (or timeout), exit status, elapsed time and CPU time (system and user), and this information is exported by the PMDA. The tags are used to identify the individual commands amongst the values exported by the PMDA, and form the external instance domain identifiers for the .B pmdashping metrics which relate to each command. .PP .SH INSTALLATION In order for a host to export the names, help text and values for the shping performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/shping # ./Install .in .fi .ft 1 .PP The set of ``tag'' and ``command'' pairs may be specified from a default (sample) configuration file, a customized file or entered interactively as part of the .B Install script. .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/shping # ./Remove .in .fi .ft 1 .PP .B pmdashping is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdashping .TP 10 .B $PCP_PMDAS_DIR/shping/help default help text file for the shping metrics .TP 10 .B $PCP_PMDAS_DIR/shping/sample.conf example configuration file with a number of common commands .TP 10 .B $PCP_PMDAS_DIR/shping/Install installation script for the .B pmdashping agent .TP 10 .B $PCP_PMDAS_DIR/shping/Remove undo installation script for .B pmdashping .TP 10 .B $PCP_LOG_DIR/pmcd/shping.log default log file for error messages and other information from .B pmdashping .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmcd (1) and .BR pmgshping (1). pcp-3.8.12ubuntu1/man/man1/pmdasendmail.10000664000000000000000000000761412272262501014741 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .\" I am variants ... .ds ia sendmail .ds IA SENDMAIL .ds Ia Sendmail .TH PMDASENDMAIL 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdasendmail\f1 \- \*(ia performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/\*(ia/pmda\*(ia\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION .B pmda\*(ia is a \*(ia Performance Metrics Domain Agent (PMDA) which exports mail traffic statistics as collected by .BR sendmail (1). .PP Before the \*(ia PMDA can export any metrics, .BR sendmail (1) must have statistics collection enabled. This involves checking the name of the statistics file, as given by the .B OS or .B "O StatusFile" control lines in .BR /etc/sendmail.cf , and then creating this file if it does not already exist. Removing the file will terminate statistics collection by .BR sendmail (1) and hence the \*(ia PMDA. .PP A brief description of the .B pmda\*(ia command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I \*(ia.log is written in the current directory of .BR pmcd (1) when .B pmda\*(ia is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP 5 .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .PP There are no communication options, as the .I Install script ensures the \*(ia PMDA will be connected to PMCD by a pipe. .SH INSTALLATION If you want access to the names, help text and values for the \*(ia performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/\*(ia # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/\*(ia # ./Remove .in .fi .ft 1 .PP .B pmda\*(ia is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmda\*(ia .TP .B $PCP_PMDAS_DIR/\*(ia/help default help text file for the \*(ia metrics .TP .B $PCP_PMDAS_DIR/\*(ia/Install installation script for the .B pmda\*(ia agent .TP .B $PCP_PMDAS_DIR/\*(ia/Remove undo installation script for the .B pmda\*(ia agent .TP .B $PCP_LOG_DIR/pmcd/\*(ia.log default log file for error messages and other information from .B pmda\*(ia .TP .B /etc/sendmail.cf .B sendmail configuration file to identify the name of the statistics file .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmcd (1) and .BR sendmail (1). pcp-3.8.12ubuntu1/man/man1/pmclient.10000664000000000000000000001135412272262501014112 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMCLIENT 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmclient\f1 \- a simple performance metrics client .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS \f3pmclient\f1 [\f3\-a\f1 \f2archive\f1] [\f3\-h\f1 \f2host\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-p\f1] [\f3\-S\f1 \f2numsec\f1] [\f3\-s\f1 \f2samples\f1] [\f3\-t\f1 \f2interval\f1] [\f3\-Z\f1 \f2timezone\f1] [\f3\-z\f1] .SH DESCRIPTION .B pmclient is a simple client that uses the Performance Metrics Application Programming Interface (PMAPI) to report some high-level system performance metrics. .PP The real value of .B pmclient is as a sample client using the .BR PMAPI (3), interfaces and to this end the source code is included with the Performance Co-Pilot (PCP) package (see .BR PCPIntro (1)), and is typically installed in .IR /usr/share/pcp/demos/pmclient . .PP Normally .B pmclient operates on the distributed Performance Metrics Name Space (PMNS), however if the .B \-n option is specified an alternative local PMNS is loaded from the file .IR pmnsfile . .PP Unless directed to another host by the .B \-h option, or to an archive by the .B \-a option, .B pmclient will contact the Performance Metrics Collector Daemon (PMCD) on the local host to obtain the required information. The .B \-a and .B \-h options are mutually exclusive. .PP By default, .B pmclient reports the time of day according to the local timezone on the system where .B pmclient is run. The .B \-Z option changes the timezone to .I timezone in the format of the environment variable .B TZ as described in .BR environ (5). The .B \-z option changes the timezone to the local timezone at the host that is the source of the performance metrics, as identified via either the .B \-h or .B \-a options. .PP Other options control the specific information to be reported. .TP \f3\-p\f1 The default behavior for replaying an archive, is to replay at full speed. The .B \-p option may be used in conjunction with an archive, to request that the prevailing real-time delay be applied between samples (see .BR \-t ) to effect a pause. .TP \f3\-S\f1 \f2numsec\f1 The .B \-S option may be used in conjunction with an archive to request that display start at the time .I numsec seconds from the start of the archive. .TP \f3\-s\f1 \f2samples\f1 The argument .I samples defines the number of samples to be retrieved and reported. If samples is 0 or .B \-s is not specified, .B pmclient will sample and report continuously (in real time mode) or until the end of the PCP archive (in archive mode). .TP \f3\-t\f1 \f2interval\f1 The default update \f2interval\f1 may be set to something other than the default 5 seconds. The .I interval argument follows the syntax described in .BR PCPIntro (1), and in the simplest form may be an unsigned integer (the implied units in this case are seconds). .PP The output from .B pmclient is directed to standard output, and lists .IP + 3 Aggregate CPU utilization, in the range 0 to 1. .IP + If the system has more than 1 CPU, the ordinal number of the busiest CPU, in the range 0 to ... .IP + If the system has more than 1 CPU, the CPU utilization for the busiest CPU. .IP + Real free memory in Mbytes. .IP + Aggregate physical disk I/O operations per second (IOPS). .IP + Load average over the last 1 minute and over the last 15 minutes. .PP .SH FILES .PD 0 .TP 10 .BI $PCP_VAR_DIR/pmns/ * default PMNS specification files .TP .B $PCP_DEMOS_DIR/pmclient source code and Makefiles when .I pcp.sw.demo is installed .TP .BI $PCP_SYSCONF_DIR/pmlogger/config.pmclient .BR pmlogger (1) configuration for creating an archive suitable for replay with .B pmclient .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmchart (1), .BR pmgenmap (1), .BR pmstat (1), .BR PMAPI (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS All are generated on standard error, and are intended to be self-explanatory. pcp-3.8.12ubuntu1/man/man1/pmdate.10000664000000000000000000000337512272262501013555 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDATE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdate\f1 \- display an offset date .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS .B pmdate [ \fIoffset\fR ... ] .I format .SH DESCRIPTION .B pmdate displays the current date and/or time, with an optional offset. .PP An .I offset is specified with a leading sign (``+'' or ``-''), followed by an integer value, followed by one of the following ``scale'' specifiers; .IP S seconds .PD 0 .IP M minutes .IP H hours .IP d days .IP m months .IP y years .PD .PP The output .I format follows the same rules as for .BR date (1) and .BR strftime (3). .PP For example, the following will display the date a week ago as DDMMYYYY; .in +8n .ft CW pmdate \-7d %d%m%Y .ft R .in -8n .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR date (1), .BR strftime (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmsleep.10000664000000000000000000000242212272262501013740 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2007 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMSLEEP 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmsleep\f1 \- portable subsecond-capable sleep .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS .B $PCP_BINADM_DIR/pmsleep .I interval .SH DESCRIPTION .B pmsleep sleeps for .I interval. The .I interval argument follows the syntax described in .BR PCPIntro (1) for .B \-t, and in the simplest form may be an unsigned integer or floating point constant (the implied units in this case are seconds). .SH DIAGNOSTICS The exit status is 0 for success, or 1 for a malformed command line. If the underlying .B nanosleep (2) system call fails, an errno is returned. .SH SEE ALSO .BR sleep (1), .BR nanosleep (3). pcp-3.8.12ubuntu1/man/man1/pmlock.10000664000000000000000000000213212272262501013556 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOCK 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmlock\f1 \- simple file-based mutex .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS .B $PCP_BINADM_DIR/pmlock [ .B \-v ] .I file .SH DESCRIPTION .B pmlock attempts to acquire an exclusive lock by creating .I file with a mode of 0. .PP The exit status is 0 for success, 1 for failure. .PP To release the lock, unlink .IR file . .PP In the event of a failure, the .B \-v option produces an explanatory message on .IR stdout . pcp-3.8.12ubuntu1/man/man1/pmdasummary.10000664000000000000000000000663712272262501014646 0ustar '\"macro stdmacro .TH PMDASUMMARY 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdasummary\f1 \- summary performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/summary/pmdasummary\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-h\f1 \f2helpfile\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] \f2pmie-command-line\f1 .SH DESCRIPTION .B pmdasummary is a Performance Metrics Domain Agent (PMDA) which derives performance metrics values from values made available by other PMDAs. .B pmdasummary consists of two processes: .TP .B pmie process The inference engine for performance values .BR pmie (1) is used to periodically sample values for the base metrics and compute the derived values. This process is launched with the given \f2pmie-command-line\f1 arguments by the main process, described below. .TP .B main process The main process reads and buffers the values computed by .BR pmie (1) and makes them available to the performance metrics collector daemon .BR pmcd (1). .PP A brief description of the .B pmdasummary command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP 5 .B \-h This option specifies an alternative help text file .I helpfile for describing the metrics that .B pmdasummary represents. .TP 5 .B \-l Location of the log file. By default, a log file named .I summary.log is written in the current directory of .BR pmcd (1) when .B pmdasummary is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP 5 .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .SH INSTALLATION If you want access to the names, help text and values for the summary performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/summary # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/summary # ./Remove .in .fi .ft 1 .PP .B pmdasummary is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdasummary .TP 10 .B $PCP_PMDAS_DIR/summary/expr.pmie default .BR pmie (1) expressions defining the summary metrics .TP 10 .B $PCP_PMDAS_DIR/summary/help default help text for the summary metrics .TP 10 .B $PCP_PMDAS_DIR/summary/Install installation script for the .B pmdasummary agent .TP 10 .B $PCP_PMDAS_DIR/summary/Remove undo installation script for the .B pmdasummary agent .TP 10 .B $PCP_LOG_DIR/pmcd/summary.log default log file for error messages and other information from .B pmdasummary .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmcd (1) and .BR pmie (1). pcp-3.8.12ubuntu1/man/man1/pmstore.10000664000000000000000000000717312272262501013774 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMSTORE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmstore\f1 \- modify performance metric values .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS \f3pmstore\f1 [\f3\-h\f1 \f2host\f1] [\f3\-i\f1 \f2instances\f1] [\f3\-n\f1 \f2pmnsfile\f1] \f2metricname\f1 \f2value\f1 .SH DESCRIPTION Under certain circumstances, it is useful to be able to modify the values of performance metrics, for example to re-initialize counters or to assign new values to metrics that act as control variables. .PP .B pmstore changes the current values for the nominated instances of a single performance metric, as identified by .I metricname and the list of instance identifiers following the .B \-i argument. .I instances must be a single argument, with elements of the list separated by commas and/or white space. By default all instances of .I metricname will be updated. .PP Normally .B pmstore operates on the default Performance Metrics Name Space (PMNS), however if the .B \-n option is specified an alternative namespace is loaded from the file .IR pmnsfile. .PP Unless directed to another host by the .B \-h option, .B pmstore will interact with the Performance Metric Collector Daemon (PMCD) on the local host. .PP The interpretation of .I value is dependent on the syntax used in its specification and the underlying data type of .IR metricname , as follows. .IP 1. 4 If the metric has an \fBinteger\fR type, then .I value should be an optional leading hyphen, followed either by decimal digits or ``0x'' and some hexadecimal digits. ``0X'' is also acceptable in lieu of ``0x''. See .BR strtol (3C) and the related routines. .IP 2. 4 If the metric has a \fBfloating point\fR type, then .I value should be either in the form of an integer described above, or a fixed point number, or a number in scientific notation. See .BR strtod (3C). .IP 3. 4 If the metric has a \fBstring\fR type, then .I value is interpreted as a literal string of ASCII characters. .IP 4. 4 If the metric has any other type (i.e. .B PM_TYPE_EVENT or .BR PM_TYPE_AGGREGATE ) then no encoding of .I value from the command line makes sense, and the values of these metrics cannot be modified with .BR pmstore . .PP The output reports the old value and the new value for each updated instance of the requested metric. .SH FILES .PD 0 .TP 10 .BI $PCP_VAR_DIR/pmns/ * default PMNS specification files .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmcd (1), .BR pminfo (1), .BR pmval (1), .BR strtod (3C) and .BR strtol (3C). .SH DIAGNOSTICS Two messages indicate a mismatch between the internal data type for .I metricname and the .I value provided. .P The value "???" is out of range for the data type (PM_TYPE_...) .P The value "???" is incompatible with the data type (PM_TYPE_...) pcp-3.8.12ubuntu1/man/man1/pmdatrace.10000664000000000000000000001352612272262501014242 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDATRACE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdatrace\f1 \- application-level transaction performance metrics domain agent .SH SYNOPSIS \f3$PCP_PMDAS_DIR/trace/pmdatrace\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-A\f1 \f2access\f1] [\f3\-I\f1 \f2port\f1] [\f3\-M\f1 \f2username\f1] [\f3\-N\f1 \f2buckets\f1] [\f3\-T\f1 \f2period\f1] [\f3\-U\f1 \f2units\f1] .br .SH DESCRIPTION .B pmdatrace is a Performance Metrics Domain Agent (PMDA) which exports transaction performance metrics from application processes which use the .I pcp_trace library described in .BR pmdatrace (3). .PP A brief description of the .B pmdatrace command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP 5 .B \-l Location of the log file. By default, a log file named .I trace.log is written in the current directory of .BR pmcd (1) when .B pmdatrace is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP 5 .B \-A Host-based access control for .BR pmdatrace . .I access must be either an allow or deny specification, using either allow:hostspec:maxconns or disallow:hostspec, where `allow' and `disallow' are keywords, `hostspec' is a host specification conforming to the format used by both .BR pmcd (1) and .BR pmlogger (1), and `maxconns' is the maximum number of connections allowed from a given `hostspec'. Using a maximum connections of zero specifies an unlimited number of connections for the accompanying `hostspec'. .TP 5 .B \-I Communicate with .I pcp_trace clients via the given Internet .IR port . This can alternatively be specified by setting .B $PCP_TRACE_PORT in the environment to some valid port number (use of the .B \-I option overrides this). The default port number is 4323. .TP 5 .B \-T \f2period\f1 defines the aggregation period used to compute the recent averages and extrema. Specified as a time interval using the syntax described in .BR PCPIntro (1) for the common .B \-t PCP argument, e.g. \c .B "30 seconds" or .BR "1 min" . The default is 60 seconds. .TP 5 .B \-M User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .TP 5 .B \-N Internally, the aggregation \f2period\f1 is divided into \f2bucket\f1 divisions, and the rolling average is recomputed every \f2period\f1/\f2bucket\f1 seconds. For example, the defaults correspond to \-T 60 and \-N 12, which means the average is recomputed every five seconds for a period covering the prior 60 seconds. .TP 5 .B \-U This option allows the dimension and scale associated with the observation value metric to be configured. \f2units\f1 is a comma-separated string of six integer values, which are the space dimension, time dimension, count dimension, space scale, time scale, and count scale, respectively. The default dimension and scale is ``none'', which is equivalent to presenting ``0,0,0,0,0,0'' as the argument to \-U. The units associated with a metric are most easily viewed using the \-d (metric description) option to .BR pminfo (1). The Install script described below steps through this option quite explicitly, so it is recommended that the Install script be used for building up the \f2units\f1 specification. .PP Essentially, the exported metrics provide statistics on the time for completion of each transaction, and an average count of transactions completed and watch points passed over a given time \f2period\f1. .PP .SH INSTALLATION In order for a host to export the names, help text and values for the Trace performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/trace # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/trace # ./Remove .in .fi .ft 1 .PP .B pmdatrace is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdatrace .TP 10 .B $PCP_PMDAS_DIR/trace/help default help text file for the trace metrics .TP 10 .B $PCP_DEMOS_DIR/trace/* example programs which use the .I pcp_trace library .TP 10 .B $PCP_PMDAS_DIR/trace/Install installation script for the .B pmdatrace agent .TP 10 .B $PCP_PMDAS_DIR/trace/Remove undo installation script for .B pmdatrace .TP 10 .B $PCP_LOG_DIR/pmcd/trace.log default log file for error messages and other information from .B pmdatrace .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmtrace (1), .BR PMAPI (3) and .BR pmdatrace (3). pcp-3.8.12ubuntu1/man/man1/pmdatrivial.10000664000000000000000000000675112272262501014620 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .\" I am variants ... .ds ia trivial .ds IA TRIVIAL .ds Ia Trivial .TH PMDATRIVIAL 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdatrivial\f1 \- \*(ia performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/\*(ia/pmda\*(ia\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION .B pmda\*(ia is the simplest possible Performance Metrics Domain Agent (PMDA) which exports a single performance metric, the time in seconds since the 1st of January, 1970. .PP The \*(ia PMDA is shipped as source code and is designed to be an aid for PMDA developers. .PP A brief description of the .B pmda\*(ia command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I \*(ia.log is written in the current directory of .BR pmcd (1) when .B pmda\*(ia is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP 5 .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .SH INSTALLATION If you want access to the names, help text and values for the \*(ia performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/\*(ia # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/\*(ia # ./Remove .in .fi .ft 1 .PP .B pmda\*(ia is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmda\*(ia .TP 10 .B $PCP_PMDAS_DIR/\*(ia/help default help text file for the \*(ia metrics .TP 10 .B $PCP_PMDAS_DIR/\*(ia/Install installation script for the .B pmda\*(ia agent .TP 10 .B $PCP_PMDAS_DIR/\*(ia/Remove undo installation script for the .B pmda\*(ia agent .TP 10 .B $PCP_LOG_DIR/pmcd/\*(ia.log default log file for error messages and other information from .B pmda\*(ia .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmdasample (1), .BR pmdasimple (1), .BR pmdatxmon (1) and .BR PMDA (3). pcp-3.8.12ubuntu1/man/man1/pmdumplog.10000664000000000000000000001353012272262501014301 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDUMPLOG 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdumplog\f1 \- dump internal details of a performance metrics archive log .SH SYNOPSIS \f3pmdumplog\f1 [\f3\-adiLlmrstz\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-S\f1 \f2starttime\f1] [\f3\-T\f1 \f2endtime\f1] [\f3\-Z\f1 \f2timezone\f1] \f2archive\f1 [\f2metricname\f1 ...] .br \f3pmdumplog\f1 [\f3\-v\f1 \f2file\f1] .SH DESCRIPTION .B pmdumplog dumps assorted control, metadata, index and state information from the files of a Performance Co-Pilot (PCP) archive log. The archive log has the base name .I archive and must have been previously created using .BR pmlogger (1). .PP Normally .B pmdumplog operates on the distributed Performance Metrics Name Space (PMNS), however if the .B \-n option is specified an alternative local PMNS is loaded from the file .IR pmnsfile. .PP If any .I metricname arguments appear, the report will be restricted to information relevant to the named performance metrics. If .I metricname is a non-leaf node in the namespace (see \c .BR pmns (5)), then .B pmdumplog will recursively descend the archive's namespace and report on all leaf nodes. .PP The options control the specific information to be reported. .TP 5 .B \-a Report everything, i.e. the flags .BR \-d , .BR \-i , .BR \-l , .BR \-m , .BR \-s and .BR \-t . .TP .B \-d Display the metadata and descriptions for those performance metrics that appear at least once in the archive: see .BR pmLookupDesc (3) for more details on the metadata describing metrics. .TP .B \-i Display the instance domains, and any variations in their instance members over the duration of the archive: see .BR pmGetInDom (3) for more details on instance domains. .TP .B \-l Dump the archive label, showing the log format version, the time and date for the start and (current) end of the archive, and the host from which the performance metrics values were collected. .TP .B \-L Like .BR \-l , just a little more verbose. .TP .B \-m Print the values for the performance metrics from the archive. This is the default display option. .RS +5n .P Metrics without an instance domain are reported as: .br .ti +2n [\fItimestamp\fR] \fImetric-id\fR (\fImetric-name\fR): \fBvalue1\fR \fIvalue2\fR .P Metrics with an instance domain are reported as: .br .ti +2n [\fItimestamp\fR] \fImetric-id\fR (\fImetric-name\fR): .br .ti +6n \fBinst\fR [\fIinternal-id\fR \fBor\fR "\fIexternal-id\fR"] \fBvalue1\fR \fIvalue2\fR .P The \fItimestamp\fR is only reported for the first metric in a group of metrics sharing the same timestamp. .RE .TP .B \-r Process the archive in reverse order, from most recent to oldest recorded metric values. .TP .B \-S When using the .B \-m option, the report will be restricted to those records logged at or after .IR starttime . Refer to .BR PCPIntro (1) for a complete description of the syntax for .IR starttime . .TP .B \-s Report the size in bytes of each physical record in the archive. .TP .B \-T When using the .B \-m option, the report will be restricted to those records logged before or at .IR endtime . Refer to .BR PCPIntro (1) for a complete description of the syntax for .IR endtime . .TP .B \-t Dump the temporal index that is used to provide accelerated access to large archive files. .RS .PP The integrity of the index will also be checked. If the index is found to be corrupted, the ``*.index'' file can be renamed or removed and the archive will still be accessible, however retrievals may take longer without the index. Note however that a corrupted temporal index is usually indicative of a deeper malaise that may infect all files in a PCP archive. .RE .TP .B \-v Verbose mode. Dump the records from a physical archive file in hexadecimal format. In this case .I file is the name of a single file, usually a basename (as would otherwise appear as the .I archive command line argument), concatenated with ``.'' followed by one of .B meta (the metadata), .B index (the temporal index), or a digit (one of the volumes of metric values). .sp 1.5v Use of .B \-v precludes the use of all other options and arguments. .PP By default, .B pmdumplog reports the time of day according to the local timezone on the system where .B pmdumplog is run. The .B \-Z option changes the timezone to .I timezone in the format of the environment variable .B TZ as described in .BR environ (5). The .B \-z option changes the timezone to the local timezone at the host that is the source of the performance metrics, as specified in the label record of the archive log. .SH FILES .PD 0 .TP 10 .BI $PCP_VAR_DIR/pmns/ * default local PMNS specification files .TP .BI $PCP_LOG_DIR/pmlogger/ hostname Default directory for PCP archives containing performance metric values collected from the host .IR hostname . .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmlogcheck (1), .BR pmlogger (1), .BR pmlogger_check (1), .BR pmlogger_daily (1), .BR pmloglabel (1), .BR pmlogmerge (1), .BR PMAPI (3), .BR pmGetInDom (3), .BR pmLookupDesc (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). pcp-3.8.12ubuntu1/man/man1/pmieconf.10000664000000000000000000002110012272262501014065 0ustar '\"macro stdmacro .ie \(.g \{\ .\" ... groff (hack for khelpcenter, man2html, etc.) .TH PMIECONF 1 "PCP" "Performance Co-Pilot" \} .el \{\ .if \nX=0 .ds x} PMIECONF 1 "PCP" "Performance Co-Pilot" .if \nX=1 .ds x} PMIECONF 1 "Performance Co-Pilot" .if \nX=2 .ds x} PMIECONF 1 "" "\&" .if \nX=3 .ds x} PMIECONF "" "" "\&" .TH \*(x} .rr X \} .SH NAME \f3pmieconf\f1 \- display and set configurable pmie rule variables .SH SYNOPSIS \f3pmieconf\f1 [\f3\-cFv\f1] [\f3\-f\f1 \f2file\f1] [\f3\-r\f1 \f2rulepath\f1] [\f2command\f1 [\f2args...\f1]] .SH DESCRIPTION .B pmieconf is a utility for viewing and configuring variables from generalized .BR pmie (1) rules. The set of generalized rules is read in from .IR rulepath , and the output .I file produced by .B pmieconf is a valid input file for .BR pmie . .PP A brief description of the .B pmieconf command line options follows: .TP 8 \f3-c\f1 When run from automated .B pmie setup processes, this option is used to add a specific message and timestamp indicating that this is the case. It is not appropriate when using the tool interactively. .TP 8 \f3\-f\f1 \f2file\f1 Any rule modifications resulting from .B pmieconf manipulation of variable values will be written to \f2file\f1. The default value of \f2file\f1 is dependent on the user ID \- for the root user, the file .I $PCP_VAR_DIR/config/pmieconf/config.pmie is used, for other users the default is .IR $HOME/.pcp/pmie/config.pmie . .TP 8 \f3\-F\f1 Forces the .B pmieconf output .I file to be created (or updated), after which .B pmieconf immediately exits. .TP 8 \f3\-r\f1 \f2rulepath\f1 Allows the source of generalized .B pmie rules to be changed \- \f2rulepath\f1 is a colon-delimited list of .BR pmieconf (5) rule files and/or subdirectories. The default value for .I rulepath is .IR $PCP_VAR_DIR/config/pmieconf . Use of this option overrides the .B PMIECONF_PATH environment variable which has a similar function. .TP 8 \f3\-v\f1 Verbose mode. Additional information associated with each rule and its associated variables will be displayed. This is the complete list of variables which affects any given rule (by default, global variables are not displayed with the rule). .PP The .B pmieconf .IR command s allow information related to the various rules and configurable variables to be displayed or modified. If no .B pmieconf .IR command s are presented on the command line, .B pmieconf prompts for .IR command s interactively. .PP The .B pmieconf .I command language is described here: .TP 8 .B "help [ { . | all | global | | } [] ]" Without arguments, the .B help command displays the syntax for all of the available .B pmieconf commands. With one argument, a description of one or more of the generalized rules is displayed. With two arguments, a description of a specific variable relating to one or more of the generalized rules is displayed. .TP 8 .B "rules [ enabled | disabled ]" Display the name and short summary for all of the generalized rules found on .IR rulepath . Each of the rule names can be used in place of the keyword .B in this command syntax description. The .B enabled and .B disabled options can be used to filter the set of rules displayed to just those which are enabled or disabled respectfully. .TP 8 .B "groups" Display the name of all of the rule groups that were found on .IR rulepath . Each of the group names can be used in place of the keyword .B in this command syntax description, which applies the command to all rules within the rule group. .TP 8 .B "status" Display status information relating to the current .B pmieconf session, including a list of running .B pmie processes which are currently using .IR file . .TP 8 .B "enable { . | all | | }" Enables the specified rule or group of rules. An enabled rule is one which will be included in the .B pmie configuration file generated by .BR pmieconf . Any enabled "actions" will be appended to the rule's "predicate", in a manner conforming to the .B pmie syntax ("actions" can be viewed using the .B "list global" command, described below). .TP 8 .B "disable { . | all | | }" Disables the specified rule or group of rules. If the rule was previously enabled, it will be removed from the .B pmie configuration file generated by .BR pmieconf , and hence no longer evaluated when .B pmie is restarted (using .B pmieconf does not affect any existing .B pmie processes using .IR file ). .TP 8 .B "list { . | all | global | | } []" Display the values for a specific rule variable; or for all variables of a rule, a rule group, all rules, or the global variables. .TP 8 .B "modify { . | all | global | | } " Enable, disable, or otherwise change the value for one or more rule variables. This value must be consistent with the type of the variable, which can be inferred from the format of the printed value - e.g. strings will be enclosed in double-quotes, percentages have the ``%'' symbol appended, etc. Note that certain rule variables cannot be modified through .B pmieconf \- "predicate" and "help", for example. .TP 8 .B "undo { . | all | global | | } []" Applicable only to a variable whose value has been modified - this .I command simply reverts to the default value for the given variable. .TP 8 .B "quit" Save any changes made to .I file and then exit .BR pmieconf . .TP 8 .B "abort" Exit .B pmieconf immediately without saving any changes to .IR file . .PP Each of the commands above can be shortened by simply using the first character of the command name, and also ``?'' for help. .PP Use of the .B all keyword causes the command to be applied to all of the rules. The .B global keyword refers to those variables which are applied to every rule. Such variables can be changed either globally or locally, for example: .sp .nf pmieconf> modify global delta "5 minutes" pmieconf> modify memory delta "1 minute" .fi .sp causes all rules to now be evaluated once every five minutes, except for rules in the "memory" group which are to be evaluated once per minute. .PP The ``.'' character is special to .B pmieconf \- it refers to the last successfully used value of .BR all , .BR global , .B or .BR . .SH EXAMPLES Specify that all of the rules in the "memory" group should be evaluated: .sp .nf pmieconf> modify memory enabled yes .fi .sp Change your mind, and revert to using only the "memory" rules which were enabled by default: .sp .nf pmieconf> undo memory enabled .fi .sp Specify that notification of rules which evaluate to true should be sent to .BR syslogd (1): .sp .nf pmieconf> modify global syslog_action yes .fi .sp Specify that rules in the "per_cpu" group should use a different holdoff value to other rules: .sp .nf pmieconf> help global holdoff rule: global [generic parameters applied to all rules] var: holdoff help: Once the predicate is true and the action is executed, this variable allows suppression of further action execution until the specified interval has elapsed. A value of zero enables execution of the action if the rule predicate is true at the next sample. Default units are seconds and common units are "second", "sec", "minute", "min" and "hour". pmieconf> modify per_cpu holdoff "1 hour" .fi .sp Lower the threshold associated with a particular variable for a specified rule: .sp .nf pmieconf> l cpu.syscall predicate rule: cpu.syscall [High aggregate system call rate] predicate = some_host ( ( kernel.all.syscall $hosts$ ) > $threshold$ count/sec * hinv.ncpu $hosts$ ) pmieconf> m . threshold 7000 pmieconf> l . threshold rule: cpu.syscall [High aggregate system call rate] threshold = 7000 .fi .sp .SH ENVIRONMENT The environment variable .B PMIECONF_PATH has a similar function to the .B \-r option described above, and if set will be used provided no .B \-r option is presented. .SH FILES .PD 0 .TP 10 .IR $PCP_VAR_DIR/config/pmieconf/ */* generalized system resource monitoring rules .TP 10 .I $PCP_VAR_DIR/config/pmieconf/config.pmie default super-user settings for system resource monitoring rules .TP 10 .I $HOME/.pcp/pmie/config.pmie default user settings for system resource monitoring rules .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmie (1), .BR pmie_check (1) and .BR pmieconf (5). pcp-3.8.12ubuntu1/man/man1/pcpintro.10000664000000000000000000011103112272262501014126 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012-2013 Red Hat. .\" Copyright (c) 2008 Aconex, Inc. All Rights Reserved. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PCPINTRO 1 "PCP" "Performance Co-Pilot" .SH NAME \f3PCPIntro\f1 \- introduction to the Performance Co-Pilot (PCP) .SH INTRODUCTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. The Performance Co-Pilot (PCP) is a toolkit designed for monitoring and managing system-level performance. These services are distributed and scalable to accommodate the most complex system configurations and performance problems. .PP PCP supports many different platforms, including (but not limited to) Linux, MacOSX, Solaris and Windows. From a high-level PCP can be considered to contain two classes of software utility: .IP "\fIPCP Collectors\fR" 8 These are the parts of PCP that collect and extract performance data from various sources, e.g. the operating system kernel. .IP "\fIPCP Monitors\fR" 8 These are the parts of PCP that display data collected from hosts (or archives) that have the .I "PCP Collector" installed. Many monitor tools are available as part of the core PCP release, while other (typically graphical) monitoring tools are available separately in the PCP GUI package. .PP This manual entry describes the high-level features and options common to most PCP utilities available on all platforms. .SH OVERVIEW The PCP architecture is distributed in the sense that any PCP tool may be executing remotely. On the host (or hosts) being monitored, each domain of performance metrics, whether the kernel, a service layer, a database management system, a web server, an application, etc. requires a Performance Metrics Domain Agent (PMDA) which is responsible for collecting performance measurements from that domain. All PMDAs are controlled by the Performance Metrics Collector Daemon .RB ( pmcd (1)) on the same host. .PP Client applications (the monitoring tools) connect to .BR pmcd (1), which acts as a router for requests, by forwarding requests to the appropriate PMDA and returning the responses to the clients. Clients may also access performance data from a PCP archive (created using .BR pmlogger (1)) for retrospective analysis. .SS Security philosophy PCP redistributes a wealth of performance information within a host and across its networks. The following security philosophy underlies the setting of several .I defaults that control how much information is sent and received. .PP By default, the information exposed by PMCD about a host is approximately of the same level of confidentiality as available to a completely unprivileged user on that host. So, performance data that is available to be .I read completely freely on a machine may be made available by PMCD to the network. .PP However, the host running PMCD and its network is .I not assumed to run only friendly applications. Therefore, .I write type operations, including from the local host, are not permitted by default. .PP These defaults may be overridden (expanded or reduced) in several ways, including by specifying network ACLs in .BR pmcd.conf , activating non-default PMDAs, or by using PMCD connections that pass user credentials. For example, some PMDAs automatically provide greater information for particular credentialed users or groups. .PP .SS Applications The following performance monitoring applications are primarily console based, typically run directly from the command line, and are just a small subset of the tools available as part of the base PCP package. .PP Each tool or command is documented completely in its own reference page. .TP .B pmstat Outputs an ASCII high-level summary of system performance. .TP .B pmie An inference engine that can evaluate predicate-action rules to perform alarms and automate system management tasks. .TP .B pminfo Interrogate specific performance metrics and the metadata that describes them. .TP .B pmlogger Generates PCP archives of performance metrics suitable for replay by most PCP tools. .TP .B pmval Simple periodic reporting for some or all instances of a performance metric, with optional VCR time control. .PP If the PCP GUI package is installed then the following additional tools are available. .TP .B pmchart Displays trends over time of arbitrarily selected performance metrics from one or more hosts. .TP .B pmtime Time control utility for coordinating the time between multiple tools (including pmchart and pmval). .TP .B pmdumptext Produce ASCII reports for arbitrary combinations of performance metrics. .SH COMMON COMMAND LINE ARGUMENTS There is a set of common command line arguments that are used consistently by most PCP tools. .TP .BI "\-a " archive Performance metric information is retrospectively retrieved from the Performance Co-Pilot (PCP) .IR archive , previously generated by .BR pmlogger (1). The .B \-a and .B \-h options are mutually exclusive. .RS .PP .I archive is either the base name common to all of the physical files created by an instance of .BR pmlogger (1), or any one of the physical files, e.g. .I myarchive (base name) or .IB myarchive .meta (the metadata file) or .IB myarchive .index (the temporal index) or .IB myarchive .0 (the first data volume of .IR archive ) or .IB myarchive .0.bz2 or .IB myarchive .0.bz (the first data volume compressed with .BR bzip2 (1)) or .IB myarchive .0.gz or .IB myarchive .0.Z or .IB myarchive .0.z (the first data volume compressed with .BR gzip (1)), .IB myarchive .1 or .IB myarchive .3.bz2 or .IB myarchive .42.gz etc. .RE .TP .BI "\-a " archive\f1[ , archive , \f1...] An alternate form of .B \-a for applications that are able to handle multiple archives. .TP .BI "\-h " hostname Unless directed to another host by the .B \-h option, or to an archive by the .B \-a option, the source of performance metrics will be the Performance Metrics Collector Daemon (PMCD) on the local host. Refer to the .B "PMCD HOST SPECIFICATION" section later for further details on the many options available when forming the .I hostname specification, as well as a detailed description of the default local host connection. The .B \-a and .B \-h options are mutually exclusive. .TP .BI "\-s " samples The argument .I samples defines the number of samples to be retrieved and reported. If .I samples is 0 or .B \-s is not specified, the application will sample and report continuously (in real time mode) or until the end of the PCP archive (in archive mode). .TP .B \-z Change the reporting timezone to the local timezone at the host that is the source of the performance metrics, as identified via either the .B \-h or .B \-a options. .TP .BI "\-Z " timezone By default, applications report the time of day according to the local timezone on the system where the application is executed. The .B \-Z option changes the timezone to .I timezone in the format of the environment variable .B TZ as described in .BR environ (5). .SH INTERVAL SPECIFICATION AND ALIGNMENT Most PCP tools operate with periodic sampling or reporting, and the .B \-t and .B \-A options may be used to control the duration of the sample interval and the alignment of the sample times. .TP .BI "\-t " interval .RS Set the update or reporting interval. .PP The .I interval argument is specified as a sequence of one or more elements of the form .nf .in +1.0i \f2number\f1[\f2units\f1] .in .fi where \f2number\f1 is an integer or floating point constant (parsed using .BR strtod (3)) and the optional \f2units\f1 is one of: .BR seconds , .BR second , .BR secs , .BR sec , .BR s , .BR minutes , .BR minute , .BR mins , .BR min , .BR m , .BR hours , .BR hour , .BR h , .BR days , .B day and .BR d . If the .I unit is empty, .B second is assumed. .PP In addition, the upper case (or mixed case) version of any of the above is also acceptable. .PP Spaces anywhere in the .I interval are ignored, so .BR "4 days 6 hours 30 minutes" , .BR "4day6hour30min" , .B "4d6h30m" and .B "4d6.5h" are all equivalent. .PP Multiple specifications are additive, e.g. ``\fB1hour 15mins 30secs\fR'' is interpreted as 3600+900+30 seconds. .RE .TP .BI "\-A " align .RS By default samples are not necessarily aligned on any natural unit of time. The .B \-A option may be used to force the initial sample to be aligned on the boundary of a natural time unit. For example .BR "\-A 1sec" , .B "\-A 30min" and .B "-A 1hour" specify alignment on whole seconds, half and whole hours respectively. .PP The .I align argument follows the syntax for an .I interval argument described above for the .B \-t option. .PP Note that alignment occurs by advancing the time as required, and that .B \-A acts as a modifier to advance both the start of the time window (see the next section) and the origin time (if the .B \-O option is specified). .RE .SH TIME WINDOW SPECIFICATION Many PCP tools are designed to operate in some time window of interest, e.g. to define a termination time for real-time monitoring or to define a start and end time within a PCP archive log. .PP In the absence of the .B \-O and .B \-A options to specify an initial sample time origin and time alignment (see above), the PCP application will retrieve the first sample at the start of the time window. .PP The following options may be used to specify a time window of interest. .TP .BI "\-S " starttime .RS By default the time window commences immediately in real-time mode, or coincides with time at the start of the PCP archive log in archive mode. The .B \-S option may be used to specify a later time for the start of the time window. .P The .I starttime parameter may be given in one of three forms (\c .I interval is the same as for the .B \-t option as described above, .I ctime is described below): .TP \f2interval\f1 To specify an offset from the current time (in real-time mode) or the beginning of a PCP archive (in archive mode) simply specify the interval of time as the argument. For example .B "\-S 30min" will set the start of the time window to be exactly 30 minutes from now in real-time mode, or exactly 30 minutes from the start of a PCP archive. .TP \-\f2interval\f1 To specify an offset from the end of a PCP archive log, prefix the \f2interval\f1 argument with a minus sign. In this case, the start of the time window precedes the time at the end of archive by the given interval. For example .B "\-S \-1hour" will set the start of the time window to be exactly one hour before the time of the last sample in a PCP archive log. .TP @\f2ctime\f1 To specify the calendar date and time (local time in the reporting timezone) for the start of the time window, use the .BR ctime (3) syntax preceded by an at sign. For example .B "\-S '@ Mon Mar 4 13:07:47 1996'" .RE .TP .BI "\-T " endtime .RS By default the end of the time window is unbounded (in real-time mode) or aligned with the time at the end of a PCP archive log (in archive mode). The .B \-T option may be used to specify an earlier time for the end of the time window. .PP The .I endtime parameter may be given in one of three forms (\c .I interval is the same as for the .B \-t option as described above, .I ctime is described below): .TP \f2interval\f1 To specify an offset from the start of the time window simply use the interval of time as the argument. For example .B "\-T 2h30m" will set the end of the time window to be 2 hours and 30 minutes after the start of the time window. .TP \-\f2interval\f1 To specify an offset back from the time at the end of a PCP archive log, prefix the \f2interval\f1 argument with a minus sign. For example .B "\-T \-90m" will set the end of the time window to be 90 minutes before the time of the last sample in a PCP archive log. .TP @\f2ctime\f1 To specify the calendar date and time (local time in the reporting timezone) for the end of the time window, use the .BR ctime (3) syntax preceded by an at sign. For example .B "\-T '@ Mon Mar 4 13:07:47 1996'" .RE .TP .BI "\-O " origin .RS By default samples are fetched from the start of the time window (see description of .B \-S option) to the end of the time window (see description of .B \-T option). The .B \-O option allows the specification of an origin within the time window to be used as the initial sample time. This is useful for interactive use of a PCP tool with the .BR pmtime (1) VCR replay facility. .PP The \f2origin\f1 argument accepted by .B \-O conforms to the same syntax and semantics as the .I starttime argument for the .B \-T option. .PP For example .B "\-O -0" specifies that the initial position should be at the end of the time window; this is most useful when wishing to replay ``backwards'' within the time window. .RE .PP The \f2ctime\f1 argument for the .BR \-O , .B \-S and .B \-T options is based upon the calendar date and time format of .BR ctime (3), but may be a fully specified time string like .B "Mon Mar 4 13:07:47 1996" or a partially specified time like .BR "Mar 4 1996" , .BR "Mar 4" , .BR "Mar" , .B "13:07:50" or .BR "13:08" . .PP For any missing low order fields, the default value of 0 is assumed for hours, minutes and seconds, 1 for day of the month and Jan for months. Hence, the following are equivalent: .B "\-S '@ Mar 1996'" and .BR "\-S '@ Mar 1 00:00:00 1996'" . .PP If any high order fields are missing, they are filled in by starting with the year, month and day from the current time (real-time mode) or the time at the beginning of the PCP archive log (archive mode) and advancing the time until it matches the fields that are specified. So, for example if the time window starts by default at ``Mon Mar 4 13:07:47 1996'', then .B "\-S @13:10" corresponds to 13:10:00 on Mon Mar 4, 1996, while .B "\-S @10:00" corresponds to 10:00:00 on Tue Mar 5, 1996 (note this is the following day). .PP For greater precision than afforded by .BR ctime (3), the seconds component may be a floating point number. .P Also the 12 hour clock (am/pm notation) is supported, so for example .B "13:07" and .B "1:07 pm" are equivalent. .SH "PERFORMANCE METRICS \- NAMES AND IDENTIFIERS" The number of performance metric names supported by PCP on most platforms ranges from many hundreds to several thousand. The PCP libraries and applications use an internal identification scheme that unambiguously associates a single integer with each known performance metric. This integer is known as the Performance Metric Identifier, or PMID. Although not a requirement, PMIDs tend to have global consistency across all systems, so a particular performance metric usually has the same PMID. .PP For all users and most applications, direct use of the PMIDs would be inappropriate (e.g. this would limit the range of accessible metrics, make the code hard to maintain, force the user interface to be particularly baroque, etc.). Hence a Performance Metrics Name Space (PMNS) is used to provide external names and a hierarchic classification for performance metrics. A PMNS is represented as a tree, with each node having a label, a pointer to either a PMID (for leaf nodes) or a set of descendent nodes in the PMNS (for non-leaf nodes). .PP A node label must begin with an alphabetic character, followed by zero or more characters drawn from the alphabetics, the digits and character \`_\' (underscore). For alphabetic characters in a node label, upper and lower case are distinguished. .PP By convention, the name of a performance metric is constructed by concatenation of the node labels on a path through the PMNS from the root node to a leaf node, with a ``.'' as a separator. The root node in the PMNS is unlabeled, so all names begin with the label associated with one of the descendent nodes below the root node of the PMNS, e.g. \c .CW "kernel.percpu.syscall". Typically (although this is not a requirement) there would be at most one name for each PMID in a PMNS. For example .CW kernel.all.cpu.idle and .CW disk.dev.read are the unique names for two distinct performance metrics, each with a unique PMID. .PP Groups of related PMIDs may be named by naming a non-leaf node in the PMNS tree, e.g. \c .CW disk . .PP The default local PMNS used by .B pmcd is located at .B $PCP_VAR_DIR/pmns/root however the environment variable .B PMNS_DEFAULT may be set to the full pathname of a different PMNS which will then be used as the default local PMNS. .PP Most applications do not use the local PMNS directly, but rather import parts of the PMNS as required from the same place that performance metrics are fetched, i.e. from .BR pmcd (1) for live monitoring or from a PCP archive for retrospective monitoring. .PP To explore the PMNS use .BR pminfo (1), or if the PCP GUI package is installed the New Chart and Metric Search windows within .BR pmchart (1). .SH PERFORMANCE METRIC SPECIFICATIONS In configuration files and (to a lesser extent) command line options, metric specifications adhere to the following syntax rules. .PP If the source of performance metrics is real-time from .BR pmcd (1) then the accepted syntax is .br .ti +1i \fIhost\fB:\fImetric\fB[\fIinstance1\fB,\fIinstance2\fB,\fR...\fB]\fR .PP If the source of performance metrics is a PCP archive log then the accepted syntax is .br .ti +1i \fIarchive\fB/\fImetric\fB[\fIinstance1\fB,\fIinstance2\fB,\fR...\fB]\fR .PP The .IB host :\fR, .IB archive / and \fB[\fIinstance1\fB,\fIinstance2\fB,\fR...\fB]\fR components are all optional. .PP The .B , delimiter in the list of instance names may be replaced by white space. .PP Special characters in .I instance names may be escaped by surrounding the name in double quotes or preceding the character with a backslash. .PP White space is ignored everywhere except within a quoted .I instance name. .PP An empty .I instance is silently ignored, and in particular ``\fB[]\fR'' is the same as no .IR instance , while ``\fB[one,,,two]\fR'' is parsed as specifying just the two instances ``\fBone\fP'' and ``\fBtwo\fP''. .PP As a special case, if the .B host is the single character ``@'' then this refers to a .B PM_CONTEXT_LOCAL source, see .BR pmNewContext (3). .SH SECURE PMCD CONNECTIONS Since PCP version 3.6.11, a monitor can explicitly request a secure connection to a collector host running .BR pmcd (1) or .BR pmproxy (1) using the PM_CTXFLAG_SECURE context flag. If the PCP Collector host supports this feature - refer to the pmcd.feature.secure metric for confirmation of this - a TLS/SSL (Transport Layer Security or Secure Sockets Layer) connection can be established which uses public key cryptography and related techniques. These features aim to prevent eavesdropping and data tampering from a malicious third party, as well as providing server-side authentication (confident identification of a server by a client) which can be used to guard against man-in-the-middle attacks. .PP A secure .B pmcd connection requires use of certificate-based authentication. The security features offered by .B pmcd and .B pmproxy are implemented using the Network Security Services (NSS) APIs and utilities. The NSS .BR certutil tool can be used to create certificates suitable for establishing trust between PCP monitor and collector hosts. .PP A complete description is beyond the scope of this document, refer to the .BR "PCP ENVIRONMENT" , .B "FILES" and .B "SEE ALSO" sections for detailed information. This includes links to tutorials on the steps involved in setting up the available security features. .SH PMCD HOST SPECIFICATION In the absence of an explicit host name specification, most tools will default to the local host in live update mode. In PCP releases since 3.8.4 onward, this results in an efficient local protocol being selected \- typically a Unix domain socket. If this option is used (which can also be explicitly requested via the .I unix: host specification described below), it is important to note that all connections will be automatically authenticated. In other words, the credentials of the user invoking a client tool will automatically be made available to .BR pmcd (1) and all of its PMDAs, on the users behalf, such that results can be customized to the privilege levels of individual users. .PP Names of remote hosts running the .BR pmcd (1) daemon can of course also be provided to request a remote host be used. The most basic form of .B pmcd host specification is a simple host name, possibly including the domain name if necessary. However, this can be extended in a number of ways to further refine attributes of the connection made to .BR pmcd . .PP The .B pmcd port number and also optional .BR pmproxy (1) hostname and its port number, can be given as part of the host specification, since PCP version 3.0. These supersede (and override) the old-style PMCD_PORT, PMPROXY_HOST and PMPROXY_PORT environment variables. .PP The following are valid hostname specifications that specify connections to .B pmcd on host .I nas1.servers.com with/without a list of ports and with/without a .BR pmproxy (1) connection through a firewall. .PP .in +0.5i .nf .ft CW $ pcp \-h nas1.servers.com:44321,4321@firewall.servers.com:44322 $ pcp \-h nas1.servers.com:44321@firewall.servers.com:44322 $ pcp \-h nas1.servers.com:44321@firewall.servers.com $ pcp \-h nas1.servers.com@firewall.servers.com $ pcp \-h nas1.servers.com:44321 .ft R .fi .in .PP In addition, security attributes and credentials can also be specified. These include username, an optional password (can be given interactively and may depend on the authentication mechanism employed), whether to use secure (encrypted) or native (naked) protocol, and so on. The previous examples all default to native protocol, and use no authentication. This can be altered, as in the following examples. .PP .in +0.5i .nf .ft CW $ pcp \-h pcps://nas1.servers.com:44321?username=tanya&method=gssapi $ pcp \-h pcps://nas2.servers.com@firewalls.r.us?method=plain $ pcp \-h pcp://nas3.servers.com $ pcp \-h unix: $ pcp \-h local: .ft R .fi .in .PP The choice of authentication method, and other resulting parameters like username, optionally password, etc, depends on the SASL2 configuration used by each (remote) .BR pmcd . Tutorials are available specifying various aspects of configuring the authentication module(s) used, these fine details are outside the scope of this document. .PP The final .I local: example above is now the default for most tools. This connection is an automatically authenticated local host connection on all platforms that support Unix domain sockets. No password is required and authentication is automatic. This is also the most efficient (lowest overhead) communication channel available. .PP The difference between .I unix: and .I local: is that the former is a strict Unix domain socket specification (connection fails if it cannot connect that way), whereas the latter has a more forgiving fallback to using .I localhost (i.e. a regular Inet socket connection is used when Unix domain socket connections are unavailable). .SH ENVIRONMENT In addition to the PCP run-time environment and configuration variables described in the .B "PCP ENVIRONMENT" section below, the following environment variables apply to all installations. .TP .B PCP_CONSOLE When set, this changes the default console from .I /dev/tty (on Unix) or .I CON: (on Windows) to be the specified console. The special value of .I none can be used to indicate no console is available for use. This is used in places where console-based tools need to interact with the user, and in particular is used when authentication is being performed. .TP .B PCP_DERIVED_CONFIG When set, this variable defines the path to a file that contains definitions of derived metrics as per the syntax described in .BR pmLoadDerivedConfig (3). Derived metrics may be used to extend the available metrics with new (derived) metrics using simple arithmetic expressions. .RS .PP If .B PCP_DERIVED_CONFIG is set, the derived metric definitions are processed automatically as each new source of performance metrics is established (i.e. each time a .BR pmNewContext (3) is called) or when requests are made against the PMNS. .RE .TP .B PCP_SECURE_SOCKETS When set, this variable forces any monitor tool connections to be established using the certificate-based secure sockets feature. If the connections cannot be established securely, they will fail. .TP .B PCP_SECURE_DB_METHOD With secure socket connections, the certificate and key database is stored using the .B sql: method by default. Use .B PCP_SECURE_DB_METHOD to override the default, most usually setting the value to the empty string (for the older database methods). .TP .B PCP_STDERR Many PCP tools support the environment variable .BR PCP_STDERR , which can be used to control where error messages are sent. When unset, the default behavior is that ``usage'' messages and option parsing errors are reported on standard error, other messages after initial startup are sent to the default destination for the tool, i.e. standard error for ASCII tools, or a dialog for GUI tools. .RS .PP If .B PCP_STDERR is set to the literal value .B DISPLAY then all messages will be displayed in a dialog. This is used for any tools launched from the a Desktop environment. .PP If .B PCP_STDERR is set to any other value, the value is assumed to be a filename, and all messages will be written there. .RE .TP .B PMCD_CONNECT_TIMEOUT When attempting to connect to a remote .BR pmcd (1) on a machine that is booting, the connection attempt could potentially block for a long time until the remote machine finishes its initialization. Most PCP applications and some of the PCP library routines will abort and return an error if the connection has not been established after some specified interval has elapsed. The default interval is 5 seconds. This may be modified by setting .B PMCD_CONNECT_TIMEOUT in the environment to a real number of seconds for the desired timeout. This is most useful in cases where the remote host is at the end of a slow network, requiring longer latencies to establish the connection correctly. .TP .B PMCD_RECONNECT_TIMEOUT When a monitor or client application loses a connection to a .BR pmcd (1), the connection may be re-established by calling a service routine in the PCP library. However, attempts to reconnect are controlled by a back-off strategy to avoid flooding the network with reconnection requests. By default, the back-off delays are 5, 10, 20, 40 and 80 seconds for consecutive reconnection requests from a client (the last delay will be repeated for any further attempts after the fifth). Setting the environment variable .B PMCD_RECONNECT_TIMEOUT to a comma separated list of positive integers will re-define the back-off delays, e.g. setting .B PMCD_RECONNECT_TIMEOUT to ``1,2'' will back-off for 1 second, then attempt another connection request every 2 seconds thereafter. .TP .B PMCD_REQUEST_TIMEOUT For monitor or client applications connected to .BR pmcd (1), there is a possibility of the application "hanging" on a request for performance metrics or metadata or help text. These delays may become severe if the system running .B pmcd crashes, or the network connection is lost. By setting the environment variable .B PMCD_REQUEST_TIMEOUT to a number of seconds, requests to .B pmcd will timeout after this number of seconds. The default behavior is to be willing to wait 10 seconds for a response from every .B pmcd for all applications. .TP .B PMCD_WAIT_TIMEOUT .br When .BR pmcd (1) is started from .B $PCP_RC_DIR/pcp then the primary instance of .BR pmlogger (1) will be started if the configuration flag .B pmlogger is chkconfig'ed on and .B pmcd is running and accepting connections. .RS .PP The check on .BR pmcd 's readiness will wait up to .B PMCD_WAIT_TIMEOUT seconds. If .B pmcd has a long startup time (such as on a very large system), then .B PMCD_WAIT_TIMEOUT can be set to provide a maximum wait longer than the default 60 seconds. .RE .TP .B PMNS_DEFAULT If set, then interpreted as the full pathname to be used as the default local PMNS for .BR pmLoadNameSpace (3). Otherwise, the default local PMNS is located at .B $PCP_VAR_DIR/pcp/pmns/root for base PCP installations. .TP .B PCP_COUNTER_WRAP Many of the performance metrics exported from PCP agents have the semantics of .I counter meaning they are expected to be monotonically increasing. Under some circumstances, one value of these metrics may smaller than the previously fetched value. This can happen when a counter of finite precision overflows, or when the PCP agent has been reset or restarted, or when the PCP agent is exporting values from some underlying instrumentation that is subject to some asynchronous discontinuity. The environment variable .B PCP_COUNTER_WRAP may be set to indicate that all such cases of a decreasing ``counter'' should be treated as a counter overflow, and hence the values are assumed to have wrapped once in the interval between consecutive samples. This ``wrapping'' behavior was the default in earlier PCP versions, but by default has been disabled in PCP release from version 1.3 on. .TP .B PMDA_PATH The .B PMDA_PATH environment variable may be used to modify the search path used by .BR pmcd (1) and .BR pmNewContext (3) (for .B PM_CONTEXT_LOCAL contexts) when searching for a daemon or DSO PMDA. The syntax follows that for .B PATH in .BR sh (1), i.e. a colon separated list of directories, and the default search path is ``/var/pcp/lib:/usr/pcp/lib'', (or ``/var/lib/pcp/lib'' on Linux, depending on the value of the $PCP_VAR_DIR environment variable). .TP .B PMCD_PORT The TPC/IP port(s) used by .BR pmcd (1) to create the socket for incoming connections and requests, was historically 4321 and more recently the officially registered port 44321; in the current release, .B both port numbers are used by default as a transitional arrangement. This may be over-ridden by setting .B PMCD_PORT to a different port number, or a comma-separated list of port numbers. If a non-default port is used when .B pmcd is started, then every monitoring application connecting to that .B pmcd must also have .B PMCD_PORT set in their environment before attempting a connection. .PP The following environment variables are relevant to installations in which .BR pmlogger (1), the PCP archive logger, is used. .TP .B PMLOGGER_PORT The environment variable .B PMLOGGER_PORT may be used to change the base TCP/IP port number used by .BR pmlogger (1) to create the socket to which .BR pmlc (1) instances will try and connect. The default base port number is 4330. When used, .B PMLOGGER_PORT should be set in the environment before .B pmlogger is executed. .TP .B PMLOGGER_REQUEST_TIMEOUT When .BR pmlc (1) connects to .BR pmlogger (1), there is a remote possibility of .BR pmlc \&"hanging" on a request for information as a consequence of a failure of the network or .BR pmlogger . By setting the environment variable .B PMLOGGER_REQUEST_TIMEOUT to a number of seconds, requests to .B pmlogger will timeout after this number of seconds. The default behavior is to be willing to wait forever for a response from each request to a .BR pmlogger . When used, .B PMLOGGER_REQUEST_TIMEOUT should be set in the environment before .B pmlc is executed. .PP If you have the PCP product installed, then the following environment variables are relevant to the Performance Metrics Domain Agents (PMDAs). .TP .B PMDA_LOCAL_PROC Use this variable has been deprecated and it is now ignored. If the ``proc'' PMDA is configured as a DSO for use with .BR pmcd (1) on the local host then all of the ``proc'' metrics will be available to applications using a .B PM_CONTEXT_LOCAL context. .RS .PP The previous behaviour was that if this variable was set, then a context established with the .I type of .B PM_CONTEXT_LOCAL will have access to the ``proc'' PMDA to retrieve performance metrics about individual processes. .RE .TP .B PMDA_LOCAL_SAMPLE Use this variable has been deprecated and it is now ignored. If the ``sample'' PMDA is configured as a DSO for use with .BR pmcd (1) on the local host then all of the ``sample'' metrics will be available to applications using a .B PM_CONTEXT_LOCAL context. .RS .PP The previous behaviour was that if this variable was set, then a context established with the .I type of .B PM_CONTEXT_LOCAL will have access to the ``sample'' PMDA if this optional PMDA has been installed locally. .RE .TP .B PMIECONF_PATH If set, .BR pmieconf (1) will form its .BR pmieconf (5) specification (set of parameterized .BR pmie (1) rules) using all valid .B pmieconf files found below each subdirectory in this colon-separated list of subdirectories. If not set, the default is .BR $PCP_VAR_DIR/config/pmieconf . .SH FILES .PD 0 .TP 10 .B /etc/pcp.conf Configuration file for the PCP runtime environment, see .BR pcp.conf (5). .TP .B /etc/pki/nssdb Optionally contains a Network Security Services database with a "PCP Collector" certificate providing trusted identification for the collector host. .TP .B $HOME/.pcp User-specific directories containing configuration files for customisation of the various monitor tools, such as .BR pmchart (1). .TP .B $HOME/.pki/nssdb A shared Network Security Services (NSS) database directory containing per-user certificates identifying known valid remote .B pmcd collector hosts. The NSS .B certutil tool is one of several that can be used to maintain this database. .TP .B $PCP_RC_DIR/pcp Script for starting and stopping .BR pmcd (1). .TP .B $PCP_PMCDCONF_PATH Control file for .BR pmcd (1). .TP .B $PCP_PMCDOPTIONS_PATH Command line options passed to .BR pmcd (1) when it is started from .BR $PCP_RC_DIR/pcp . All the command line option lines should start with a hyphen as the first character. This file can also contain environment variable settings of the form "VARIABLE=value". .TP .B $PCP_BINADM_DIR Location of PCP utilities for collecting and maintaining PCP archives, PMDA help text, PMNS files etc. .TP .B $PCP_PMDAS_DIR Parent directory of the installation directory for Dynamic Shared Object (DSO) PMDAs. .TP .B $PCP_RUN_DIR/pmcd.pid If pmcd is running, this file contains an ascii decimal representation of its process ID. .TP .B $PCP_LOG_DIR/pmcd Default location of log files for .BR pmcd (1), current directory for running PMDAs. Archives generated by .BR pmlogger (1) are generally below .BR $PCP_LOG_DIR/pmlogger . .TP .B $PCP_LOG_DIR/pmcd/pmcd.log Diagnostic and status log for the current running .BR pmcd (1) process. The first place to look when there are problems associated with .BR pmcd . .TP .B $PCP_LOG_DIR/pmcd/pmcd.log.prev Diagnostic and status log for the previous .BR pmcd (1) instance. .TP .B $PCP_LOG_DIR/NOTICES Log of .BR pmcd (1) and PMDA starts, stops, additions and removals. .TP .B $PCP_VAR_DIR/config Contains directories of configuration files for several PCP tools. .TP .B $PCP_SYSCONF_DIR/pmcd/rc.local Local script for controlling PCP boot, shutdown and restart actions. .TP .B $PCP_VAR_DIR/pmns Directory containing the set of PMNS files for all installed PMDAs. .TP .B $PCP_VAR_DIR/pmns/root The ASCII .BR pmns (5) exported by .BR pmcd (1) by default. This PMNS is be the super set of all other PMNS files installed in .BR $PCP_VAR_DIR/pmns . .PP In addition, if the PCP product is installed the following files and directories are relevant. .TP .B $PCP_LOG_DIR/NOTICES In addition to the .BR pmcd (1) and PMDA activity, may be used to log alarms and notices from .BR pmie (1) via .BR pmpost (1). .TP .B $PCP_PMLOGGERCONTROL_PATH Control file for .BR pmlogger (1) instances launched from .B $PCP_RC_DIR/pcp and/or managed by .BR pmlogger_check (1) and .BR pmlogger_daily (1) as part of a production PCP archive collection setup. .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmcd (1), .BR pmie (1), .BR pmie_daily (1), .BR pminfo (1), .BR pmlc (1), .BR pmlogger (1), .BR pmlogger_daily (1), .BR pmstat (1), .BR pmval (1), .BR pcp (1), .BR pcp.conf (5), .BR pcp.env (5), and .BR pmns (5). .PP If the PCP GUI package is installed, then the following entries are also relevant: .br .BR pmchart (1), .BR pmtime (1), and .BR pmdumptext (1). .PP If the secure sockets extensions have been enabled, then the following references are also relevant: .br .I "http://oss.sgi.com/projects/pcp/pcp-gui.git/man/html/index.html" .br .I "http://www.mozilla.org/projects/security/pki/nss/#documentation" .br .I "http://www.mozilla.org/projects/security/pki/nss/tools/certutil.html" .PP Also refer to the books .I "Performance Co-Pilot User's and Administrator's Guide" and .IR "Performance Co-Pilot Programmer's Guide" which can be found at http://techpubs.sgi.com. pcp-3.8.12ubuntu1/man/man1/pmafm.10000664000000000000000000001252212272262501013375 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMAFM 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmafm\f1 \- Performance Co-Pilot archive folio manager .SH SYNOPSIS \f3pmafm\f1 \f2folioname\f1 [\f2command\f1 [\f2arg\f1 ...]] .SH DESCRIPTION A collection of one or more Performance Co-Pilot (PCP) archive logs may be combined with a control file to produce a PCP archive folio. Archive folios are created using either .BR mkaf (1) or the interactive ``record mode'' services of PCP clients like .BR pmchart (1). .PP .B pmafm provides a number of services that may be used to process folios. In particular, it provides support for execution of PCP tools using one or more of the component archive logs within an archive folio. .PP The target folio is identified by the folio control file .IR folioname . The syntax for a folio control file is described in .BR mkaf (1). .PP If present, the command and arguments following .I folioname are interpreted and executed as a single command, otherwise commands are read from standard input. .PP The following commands are supported. .TP .B archives Subsequent commands apply to all archives in the folio. .TP \f3archives\f1 \f2N\f1[,...] Archives within a folio are numbered 1, 2, etc. Subsequent commands are restricted to apply only to the designated archives. .TP \f3archives\f1 \f2name\f1[,...] Archives within a folio have unique names. Subsequent commands are restricted to apply only to the designated archives. .TP .B check Validate the presence and format of each file in the folio and the component archives. .TP .B help .br A brief reminder of the command syntax. .B ? is a synonym for .BR help . .TP .B hosts .br Subsequent commands apply to all archives in the folio. .TP \f3hosts\f1 \f2hostname\f1[,...] Subsequent commands are restricted to apply only to those archives that match the designated hostnames. .TP \f3list\f1 [\f3verbose\f1] Display the contents of the folio. By default the control header and the ordinal number, hostname and archive base name for each archive in the folio. The .B verbose option causes .B pmafm to dump the label record from each archive using .BR "pmdumplog \-l" . .if t .sp 0.5v .IP "" The first named archive in the folio is assumed to be associated with the default host for any tool that tries to replay multiple archives from the folio. .if t .sp .TP .BR quit .br Exit .BR pmafm . .TP .BR remove .br Echo on standard output the .BR sh (1) commands required to remove all of the physical files associated with this archive folio. .TP \f3repeat\f1 \f2tool\f1 [\f2arg\f1 ...] Execute the known PCP .I tool once per selected archive. For example, the command .br .ti +5n .ft CW repeat pmval \-t60 kernel.all.load .br would run .BR pmval (1) once per archive, with an appropriate .B \-a argument. .TP .B replay .br Some archive folios are created by tools (e.g. \c .BR pmchart (1)) that provide sufficient information to allow all of the information in all of the archives of a folio to be replayed. .TP [\f3run\f1] \f2tool\f1 [\f2arg\f1 ...] Execute the known PCP .I tool on the selected archives. Some PCP tools are able to process multiple concurrent archives, and in this case the tool is run once with the list of all selected archives passed via a .B \-a argument. Otherwise, this command is synonymous with .BR repeat . .TP .B selections Display those archives that would be selected for processing with a .BR repeat , .B replay or .B run command. .PP The restrictions via any .B hosts and .B archives commands are conjuncted. These restrictions serve to limit the specific archives processed in the subsequent .BR repeat , .BR replay , .B run and .B selections commands. By default, all archives are selected. .PP Keywords in commands may be abbreviated provided no ambiguity is introduced, e.g. .BR help , .B hel and .B he are synonymous, but .B h is ambiguous. .SH FILES .PD 0 .TP 10 .BI $PCP_SYSCONF_DIR/pmafm/ * control files that define the behavior of each PCP tool known to .BR pmafm . This information may be customized or extended, see .I $PCP_SYSCONF_DIR/pmafm/pcp for documentation of the syntax and semantics of these files. .TP .BI $HOME/.pcp/pmafm/ * User customization of the control files. All files in this directory are treated in the same manner as control files in the .I $PCP_SYSCONF_DIR/pmafm directory. .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .PP .BR mkaf (1), .BR pmchart (1), .BR pmview (1), .BR PMAPI (3), .BR pmRecordSetup (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS Many, but all are intended to be easily understood. pcp-3.8.12ubuntu1/man/man1/pmdatxmon.10000664000000000000000000001077212272262501014311 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .\" I am variants ... .ds ia txmon .ds IA TXMON .ds Ia Txmon .TH PMDATXMON 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdatxmon\f1 \- \*(ia performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/\*(ia/pmda\*(ia\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] \f2tx_type\f1 ... .br \f3$PCP_PMDAS_DIR/\*(ia/txrecord\f1 [\f3\-l\f1] .br \f3$PCP_PMDAS_DIR/\*(ia/txrecord\f1 \f2tx_type servtime\f1 [\f2tx_type servtime\f1 ... ] .br \f3$PCP_PMDAS_DIR/\*(ia/genload\f1 .SH DESCRIPTION .B pmda\*(ia is an example Performance Metrics Domain Agent (PMDA) which exports a small number of performance metrics from a simulated transaction monitor. .PP The \*(ia PMDA is shipped as both binary and source code and is designed to be an aid for PMDA developers; the \*(ia PMDA demonstrates how performance data can be exported from an application (in this case .BR txrecord ) to the PCP infrastructure via a shared memory segment. As a matter of convenience, .B pmda\*(ia creates (and destroys on exit) the shared memory segment. .PP The .I tx_type arguments are arbitrary unique tags used to identify different transaction types. .PP The .B txrecord application simulates the processing of one or more transactions identified by .I tx_type and with an observed service time of .I servtime . .PP With the .B \-l option, .B txrecord displays the current summary of the transaction activity from the shared memory segment. .PP .B genload is a shell and .BR awk (1) script that acts as a front-end to .B txrecord to generate a constant load of simulated transaction activity. .PP A brief description of the .B pmda\*(ia command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I \*(ia.log is written in the current directory of .BR pmcd (1) when .B pmda\*(ia is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP 5 .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .SH INSTALLATION If you want access to the names, help text and values for the \*(ia performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/\*(ia # ./Install .in .fi .ft 1 .PP You will be prompted for the .I tx_type tags. .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/\*(ia # ./Remove .in .fi .ft 1 .PP .B pmda\*(ia is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmda\*(ia .TP .B $PCP_PMDAS_DIR/\*(ia/help default help text file for the \*(ia metrics .TP .B $PCP_PMDAS_DIR/\*(ia/Install installation script for the .B pmda\*(ia agent .TP .B $PCP_PMDAS_DIR/\*(ia/Remove undo installation script for the .B pmda\*(ia agent .TP .B $PCP_LOG_DIR/pmcd/\*(ia.log default log file for error messages and other information from .B pmda\*(ia .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmdasample (1), .BR pmdatrivial (1), .BR txmonvis (1) and .BR PMDA (3). pcp-3.8.12ubuntu1/man/man1/pmlogsummary.10000664000000000000000000002340312272262501015031 0ustar '\"! tbl | mmdoc '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOGSUMMARY 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmlogsummary\f1 \- calculate averages of metrics stored in a PCP archive .SH SYNOPSIS \f3pmlogsummary\f1 [\f3\-abfFHiIlmMNsvxyz\f1] [\f3\-B\f1 \f2nbins\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-p\f1 \f2precision\f1] [\f3\-S\f1 \f2starttime\f1] [\f3\-T\f1 \f2endtime\f1] [\f3\-Z\f1 \f2timezone\f1] \f2archive\f1 [\f2metricname\f1 ...] .SH DESCRIPTION .B pmlogsummary prints statistical information about metrics of numeric type contained within the files of a Performance Co-Pilot (PCP) archive log. The default output prints time averages for both counter and non-counter metrics. The archive log has the base name .IR archive , typically created using .BR pmlogger (1). .PP The metrics of interest are named in the .I metricname arguments. If .I metricname is a non-leaf node in the Performance Metrics Name Space (\c .BR pmns (5)), then .B pmlogsummary will recursively descend the PMNS and report on all leaf nodes. If no .I metricname argument is given, the root of the namespace is used. .PP Normally .B pmlogsummary operates on the default .BR pmns (5), however if the .B \-n option is specified an alternative namespace is loaded from the file .IR pmnsfile . .PP The command line options .B \-S and .B \-T can be used to specify a time window over which metrics should be summarized. These options are common to most Performance Co-Pilot tools and are fully described in .BR PCPIntro (1). .PP The remaining options control the specific information to be reported. Metrics with counter semantics are converted to rates before being evaluated. .TP .B \-a Print all information. This is equivalent to .BR \-blmMy . .TP .B \-b Print both forms of averaging, that is both stochastic and time averaging. .TP .B \-B Print the approximate distribution of values, using histogram bins such that the value range (minimum - maximum) for each metric is divided equally into .I nbins bins, and each bin accumulates the frequency of observed values in the corresponding range. Refer to the ``OUTPUT FORMAT'' section below for a description of how the distribution of values is reported). .TP .B \-f Spreadsheet format \- the tab character is used to delimit each field printed. This option is intended to allow .B pmlogsummary output to be imported directly into common spreadsheet applications. .TP .B \-F Spreadsheet format \- the comma character is used to delimit each field printed. This option is intended to allow .B pmlogsummary output to be imported directly into common spreadsheet applications which support the Comma Separated Value (.csv) format. .TP .B \-H Print a one-line header at the start showing what each field represents. .TP .B \-l Also print the archive label, showing the log format version, the time and date for the start and (current) end of the archive time window, and the host from which the performance metrics values were collected. .TP .B \-i Also print the time at which the minimum value was logged. The format of this timestamp is described in the ``OUTPUT FORMAT'' section below. .TP .B \-I Also print the time at which the maximum value was logged. The format of this timestamp is described in the ``OUTPUT FORMAT'' section below. .TP .B \-m Also print the minimum logged value for each metric. .TP .B \-M Also print the maximum logged value for each metric. .TP .B \-s Print (only) the sum of all logged values for each metric. .TP .B \-N Suppress any warnings resulting from individual archive fetches (default). .TP .B \-p Print all floating point numbers with .I precision digits after the decimal place. .TP .B \-v Report (verbosely) on warnings resulting from individual archive fetches. .TP .B \-x Print stochastic averages instead of the default (time averages). .TP .B \-y Also print the number of samples encountered in the archive for each metric. .PP By default, .B pmlogsummary reports the time of day according to the local timezone on the system where .B pmlogsummary is run. The .B \-Z option changes the timezone to .I timezone in the format of the environment variable .B TZ as described in .BR environ (5). The .B \-z option changes the timezone to the local timezone at the host that is the source of the performance metrics, as specified in the label record of the archive log. .SH OUTPUT FORMAT The .B pmlogsummary output format is spartan as it is intended to be post-processed with standard tools. This means that there is no annotation associated with each output field which would make processing harder. The intention is that .B pmlogsummary output be massaged into a format which can be used by a spreadsheet program, is suitable for inclusion in a web page, or whatever. .PP For each metric, .B pmlogsummary produces a single output line as follows: .PP .in 1.0i .ft CW .nf \f2metricname\f1 \f2value(s)\f1 \f2units\f1 .fi .ft R .in .PP For metrics with multiple instances, .B pmlogsummary produces multiple lines of output as follows: .PP .in 1.0i .ft CW .nf \f2metricname\f1 ["\f2instance 1\f1"] \f2value(s)\f1 \f2units\f1 \f2metricname\f1 ["\f2instance 2\f1"] \f2value(s)\f1 \f2units\f1 \f2metricname\f1 ["\f2instance N\f1"] \f2value(s)\f1 \f2units\f1 .fi .ft R .in .PP The printed \f2value(s)\f1 for each metric always follow this order: stochastic average, time average, minimum, minimum timestamp, maximum, maximum timestamp, count, [bin 1 range], bin 1 count, ... [bin .I nbins range], bin .I nbins count. The individual values for each metric are space-separated (unless the .B \-f option is used). .PP All counter metrics which are measured in units of time will be converted to seconds before being rate converted and used in the .B pmlogsummary calculations. The values calculated for these metrics are also printed in seconds. .PP The units will be displayed in the format described by .BR pmUnitsStr (3). .PP Given either of the .B -i or .B -I options, .B pmlogsummary produces two different timestamp formats, depending on the interval over which it is run. For an interval greater than 24 hours, the date is displayed in addition to the time at which the maxima and/or minima occurred. If the extent of the data being checked is less than 24 hours, a more precise format is used (time is displayed with millisecond precision, but without the date). .PP .SH NOTES The average for an individual metric is calculated as follows: .PP Non-counter metrics are averaged using stochastic averaging - each observation has an equal weighting towards the calculation of the average (the sum of all values divided by the total number of values, for each metric). .PP Counter metrics are averaged using time averaging (by default), but the .B \-x option can be used to specify that counters be averaged using the stochastic method instead. When calculating a time average, the sum of the product of each sample value multiplied by the time difference between each sample, is divided by the total time over which that metric was logged. .PP Counter metrics whose measurements do not span 90% of the archive will be printed with the metric name prefixed by an asterisk (*). .PP .SH EXAMPLE .sp .nf $ pmlogsummary \-aN \-p 1 \-B 3 surf network.interface.out.bytes Log Label (Log Format Version 1) Performance metrics from host www.sgi.com commencing Tue Jan 14 20:50:50.317 1997 ending Wed Jan 29 10:13:07.387 1997 network.interface.out.bytes ["xpi0"] 202831.3 202062.5 20618.7 \e 1235067.7 971 [<=425435.0] 912 [<=830251.4] 42 [<=1235067.7] \e 17 byte / sec network.interface.out.bytes ["xpi1"] 0.0 0.0 0.0 0.0 1033 [<=0.0] \e 1033 [] 0 [] 0 byte / sec network.interface.out.bytes ["et0"] 0.0 0.0 0.0 0.0 1033 [<=0.0] \e 1033 [] 0 [] 0 byte / sec network.interface.out.bytes ["lo0"] 899.0 895.2 142.6 9583.1 1031 \e [<=3289.4] 1027 [<=6436.2] 3 [<=9583.1] 1 byte / sec .fi .sp A description of each field in the first line of statistical output, which describes one instance of the network.interface.out.bytes metric, follows: .TS box,center; cf(R) | cf(R) lf(CW) | lf(R). Field Meaning _ ["xpi0"] instance name 202831.3 stochastic average 202062.5 time average 20618.7 minimum value 1235067.7 maximum value 971 total number of values for this instance [<=425435.0] range for first bin (20618.7-425435.0) 912 number of values in first bin [<=830251.4] range for second bin (425435.0-830251.4) 42 number of values in second bin [<=1235067.7] range for third bin (830251.4-1235067.7) 17 number of values in third bin byte / sec base units for this metric .TE .SH FILES .PD 0 .TP 10 .BI $PCP_VAR_DIR/pmns/ * default PMNS specification files .TP .BI $PCP_LOG_DIR/pmlogger/ hostname Default directory for PCP archives containing performance metric values collected from the host .IR hostname . .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmchart (1), .BR pmdumptext (1), .BR pmlogextract (1), .BR pmlogger (1), .BR pmval (1), .BR PMAPI (3), .BR pmUnitsStr (3) and .BR pmns (5). .SH DIAGNOSTICS All are generated on standard error and are intended to be self- explanatory. pcp-3.8.12ubuntu1/man/man1/pmdammv.10000664000000000000000000001125612272262521013743 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMDAMMV 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdammv\f1 \- memory mapped values performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/mmv/pmdammv\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION .B pmdammv is a Performance Metrics Domain Agent (PMDA) which exports application level performance metrics using memory mapped files. It offers an extremely low overhead instrumentation facility that is well-suited to long running, mission critical applications where it is desirable to have performance metrics and availability information permanently enabled. .PP The .B mmv PMDA exports instrumentation that has been added to an application using the MMV APIs (refer to .BR mmv_stats_init (3) and .BR mmv (5) for further details). These APIs can be called from several languages, including C, C++, Perl, Python and Java (via the separate ``Parfait'' class library). .PP A brief description of the .B pmdammv command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I mmv.log is written in the current directory of .BR pmcd (1) when .B pmdammv is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .SH INSTALLATION If you want access to the names, help text and values for the mmv performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/mmv # ./Install .in .fi .ft 1 .PP Note that the default mechanism for sharing memory mapped values between instrumented applications and the .B mmv PMDA involves the creation of a world-writeable .I $PCP_TMP_DIR/mmv directory with the sticky-bit set (similar to .I /tmp and .IR /var/tmp , for example). This suffices to allow any application, running under any user account, to communicate with the PMDA (which runs under the "pcp" account by default). This may not be desirable for every environment, and one should consider the security implications of any directory setup like this (similar classes of issues exist as those that affect the system temporary file directories). .PP The installation process will not overwrite any existing .I $PCP_TMP_DIR/mmv directory. Thus it is possible to implement an alternate permissions strategy with no world-writable directory for sharing files - any directory readable by user or group "pcp" will suffice. .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/mmv # ./Remove .in .fi .ft 1 .PP .B pmdammv is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdammv .TP 10 .B $PCP_TMP_DIR/mmv directory housing memory mapped value files .TP 10 .B $PCP_PMDAS_DIR/mmv/help default help text file for the mmv metrics .TP 10 .B $PCP_PMDAS_DIR/mmv/Install installation script for the .B pmdammv agent .TP 10 .B $PCP_PMDAS_DIR/mmv/Remove undo installation script for the .B pmdammv agent .TP 10 .B $PCP_LOG_DIR/pmcd/mmv.log default log file for error messages and other information from .B pmdammv .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR mmv_stats_init (3), .BR mmv (5), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/newhelp.10000664000000000000000000000731412272262501013742 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .\" .TH NEWHELP 1 "PCP" "Performance Co-Pilot" .SH NAME \f3newhelp\f1 \- generate a performance metrics help database .SH SYNOPSIS \f3$PCP_BINADM_DIR/newhelp\f1 [\f3\-V\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-o\f1 \f2outputfile\f1] [\f3\-v\f1 \f2version\f1] [\f2file\f1 ...] .SH DESCRIPTION .B newhelp generates the Performance Co-Pilot help text files used by Performance Metric Domain Agents (PMDAs). .PP Normally .B newhelp operates on the default Performance Metrics Namespace (PMNS), however if the .B \-n option is specified an alternative namespace is loaded from the file .IR pmnsfile . .PP When there is only one input file, the base name of the new database is derived from the name of the input .IR file , otherwise the .B \-o flag must be given to explicitly name the database. If no input files are supplied, .B newhelp reads from the standard input stream, in which case the .B \-o flag must be given. .PP If the output file name is determined to be .BR foo , .B newhelp will create .B foo.dir and .BR foo.pag . .PP Although historically there have been multiple help text file formats, the only format currently supported using the .B \-v option is .I version 2, and this is the default if no .B \-v flag is provided. .PP The .B \-V flag causes verbose messages to be printed while .B newhelp is parsing its input. .PP The first line of each entry in a help source file consists of an \&``@'' character beginning the line followed by a space and then the performance metric name and a one line description of the metric. Following lines (up to the next line beginning with ``@'' or end of file) may contain a verbose help description. E.g. .PP .ft CW .nf .in +0.5i # # This is an example of newhelp's input syntax # @ kernel.all.cpu.idle CPU idle time A cumulative count of the number of milliseconds of CPU idle time, summed over all processors. .in .fi .ft 1 .PP Three-part numeric metric identifiers (PMIDs) may be used in place of metric names, e.g. \c .ft CW 60.0.23 .ft 1 rather than .ft CW kernel.all.cpu.idle .ft 1 in the example above. Other than for dynamic metrics (where the existence of a metric is known to a PMDA, but not visible in the PMNS and hence has no name that could be known to .IR newhelp ) use of this syntactic variant is not encouraged. .PP Lines beginning with ``#'' are ignored, as are blank lines in the file before the first ``@''. The verbose help text is optional. .PP As a special case, a ``metric'' name of the form .I NNN.MM (for numeric .I NNN and .IR MM ) is interpreted as an instance domain identification, and the text describes the instance domain. .SH FILES .PD 0 .TP 10 .BI $PCP_VAR_DIR/pmns/ * default PMNS specification files .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR chkhelp (1), .BR PMAPI (3), .BR pmLookupInDomText (3), .BR pmLookupText (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmlogcheck.10000664000000000000000000000774612272262501014425 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOGCHECK 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmlogcheck\f1 \- checks for invalid data in a PCP archive .SH SYNOPSIS \f3pmlogcheck\f1 [\f3\-lz\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-S\f1 \f2start\f1] [\f3\-T\f1 \f2finish\f1] [\f3\-Z\f1 \f2timezone\f1] \f2archive\f1 .SH DESCRIPTION .B pmlogcheck prints information about the nature of any invalid data which it detects in a PCP archive. Of particular interest are wrapped values for metrics which are expected to have monotonically increasing values. The archive has the base name .I archive and must have been previously created using .BR pmlogger (1). .PP Normally .B pmlogcheck operates on the default Performance Metrics Namespace (\c .BR pmns (5)), however if the .B \-n option is specified an alternative namespace is loaded from the file .IR pmnsfile . .PP The command line options .B \-S and .B \-T can be used to specify a time window over which metrics should be summarized. These options are common to many Performance Co-Pilot tools and are fully described in .BR PCPIntro (1). .PP The .B \-l option prints the archive label, showing the log format version, the time and date for the start and (current) end of the archive, and the host from which the performance metrics values were collected. .PP By default, .B pmlogcheck reports the time of day according to the local timezone on the system where .B pmlogcheck is run. The .B \-Z option changes the timezone to .I timezone in the format of the environment variable .B TZ as described in .BR environ (5). The .B \-z option changes the timezone to the local timezone at the host that is the source of the performance metrics, as specified in the label record of the archive log. .SH OUTPUT FORMAT For each metric having ``counter'' semantics (i.e. the metric is expected to increase monotonically) which has been detected as having wrapped at some point in the archive, .B pmlogcheck produces output describing the metric name (with instance identifiers where appropriate), the internal storage type for the metric, the value of the metric before the counter wrap (with its associated timestamp), and the value of the metric after the wrap (also with a timestamp). .PP .B pmlogcheck produces two different timestamp formats, depending on the interval over which it is run. For an interval greater than 24 hours, the date is displayed in addition to the time at which the counter wrap occurred. If the extent of the data being checked is less than 24 hours, a more precise format is used (time is displayed with millisecond precision, but without the date). .PP .SH FILES .PD 0 .TP 10 .BI $PCP_VAR_DIR/pmns/ * default PMNS specification files .TP .BI $PCP_LOG_DIR/pmlogger/ hostname default directory for PCP archives containing performance data collected from the host .IR hostname . .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmdumplog (1), .BR pmlogextract (1), .BR pmlogger (1), .BR pmlogmerge (1), .BR pmlogsummary (1), .BR pmval (1), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). .SH DIAGNOSTICS All are generated on standard error and are intended to be self- explanatory. pcp-3.8.12ubuntu1/man/man1/pmloglabel.10000664000000000000000000001125012272262501014410 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2008 Aconex. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOGLABEL 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmloglabel\f1 \- check and repair a performance metrics archive label .SH SYNOPSIS \f3pmloglabel\f1 [\f3\-Llsv\f1] [\f3\-h\f1 \f2hostname\f1] [\f3\-p\f1 \f2pid\f1] [\f3\-V\f1 \f2version\f1] [\f3\-Z\f1 \f2timezone\f1] \f2archive\f1 .SH DESCRIPTION .B pmloglabel verifies, reports on, and can modify all details of the labels in each of the files of a Performance Co-Pilot (PCP) archive log. The archive log has the base name .I archive and must have been previously created using .BR pmlogger (1). .PP Each of the files in a PCP archive (metadata, temporal index, and one or more data volumes) must contain a valid label at the start, else the PCP tools will refuse to open the archive at all. .PP Thus, the primary function of .B pmloglabel is to be able to repair any inconsistent or corrupt label fields, such that the entire archive is not lost. It will not check the remainder of the archive, but it will give you a fighting chance to recover otherwise lost data. Together, .B pmloglabel and .B pmlogextract are able to produce a valid PCP archive from many forms of corruption. .PP Note that if the temporal index is found to be corrupt, the "*.index" file can be safely moved aside and the archive will still be accessible, however retrievals may take longer without the index. .PP The options control the specific information to be reported, or the specific fields to be modified: .TP 5 .B \-h Modify the logged .I hostname in the archive label, for all files in the archive. .TP .B \-l Dump out the archive label, showing the log format version, the time and date for the start and (current) end of the archive, and the host from which the performance metrics values were collected. .TP .B \-L Like .BR \-l , just a little more verbose, showing also the timezone and creator process identifier from the archive label. .TP .B \-p Set the process identifier stored in the archive label to .IR pid , for all files in the archive. .TP .B \-s Rewrite the sentinel values which precede and follow the archive label, for all files in the archive. .TP .B \-v Verbose mode. Additional progress information is produced at each step. .TP .B \-V Stamp the .I version number into the magic number field at the start of the archive label, for all files in the archive. .TP .B \-Z Changes the timezone in the archive labels to .I timezone in the format of the environment variable .B TZ as described in .BR environ (5). .PP .SH EXAMPLES The following demonstrates the use of .B pmloglabel in finding and then correcting a corrupt field (PID) in the label of the temporal index of an archive named "20080125". .PP .sp 0.5v .in +1i .ft CW .nf $ pmdumplog \-l 20080125 pmdumplog: Cannot open archive "20080125": Illegal label record at start of a PCP archive log file $ pmloglabel 20080125 Mismatched PID (5264/5011) between temporal index and data volume 0 $ pmloglabel \-p 5264 20080125 $ pmdumplog \-l 20080125 Log Label (Log Format Version 2) Performance metrics from host fw1 commencing Fri Jan 25 00:10:09.341 2008 ending Sat Jan 26 00:09:54.344 2008 .fi .SH EXIT STATUS .B pmloglabel exits with status 0 if the archive labels are clean. If invoked incorrectly, the exit status will be 1. If corruption is detected and still exists at the end, the exit status will be 2. If requested to write out the archive labels, and some aspect of that write out fails, then the exit status will be 3. .SH FILES .PD 0 .TP 10 .BI $PCP_LOG_DIR/pmlogger/ hostname Default directory for PCP archives containing performance metric values collected from the host .IR hostname . .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmlogcheck (1), .BR pmlogextract (1), .BR pmlogger (1), .BR pmlogger_check (1), .BR pmlogger_daily (1), .BR pmlogrewrite (1), .BR pcp.conf (5), and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmcpp.10000664000000000000000000001037612272262501013421 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2011 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMCPP 1 "" "Performance Co-Pilot" .SH NAME \f3pmcpp\f1 \- simple preprocessor for the Performance Co-Pilot .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS .B pmcpp [\f3\-D\f1 \f2name\f1[=\f2value\f1] ...] [\f2infile\f1] .SH DESCRIPTION .B pmcpp provides a very simple pre-processor for manipulating Performance Metric Name Space (PMNS) files for the Performance Co-Pilot (PCP). It is most commonly used internally to process the PMNS file(s) after .BR pmLoadNameSpace (3) or .BR pmLoadASCIINameSpace (3) is called. .PP Input lines are read from .I infile (or standard input if .I infile is not specified), processed and written to standard output. .PP All C-style comments of the form /* ... */ are stripped from the input stream. .PP There are no predefined macros for .B pmcpp although macros may be defined on the command line using the .B \-D option, where .I name and .I value must follow the same rules as described below for the .B #define directive. .PP .B pmcpp accepts the following directives in the input stream (like .BR cpp (1)): .IP * 3n \fB#include "\fIfilename\fB"\fR .br or .br \fB#include <\fIfilename\fB>\fR .br In either case the directory search path for .I filename tries .I filename first, then the directory for the command line .I infile (if any), followed by the .B $PCP_VAR_DIR/pmns directory. .B #include directives may be nested, up to a maximum depth of 5. .IP * 3n \fB#define \fIname value\fR .br Defines a value for the macro .I name which must be a valid C-style name, so leading alphabetic or ``_'' followed by zero or more alphanumerics or ``_''. .I value is optional (and defaults to an empty value) but when present it may .B not contain white space and quoting or escaping is .B not supported. .IP * 3n \fB#undef \fIname\fR .br Removes the macro definition, if any, for .IR name . .IP * 3n \fB#ifdef \fIname\fR .br \&... .br \fB#endif\fR .br or .br \fB#ifndef \fIname\fR .br \&... .br \fB#endif\fR .br The enclosing lines will be stripped or included, depending if the macro .I name is defined or not. .PP Macro substitution is achieved by breaking the input stream into words separated by white space or one of the characters ``.'' or ``:'' \- this matches the syntax of the PMNS, see .BR pmns (5). Each word is checked and if it matches a macro name, the word is replaced by the macro value, otherwise the word is unchanged. .PP There is generally one output line for each input line, although the line may be empty if the text has been stripped due to the handling of comments or conditional directives. When there is a change in the input stream, an additional output line is generated of the form: .PP .ti +10n # line "name" .PP to indicate the .I following line of output corresponds to line number .I line of the input file .IR name . .PP Important .BR cpp (1) features that are .B not supported by .B pmcpp include: .IP * 3n \fB#if \fIexpr\fR .br \&... .br \fB#endif\fR .IP * 3n Nested use of .B #ifdef or .BR #ifndef . .IP * 3n .B #else within an .B #ifdef or .BR #ifndef . .IP * 3n Stripping C++ style comments, as in // comment .IP * 3n Error recovery - the first error encountered by .B pmcpp will be fatal. .IP * 3n .BR cpp (1) command line options like .B \-U , .B \-P and .BR \-I . .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR cpp (1), .BR pmLoadASCIINameSpace (3), .BR pmLoadNameSpace (3), .BR pmns (5), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmlogextract.10000664000000000000000000002455412272262501015016 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOGEXTRACT 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmlogextract\f1 \- reduce, extract, concatenate and merge Performance Co-Pilot archives .SH SYNOPSIS \f3pmlogextract\f1 [\f3\-dfwz\f1] [\f3\-c\f1 \f2configfile\f1] [\f3\-S\f1 \f2starttime\f1] [\f3\-s\f1 \f2samples\f1] [\f3\-T\f1 \f2endtime\f1] [\f3\-v\f1 \f2volsamples\f1] [\f3\-Z\f1 \f2timezone\f1] \f2input\f1 [...] \f2output\f1 .SH DESCRIPTION .B pmlogextract reads one or more Performance Co-Pilot (PCP) archive logs identified by .I input and creates a temporally merged and/or reduced PCP archive log in .IR output . The nature of merging is controlled by the number of input archive logs, while the nature of data reduction is controlled by the command line arguments. The input(s) must be PCP archive logs created by .BR pmlogger (1) with performance data collected from the .B same host, but usually over different time periods and possibly (although not usually) with different performance metrics being logged. .PP If only one .I input is specified, then the default behavior simply copies the input PCP archive log, into the output PCP archive log. When two or more PCP archive logs are specified as .IR input , the logs are merged (or concatenated) and written to .IR output . .PP In the output archive log a ``mark'' record will be inserted at a time just past the end of each of the input archive logs to indicate a possible temporal discontinuity between the end of one input archive log and the start of the next input archive log. See the .B "MARK RECORDS" section below for more information. There is no ``mark'' record after the end of the .I last (in temporal order) of the input archive logs. .SH COMMAND LINE OPTIONS The command line options for .B pmlogextract are as follows: .PP .TP 7 .BI \-c " configfile" Extract only the metrics specified in .I configfile from the .I input PCP archive log(s). The .I configfile syntax accepted by .B pmlogextract is explained in more detail in the .B Configuration File Syntax section. .PP .TP 7 .B \-d Desperate mode. Normally if a fatal error occurs, all trace of the partially written PCP archive .I output is removed. With the .B \-d option, the .I output archive log is not removed. .PP .TP 7 .B \-f For most common uses, all of the input archive logs will have been collected in the same timezone. But if this is not the case, then .B pmlogextract must choose one of the timezones from the input archive logs to be used as the timezone for the output archive log. The default is to use the timezone from the .I last input archive log. The .B \-f option forces the timezone from the .I first input archive log to be used. .TP 7 .BI \-S " starttime" Define the start of a time window to restrict the samples retrieved or specify a ``natural'' alignment of the output sample times; refer to .BR PCPIntro (1). See also the .B \-w option. .PP .TP 7 .BI \-s " samples" The argument .I samples defines the number of samples to be written to .IR output . If .I samples is 0 or .B -s is not specified, .B pmlogextract will sample until the end of the PCP archive log, or the end of the time window as specified by .BR -T , whichever comes first. The .B -s option will override the .B -T option if it occurs sooner. .PP .TP 7 .BI \-T " endtime" Define the termination of a time window to restrict the samples retrieved or specify a ``natural'' alignment of the output sample times; refer to .BR PCPIntro (1). See also the .B \-w option. .PP .TP 7 .BI \-v " volsamples" The .I output archive log is potentially a multi-volume data set, and the .B \-v option causes .B pmlogextract to start a new volume after .I volsamples log records have been written to the archive log. .RS 7 .PP Independent of any .B \-v option, each volume of an archive is limited to no more than 2^31 bytes, so .I pmlogextract will automatically create a new volume for the archive before this limit is reached. .RE .PP .TP 7 .B \-w Where .B \-S and .B \-T specify a time window within the same day, the .B \-w flag will cause the data within the time window to be extracted, for every day in the archive log. For example, the options .B \-w \-S "@11:00" \-T "@15:00" specify that .B pmlogextract should include archive log records only for the periods from 11am to 3pm on each day. When .B \-w is used, the .I output archive log will contain ``mark'' records to indicate the temporal discontinuity between the end of one time window and the start of the next. .PP .TP 7 .BI \-Z " timezone" Use .I timezone when displaying the date and time. .I Timezone is in the format of the environment variable .B TZ as described in .BR environ (5). .PP .TP 7 .B \-z Use the local timezone of the host from the input archive logs. The default is to initially use the timezone of the local host. .SH CONFIGURATION FILE SYNTAX The .I configfile contains metrics of interest, listed one per line. Instances may also be specified, but they are optional. The format for each metric name is metric [[instance[,instance...]]] where .I metric may be a leaf or a non-leaf node in the Performance Metrics Namespace (PMNS, see .BR pmns (5)). If a metric refers to a non-leaf node in the PMNS, .B pmlogextract will recursively descend the PMNS and include all metrics corresponding to descendent leaf nodes. Instances are optional, and may be specified as a list of one or more space (or comma) separated names, numbers or strings. Elements in the list that are numbers are assumed to be external instance identifiers - see .BR pmGetInDom (3) for more information. If no instances are given, then the logging specification is applied to all instances of the associated metric(s). .SH CONFIGURATION FILE EXAMPLE This is an example of a valid .IR configfile : .PP # # config file for pmlogextract # kernel.all.cpu kernel.percpu.cpu.sys ["cpu0","cpu1"] disk.dev ["dks0d1"] .SH MARK RECORDS When more than one input archive log contributes performance data to the output archive log, then ``mark'' records are inserted to indicate a possible discontinuity in the performance data. .PP A ``mark'' record contains a timestamp and no performance data and is used to indicate that there is a time period in the PCP archive log where we do not know the values of .B any performance metrics, because there was no .BR pmlogger (1) collecting performance data during this period. Since these periods are often associated with the restart of a service or .BR pmcd (1) or a system, there may be considerable doubt as to the continuity of performance data across this time period. .PP The rationale behind ``mark'' records may be demonstrated with an example. Consider one input archive log that starts at 00:10 and ends at 09:15 on the same day, and another input archive log that starts at 09:20 on the same day and ends at 00:10 the following morning. The would be a very common case for archives managed and rotated by .BR pmlogger_check (1) and .BR pmlogger_daily (1). .PP The output archive log would contain: .ta 12n .br 00:10.000 first record from first input archive log .br \&... .br 09:15.000 last record from first input archive log .br 09:15.001 .br 09:20.000 first record from second input archive log .br \&... .br 01:10.000 last record from second input archive log .PP The time period where the performance data is missing starts just after 09:15 and ends just before 09:20. When the output archive log is processed with any of the PCP reporting tools, the ``mark'' record is used to indicate a period of missing data. For example in the archive above, if one was reporting the average I/O rate at 30 minute intervals, aligned on the hour, then there would be data for the intervals ending at 09:00 and 10:00 but no data reported for the interval ending at 09:30 as this spans a ``mark'' record. .PP The presence of ``mark'' records in a PCP archive log can be established using .BR pmdumplog (1) where a timestamp and the annotation .B is used to indicate a ``mark'' record. .SH FILES .PD 0 For each of the .I input and .I output archive logs, several physical files are used. .TP 10 \f2archive\f3.meta metadata (metric descriptions, instance domains, etc.) for the archive log .TP \f2archive\f3.0 initial volume of metrics values (subsequent volumes have suffixes .BR 1 , .BR 2 , \&...) \- for .I input these files may have been previously compressed with .BR bzip2 (1) or .BR gzip (1) and thus may have an additional .B .bz2 or .B .gz suffix. .TP \f2archive\f3.index temporal index to support rapid random access to the other files in the archive log. .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmdumplog (1), .BR pmlc (1), .BR pmlogger (1), .BR pmlogreduce (1), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS All error conditions detected by .B pmlogextract are reported on .I stderr with textual (if sometimes terse) explanation. .PP Should one of the input archive logs be corrupted (this can happen if the .B pmlogger instance writing the log suddenly dies), then .B pmlogextract will detect and report the position of the corruption in the file, and any subsequent information from that archive log will not be processed. .PP If any error is detected, .B pmlogextract will exit with a non-zero status. .SH CAVEATS The preamble metrics (pmcd.pmlogger.archive, pmcd.pmlogger.host, and pmcd.pmlogger.port), which are automatically recorded by .B pmlogger at the start of the archive, may not be present in the archive output by .BR pmlogextract . These metrics are only relevant while the archive is being created, and have no significance once recording has finished. pcp-3.8.12ubuntu1/man/man1/pmdaib.10000664000000000000000000001010312272262501013522 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2009 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMDAIB 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaib\f1 \- Infiniband performance metrics domain agent (PMDA) .SH SYNOPSYS \f3$PCP_PMDAS_DIR/infiniband/pmdaib\f1 [\f3\-c\f1 \f2configFile\f1] [\f3\-D\f1 \f2debug\f1] [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-w\f1] .SH DESCRIPTION .B pmdaib is a Performance Metrics Domain Agent (PMDA) which exports information and performance metrics about local Infiniband HCAs and local or remote Infiniband GUIDs. .PP A brief description of the .B pmdaib command line options follows: .TP 5 .B \-c Location of the config file. By default, the config file is named .BR $PCP_PMDAS_DIR/infiniband/config. See .BR "CONFIG FILE" for more information. .TP .B -D A debug values, as specified by .B pmdbg (1) .TP .B \-d Specify an alternate performance metrics .I domain number. Almost never necessary. .TP .B \-l Location of the log file. By default, a log file named .I ib.log is written to .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-w Write out the default config file to .BR $PCP_PMDAS_DIRS/infiniband and exit immediately. The written config file will contain the local HCA ports. It will not overwrite an existing file. This argument should only be used to create the template config file and should never appear in .I pmcd.conf. See .BR "CONFIG FILE" for more information on the file format and on monitoring remote GUIDs. .SH CONFIG FILE By default, the PMDA will operate without using a config file. In this mode of operation the local HCA ports will be monitored. Note that if a new HCA is added to the machine that instance domain naming may change because it will always be based on the kernel's naming. .PP In cases where this is not acceptable, or in the case where monitoring remote Infiniband ports is required, a config file must be created. A "template" file can be created by running the .B pmdaib daemon with the .B \-w argument. This will create a config file with the local ports and GUIDs. .PP If the config file is .I executable then it will be run and the output will be used as the config file. .PP The config file is composed of line-based records. Blank lines and everything after the .I hash (#) character are ignored. Each line has 6 fields: .PP [\f3instName\f1] [\f3portGUID\f1] [\f3portNum\f1] via [\f3localPortName\f1]:[\f3localPortNum\f1] .PP The first field is used to give a static instance name to the Infiniband port that has a specific GUID. All of the other fields must be properly specified in order to monitor a particular port. .PP For example, to monitor port 1 of the local HCA called 'mthca0' a possible config file line would be: .PP myPort1 0xdeadbeef01234567 1 via mthca0:1 .PP Remote ports can be easily monitored by specifying the GUID of the HCA or switch and specifying the remote port number. The \f3localPortName\f1:\f3localPortNum\f1 tuple specifies which local HCA and port to use as the "first hop" in contacting the remote GUID. E.g., to monitor port 13 of a remote switch which is connected to the fabric on the first port of the second HCA: .PP switch13 0xfeeffeefabcdabcd 13 via mthca1:1 .SH LOCAL CONTEXT The Infiniband pmda also supports accessing the metrics via .B PM_CONTEXT_LOCAL when using the PMAPI interface. In order to use the Infiniband pmda in this way, set the environment variable .B PMDA_LOCAL_IB prior to calling .B pmNewContext(3). .SH SEE ALSO .BR pmcd(1), .BR PMAPI(3), .BR pmContextNew(3), .BR ibnetdiscover(8). pcp-3.8.12ubuntu1/man/man1/pmdaweblog.10000664000000000000000000003456212272262501014426 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAWEBLOG 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaweblog\f1 \- performance metrics domain agent (PMDA) for Web server logs .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS \f3$PCP_PMDAS_DIR/weblog/pmdaweblog\f1 [\f3\-Cp\f1] [\f3\-d\f1 \f2domain\f1] [\f3\-h\f1 \f2helpfile\f1] [\f3\-i\f1 \f2port\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-n\f1 \f2idlesec\f1] [\f3\-S\f1 \f2num\f1] [\f3\-t\f1 \f2delay\f1] [\f3\-u\f1 \f2socket\f1] [\f3\-U\f1 \f2username\f1] \f2configfile\f1 .SH DESCRIPTION .B pmdaweblog is a Performance Metrics Domain Agent .RB ( PMDA (3)) that scans Web server logs to extract metrics characterizing Web server activity. These performance metrics are then made available through the infrastructure of the Performance Co-Pilot (PCP). .PP The .I configfile specifies which Web servers are to be monitored, their associated access logs and error logs, and a regular-expression based scheme for extracting detailed information about each Web access. This file is maintained as part of the PMDA installation and/or de-installation by the scripts .B Install and .B Remove in the directory .BR $PCP_PMDAS_DIR/weblog . For more details, refer to the section below covering installation. .PP Once started, .B pmdaweblog monitors a set of log files and in response to a request for information, will process any new information that has been appended to the log files, similar to a .BR tail (1). There is also periodic "catch up" to process new information from all log files, and a scheme to detect the rotation of log files. .PP Like all other PMDAs, .B pmdaweblog is launched by .BR pmcd (1) using command line options specified in .I $PCP_PMCDCONF_PATH \- the .B Install script will prompt for appropriate values for the command line options, and update .IR $PCP_PMCDCONF_PATH . .PP A brief description of the .B pmdaweblog command line options follows: .TP .B \-C Check the configuration and exit. .TP .BI \-d " domain" Specify the .I domain number. It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the .B pmdaweblog PMDA on all hosts. .RS .P For most installations, the default .I domain as encapsulated in the file .B $PCP_PMDAS_DIR/weblog/domain.h will suffice. For alternate values, check .I $PCP_PMCDCONF_PATH for the .I domain values already in use on this host, and the file .B $PCP_VAR_DIR/pmns/stdpmid contains a repository of ``well known'' .I domain assignments that probably should be avoided. .RE .TP .BI \-h " helpfile" Get the help text from the supplied .I helpfile rather than from the default location. .TP .BI \-i " port" Communicate with .BR pmcd (1) on the specified Internet .I port (which may be a number or a name). .TP .BI \-l " logfile" Location of the log file. By default, a log file named .I weblog.log is written in the current directory of .BR pmcd (1) when .B pmdaweblog is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .BI \-n " idlesec" If a Web server log file has not been modified for .IR idlesec seconds, then the file will be closed and re-opened. This is the only way .B pmdaweblog can detect any asynchronous rotation of the logs by Web server administrative scripts. The default period is 20 seconds. This value may be changed dynamically using .BR pmstore (1) to modify the value of the performance metric .BR web.config.check . .I .TP .B \-p Communicate with .BR pmcd (1) via a pipe. .TP .BI \-S " num" Specify the maximum number of Web servers per .IR sproc . It may be desirable (from a latency and load balancing perspective) or necessary (due to file descriptor limits) to delegate responsibility for scanning the Web server log files to several .IR sprocs . .B pmdaweblog will ensure that each .I sproc handles the log files for at most .I num Web servers. The default value is 80 Web servers per .IR sproc . .TP .BI \-t " delay" To avoid the need to scan a lot of information from the Web server logs in response to a single request for performance metrics, all log files will be checked at least once every .I delay seconds. The default is 15 seconds. This value may by changed dynamically using .BR pmstore (1) to modify the value of the performance metric .BR web.config.catchup . .TP .BI \-u " socket" Communicate with .BR pmcd (1) via the given Unix domain .IR socket . .TP .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .SH INSTALLATION The PCP framework allows metrics to be collected on one host and monitored from another. These hosts are referred to as .I collector and .I monitor hosts, respectively. A host may be both a collector and a monitor. .PP Collector hosts require the installation of the agent, while monitoring hosts require no agent installation at all. .PP For collector hosts do the following as root: .PP .ft CW .nf .in +0.25i # cd $PCP_PMDAS_DIR/weblog # ./Install .in .fi .ft 1 .PP The installation procedure prompts for a default or non-default installation. A default installation will search for known server configurations and automatically configure the PMDA for any server log files that are found. A non-default installation will step through each server, prompting the user for other server configurations and arguments to .BR pmdaweblog . The end result of a collector installation is to build a configuration file that is passed to .B pmdaweblog via the .I configfile argument. .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.25i # cd $PCP_PMDAS_DIR/weblog # ./Remove .in .fi .ft 1 .PP .B pmdaweblog is launched by .BR pmcd (1) and should never be executed directly. The .B Install and .B Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH CONFIGURATION The configuration file for the weblog PMDA is an ASCII file that can be easily modified. Empty lines and lines beginning with '\f3#\f1' are ignored. All other lines must be either a regular expression or server specification. .PP Regular expressions, which are used on both the access and error log files, must be of the form: .PP .in +0.25i .B regex .I regexName regexp .in .I or .PP .in +0.25i .B regex_posix .I regexName ordering regexp_posix .in .PP The .I regexName is a word which uniquely identifies the regular expression. This is the reference used in the server specification. The .I regexp for access logs is in the format described for .BR regcmp (3). The .I regexp_posix for access logs is in the format described for .BR regcomp (3). The argument .I ordering is explained below. The .B Posix form should be available on all platforms. .PP The regular expression requires the specification of up to four arguments to be extracted from each line of a Web server access log, depending on the type of server. In the most common case there are two arguments representing the method and the size. .PP For the non\- .B Posix version, argument .I $0 should contain the method: .BR GET , .B HEAD , .B POST or .BR PUT . The method .B PUT is treated as a synonym for .BR POST , and anything else is categorized as .BR OTHER . .PP The second argument, .IR $1 , should contain the size of the request. A size of ``\f3\-\f1'' or `` '' is treated as unknown. .PP Argument .I $3 should contain the status code returned to the client browser and argument .I $4 should contain the status code returned to the server from a remote host. These latter two arguments are used for caching servers and must be specified as a pair (or .I $3 will be ignored). For further information on status codes, refer to the web site .B http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html .PP Some legal non\- .B Posix regex expression specifications for monitoring an access log are: .PP .ft CW .nf .in +0.25i # pattern for CERN, NCSA, Netscape etc Access Logs regex CERN ] "([A\-Za\-z][\-A\-Za\-z]+)$0 .*" [\-0\-9]+ ([\-0\-9]+)$1 # pattern for FTP Server access logs (normally in SYSLOG) regex SYSLOG_FTP ftpd[.*]: ([gp][\-A\-Za\-z]+)$0( )$1 .in .fi .ft 1 .PP There is 1 special types of access logs with the .I RegexName .I SQUID. This formats extract 4 parameters but since the .B Squid log file uses text-based status codes, it is handled as a special case. .PP In the examples below, .I NS_PROXY parses the Netscape/W3C .I Common Extended Log Format and .I SQUID parses the default Squid Object Cache format log file. .PP .ft CW .nf .in +0.25i # pattern for Netscape Proxy Server Extended Logs regex NS_PROXY ] "([A\-Za\-z][\-A\-Za\-z]+)$0 .*" ([\-0\-9]+)$2 \\ .in +0.5i ([\-0\-9]+)$1 ([\-0\-9]+)$3 .in # pattern for Squid Cache logs regex SQUID [0\-9]+\.[0\-9]+[ ]+[0\-9]+ [a\-zA\-Z0\-9\.]+ \\ .in +0.5i ([_A\-Z]+)$3\/([0\-9]+)$2 ([0\-9]+)$1 ([A\-Z]+)$0 .in .in .fi .ft 1 .PP The .I regexp for the error logs does not require any arguments, only a match. Some legal expressions are: .PP .ft CW .nf .in +0.25i # pattern for CERN, NCSA, Netscape etc Error Logs regex CERN_err . # pattern for FTP Server error logs (normally in SYSLOG) regex SYSLOG_FTP_err FTP LOGIN FAILED .in .fi .ft 1 .PP If .B POSIX compliant regular expressions are used, additional information is required since the order of parameters cannot be specified in the regular expression. For backwards compatibility, the common case of two parameters the order may be specified as .I method,size or .I size,method In the general case, the ordering is specified by one of the following methods: .TP 0.5in n1,n2,n3,n4 where nX is a digit between 1 and 4. Each comma-seperated field represents (in order) the argument number for .I method,size,client_status,server_status .TP 0.5in - Used for cases like the error logs where the content is ignored. .PP As for the non- .B Posix format, the .I SQUID RegexName is treated as a special case to match the non-numerical status codes. .PP Some legal .B Posix regex expression specifications for monitoring an access log are: .PP .ft CW .nf .in +0.25i # pattern for CERN, NCSA, Netscape, Apache etc Access Logs regex_posix CERN method,size ][ \\]+"([A\-Za\-z][\-A\-Za\-z]+) \\ .in +0.5i [^"]*" [\-0\-9]+ ([\-0\-9]+) .in # pattern for CERN, NCSA, Netscape, Apache etc Access Logs regex_posix CERN 1,2 ][ \\]+"([A\-Za\-z][\-A\-Za\-z]+) \\ .in +0.5i [^"]*" [\-0\-9]+ ([\-0\-9]+) .in # pattern for FTP Server access logs (normally in SYSLOG) regex_posix SYSLOG_FTP method,size ftpd[.*]: \\ .in +0.5i ([gp][\-A\-Za\-z]+)( ) .in # pattern for Netscape Proxy Server Extended Logs regex_posix NS_PROXY 1,3,2,4 ][ ]+"([A\-Za\-z][\-A\-Za\-z]+) \\ .in +0.5i [^"]*" ([\-0\-9]+) ([\-0\-9]+) ([\-0\-9]+) .in # pattern for Squid Cache logs regex_posix SQUID 4,3,2,1 [0\-9]+\.[0\-9]+[ ]+[0\-9]+ \\ .in +0.5i [a\-zA\-Z0\-9\.]+ ([_A\-Z]+)\/([0\-9]+) ([0\-9]+) ([A\-Z]+) .in # pattern for CERN, NCSA, Netscape etc Error Logs regex_posix CERN_err \- . # pattern for FTP Server error logs (normally in SYSLOG) regex_posix SYSLOG_FTP_err \- FTP LOGIN FAILED .in .fi .ft 1 .PP A Web server can be specified using this syntax: .PP .ft CW .nf .in +0.25i \f3server \f2serverName \f3on\f2|\f3off \f2accessRegex accessFile errorRegex errorFile .in .fi .ft 1 .PP The .I serverName must be unique for each server, and is the name given to the instance for the associated performance metrics. See .BR PMAPI (3) for a discussion of PCP instance domains. The .B on or .B off flag indicates whether the server is to be monitored when the PMDA is installed. This can altered dynamically using .BR pmstore (1) for the metric .BR web.perserver.watched , which has one instance for each Web server named in .IR configfile . .PP Two files are monitored for each Web server, the access and the error log. Each file requires the name of a previously declared regular expression, and a file name. The log files specified for each server do not have to exist when the weblog PMDA is installed. The PMDA will continue to check for non-existent log files and open them when possible. Some legal server specifications are: .PP .ft CW .nf .in +0.25i # Netscape Server on Port 80 at IP address 127.55.555.555 server 127.55.555.555:80 on CERN /logs/access CERN_err /logs/errors # FTP Server. server ftpd on SYSLOG_FTP /var/log/messages SYSLOG_FTP_err /var/log/messages .in .fi .ft 1 .SH CAVEATS Specifying regular expressions with an incorrect number of arguments, anything other than 2 for access logs, and none for error logs, may cause the PMDA to behave incorrectly and even crash. This is due to limitations in the interface of .BR regex (3). .SH FILES .TP 10 .B $PCP_PMDAS_DIR/weblog installation directory for the weblog PMDA .TP .B $PCP_PMDAS_DIR/weblog/Install installation script for the weblog PMDA .TP .B $PCP_PMDAS_DIR/weblog/Remove de-installation script for the weblog PMDA .TP .B $PCP_LOG_DIR/pmcd/weblog.log default log file for error reporting .TP .I $PCP_PMCDCONF_PATH .B pmcd configuration file that specifies the command line options to be used when .B pmdaweblog is launched .TP .B $PCP_LOG_DIR/NOTICES log of PMDA installations and removals .TP .B $PCP_VAR_DIR/config/web/weblog.conf likely location of the weblog PMDA configuration file .TP .B $PCP_DOC_DIR/pcpweb/index.html the online HTML documentation for PCPWEB .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmcd (1), .BR pmchart (1), .BR pmdawebping (1), .BR pminfo (1), .BR pmstore (1), .BR pmview (1), .BR tail (1), .BR weblogvis (1), .BR webvis (1), .BR PMAPI (3), .BR PMDA (3) and .BR regcmp (3). pcp-3.8.12ubuntu1/man/man1/chkhelp.10000664000000000000000000000661612272262501013722 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH CHKHELP 1 "PCP" "Performance Co-Pilot" .SH NAME \f3chkhelp\f1 \- check performance metrics help text files .SH SYNOPSIS \f3$PCP_BINADM_DIR/chkhelp\f1 [\f3\-eHiOp\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-v\f1 \f2version\f1] \f2helpfile\f1 [\f2metricname\f1 ...] .SH DESCRIPTION .B chkhelp checks the consistency of Performance Co-Pilot help text files generated by .BR newhelp (1) and used by Performance Metric Domain Agents (PMDAs). The checking involves scanning the files, and optionally displaying selected entries. .PP The files \f2helpfile\f3.dir\f1 and \f2helpfile\f3.pag\f1 are created by .BR newhelp (1), and are assumed to already exist. .PP Without any options or .I metricname arguments, .B chkhelp silently verifies the structural integrity of the help files. .PP If any .I metricname arguments are specified, then the help entries for only the corresponding metrics will be processed. .PP If no .I metricname arguments are specified, then at least one of the options .B \-i or .B \-p must be given. The .B \-i option causes entries for all instance domains to be processed (ignoring entries for performance metrics). The .B \-p option causes entries for all metrics to be displayed (ignoring entries for instance domains). .PP When metric entries are to be processed (via either the .I metricname arguments or the .B \-p option or the .B \-i option), the .B \-O and .B \-H options request the display of the one-line and verbose help text respectively. The default is .BR \-O . .PP Although historically there have been multiple help text file formats, the only format currently supported using the .B \-v option is .I version 2, and this is the default if no .B \-v flag is provided. .PP Normally .B chkhelp operates on the default Performance Metrics Namespace (PMNS), however if the .B \-n option is specified an alternative namespace is loaded from the file .IR pmnsfile . .PP The .B \-e option provides an existence check where all of the specified metrics from the PMNS (note, not from .IR helpfile ) are scanned, and only the names of the metrics for which .B no help text exists are reported. The .B \-e option is mutually exclusive with the .B \-i and/or .B \-p options. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR newhelp (1), .BR PMAPI (3), .BR pmLookupInDomText (3), .BR pmLookupText (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS There are all sorts of reasons a help database may be inconsistent, the most likely is that a performance metric in the database is not defined in the loaded PMNS. pcp-3.8.12ubuntu1/man/man1/pminfo.10000664000000000000000000001434412272262501013571 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMINFO 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pminfo\f1 \- display information about performance metrics .SH SYNOPSIS \f3pminfo\f1 [\f3\-dfFLmMtTvxz\f1] [\f3\-a\f1 \f2archive\f1] [\f3\-b\f1 \f2batchsize\f1] [\f3\-c\f1 \f2dmfile\f1] [\f3\-h\f1 \f2hostname\f1] [\f3\-K\f1 \f2spec\f1] [\f3\-\f1[\f3n\f1|\f3N\f1] \f2pmnsfile\f1] [\f3\-O\f1 \f2time\f1] [\f3\-Z\f1 \f2timezone\f1] [\f2metricname\f1 ...] .SH DESCRIPTION .B pminfo displays various types of information about performance metrics available through the facilities of the Performance Co-Pilot (PCP). .PP Normally .B pminfo operates on the distributed Performance Metrics Name Space (PMNS), however if the .B \-n option is specified an alternative local PMNS is loaded from the file .IR pmnsfile. The .B \-N option supports the same function as .BR \-n , except for the handling of duplicate Performance Metric Identifiers (PMIDs) in .I pmnsfile \- duplicates are allowed with .B \-N they are not allowed with .BR \-n . .PP The metrics of interest are named in the .I metricname arguments. If .I metricname is a non-leaf node in the PMNS, then .B pminfo will recursively descend the PMNS and report on all leaf nodes. If no .I metricname argument is given, the root of the PMNS is used. .PP Unless directed to another host by the .B \-h option, by default .B pminfo will contact the Performance Metrics Collector Daemon (PMCD) on the local host. The connection to a PMCD is only required if .B pminfo requires distributed PMNS information, and/or meta-data describing metrics, and/or metric values, and/or help text. .PP The .B \-a option causes .B pminfo to use the specified archive rather than connecting to a PMCD. The .B \-a , \-h and .B \-L options are mutually exclusive. .PP The .B \-L option causes .B pminfo to use a local context to collect metrics from PMDAs on the local host without PMCD. Only some metrics are available in this mode. The .BR \-a , \-h and .B \-L options are mutually exclusive. .PP The .B \-b option may be used to define the maximum size of the group of metrics to be fetched in a single request for the .B \-f and .B \-v options. The default value for .I batchsize is 20. .PP Other options control the specific information to be reported. .TP 5 .B \-c The .I dmfile argument specifies a file that contains derived metric definitions in the format described for .BR pmLoadDerivedConfig (3). The .B \-c option provides a way to load derived metric definitions that is an alternative to the more generic use of the .B PCP_DERIVED_CONFIG environment variable as described in .BR PCPIntro (1). Using the .B \-c option and the .B PCP_DERIVED_CONFIG environment variable to specify the .B same configuration is a bad idea, so choose one or the other method. .TP .B \-d Metric descriptions detailing the PMID, data type, data semantics, units, scale and associated instance domain. .TP .B \-f Fetch and print values for all instances. When fetching from an archive, only those instances present in the first archive record for a metric will be displayed; see also the .B \-O option, else use .BR pmdumplog (1) which may be a better tool for examining archives. .TP .B \-F Same as .B \-f but try harder to fetch instances for metrics which have non-enumerable instance domains (e.g. metrics in the ``proc'' subtree of the default PMNS). .TP .B \-K When using the .B \-L option to fetch metrics from a local context, the .B \-K option may be used to control the DSO PMDAs that should be made accessible. The .I spec argument conforms to the syntax described in .BR __pmSpecLocalPMDA (3). More than one .B \-K option may be used. .TP .B \-m Print the PMID in terse mode. .TP .B \-M Print the PMID in verbose mode. .TP .B \-O When used in conjunction with an archive source of metrics and the options .B \-f or .BR \-F , the .I time argument defines a time origin at which the metrics should be fetched from the archive. Refer to .BR PCPIntro (1) for a complete description of this option, and the syntax for the .I time argument. .RS .PP When the ``ctime'' format is used for the .I time argument in a .B \-O option, the timezone becomes an issue. The default is to use the local timezone on the system where .B pminfo is run. The .B \-Z option changes the timezone to .I timezone in the format of the environment variable .B TZ as described in .BR environ (5). The .B \-z option changes the timezone to the local timezone at the host that is the source of the performance metrics, as identified via the .B \-a option. .RE .TP .B \-t Print the ``one line'' help summary, if available. .TP .B \-T Print the help text, if available. .TP .B \-v Verify mode in which descriptions and values are retrieved, but only error conditions are reported. This option silently disables any output from the options .BR \-f , .BR \-M , .BR \-m , .B \-t and .BR \-T . .TP .B \-x Like the .B \-f option, but with the additional functionality that if a value is processed that is of type PM_TYPE_EVENT, then the event records will be unpacked and the details of each event record reported. .SH FILES .PD 0 .TP 10 .BI $PCP_VAR_DIR/pmns/ * default local PMNS specification files .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmchart (1), .BR pmdumplog (1), .BR pmdumptext (1), .BR pmprobe (1), .BR pmval (1), .BR PMAPI (3), .BR pmLoadDerivedConfig (3), .BR __pmSpecLocalPMDA (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). pcp-3.8.12ubuntu1/man/man1/pmlc.10000664000000000000000000003101012272262501013221 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLC 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmlc\f1 \- configure active Performance Co-Pilot pmlogger(s) interactively .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS \f3pmlc\f1 [\f3\-e\f1] [\f3\-h\f1 \f2host\f1] [\f3\-i\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-P\f1] [\f3\-p\f1 \f2port\f1] [\f3\-Z\f1 \f2timezone\f1] [\f3\-z\f1] [\f3pid\f1] .SH DESCRIPTION .B pmlc may be used to change those metrics and instances which a .BR pmlogger (1) writes to a Performance Co-Pilot archive (see .BR PCPIntro (1)), the frequency with which the metrics are collected and whether the logging is mandatory, advisory, on or off. It also reports the current logging status of metrics and instances. .B pmlc may be used to control pmlogger instances on remote hosts as well as those on the local host. .PP Normally .B pmlc operates on the distributed Performance Metrics Name Space (PMNS), however if the .B \-n option is specified an alternative local PMNS is loaded from the file .IR pmnsfile . .PP If the .B \-P option is specified, .B pmlc will attempt to start with a connection to the primary pmlogger on the local host. If the .B \-p option is specified, then .B pmlc will attempt to start with a connection to the pmlogger on this TCP/IP .IR port . Alternatively, if .I pid is specified, a connection to the pmlogger instance with that process id will be attempted on startup. The .B \-h option may only be used if .BR \-P, .B \-p .I port or a .I pid is also specified. In that case .B pmlc will initially connect to the specified (remote) pmlogger instance on .I host rather than the local host. If the connection to the specified pmlogger instance cannot be established, .B pmlc will start with no connection. These options typically allow the same file of .B pmlc commands to be directed to multiple pmlogger instances by varying the command line arguments. Note that .BR -P , .B \-p .IR port , .IR pid and .B \-h are used only when making an initial connection to a pmlogger instance. They are not used as defaults if subsequent connections are made interactively (see the .B connect command below). .PP By default, .B pmlc reports the time of day according to the local timezone on the system where .B pmlc is run. The .B \-Z option changes the timezone to .IR timezone in the format of the environment variable .B TZ as described in .BR environ (5). The .B \-z option changes the timezone to the timezone of the pmlogger instance from which information is being obtained. Only one of .B \-z or .B \-Z may be specified. .PP If standard input is from a tty, .B pmlc is interactive, with prompts. The .B \-i flag may be used to force interactive behavior, and is typically used in conjunction with .B \-e to echo all command input on standard output. .PP The following commands may be used: .PP .TP 4 \f3show\f1 [ \f3loggers\f1 ] [ \f3@\f2host\f1 ] Displays the process identities of all pmlogger instances running on the local host (or .IR host , if specified). The primary pmlogger pid is parenthesized because it can be referred to as "primary" as well as by its pid. .TP 4 \f3connect\f1 \f2pid\f1 [ \f3@\f2host\f1 ] .br .in -4 \f3connect\f1 \f3primary\f1 [ \f3@\f2host\f1 ] .in Connects .B pmlc to the specified pmlogger process. Any existing connection to a pmlogger instance is closed first. Each pmlogger instance will accept at most one connection at a time, so if the connection is successfully established, your .B pmlc will be the only one controlling the pmlogger instance it is connected to. .TP 4 \f3new volume\f1 This command works only while a connection to a pmlogger instance is established. It tells the pmlogger to close the current volume of the log and open a new volume. Closed volumes may be archived, e.g. as part of a regular log management procedure to control the size of the physical log files. .TP 4 \f3status\f1 This command works only while a connection to a pmlogger instance is established. It prints information about the state of the pmlogger instance and its associated log. .TP 4 \f3timezone\f1 \f3local\f1 | \f3logger\f1 | \f3"\f2timezone\f3"\f1 This command sets the time zone used when times are printed. .B local means use the time zone of the machine that .B pmlc is running on. .B logger means use the time zone of the machine where the pmlogger instance is running. Alternatively an explicit .I timezone enclosed in quotes may be supplied (refer to .B TZ in .BR environ (5) for details). The default time zone is .B local unless one of the .B \-z or .B \-Z options has been supplied on the command line. .TP 4 \f3flush\f1 This command works only while a connection to a pmlogger instance is established, and requests the pmlogger instance to flush to disk all buffers associated with the current archive. For old-timers, \f3sync\f1 is a synonym for \f3flush\f1. .TP 4 \f3help\f1 Displays a summary of the available commands. .sp 0.5v \f3h\f1 and \f3?\f1 are synonyms for \f3help\f1. .TP 4 \f3quit\f1 Exits from .BR pmlc . .PP The remaining commands query and change the logging state of metrics and instances. They will work only if .B pmlc has a connection to a pmlogger instance. Metrics may be specified as fully qualified names (e.g. hinv.ncpu) or subtrees of the PMNS (e.g. hinv) which are expanded to include all metrics in the subtree (e.g. hinv.ncpu, hinv.cpuclock, etc.). Lists of metrics may be specified by enclosing them in braces with spaces or a comma between metrics (e.g. {hinv.ncpu hinv.ndisk}). Subtrees of metrics may be included in such lists. .PP Each individual metric specification may be further qualified with a space or comma separated list of instances in square brackets (e.g. kernel.all.load["1 minute", "5 minute"]). External instance names or numeric internal instance identifiers or both may be used in the same list (e.g. sample.colour.[red,1,"blue"]). If an instance qualification is applied to a subtree of the PMNS all of the metrics in the subtree must have the same instance domain. Instance qualifications may not be applied to entire lists of metrics but may appear inside such lists. .PP If no instances are specified for a metric, all instances are used. All instances means all instances available at the time the pmlogger instance in question fetches the metrics for logging. If an instance domain changes over time this is not always the same as the set of instances displayed by .BR pmlc , which can only display the currently available instances. To prevent unintentional errors, only the instances that are currently available to .B pmlc may appear in instance specifications. .TP 4 \f3query\f2 metriclist\f1 The current logging state of each metric (and instances, where applicable) in .I metriclist is displayed. This includes the logging state (e.g. on, maybe, off) and the logging interval for each metric (and instance) requested. The following abbreviations pertaining to metrics (and instances) may appear in the output: .BR adv , advisory; .BR mand , mandatory; .BR nl , not in the log; .BR na , in the log but not currently available from its Performance Metrics Domain Agent (PMDA). Where appropriate, an instance name will appear last on a line preceded by its numeric internal instance identifier. .TP 4 [ \f3log\f1 ] \f3mandatory on\f2 interval\f1 \f2metriclist\f1 This form of the .B log command turns on logging for the metrics (and any instances) in .IR metriclist. .I interval specifies how often the specified metrics/instances should be logged. .B once indicates that the metrics/instances should appear at most once in the log. More often one would use the optional keyword .B every followed by a positive number and one of .B millisecond (or .BR msec ), .B second (or .BR sec ), .B minute (or .BR min ), .B hour or their plurals. .sp 0.5v Note that the keyword .B default which may be used for the default .I interval in a .BR pmlogger (1) configuration file cannot be used in .BR pmlc . .sp 0.5v Internal limitations require the .I interval to be less than (approximately) 74 hours. An .I interval value of zero is a synonym for .BR once . .TP 4 [ \f3log\f1 ] \f3mandatory off\f1 \f2metriclist\f1 This tells the pmlogger instance not to log any of the metrics/instances in .IR metriclist . .TP 4 [ \f3log\f1 ] \f3mandatory maybe\f1 \f2metriclist\f1 This tells the pmlogger instance to honor any subsequent advisory logging requests for the metrics/instances in .IR metriclist . If the current logging state of the metrics/instances is mandatory (either on or off) the new state will be set to maybe (effectively advisory off). If the current state of the metrics/instances is already advisory (either on or off) the state(s) for the metrics/instances will remain as they are. .TP 4 [ \f3log\f1 ] \f3advisory on\f2 interval\f1 \f2metriclist\f1 .br .in -4 [ \f3log\f1 ] \f3advisory off\f1 \f2metriclist\f1 .in Advisory logging is only applicable if the last logging state specified for a metric/instance was "mandatory maybe" (which permits subsequent advisory logging control) or if the logging state is already advisory. These two statements turn advisory logging on or off (respectively) for the specified metrics/instances. .sp 0.5v The interpretation for .I interval is as above for the .B mandatory case. .PP There is no continuation character required for commands that span lines. .PP The word .B at may be used interchangeably with .BR @ . .PP A request to log all instances of a metric will supersede any prior request to log either all or specific instances of a metric (if the request specifies a permissible transition in the logging state). A request to log specific instances of a metric when all instances of a metric are already being logged is refused by .BR pmlogger . .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmdumplog (1), .BR pmlogger (1), .BR pcp.conf (5), .BR pcp.env (5) and .BR environ (5). .SH DIAGNOSTICS Most error or warning messages are self-explanatory. A message of the form .br .in +05.v Warning: unable to change logging state for... .in followed by a list of metrics (and possibly instances) indicates that .B pmlogger refused the request for the metrics (and instances) that appear. Any metrics (and instances) that were specified but do not appear in the message have had their logging state updated successfully (no news is good news). Usually this warning results from requesting advisory logging when a mandatory control is already in place, or requesting logging for specific instances when all instances are already being logged. .SH CAVEAT If all instances of a metric are being logged and a request is made to log specific instances of the metric with the same state and frequency, the request may appear to succeed, even though .B pmlogger has refused the request. This is not normally a problem, as the required information will still be placed into the log by .BR pmlogger . .PP However in the case where the metric is to be logged once, the outcome is not what might be expected. When .B pmlogger receives a request to log a metric once, it places the current value(s) of the metric into the log as soon as it can, regardless of whether the metric is already in the log. This may be used to force values into the log. When a request to log specific instances of a metric arrives and is refused because all instances of the metric are already being logged, .B pmlogger does not place values for the instances requested into the log. It returns the current logging state for each instance requested to .BR pmlc . The requested and returned states are identical, so .B pmlc doesn't raise an error as it should. .PP To ensure that only certain instances of a metric are being logged, one should always turn off logging for all instances of the metric prior to turning on logging for the specific instances required. pcp-3.8.12ubuntu1/man/man1/pmnsmerge.10000664000000000000000000001006312272262501014270 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNSMERGE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmnsmerge\f1 \- merge multiple versions of a Performance Co-Pilot PMNS .SH SYNOPSIS .B $PCP_BINADM_DIR/pmnsmerge [\f3\-adfv\f1] .I infile [...] .I outfile .SH DESCRIPTION .B pmnsmerge merges multiple instances of a Performance Metrics Name Space (PMNS), as used by the components of the Performance Co-Pilot (PCP). .P Each .I infile argument names a file that includes the root of a PMNS, of the form .P .sp 0.5v .in +1i .ft CW .nf root { /* arbitrary stuff */ } .fi .ft 1 .in -1i .sp 0.5v .P The order in which the .I infile files are processed is determined by the presence or absence of embedded control lines of the form .ft CW #define _DATESTAMP \f(COYYYYMMDD\fP .ft 1 .P Files without a control line are processed first and in the order they appear on the command line. The other files are then processed in order of ascending \f(CW_DATESTAMP\fP. .P The .B \-a option suppresses the argument re-ordering and processes all files in the order they appear on the command line. .P The merging proceeds by matching names in PMNS, only those \fBnew\fP names in each PMNS are considered, and these are added after any existing metrics with the longest possible matching prefix in their names. For example, merging these two input PMNS .P .sp 0.5v .in +1i .ft CW .nf root { root { surprise 1:1:3 mine 1:1:1 mine 1:1:1 foo foo yawn yours 1:1:2 } } foo { foo { fumble 1:2:1 mumble 1:2:3 stumble 1:2:2 stumble 1:2:2 } } yawn { sleepy 1:3:1 } .fi .ft 1 .in -1i .P Produces the resulting PMNS in .IR out . .P .sp 0.5v .in +1i .ft CW .nf root { mine 1:1:1 foo yours 1:1:2 surprise 1:1:3 yawn } foo { fumble 1:2:1 stumble 1:2:2 mumble 1:2:3 } yawn { sleepy 1:3:1 } .fi .ft 1 .P To avoid accidental over-writing of PMNS files, .I outfile is expected to not exist when .B pmnsmerge starts. The .B \-f option forces the removal of .I outfile (if it exists), before the check is made. .PP The .B \-d option allows the resultant PMNS to optionally contain duplicate PMIDs with different names in the PMNS. By default this condition is considered an error. .PP The .B \-v option produces one line of diagnostic output as each .I infile is processed. .PP Once all of the merging has been completed, .B pmnsmerge will attempt to load the resultant namespace using .BR pmLoadASCIINameSpace (3) \- if this fails for any reason, .I outfile will still be created, but .B pmnsmerge will report the problem and exit with non-zero status. .SH CAVEAT Once the writing of the new .I outfile file has begun, the signals SIGINT, SIGHUP and SIGTERM will be ignored to protect the integrity of the new file. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmnsadd (1), .BR pmnsdel (1), .BR pmLoadASCIINameSpace (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). pcp-3.8.12ubuntu1/man/man1/autofsd-probe.10000664000000000000000000000374512272262501015056 0ustar '\"macro stdmacro .TH AUTOFSD-PROBE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3autofsd-probe\f1 \- probe AutoFS mount/unmount daemon .SH SYNOPSIS \f3$PCP_BINADM_DIR/autofsd-probe\f1 [\f3\-h\f1 \f2host\f1] [\f3\-t\f1 \f2timeout\f1] .SH DESCRIPTION .B autofsd-probe will check the status of the .BR autofsd (1) daemon on the specified .IR host . .PP Unless directed to another .I host by the .B \-h option, .B autofsd-probe will contact the .B AutoFS daemon on the local host. .PP The .B AutoFS file system is built on the Remote Procedure Call (\c .BR RPC (3)) library routines. The .B \-t option allows the total timeout and retry timeout intervals to be set for all remote procedure call operations used with .BR autofsd-probe . This option accepts an interval argument in the form described in the .BR PCPintro (1) manual page. .PP .B autofsd-probe is typically used in an automated fashion from within .BR pmdashping (1) and in conjunction with .BR pmie (1), for monitoring response time and service failure. .PP By default .B autofsd-probe will not produce any output, unless there is an error in which case a diagnostic message will be displayed and the exit status will indicate the reason for failure. .SH DIAGNOSTICS If .B autofsd-probe succeeds, then 0 will be returned. If the attempt to establish a connection with .B autofsd fails, then 2 is returned. If the subsequent attempt to invoke an .B autofsd response fails, then 1 will be returned. .PP In the case of a syntactical command line error, 4 is returned and the usage message is displayed. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR autofs (1), .BR autofsd (1), .BR PCPintro (1), .BR pmdashping (1), .BR pmie (1) and .BR RPC (3). pcp-3.8.12ubuntu1/man/man1/pmdagluster.10000664000000000000000000000575412272262501014635 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAGLUSTER 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdagluster\f1 \- Gluster Filesystem PMDA .SH DESCRIPTION \f3pmdagluster\f1 is a Performance Metrics Domain Agent (PMDA) which exports metric values about mounted gluster filesystems using the .BR gluster (8) command. This PMDA exports metrics about volumes and bricks both local and remote to the node where pmdagluster is running. .PP The gluster filesystem supports fine-grained control over enabling statistics on individual volumes, so that the values are optionally enabled or disabled on systems where they are not desired to be monitored. .PP The .BR pmstore (1) command can be used to enable and disable profiling of volumes. Using the individual instances of the gluster.volume.profile metric, one can set their values (and associated profiling) either on (1) or off (0). Additionally, .BR pminfo (1) can report on the current status of profiling of each volume. .P .ft CW .nf .in +0.5i # pminfo \(hyf gluster.volume.profile gluster.volume.profile inst [0 or "gv0"] value 0 inst [1 or "gv1"] value 1 # pmstore \(hyi "gv0" gluster.volume.profile 1 gluster.volume.profile inst [0 or "gv0"] old value=0 new value=1 .in .fi .PP Further details on the gluster filesystem can be found at http://www.gluster.org .SH INSTALLATION Install the gluster PMDA by using the Install script as root: .PP # cd $PCP_PMDAS_DIR/gluster .br # ./Install .PP To uninstall, do the following as root: .PP # cd $PCP_PMDAS_DIR/gluster .br # ./Remove .PP \fBpmdagluster\fR is launched by \fIpmcd\fR(1) and should never be executed directly. The Install and Remove scripts notify \fIpmcd\fR(1) when the agent is installed or removed. .SH FILES .IP "\fB$PCP_PMDAS_DIR/gluster/Install\fR" 4 installation script for the \fBpmdagluster\fR agent .IP "\fB$PCP_PMDAS_DIR/gluster/Remove\fR" 4 undo installation script for the \fBpmdagluster\fR agent .IP "\fB$PCP_LOG_DIR/pmcd/gluster.log\fR" 4 default log file for error messages from \fBpmdagluster\fR .SH PCP ENVIRONMENT Environment variables with the prefix \fBPCP_\fR are used to parameterize the file and directory names used by \fBPCP\fR. On each installation, the file \fB/etc/pcp.conf\fR contains the local values for these variables. The \fB$PCP_CONF\fR variable may be used to specify an alternative configuration file, as described in \fIpcp.conf\fR(5). .SH SEE ALSO .BR pmcd (1), .BR pminfo (1), .BR pmstore (1), and .BR gluster (8) pcp-3.8.12ubuntu1/man/man1/pmdaroomtemp.10000664000000000000000000000666512272262521015016 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMDAROOMTEMP 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaroomtemp\f1 \- room temperature performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/roomtemp/pmdaroomtemp\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] .SH DESCRIPTION .B pmdaroomtemp is a Performance Metrics Domain Agent (PMDA) which exports the temperature from one or more sensors built using the DS2480 and DS1280 chipsets and MicroLAN technology from Dallas Semiconductor Corporation. .PP The .B roomtemp PMDA exports metrics that reflect the temperatures from one or more of these devices, in both degrees Celcius and Fahrenheit. Each metric has one instance for each temperature sensor device. The external instance identifiers are the serial numbers (in hex) of the DS1280 chips discovered when the MicroLAN was probed. .PP A brief description of the .B pmdaroomtemp command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I roomtemp.log is written in the current directory of .BR pmcd (1) when .B pmdaroomtemp is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .SH INSTALLATION If you want access to the names, help text and values for the roomtemp performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/roomtemp # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/roomtemp # ./Remove .in .fi .ft 1 .PP .B pmdaroomtemp is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdaroomtemp .TP 10 .B $PCP_PMDAS_DIR/roomtemp/help default help text file for the roomtemp metrics .TP 10 .B $PCP_PMDAS_DIR/roomtemp/Install installation script for the .B pmdaroomtemp agent .TP 10 .B $PCP_PMDAS_DIR/roomtemp/Remove undo installation script for the .B pmdaroomtemp agent .TP 10 .B $PCP_LOG_DIR/pmcd/roomtemp.log default log file for error messages and other information from .B pmdaroomtemp .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/GNUmakefile0000664000000000000000000000535112272262521014271 0ustar # # Copyright (c) 2012-2014 Red Hat. # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs MAN_SECTION = 1 MAN_PAGES = \ chkhelp.1 dbpmda.1 mkaf.1 newhelp.1 pcp.1 pcpintro.1 pmafm.1 \ pmcd.1 pmcd_wait.1 pmclient.1 pmconfig.1 pmdbg.1 pmdumplog.1 \ pmerr.1 pmgenmap.1 pmhostname.1 pmie.1 pmie_check.1 pminfo.1 \ pmlc.1 pmlock.1 pmlogcheck.1 pmlogconf.1 pmlogextract.1 \ pmlogger.1 pmlogger_check.1 pmnewlog.1 pmnsadd.1 pmnsdel.1 \ pmnsmerge.1 pmpost.1 pmprobe.1 pmsocks.1 pmstat.1 pmstore.1 \ pmtrace.1 pmval.1 pmlogsummary.1 pmdate.1 \ pmloglabel.1 genpmda.1 pmproxy.1 pmlogreduce.1 \ autofsd-probe.1 pmie2col.1 telnet-probe.1 pmsleep.1 pmsignal.1 \ pmieconf.1 pmiestatus.1 pmevent.1 pmcpp.1 pmlogrewrite.1 \ pmatop.1 pmcollectl.1 pmwtf.1 collectl2pcp.1 pmmgr.1 pmfind.1 \ \ pmdaapache.1 pmdabash.1 pmdacisco.1 \ pmdagfs2.1 pmdagluster.1 \ pmdakernel.1 \ pmdalogger.1 pmdamailq.1 pmdammv.1 pmdamounts.1 \ pmdasample.1 pmdasendmail.1 pmdashping.1 pmdasimple.1 \ pmdasummary.1 \ pmdatrace.1 pmdatrivial.1 pmdatxmon.1 pmdaweblog.1 \ LINUX_PMDA_PAGES = \ pmdalmsensors.1 pmdalustrecomm.1 pmdaproc.1 pmdaxfs.1 pmdajbd2.1 ROOMTEMP_PMDA_PAGES = pmdaroomtemp.1 SYSTEMD_PMDA_PAGES = pmdasystemd.1 RPM_PMDA_PAGES = pmdarpm.1 IB_PMDA_PAGES = pmdaib.1 WEBD_PAGES = pmwebd.1 ifeq "$(TARGET_OS)" "linux" MAN_PAGES += $(LINUX_PMDA_PAGES) else OTHER_PAGES += $(LINUX_PMDA_PAGES) endif ifneq "$(findstring $(TARGET_OS),solaris linux)" "" MAN_PAGES += $(ROOMTEMP_PMDA_PAGES) else OTHER_PAGES += $(ROOMTEMP_PMDA_PAGES) endif ifeq "$(HAVE_RPMLIB)" "1" MAN_PAGES += $(RPM_PMDA_PAGES) else OTHER_PAGES += $(RPM_PMDA_PAGES) endif ifneq "$(PMDA_SYSTEMD)" "" MAN_PAGES += $(SYSTEMD_PMDA_PAGES) else OTHER_PAGES += $(SYSTEMD_PMDA_PAGES) endif ifneq "$(PMDA_INFINIBAND)" "" MAN_PAGES += $(IB_PMDA_PAGES) else OTHER_PAGES += $(IB_PMDA_PAGES) endif ifeq "$(HAVE_LIBMICROHTTPD)" "1" MAN_PAGES += $(WEBD_PAGES) else OTHER_PAGES += $(WEBD_PAGES) endif MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) LSRCFILES = $(MAN_PAGES) $(OTHER_PAGES) default :: default_pcp default_pcp : $(MAN_PAGES) install :: install_pcp install_pcp : default_pcp @MAN_PAGES="$(MAN_PAGES)"; $(INSTALL_MAN) include $(BUILDRULES) pcp-3.8.12ubuntu1/man/man1/pmdagfs2.10000664000000000000000000000630712272262501014004 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAGFS2 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdagfs2\f1 \- Global Filesystem v2 (GFS2) PMDA .SH DESCRIPTION .B pmdagfs2 is a Performance Metrics Domain Agent (PMDA) which exports metric values about mounted GFS2 filesystems from the debugfs filesystem. This PMDA requires debugfs along with at least one mounted GFS2 filesystem to be mounted in order to be able to provide metric data. .PP This PMDA can be used with GFS2 filesystems which are both mounted as local filesystems and filesystems which are mounted as shared storage within a clustered environment. However there are some metrics which specifically require GFS2 to be setup in a clustered environment to be able to provide metric data. This is due to them expecting locking messages to be passed via the distributed lock manager (DLM) between nodes of a cluster in order to generate their output. .PP These cluster-environment-only metrics can be distinguished by the inclusion of their corresponding control metrics so that they can be optionally enabled or disabled on systems where they are not desired to be monitored or not supported. .PP .BR pmstore (3) can be used to assign values to these control metrics in order to enable (1) or disable (0) them. This mechanism is also useful on distributions that do not currently have full support for the GFS2 trace-points or provide older versions of the GFS2 driver. .PP Further details on clustering and GFS2 can be found at http://redhat.com .SH INSTALLATION Install the GFS2 PMDA by using the Install script as root: .PP # cd $PCP_PMDAS_DIR/gfs2 .br # ./Install .PP To uninstall, do the following as root: .PP # cd $PCP_PMDAS_DIR/gfs2 .br # ./Remove .PP .B pmdagfs2 is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .B pmcd when the agent is installed or removed. .SH FILES .IP "\fB$PCP_PMDAS_DIR/gfs2/help\fR" 4 default help text file for the GFS2 metrics .IP "\fB$PCP_PMDAS_DIR/gfs2/Install\fR" 4 installation script for the \fBpmdagfs2\fR agent .IP "\fB$PCP_PMDAS_DIR/gfs2/Remove\fR" 4 undo installation script for the \fBpmdagfs2\fR agent .IP "\fB$PCP_LOG_DIR/pmcd/gfs2.log\fR" 4 default log file for error messages from \fBpmdagfs2\fR .SH PCP ENVIRONMENT Environment variables with the prefix \fBPCP_\fR are used to parameterize the file and directory names used by \fBPCP\fR. On each installation, the file \fB/etc/pcp.conf\fR contains the local values for these variables. The \fB$PCP_CONF\fR variable may be used to specify an alternative configuration file, as described in \fIpcp.conf\fR(5). .SH SEE ALSO .BR pmcd (1), .BR pmstore (1), and .BR gfs2 (5). pcp-3.8.12ubuntu1/man/man1/pmcd_wait.10000664000000000000000000000571312272262501014250 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMCD_WAIT 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmcd_wait\f1 \- wait for PMCD to accept client connections .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS \f3$PCP_BINADM_DIR/pmcd_wait\f1 [\f3-h\f1 \f2host\f1] [\f3-t\f1 \f2interval\f1] [\f3\-v\f1] .SH DESCRIPTION .B pmcd_wait waits for the Performance Metrics Collector Daemon (PMCD) to be running and accepting client connections. .P Unless directed to another host by the .B \-h option, .B pmcd_wait will try to contact .BR pmcd (1) on the local host. .P .B pmcd_wait will timeout and abandon the attempt to connect to .B pmcd after 60 seconds. This default timeout interval may be changed using the .B \-t option, where the .I interval argument follows the syntax described in .BR PCPIntro (1) and in the simplest form may be an unsigned integer (the implied units in this case are seconds). .P On successful connection to .B pmcd an exit status of zero is returned. .PP If an error or timeout occurs, then a non-zero exit status is returned as described below. .PP The other options are as follows: .TP .B \-v This option turns the verbose mode on. With the verbose mode off (which is the default), no output will be generated. With verbose mode on, error messages will be output on .IR stderr . .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS Error messages will be output to .I stderr only if the verbose mode is on. .P The following exit status codes are returned: .TP .B 0 .B pmcd_wait was able to successfully connect to .B pmcd within the timeout period. .TP .B 1 A usage error occurred, use .B \-v for more details. .TP .B 2 No connection was made in the timeout interval. This will happen if .B pmcd is running but takes too long to complete the client connection, or if .B pmcd is not running and all connection attempts in the timeout interval failed with the error ECONNREFUSED. .TP .B 3 A U\s-2NIX\s+2 error occurred, use .B \-v for more details. .TP .B 4 A PCP error occurred, use .B \-v for more details. pcp-3.8.12ubuntu1/man/man1/pmdaproc.10000664000000000000000000001126212272262521014104 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMDAPROC 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaproc\f1 \- process performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/proc/pmdaproc\f1 [\f3\-AL\f1] [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-r\f1 \f2cgroup\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION .B pmdaproc is a Performance Metrics Domain Agent (PMDA) which extracts performance metrics describing the state of the individual processes running on a Linux system. .PP The .B proc PMDA exports metrics that measure the memory, processor and other resource use of each process, as well as summary information collated across all of the running processes. The PMDA uses credentials passed from the .BR PMAPI (3) monitoring tool identifying the user requesting the information, to ensure that only values the user is allowed to access are returned by the PMDA. This involves the PMDA temporarily changing its effective user and group identifiers for the duration of requests for instances and values. In other words, system calls to extract information are performed as the user originating the request and not as a privileged user. The mechanisms available for transfer of user credentials are described further in the .BR PCPIntro (1) page. .PP A brief description of the .B pmdaproc command line options follows: .TP 5 .B \-A Disables use of the credentials provided by .B PMAPI client tools, and simply runs everything under the "root" account. .TP .B \-L Changes the per-process instance domain used by most .B procproc metrics to include threads as well. .TP .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I proc.log is written in the current directory of .BR pmcd (1) when .B pmdaproc is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-r Restrict the set of processes exported in the per-process instance domain to only those processes that are contained by the specified .IR cgroup resource container. This option provides an optional finer granularity to the monitoring, and can also be used to reduce the resources consumed by .I pmdaproc during requests for instances and values. .TP .B \-U User account under which to run the agent. The default is the privileged "root" account, with seteuid (2) and setegid (2) switching for accessing most information. .SH INSTALLATION The .B proc PMDA is installed and available by default. If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/proc # ./Remove .in .fi .ft 1 .PP If you want to establish access to the names, help text and values for the proc performance metrics once more, after removal, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/proc # ./Install .in .fi .ft 1 .PP .B pmdaproc is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdaproc .TP 10 .B $PCP_PMDAS_DIR/proc/help default help text file for the proc metrics .TP 10 .B $PCP_PMDAS_DIR/proc/Install installation script for the .B pmdaproc agent .TP 10 .B $PCP_PMDAS_DIR/proc/Remove undo installation script for the .B pmdaproc agent .TP 10 .B $PCP_LOG_DIR/pmcd/proc.log default log file for error messages and other information from .B pmdaproc .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR seteuid (2), .BR setegid (2), .BR PMAPI (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmnsdel.10000664000000000000000000000605112272262501013737 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNSDEL 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmnsdel\f1 \- delete a subtree of names from the Performance Co-Pilot PMNS .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS .B $PCP_BINADM_DIR/pmnsdel [\f3\-d\f1] [\f3\-n\f1 \f2namespace\f1] .I metricpath [ ... ] .SH DESCRIPTION .B pmnsdel removes subtrees of names from a Performance Metrics Name Space (PMNS), as used by the components of the Performance Co-Pilot (PCP). .P Normally .B pmnsdel operates on the default Performance Metrics Namespace (PMNS), however if the .B \-n option is specified an alternative namespace is used from the file .IR namespace . .PP The default PMNS is found in the file .I $PCP_VAR_DIR/pmns/root unless the environment variable .B PMNS_DEFAULT is set, in which case the value is assumed to be the pathname to the file containing the default PMNS. .PP The metric names to be deleted are all those for which one of the .IR metricpath arguments is a prefix in the PMNS, see .BR pmns (5). .PP All of the files defining the PMNS must be located within the directory that contains the root of the PMNS, and this would typically be .B $PCP_VAR_DIR/pmns for the default PMNS, and this would typically imply running .B pmnsdel as root. .PP Provided some initial integrity checks are satisfied, .B pmnsdel will update the necessary PMNS files. Should an error be encountered the original namespace is restored. Note that any PMNS files that are no longer referenced by the modified namespace will not be removed, even though their contents are not part of the new namespace. .PP The .B \-d option allows the resultant PMNS to optionally contain duplicate PMIDs with different names in the PMNS. By default this condition is considered an error. .SH CAVEAT Once the writing of the new .I namespace file has begun, the signals SIGINT, SIGHUP and SIGTERM will be ignored to protect the integrity of the new files. .SH FILES .PD 0 .IP \f2$PCP_VAR_DIR/pmns/root\f1 2.5i the default PMNS, when then environment variable .B PMNS_DEFAULT is unset .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmnsadd (1), .BR pmnsmerge (1), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). pcp-3.8.12ubuntu1/man/man1/pmie.10000664000000000000000000006420612272262501013235 0ustar '\"! tbl | mmdoc '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmie\f1 \- inference engine for performance metrics .SH SYNOPSIS \f3pmie\f1 [\f3\-bCdefHVvWxz\f1] [\f3\-A\f1 \f2align\f1] [\f3\-a\f1 \f2archive\f1] [\f3\-c\f1 \f2filename\f1] [\f3\-h\f1 \f2host\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-j\f1 \f2stompfile\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-O\f1 \f2offset\f1] [\f3\-S\f1 \f2starttime\f1] [\f3\-T\f1 \f2endtime\f1] [\f3\-t\f1 \f2interval\f1] [\f3\-U\f1 \f2username\f1] [\f3\-Z\f1 \f2timezone\f1] [\f2filename ...\f1] .SH DESCRIPTION .B pmie accepts a collection of arithmetic, logical, and rule expressions to be evaluated at specified frequencies. The base data for the expressions consists of performance metrics values delivered in real-time from any host running the Performance Metrics Collection Daemon (PMCD), or using historical data from Performance Co-Pilot (PCP) archive logs. .P As well as computing arithmetic and logical values, .B pmie can execute actions (popup alarms, write system log messages, and launch programs) in response to specified conditions. Such actions are extremely useful in detecting, monitoring and correcting performance related problems. .P The expressions to be evaluated are read from configuration files specified by one or more .I filename arguments. In the absence of any .IR filename , expressions are read from standard input. .P A description of the command line options specific to .B pmie follows: .TP 5 .B \-a .I archive is the base name of a PCP archive log written by .BR pmlogger (1). Multiple instances of the .B \-a flag may appear on the command line to specify a set of archives. In this case, it is required that only one archive be present for any one host. Also, any explicit host names occurring in a .B pmie expression must match the host name recorded in one of the archive labels. In the case of multiple archives, timestamps recorded in the archives are used to ensure temporal consistency. .TP .B \-b Output will be line buffered and standard output is attached to standard error. This is most useful for background execution in conjunction with the .B \-l option. The .B \-b option is always used for .B pmie instances launched from .BR pmie_check (1). .TP .B \-C Parse the configuration file(s) and exit before performing any evaluations. Any errors in the configuration file are reported. .TP .B \-c An alternative to specifying .I filename at the end of the command line. .TP .B \-d Normally .B pmie would be launched as a non-interactive process to monitor and manage the performance of one or more hosts. Given the .B \-d flag however, execution is interactive and the user is presented with a menu of options. Interactive mode is useful mainly for debugging new expressions. .TP .B \-e When used with .BR \-V , .B \-v or .BR \-W , this option forces timestamps to be reported with each expression. The timestamps are in .BR ctime (3) format, enclosed in parenthesis and appear after the expression name and before the expression value, e.g. .nf expr_1 (Tue Feb 6 19:55:10 2001): 12 .fi .TP .B \-f If the .B \-l option is specified and there is no .B \-a option (ie. real-time monitoring) then .B pmie is run as a daemon in the background (in all other cases foreground is the default). The .B \-f option forces .B pmie to be run in the foreground, independent of any other options. .TP .B \-H The default hostname written to the stats file will not be looked up via .BR gethostbyname (3), rather it will be written as-is. This option can be useful when host name aliases are in use at a site, and the logical name is more important than the physical host name. .TP .B \-h By default performance data is fetched from the local host (in real-time mode) or the host for the first named archive on the command line (in archive mode). The \f2host\f1 argument overrides this default. It does not override hosts explicitly named in the expressions being evaluated. .TP .B \-l Standard error is sent to .IR logfile . .TP .B \-j An alternative STOMP protocol configuration is loaded from .IR stompfile . If this option is not used, and the .I stomp action is used in any rule, the default location .I $PCP_SYSCONF_DIR/pmie/config/stomp will be used. .TP .B \-n An alternative Performance Metrics Name Space (PMNS) is loaded from the file .IR pmnsfile . .TP .B \-t The .I interval argument follows the syntax described in .BR PCPIntro (1), and in the simplest form may be an unsigned integer (the implied units in this case are seconds). The value is used to determine the sample interval for expressions that do not explicitly set their sample interval using the .B pmie variable \f(CWdelta\f1 described below. The default is 10.0 seconds. .TP \f3\-U\f1 \f2username\f1 User account under which to run .BR pmie . The default is the current user account for interactive use. When run as a daemon, the unprivileged "pcp" account is used in current versions of PCP, but in older versions the superuser account ("root") was used by default. .TP .B \-v Unless one of the verbose options .BR \-V , .B \-v or .B \-W appears on the command line, expressions are evaluated silently, the only output is as a result of any actions being executed. In the verbose mode, specified using the .B \-v flag, the value of each expression is printed as it is evaluated. The values are in canonical units; bytes in the dimension of ``space'', seconds in the dimension of ``time'' and events in the dimension of ``count''. See .BR pmLookupDesc (3) for details of the supported dimension and scaling mechanisms for performance metrics. The verbose mode is useful in monitoring the value of given expressions, evaluating derived performance metrics, passing these values on to other tools for further processing and in debugging new expressions. .TP .B \-V This option has the same effect as the .B \-v option, except that the name of the host and instance (if applicable) are printed as well as expression values. .TP .B \-W This option has the same effect as the .B \-V option described above, except that for boolean expressions, only those names and values that make the expression true are printed. These are the same names and values accessible to rule actions as the %h, %i and %v bindings, as described below. .TP .B \-x Execute in domain agent mode. This mode is used within the Performance Co-Pilot product to derive values for summary metrics, see .BR pmdasummary (1). Only restricted functionality is available in this mode (expressions with actions may .B not be used). .TP .B \-Z Change the reporting timezone to .I timezone in the format of the environment variable .B TZ as described in .BR environ (5). .TP .B \-z Change the reporting timezone to the timezone of the host that is the source of the performance metrics, as identified via either the .B \-h option or the first named archive (as described above for the .B \-a option). .P The .BR \-S , .BR \-T , .BR \-O , and .B \-A options may be used to define a time window to restrict the samples retrieved, set an initial origin within the time window, or specify a ``natural'' alignment of the sample times; refer to .BR PCPIntro (1) for a complete description of these options. .P Output from .B pmie is directed to standard output and standard error as follows: .TP 5 .B stdout Expression values printed in the verbose .B \-v mode and the output of .B print actions. .TP .B stderr Error and warning messages for any syntactic or semantic problems during expression parsing, and any semantic or performance metrics availability problems during expression evaluation. .SH EXAMPLES The following example expressions demonstrate some of the capabilities of the inference engine. .P The directory .I $PCP_DEMOS_DIR/pmie contains a number of other annotated examples of .B pmie expressions. .P The variable .ft CW delta .ft 1 controls expression evaluation frequency. Specify that subsequent expressions be evaluated once a second, until further notice: .P .ft CW .nf .in +0.5i delta = 1 sec; .in .fi .ft 1 .P If total syscall rate exceeds 5000 per second per CPU, then display an alarm notifier: .P .ft CW .nf .in +0.5i kernel.all.syscall / hinv.ncpu > 5000 count/sec -> alarm "high syscall rate"; .in .fi .ft 1 .P If the high syscall rate is sustained for 10 consecutive samples, then launch .BR top (1) in an .BR xwsh (1G) window to monitor processes, but do this at most once every 5 minutes: .P .ft CW .nf .in +0.5i all_sample ( kernel.all.syscall @0..9 > 5000 count/sec * hinv.ncpu ) -> shell 5 min "xwsh \-e 'top'"; .in .fi .ft 1 .P The following rules are evaluated once every 20 seconds: .P .ft CW .nf .in +0.5i delta = 20 sec; .in .fi .ft 1 .P If any disk is performing more than 60 I/Os per second, then print a message identifying the busy disk to standard output and launch .BR dkvis (1): .P .ft CW .nf .in +0.5i some_inst ( disk.dev.total > 60 count/sec ) -> print "disk %i busy " & shell 5 min "dkvis"; .in .fi .ft 1 .P Refine the preceding rule to apply only between the hours of 9am and 5pm, and to require 3 of 4 consecutive samples to exceed the threshold before executing the action: .P .ft CW .nf .in +0.5i $hour >= 9 && $hour <= 17 && some_inst ( 75 %_sample ( disk.dev.total @0..3 > 60 count/sec ) ) -> print "disk %i busy "; .in .fi .ft 1 .P The following rules are evaluated once every 10 minutes: .P .ft CW .nf .in +0.5i delta = 10 min; .in .fi .ft 1 .P If either the / or the /usr filesystem is more than 95% full, display an alarm popup, but not if it has already been displayed during the last 4 hours: .P .ft CW .nf .in +0.5i filesys.free #'/dev/root' / filesys.capacity #'/dev/root' < 0.05 -> alarm 4 hour "root filesystem (almost) full"; filesys.free #'/dev/usr' / filesys.capacity #'/dev/usr' < 0.05 -> alarm 4 hour "/usr filesystem (almost) full"; .in .fi .ft 1 .P The following rule requires a machine that supports the PCP environment metrics. If the machine environment temperature rises more than 2 degrees over a 10 minute interval, write an entry in the system log: .P .ft CW .nf .in +0.5i environ.temp @0 - environ.temp @1 > 2 -> alarm "temperature rising fast" & syslog "machine room temperature rise alarm"; .in .fi .ft 1 .P And last, something interesting if you have performance problems with your Oracle database: .P .ft CW .nf .in +0.5i db = "oracle.ptg1"; host = ":moomba.melbourne.sgi.com"; lru = "#'cache buffers lru chain'"; gets = "$db.latch.gets $host $lru"; total = "$db.latch.gets $host $lru + $db.latch.misses $host $lru + $db.latch.immisses $host $lru"; $total > 100 && $gets / $total < 0.2 -> alarm "high lru latch contention"; .in .fi .ft 1 .SH QUICK START The .B pmie specification language is powerful and large. .P To expedite rapid development of .B pmie rules, the .BR pmieconf (1) tool provides a facility for generating a .B pmie configuration file from a set of generalized .B pmie rules. The supplied set of rules covers a wide range of performance scenarios. .P The .I "Performance Co-Pilot User's and Administrator's Guide" provides a detailed tutorial-style chapter covering .BR pmie . .SH EXPRESSION SYNTAX This description is terse and informal. For a more comprehensive description see the .IR "Performance Co-Pilot User's and Administrator's Guide" . .P A .B pmie specification is a sequence of semicolon terminated expressions. .P Basic operators are modeled on the arithmetic, relational and Boolean operators of the C programming language. Precedence rules are as expected, although the use of parentheses is encouraged to enhance readability and remove ambiguity. .P Operands are performance metric names (see .BR pmns (5)) and the normal literal constants. .P Operands involving performance metrics may produce sets of values, as a result of enumeration in the dimensions of .BR hosts , .B instances and .BR time . Special qualifiers may appear after a performance metric name to define the enumeration in each dimension. For example, .P .in +4n .ft CW kernel.percpu.cpu.user :foo :bar #cpu0 @0..2 .ft R .in .P defines 6 values corresponding to the time spent executing in user mode on CPU 0 on the hosts ``foo'' and ``bar'' over the last 3 consecutive samples. The default interpretation in the absence of .B : (host), .B # (instance) and .B @ (time) qualifiers is all instances at the most recent sample time for the default source of PCP performance metrics. .P Host and instance names that do not follow the rules for variables in programming languages, ie. alphabetic optionally followed by alphanumerics, should be enclosed in single quotes. .P Expression evaluation follows the law of ``least surprises''. Where performance metrics have the semantics of a counter, .B pmie will automatically convert to a rate based upon consecutive samples and the time interval between these samples. All expressions are evaluated in double precision, and where appropriate, automatically scaled into canonical units of ``bytes'', ``seconds'' and ``counts''. .P A .B rule is a special form of expression that specifies a condition or logical expression, a special operator (\c .BR \-> ) and actions to be performed when the condition is found to be true. .P The following table summarizes the basic .B pmie operators: .P .ne 12v .TS box,center; c | c lf(CW) | l. Operators Explanation _ + \- * / Arithmetic < <= == >= > != Relational (value comparison) ! && || Boolean -> Rule \f(CBrising\fR Boolean, false to true transition \f(CBfalling\fR Boolean, true to false transition \f(CBrate\fR Explicit rate conversion (rarely required) .TE .P Aggregate operators may be used to aggregate or summarize along one dimension of a set-valued expression. The following aggregate operators map from a logical expression to a logical expression of lower dimension. .P .ne 16v .TS box,center; cw(2.4i) | c | cw(2.4i) lf(CB) | l | l. Operators Type Explanation _ T{ .ad l some_inst .br some_host .br some_sample T} Existential T{ .ad l True if at least one set member is true in the associated dimension T} _ T{ .ad l all_inst .br all_host .br all_sample T} Universal T{ .ad l True if all set members are true in the associated dimension T} _ T{ .ad l \f(CON\f(CB%_inst .br \f(CON\f(CB%_host .br \f(CON\f(CB%_sample\fR T} Percentile T{ .ad l True if at least \fIN\fP percent of set members are true in the associated dimension T} .TE .P The following instantial operators may be used to filter or limit a set-valued logical expression, based on regular expression matching of instance names. The logical expression must be a set involving the dimension of instances, and the regular expression is of the form used by .BR egrep (1) or the Extended Regular Expressions of .BR regcomp (3G). .P .ne 12v .TS box,center; c | cw(4i) lf(CB) | l. Operators Explanation _ match_inst T{ .ad l For each value of the logical expression that is ``true'', the result is ``true'' if the associated instance name matches the regular expression. Otherwise the result is ``false''. T} _ nomatch_inst T{ .ad l For each value of the logical expression that is ``true'', the result is ``true'' if the associated instance name does \fBnot\fP match the regular expression. Otherwise the result is ``false''. T} .TE .P For example, the expression below will be ``true'' for disks attached to controllers 2 or 3 performing more than 20 operations per second: .ft CW .nf .in +0.5i match_inst "^dks[23]d" disk.dev.total > 20; .in .fi .ft 1 .P The following aggregate operators map from an arithmetic expression to an arithmetic expression of lower dimension. .P .ne 20v .TS box,center; cw(2.4i) | c | cw(2.4i) lf(CB) | l | l. Operators Type Explanation _ T{ .ad l min_inst .br min_host .br min_sample T} Extrema T{ .ad l Minimum value across all set members in the associated dimension T} _ T{ .ad l max_inst .br max_host .br max_sample T} Extrema T{ .ad l Maximum value across all set members in the associated dimension T} _ T{ .ad l sum_inst .br sum_host .br sum_sample T} Aggregate T{ .ad l Sum of values across all set members in the associated dimension T} _ T{ .ad l avg_inst .br avg_host .br avg_sample T} Aggregate T{ .ad l Average value across all set members in the associated dimension T} .TE .P The aggregate operators \f(CWcount_inst\fR, \f(CWcount_host\fR and \f(CWcount_sample\fR map from a logical expression to an arithmetic expression of lower dimension by counting the number of set members for which the expression is true in the associated dimension. .P For action rules, the following actions are defined: .TS box,center; c | c lf(CB) | l. Operators Explanation _ alarm Raise a visible alarm with \fBxconfirm\f1(1) print Display on standard output shell Execute with \fBsh\fR(1) stomp Send a STOMP message to a JMS server syslog Append a message to system log file .TE .P Multiple actions may be separated by the \f(CW&\fR and \f(CW|\fR operators to specify respectively sequential execution (both actions are executed) and alternate execution (the second action will only be executed if the execution of the first action returns a non-zero error status. .P Arguments to actions are an optional suppression time, and then one or more expressions (a string is an expression in this context). Strings appearing as arguments to an action may include the following special selectors that will be replaced at the time the action is executed. .TP 4n \f(CB%h\fR Host(s) that make the left-most top-level expression in the condition true. .TP \f(CB%i\fR Instance(s) that make the left-most top-level expression in the condition true. .TP \f(CB%v\fR One value from the left-most top-level expression in the condition for each host and instance pair that makes the condition true. .P Note that expansion of the special selectors is done by repeating the whole argument once for each unique binding to any of the qualifying special selectors. For example if a rule were true for the host .B mumble with instances .B grunt and .BR snort , and for host .B fumble the instance .B puff makes the rule true, then the action .ft CW .nf .in +0.5i \&... -> shell myscript "Warning: %h:%i busy "; .in .fi .ft 1 will execute .B myscript with the argument string "Warning: mumble:grunt busy Warning: mumble:snort busy Warning: fumble:puff busy". .P By comparison, if the action .ft CW .nf .in +0.5i \&... -> shell myscript "Warning! busy:" " %h:%i"; .in .fi .ft 1 were executed under the same circumstances, then .B myscript would be executed with the argument string "Warning! busy: mumble:grunt mumble:snort fumble:puff". .P The semantics of the expansion of the special selectors leads to a common usage pattern in an action, where one argument is a constant (contains no special selectors) the second argument contains the desired special selectors with minimal separator characters, and an optional third argument provides a constant postscript (e.g. to terminate any argument quoting from the first argument). If necessary post-processing (eg. in .BR myscript ) can provide the necessary enumeration over each unique expansion of the string containing just the special selectors. .P For complex conditions, the bindings to these selectors is not obvious. It is strongly recommended that .B pmie be used in the debugging mode (specify the .B \-W command line option in particular) during rule development. .SH SCALE FACTORS Scale factors may be appended to arithmetic expressions and force linear scaling of the value to canonical units. Simple scale factors are constructed from the keywords: \f(CBnanosecond\fR, \f(CBnanosec\fR, \f(CBnsec\f1, \f(CBmicrosecond\fR, \f(CBmicrosec\fR, \f(CBusec\f1, \f(CBmillisecond\fR, \f(CBmillisec\fR, \f(CBmsec\f1, \f(CBsecond\fR, \f(CBsec\fR, \f(CBminute\fR, \f(CBmin\fR, \f(CBhour\f1, \f(CBbyte\fR, \f(CBKbyte\fR, \f(CBMbyte\fR, \f(CBGbyte\fR, \f(CBTbyte\f1, \f(CBcount\fR, \f(CBKcount\fR and \f(CBMcount\fR, and the operator \f(CW/\fR, for example ``\f(CBKbytes / hour\f1''. .SH MACROS Macros are defined using expressions of the form: .P .in +0.5i \fIname\fR = \fIconstexpr\f1; .in .P Where .I name follows the normal rules for variables in programming languages, ie. alphabetic optionally followed by alphanumerics. .I constexpr must be a constant expression, either a string (enclosed in double quotes) or an arithmetic expression optionally followed by a scale factor. .P Macros are expanded when their name, prefixed by a dollar (\f(CW$\fR) appears in an expression, and macros may be nested within a .I constexpr string. .P The following reserved macro names are understood. .TP 10n \f(CBminute\f1 Current minute of the hour. .TP \f(CBhour\f1 Current hour of the day, in the range 0 to 23. .TP \f(CBday\f1 Current day of the month, in the range 1 to 31. .TP \f(CBmonth\f1 Current month of the year, in the range 0 (January) to 11 (December). .TP \f(CByear\f1 Current year. .TP \f(CBday_of_week\f1 Current day of the week, in the range 0 (Sunday) to 6 (Saturday). .TP \f(CBdelta\f1 Sample interval in effect for this expression. .P Dates and times are presented in the reporting time zone (see description of .B \-Z and .B \-z command line options above). .SH AUTOMATIC RESTART It is often useful for .B pmie processes to be started and stopped when the local host is booted or shutdown, or when they have been detected as no longer running (when they have unexpectedly exited for some reason). Refer to .BR pmie_check (1) for details on automating this process. .SH EVENT MONITORING It is common for production systems to be monitored in a central location. Traditionally on UNIX systems this has been performed by the system log facilities \- see .BR logger (1), and .BR syslogd (1). On Windows, communication with the system event log is handled by .BR pcp-eventlog (1). .P .B pmie fits into this model when rules use the .I syslog action. Note that if the action string begins with \-p (priority) and/or \-t (tag) then these are extracted from the string and treated in the same way as in .BR logger (1) and .BR pcp-eventlog (1). .P However, it is common to have other event monitoring frameworks also, into which you may wish to incorporate performance events from .BR pmie . You can often use the .I shell action to send events to these frameworks, as they usually provide their a program for injecting events into the framework from external sources. .P A final option is use of the .I stomp (Streaming Text Oriented Messaging Protocol) action, which allows .B pmie to connect to a central JMS (Java Messaging System) server and send events to the PMIE topic. Tools can be written to extract these text messages and present them to operations people (via desktop popup windows, etc). Use of the .I stomp action requires a stomp configuration file to be setup, which specifies the location of the JMS server host, port number, and username/password. .P The format of this file is as follows: .P .ft CW .nf .in +0.5i host=messages.sgi.com # this is the JMS server (required) port=61616 # and its listening here (required) timeout=2 # seconds to wait for server (optional) username=joe # (required) password=j03ST0MP # (required) topic=PMIE # JMS topic for pmie messages (optional) .in .fi .ft 1 .P The timeout value specifies the time (in seconds) that .B pmie should wait for acknowledgements from the JMS server after sending a message (as required by the STOMP protocol). Note that on startup, .B pmie will wait indefinitely for a connection, and will not begin rule evaluation until that initial connection has been established. Should the connection to the JMS server be lost at any time while .B pmie is running, .B pmie will attempt to reconnect on each subsequent truthful evaluation of a rule with a .I stomp action, but not more than once per minute. This is to avoid contributing to network congestion. In this situation, where the STOMP connection to the JMS server has been severed, the .I stomp action will return a non-zero error value. .SH FILES .PD 0 .TP 10 .BI $PCP_DEMOS_DIR/pmie/ * annotated example rules .TP .BI $PCP_VAR_DIR/pmns/ * default PMNS specification files .TP .BI $PCP_TMP_DIR/pmie .B pmie maintains files in this directory to identify the running .B pmie instances and to export runtime information about each instance \- this data forms the basis of the pmcd.pmie performance metrics .TP .BI $PCP_PMIECONTROL_PATH the default set of .B pmie instances to start at boot time \- refer to .BR pmie_check (1) for details .TP .BI $PCP_SYSCONF_DIR/pmie/ * the predefined alarm action scripts (\c .BR email , .BR log , .B popup and .BR syslog ), the example action script (\c .BR sample ) and the concurrent action control file (\c .BR control.master ). .PD .SH BUGS The lexical scanner and parser will attempt to recover after an error in the input expressions. Parsing resumes after skipping input up to the next semi-colon (;), however during this skipping process the scanner is ignorant of comments and strings, so an embedded semi-colon may cause parsing to resume at an unexpected place. This behavior is largely benign, as until the initial syntax error is corrected, .B pmie will not attempt any expression evaluation. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH UNIX SEE ALSO .BR logger (1). .SH WINDOWS SEE ALSO .BR pcp-eventlog (1). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmdumplog (1), .BR pmieconf (1), .BR pmie_check (1), .BR pminfo (1), .BR pmlogger (1), .BR pmval (1), .BR PMAPI (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH USER GUIDE For a more complete description of the .B pmie language, refer to the .BR "Performance Co-Pilot Users and Administrators Guide" . This is available online from: .in +4n .nf http://techpubs.sgi.com/library/tpl/cgi-bin/getdoc.cgi?\e db=bks&fname=/SGI_Admin/books/PCP_IRIX/sgi_html/ch05.html .fi .in -4n pcp-3.8.12ubuntu1/man/man1/pmval.10000664000000000000000000002331012272262501013411 0ustar '\"! tbl | mmdoc '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMVAL 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmval\f1 \- performance metrics value dumper .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS \f3pmval\f1 [\f3\-dgrz\f1] [\f3\-A\f1 \f2align\f1] [\f3\-a\f1 \f2archive\f1] [\f3\-f\f1 \f2N\f1] [\f3\-h\f1 \f2host\f1] [\f3\-i\f1 \f2instances\f1] [\f3\-K\f1 \f2spec\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-O\f1 \f2offset\f1] [\f3\-p\f1 \f2port\f1] [\f3\-S\f1 \f2starttime\f1] [\f3\-s\f1 \f2samples\f1] [\f3\-T\f1 \f2endtime\f1] [\f3\-t\f1 \f2interval\f1] [\f3\-U\f1 \f2archive\f1] [\f3\-w\f1 \f2width\f1] [\f3\-Z\f1 \f2timezone\f1] \f2metricname\f1 .SH DESCRIPTION .de EX .in +0.5i .ie t .ft CB .el .ft B .ie t .sp .5v .el .sp .ta \\w' 'u*8 .nf .. .de EE .fi .ie t .sp .5v .el .sp .ft R .in .. .B pmval prints current or archived values for the nominated performance metric. The metric of interest is named in the .I metricname argument, subject to instance qualification with the .B \-i flag as described below. .PP Unless directed to another host by the .B \-h option, or to an archive by the .B \-a or .B \-U options, .B pmval will contact the Performance Metrics Collector Daemon (PMCD) on the local host to obtain the required information. .PP The .I metricname argument may also be given in the metric specification syntax, as described in .BR PCPIntro (1), where the source, metric and instance may all be included in the .IR metricname , e.g. thathost:kernel.all.load["1 minute"]. When this format is used, none of the .B \-h or .B \-a or .B \-U options may be specified. .PP When using the metric specification syntax, the ``hostname'' .B @ is treated specially and causes .B pmval to use a local context to collect metrics from PMDAs on the local host without PMCD. Only some metrics are available in this mode. .PP When processing an archive, .B pmval may relinquish its own timing control, and operate as a ``slave'' of a .BR pmtime (1) process that uses a GUI dialog to provide timing control. In this case, either the .B \-g option should be used to start .B pmval as the sole slave of a new .BR pmtime (1) instance, or .B \-p should be used to attach .B pmval to an existing .BR pmtime (1) instance via the IPC channel identified by the .I port argument. .PP The .BR \-S , .BR \-T , .BR \-O and .B \-A options may be used to define a time window to restrict the samples retrieved, set an initial origin within the time window, or specify a ``natural'' alignment of the sample times; refer to .BR PCPIntro (1) for a complete description of these options. .PP The other options which control the source, timing and layout of the information reported by .B pmval are as follows: .TP 5 .B \-a Performance metric values are retrieved from the Performance Co-Pilot (PCP) archive log file identified by the base name .IR archive . .TP .B \-d When replaying from an archive, this option requests that the prevailing real-time delay be applied between samples (see .BR \-t ) to effect a pause, rather than the default behaviour of replaying at full speed. .TP .B \-f Numbers are reported in ``fixed point'' notation, rather than the default scientific notation. Each number will be up to the column width determined by the default heuristics, else the .B \-w option if specified, and include .I N digits after the decimal point. So, the options .B "\-f 3 \-w 8" would produce numbers of the form 9999.999. A value of zero for .I N omits the decimal point and any fractional digits. .TP .B \-g Start .B pmval as the slave of a new .BR pmtime (1) process for replay of archived performance data using the .BR pmtime (1) graphical user interface. .TP .B \-h Current performance metric values are retrieved from the nominated .I host machine. .TP .B \-i .I instances is a list of one or more instance names for the nominated performance metric \- just these instances will be retrieved and reported (the default is to report all instances). The list must be a single argument, with elements of the list separated by commas and/or white space. .RS .PP The instance name may be quoted with single (') or double (") quotes for those cases where the instance name contains white space or commas. .PP Multiple .B \-i options are allowed as an alternative way of specifying more than one instance of interest. .PP As an example, the following are all equivalent: .EX $ pmval \-i "'1 minute','5 minute'" kernel.all.load $ pmval \-i '"1 minute","5 minute"' kernel.all.load $ pmval \-i "'1 minute' '5 minute'" kernel.all.load $ pmval \-i "'1 minute'" \-i "'5 minute'" kernel.all.load $ pmval 'localhost:kernel.all.load["1 minute","5 minute"]' .EE .RE .TP .B \-K When fetching metrics from a local context, the .B \-K option may be used to control the DSO PMDAs that should be made accessible. The .I spec argument conforms to the syntax described in .BR __pmSpecLocalPMDA (3). More than one .B \-K option may be used. .TP .B \-n Normally .B pmval operates on the default Performance Metrics Name Space (PMNS), however if the .B \-n option is specified an alternative namespace is loaded from the file .IR pmnsfile. .TP .B \-p Attach .B pmval to an existing .BR pmtime (1) time control process instance via the IPC channel identified by the \f2port\f1 argument. This option is normally only used by other tools, e.g. .BR pmchart (1), when they launch .B pmval with synchronized time control. .TP .B \-r Print raw values for cumulative counter metrics. Normally cumulative counter metrics are converted to rates. For example, disk transfers are reported as number of disk transfers per second during the preceding sample interval, rather than the raw value of number of disk transfers since the machine was booted. If you specify this option, the raw metric values are printed. .TP .B \-s The argument .I samples defines the number of samples to be retrieved and reported. If .I samples is 0 or .B \-s is not specified, .B pmval will sample and report continuously (in real time mode) or until the end of the PCP archive (in archive mode). .TP .B \-t The default update \f2interval\f1 may be set to something other than the default 1 second. The .I interval argument follows the syntax described in .BR PCPIntro (1), and in the simplest form may be an unsigned integer (the implied units in this case are seconds). .TP .B \-U Performance metric values are retrieved from the Performance Co-Pilot (PCP) archive log file identified by the base name .IR archive , although unlike .B \-a every recorded value in the archive for the selected metric and instances is reported (so no interpolation mode, and the sample interval (\c .B \-t option) is ignored. .RS +5n .PP At most one of the options .B \-a and .B \-U may be specified. .RE .TP .B \-w Set the width of each column of output to be .I width columns. If not specified columns are wide enough to accommodate the largest value of the type being printed. .TP .B \-Z By default, .B pmval reports the time of day according to the local timezone on the system where .B pmval is run. The .B \-Z option changes the timezone to .I timezone in the format of the environment variable .B TZ as described in .BR environ (5). .TP .B \-z Change the reporting timezone to the local timezone at the host that is the source of the performance metrics, as identified via either the .I metricname or the .B \-h or .B \-a or .B \-U options. .PP The following symbols may occasionally appear, in place of a metric value, in .B pmval output: A question mark symbol (?) indicates that a value is no longer available for that metric instance. An exclamation mark (!) indicates that a 64-bit counter wrapped during the sample. .PP The output from .B pmval is directed to standard output. .SH FILES .PD 0 .TP 10 .BI $PCP_VAR_DIR/pmns/ * default PMNS specification files .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmchart (1), .BR pmdumplog (1), .BR pminfo (1), .BR pmlogger (1), .BR pmtime (1), .BR PMAPI (3), .BR __pmSpecLocalPMDA (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS All are generated on standard error and are intended to be self-explanatory. .SH CAVEATS By default, .B pmval attempts to display non-integer numeric values in a way that does not distort the inherent precision (rarely more than 4 significant digits), and tries to maintain a tabular format in the output. These goals are sometimes in conflict. .PP In the absence of the .B \-f option (described above), the following table describes the formats used for different ranges of numeric values for any metric that is of type .B PM_TYPE_FLOAT or .BR PM_TYPE_DOUBLE , or any metric that has the semantics of a counter (for which .B pmval reports the rate converted value): .TS box,center; cf(R) | cf(R) rf(CW) | lf(R). Format Value Range _ ! No values available 9.999E-99 < 0.1 0.0\0\0\0 0 9.9999 > 0 and <= 0.9999 9.999\0 > 0.9999 and < 9.999 99.99\0\0 > 9.999 and < 99.99 999.9\0\0\0 > 99.99 and < 999.9 9999.\0\0\0\0 > 999.9 and < 9999 9.999E+99 > 9999 .TE pcp-3.8.12ubuntu1/man/man1/pmlogger.10000664000000000000000000004317612272262521014124 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOGGER 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmlogger\f1 \- create archive log for performance metrics .SH SYNOPSIS \f3pmlogger\f1 [\f3\-c\f1 \f2configfile\f1] [\f3\-h\f1 \f2host\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-L\f1] [\f3\-m\f1 \f2note\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-P\f1] [\f3\-r\f1] [\f3\-s\f1 \f2endsize\f1] [\f3\-t\f1 \f2interval\f1] [\f3\-T\f1 \f2endtime\f1] [\f3\-u\f1] [\f3\-U\f1 \f2username\f1] [\f3\-v\f1 \f2volsize\f1] [\f3\-V\f1 \f2version\f1] [\f3\-x\f1 \f2fd\f1] \f2archive\f1 .SH DESCRIPTION .B pmlogger creates the archive logs of performance metric values that may be ``played back'' by other Performance Co-Pilot (see .BR PCPIntro (1)) tools. These logs form the basis of the VCR paradigm and retrospective performance analysis services common to the PCP toolkit. .PP The mandatory argument .I archive is the base name for the physical files that constitute an archive log. .PP The .B \-V option specifies the version for the archive that is generated. By default a version 2 archive is generated, and the only value currently supported for .I version is 2. .PP Unless directed to another host by the .B \-h option, .B pmlogger will contact the Performance Metrics Collector Daemon (PMCD) on the local host and use that as the source of the metric values to be logged. .PP To support the required flexibility and control over what is logged and when, .B pmlogger maintains an independent two level logging state for each instance of each performance metric. At the first (mandatory) level, logging is allowed to be .B on (with an associated interval between samples), or .B off or .BR maybe . In the latter case, the second (advisory) level logging is allowed to be .B on (with an associated interval between samples), or .BR off . .PP The mandatory level allows universal specification that some metrics must be logged, or must .B not be logged. The default state for all instances of all metrics when .B pmlogger starts is mandatory maybe and advisory off. .PP Use .BR pmlc (1) to interrogate and change the logging state once .B pmlogger is running. .PP If a metric's state is mandatory (on or off) and a request is made to change it to mandatory maybe, the new state is mandatory maybe and advisory off. If a metric's state is already advisory (on or off) and a request is made to change it to mandatory maybe, the current state is retained. .PP It is not possible for .B pmlogger to log specific instances of a metric and all instances of the same metric concurrently. If specific instances are being logged and a request to log all instances is made, then all instances of the metric will be logged according to the new request, superseding any prior logging request for the metric. A request to log all instances of a metric will supersede any previous request to log all instances. A request to log specific instances of a metric when all instances are already being logged is refused. To do this one must turn off logging for all instances of the metric first. In each case, the validity of the request is checked first; for example a request to change a metric's logging state to advisory on when it is currently mandatory off is never permitted (it is necessary to change the state to mandatory maybe first). .PP Optionally, each system running .BR pmcd (1) may also be configured to run a ``primary'' .B pmlogger instance. Like .BR pmcd (1), this .B pmlogger instance is launched by .BR $PCP_RC_DIR/pcp , and is affected by the files .I $PCP_SYSCONF_DIR/pmlogger (use .BR chkconfig (1M) to activate or disable the primary .B pmlogger instance), .I $PCP_SYSCONF_DIR/pmlogger/pmlogger.options (command line options passed to the primary .BR pmlogger ) and .I $PCP_SYSCONF_DIR/pmlogger/config.default (the default initial configuration file for the primary .BR pmlogger ). .PP The primary .B pmlogger instance is identified by the .B \-P option. There may be at most one ``primary'' .B pmlogger instance on each system with an active .BR pmcd (1). The primary .B pmlogger instance (if any) must be running on the same host as the .BR pmcd (1) to which it connects, so the .B \-h and .B \-P options are mutually exclusive. .PP When launched as a non-primary instance, .B pmlogger will exit immediately if the configuration file causes no metric logging to be scheduled. The .B \-L option overrides this behavior, and causes a non-primary .B pmlogger instance to ``linger'', presumably pending some future dynamic re-configuration and state change via .BR pmlc (1). .B pmlogger will also linger without the .B \-L option being used if all the metrics to be logged are logged as once only metrics. When the once only metrics have been logged, a warning message will be generated stating that the event queue is empty and no more events will be scheduled. .PP By default all diagnostics and errors from .B pmlogger are written to the file .I pmlogger.log in the directory where .B pmlogger is launched. The .B \-l option may be used to override the default behavior. If the log file cannot be created or is not writable, output is written to standard error instead. .PP If specified, the .B \-s option instructs .B pmlogger to terminate after a certain size in records, bytes or time units has been accumulated. If .IR endsize is an integer then .IR endsize records will be written to the log. If .IR endsize is an integer suffixed by .B b or .B bytes then .IR endsize bytes of the archive data will be written out (note, however, that archive log record boundaries will not be broken and so this limit may be slightly surpassed). Other viable file size units include: .BR K , .BR Kb , .BR Kbyte , .BR Kilobyte for kilobytes and .BR M , .BR Mb , .BR Mbyte , .BR Megabyte for megabytes and .BR G , .BR Gb , .BR Gbyte , .BR Gigabyte for gigabytes. These units may be optionally suffixed by an .B s and may be of mixed case. Alternatively .IR endsize may be an integer or a floating point number suffixed using a time unit as described in .BR PCPIntro (1) for the .I interval argument (to the standard PCP .BR \-t command line option). .nf Some examples of different formats: .in 1i .B \-s 100 .B \-s 100bytes .B \-s 100K .B \-s 100Mb .B \-s 10Gbyte .B \-s 10mins .B \-s 1.5hours .in .fi The default is for .B pmlogger to run forever. .PP The .B \-r option causes the size of the physical record(s) for each group of metrics and the expected contribution of the group to the size of the PCP archive for one full day of collection to be reported in the log file. This information is reported the first time each group is successfully written to the archive. .PP The .B \-U option specifies the user account under which to run .BR pmlogger . The default is the current user account for interactive use. When run as a daemon, the unprivileged "pcp" account is used in current versions of PCP, but in older versions the superuser account ("root") was used by default. .PP The log file is potentially a multi-volume data set, and the .B \-v option causes .B pmlogger to start a new volume after a certain size in records, bytes, or time units has been accumulated for the current volume. The format of this size specification is identical to that of the .B \-s option (see above). The default is for .B pmlogger to create a single volume log. Additional volume switches can also be forced asynchronously by either using .BR pmlc (1) or sending .B pmlogger a SIGHUP signal (see below). Note, if a scheduled volume switch is in operation due to the .B \-v option, then its counters will be reset after an asynchronous switch. .PP Independent of any .B \-v option, each volume of an archive is limited to no more than 2^31 bytes, so .I pmlogger will automatically create a new volume for the archive before this limit is reached. .PP Normally .B pmlogger operates on the distributed Performance Metrics Name Space (PMNS), however if the .B \-n option is specified an alternative local PMNS is loaded from the file .IR pmnsfile. .PP Under normal circumstances, .B pmlogger will run forever (except for a .B \-s option or a termination signal). The .B \-T option may be used to limit the execution time using the format of time as prescribed by .BR PCPIntro (1). .nf Some examples of different formats: .in 1i .B \-T 10mins .B \-T '@ 11:30' .in .fi From this it can be seen that .B \-T 10mins and .B \-s 10mins perform identical actions. .PP When .B pmlogger receives a SIGHUP signal, the current volume of the log is closed, and a new volume is opened. This mechanism (or the alternative mechanism via .BR pmlc (1)) may be used to manage the growth of the log files \- once a log volume is closed, that file may be archived without ill-effect on the continued operation of .BR pmlogger . See also the .B \-v option above. .PP The buffers for the current log may be flushed to disk using the \f3flush\f1 command of .BR pmlc (1), or by sending .B pmlogger a SIGUSR1 signal or by using the .B \-u option (the latter forces every log write to be unbuffered). This is useful when the log needs to be read while .B pmlogger is still running. .P When launched with the .B \-x option, pmlogger will accept asynchronous control requests on the file descriptor \f2fd\f1. This option is only expected to be used internally by PCP applications that support ``live record mode''. .P The .B \-m option allows the string .I note to be appended to the map file for this instance of .B pmlogger in the .B $PCP_TMP_DIR/pmlogger directory. This is currently used internally to document the file descriptor (\c .IR fd ) when the .B \-x option is used, or to indicate that this .B pmlogger instance was started under the control of .BR pmlogger_check (1). .SH CONFIGURATION FILE SYNTAX The configuration file may be specified with the .B \-c option. If it is not, configuration specifications are read from standard input. .PP If .I configfile does not exist, then a search is made in the directory .I $PCP_SYSCONF_DIR/pmlogger for a file of the same name, and if found that file is used, e.g. if .I config.mumble does not exist in the current directory and the file .I $PCP_SYSCONF_DIR/pmlogger/config.mumble does exist, then .B "\-c config.mumble" and .B "\-c $PCP_SYSCONF_DIR/pmlogger/config.mumble" are equivalent. .PP The syntax for the configuration file is as follows. .IP 1. Words are separated by white space (space, tab or newline). .IP 2. The symbol ``#'' (hash) introduces a comment, and all text up to the next newline is ignored. .IP 3. Keywords (shown in .B bold below) must appear literally (i.e. in lower case). .IP 4. Each specification begins with the optional keyword .BR log , followed by one of the states .BR "mandatory on" , .BR "mandatory off" , .BR "mandatory maybe" , .BR "advisory on" or .BR "advisory off" . .IP 5. For the .B on states, a logging interval must follow using the syntax ``\c .BR once '', or ``\c .BR default '', or ``\c .B every .IR "N timeunits" '', or simply ``\c .IR "N timeunits" '' \- .I N is an unsigned integer, and .I timeunits is one of the keywords .BR msec , .BR millisecond , .BR sec , .BR second , .BR min , .BR minute , .BR hour or the plural form of one of the above. .sp 0.5v Internal limitations require the interval to be smaller than (approximately) 74 hours. An interval value of zero is a synonym for .BR once . An interval of .B default means to use the default logging interval of 60 seconds; this default value may be changed to .I interval with the .B \-t command line option. .IP "" The .I interval argument follows the syntax described in .BR PCPIntro (1), and in the simplest form may be an unsigned integer (the implied units in this case are seconds). .IP 6. Following the state and possible interval specifications comes a ``{'', followed by a list of one or more metric specifications and a closing ``}''. The list is white space (or comma) separated. If there is only one metric specification in the list, the braces are optional. .IP 7. A metric specification consists of a metric name optionally followed by a set of instance names. The metric name follows the standard PCP naming conventions, see .BR pmns (5), and if the metric name is a non-leaf node in the PMNS (see \c .BR pmns (5)), then .B pmlogger will recursively descend the PMNS and apply the logging specification to all descendent metric names that are leaf nodes in the PMNS. The set of instance names is a ``['', followed by a list of one or more space (or comma) separated names, numbers or strings, and a closing ``]''. Elements in the list that are numbers are assumed to be internal instance identifiers, other elements are assumed to be external instance identifiers \- see .BR pmGetInDom (3) for more information. .RS .PP If no instances are given, then the logging specification is applied to all instances of the associated metric. .RE .IP 8. There may be an arbitrary number of logging specifications. .IP 9. Following all of the logging specifications, there may be an optional access control section, introduced by the literal token .BR [access] . Thereafter come access control rules of the form ``\c .B allow .I hostlist .B : .I operation .BR ; '' and ``\c .B disallow .I hostlist .B : .I operation .BR ; ''. The base .I operations are .BR advisory , .BR mandatory and .BR enquire . In all other aspects, these access control statements follow the syntactic and semantic rules defined for the access control mechanisms used by PMCD and are fully documented in .BR pmcd (1). .SH EXAMPLES For each PCP utility, there is a sample .B pmlogger configuration file that could be used to create an archive log suitable for replaying with that tool (i.e. includes all of the performance metrics used by the tool). For a tool named .I foo this configuration file is located in .IR $PCP_SYSCONF_DIR/pmlogger/config.foo . .PP The following is a simple default configuration file for a primary .B pmlogger instance, and demonstrates most of the capabilities of the configuration specification language. .PP .in +0.5i .nf .ft CW log mandatory on once { hinv.ncpu hinv.ndisk } log mandatory on every 10 minutes { disk.all.write disk.all.read network.interface.in.packets [ "et0" ] network.interface.out.packets [ "et0" ] nfs.server.reqs [ "lookup" "getattr" "read" "write" ] } log advisory on every 30 minutes { environ.temp pmcd.pdu_in.total pmcd.pdu_out.total } [access] disallow * : all except enquire; allow localhost : mandatory, advisory; .ft R .fi .in .SH FILES .PD 0 .TP 10 \f2archive\f3.meta metadata (metric descriptions, instance domains, etc.) for the archive log .TP \f2archive\f3.0 initial volume of metrics values (subsequent volumes have suffixes .BR 1 , .BR 2 , \&...) .TP \f2archive\f3.index temporal index to support rapid random access to the other files in the archive log .TP .B $PCP_TMP_DIR/pmlogger .B pmlogger maintains the files in this directory as the map between the process id of the .B pmlogger instance and the IPC port that may be used to control each .B pmlogger instance (as used by .BR pmlc (1)) .TP .B $PCP_SYSCONF_DIR/pmlogger/config.default default configuration file for the primary logger instance launched from .B $PCP_RC_DIR/pcp .TP .BR $PCP_SYSCONF_DIR/pmlogger/config. * assorted configuration files suitable for creating logs that may be subsequently replayed with the PCP visualization and monitoring tools .TP .BI $PCP_LOG_DIR/pmlogger/ hostname Default directory for PCP archive files for performance metric values collected from the host .IR hostname . .TP .I \&./pmlogger.log (or .B $PCP_LOG_DIR/pmlogger/\fIhostname\fB/pmlogger.log when started automatically by either .B $PCP_RC_DIR/pcp or one of the .BR pmlogger (1) monitoring scripts such as .BR pmlogger_check (1)) .br all messages and diagnostics are directed here .TP .B $PCP_RC_DIR/pcplocal contains ``hooks'' to enable automatic restart at system boot time .PD .SH ENVIRONMENT Normally .B pmlogger creates a socket to receive control messages from .BR pmlc (1) on the first available TCP/IP port numbered 4330 or higher. The environment variable .B PMLOGGER_PORT may be used to specify an alternative starting port number. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmdumplog (1), .BR pmlc (1), .BR pmlogger_check (1), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). .SH DIAGNOSTICS The archive logs are sufficiently precious that .B pmlogger will not truncate an existing physical file. A message of the form .br .in +0.5v __pmLogNewFile: "foo.index" already exists, not over-written .br __pmLogCreate: File exists .in indicates this situation has arisen. You must explicitly remove the files and launch .B pmlogger again. .PP There may be at most one primary .B pmlogger instance per monitored host; attempting to bend this rule produces the error: .br .in +0.5v pmlogger: there is already a primary pmlogger running .in .PP Various other messages relating to the creation and/or deletion of files in .I $PCP_TMP_DIR/pmlogger suggest a permission problem on this directory, or some feral files have appeared therein. pcp-3.8.12ubuntu1/man/man1/pmdaxfs.10000664000000000000000000000665012272262521013746 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMDAXFS 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaxfs\f1 \- XFS filesystem performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/xfs/pmdaxfs\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] .SH DESCRIPTION .B pmdaxfs is a Performance Metrics Domain Agent (PMDA) which extracts performance metrics describing the state of the XFS filesystem from the Linux kernel. .PP The .B xfs PMDA exports metrics that measure information about metadata buffer usage, the journal, btree operations, inode operations, extended attributes, directories, quotas, read and write operation counts and of course throughput. .PP The PMDA provides a facility to reset the values of all counters to zero using .BR pmstore (1) with the xfs.control.reset metric. .PP A brief description of the .B pmdaxfs command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I xfs.log is written in the current directory of .BR pmcd (1) when .B pmdaxfs is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .SH INSTALLATION The .B xfs PMDA is installed and available by default on Linux. If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/xfs # ./Remove .in .fi .ft 1 .PP If you want to establish access to the names, help text and values for the XFS performance metrics once more, after removal, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/xfs # ./Install .in .fi .ft 1 .PP .B pmdaxfs is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdaxfs .TP 10 .B $PCP_PMDAS_DIR/xfs/help default help text file for the xfs metrics .TP 10 .B $PCP_PMDAS_DIR/xfs/Install installation script for the .B pmdaxfs agent .TP 10 .B $PCP_PMDAS_DIR/xfs/Remove undo installation script for the .B pmdaxfs agent .TP 10 .B $PCP_LOG_DIR/pmcd/xfs.log default log file for error messages and other information from .B pmdaxfs .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmstore (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmsignal.10000664000000000000000000000364312272262501014113 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2009 Aconex. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMSIGNAL 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmsignal\f1 \- send a signal to one or more processes .SH SYNOPSIS \f3$PCP_BINADM_DIR/pmsignal\f1 [\f3\-a\f1|\f3-l\f1] [\f3\-n\f1] [\f3\-s\f1 \fIsignal\fR] [\f2PID\f1 ...|\f2name\f1 ...] .SH DESCRIPTION .B pmsignal provides a cross-platform event signalling mechanism for use with tools from the Performance Co-Pilot toolkit. It can be used to send a named .I signal (only HUP, USR1, TERM, and KILL are accepted). to one or more processes. The processes are specified using PID or the binary name (with .B \-a option). .PP If a .I signal is not specified, then the TERM signal will be sent. .PP On Linux and UNIX platforms, .I pmsignal is a simple wrapper around the .IR kill (1) command. On Windows, the is no direct equivalent to this mechanism, and so an alternate mechanism has been implemented \- this is only honoured by PCP tools, however, not all Windows utilities. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR kill (1), .BR killall (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmie_check.10000664000000000000000000002016012272262501014361 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIE_CHECK 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmie_check\f1, \f3pmie_daily\f1 \- administration of the Performance Co-Pilot inference engine .SH SYNOPSIS .B $PCP_BINADM_DIR/pmie_check [\f3\-CNsV\f1] [\f3\-c\f1 \f2control\f1] .br .B $PCP_BINADM_DIR/pmie_daily [\f3\-NV\f1] [\f3\-c\f1 \f2control\f1] [\f3\-k\f1 \f2discard\f1] [\f3\-m\f1 \f2addresses\f1] [\f3\-x\f1 \f2compress\f1] [\f3\-X\f1 \f2program\f1] [\f3\-Y\f1 \f2regex\f1] .br .SH DESCRIPTION This series of shell scripts and associated control files may be used to create a customized regime of administration and management for the Performance Co-Pilot (see .BR PCPintro (1)) inference engine, .BR pmie (1). .PP .B pmie_daily is intended to be run once per day, preferably in the early morning, as soon after midnight as practicable. Its task is to rotate the log files for the running .B pmie processes \- these files may grow without bound if the ``print'' action is used, or any other .B pme action writes to its stdout/stderr streams. After some period, old .B pmie log files are discarded. This period is 14 days by default, but may be changed using the .B \-k option. Two special values are recognized for the period (\c .IR discard ), namely .B 0 to keep no log files beyond the current one, and .B forever to prevent any log files being discarded. .PP Log files can optionally be compressed after some period (\c .IR compress ), to conserve disk space. This is particularly useful for large numbers of .B pmie processes under the control of .BR pmie_check . The .B \-x option specifies the number of days after which to compress archive data files, and the .B \-X option specifies the program to use for compression \- by default this is .BR bzip2 (1). Use of the .B \-Y option allows a regular expression to be specified causing files in the set of files matched for compression to be omitted \- this allows only the data file to be compressed, and also prevents the program from attempting to compress it more than once. The default .I regex is ".meta$|.index$|.Z$|.gz$|.bz2|.zip$" \- such files are filtered using the .B \-v option to .BR egrep (1). .PP Use of the .B \-m option causes .B pmie_daily to construct a summary of the log files generated for all monitored hosts in the last 24 hours (lines matching `` OK '' are culled), and e-mail that summary to the set of space-separated .IR addresses . .PP .B pmie_check may be run at any time, and is intended to check that the desired set of .BR pmie (1) processes are running, and if not to re-launch any failed inference engines. Use of the .B \-s option provides the reverse functionality, allowing the set of .B pmie processes to be cleanly shutdown. Use of the .B \-C option queries the system service runlevel information for .BR pmie , and uses that to determine whether to start or stop processes. .PP Both .B pmie_check and .B pmie_daily are controlled by a PCP inference engine control file that specifies the .B pmie instances to be managed. The default control file is .B $PCP_PMIECONTROL_PATH but an alternate may be specified using the .B \-c option. .PP The control file should be customized according to the following rules. .IP 1. Lines beginning with a ``#'' are comments. .PD 0 parameters of the .IP 2. Lines beginning with a ``$'' are assumed to be assignments to environment variables in the style of .BR sh (1), and all text following the ``$'' will be .BR eval 'ed by the script reading the control file, and the corresponding variable exported into the environment. This is particularly useful to set and export variables into the environment of the administrative script, e.g. .br .in +4n .ft CW .nf $ PMCD_CONNECT_TIMEOUT=20 .fi .ft R .in -4n .br .BR Warning : The .B $PCP_PMIECONTROL_PATH file must not be writable by any user other than root. .br .IP 3. There should be one line in the control file for each .B pmie instance of the form: .in +4n .ft CW .nf \f2host\f1 \f3y\f1|\f3n\f1 \f2logfile\f1 \f2args\f1 .fi .ft R .in -4n .IP 4. Fields within a line of the control file are separated by one or more spaces or tabs. .IP 5. The .I first field is the name of the host that is the default source of the performance metrics for this .B pmie instance. .IP 6. The .I second field indicates whether this .B pmie instance needs to be started under the control of .BR pmsocks (1) to connect to a .B pmcd through a firewall (\c .B y or .BR n ). .IP 8. The .I third field is the name of the .B pmie activity log file. A useful convention is that .B pmie instances monitoring the local host with hostname .I myhost are maintained in the directory .BI $PCP_LOG_DIR/pmie/ myhost\fR, while activity logs for the remote host .I mumble are maintained in .BI $PCP_LOG_DIR/pmie/ mumble\fR. This is consistent with the way .BR pmlogger (1) maintains its activity logs and archive files. .IP 9. All other fields are interpreted as arguments to be passed to .BR pmie (1). Most typically this would be the .B \-c option. .PD .PP The following sample control lines specify one .B pmie instance monitoring the local host (\c .IR wobbly ), and another monitoring performance metrics from the host .IR splat . .PP .nf .ft CW wobbly n PCP_LOG_DIR/pmie/wobbly \-c config.default splat n PCP_LOG_DIR/pmie/splat \-c splat/cpu.conf .ft 1 .fi .PP Typical .BR crontab (5) entries for periodic execution of .B pmie_daily and .B pmie_check are given in .BR $PCP_SYSCONF_DIR/pmie/crontab (unless installed by default in .IR /etc/cron.d already) and shown below. .PP .nf .ft CW # daily processing of pmie logs 08 0 * * * $PCP_BINADM_DIR/pmie_daily # every 30 minutes, check pmie instances are running 28,58 * * * * $PCP_BINADM_DIR/pmie_check .ft 1 .fi .PP The output from the .BR cron (1) execution of the scripts may be extended using the .B \-V option to the scripts which will enable verbose tracing of their activity. By default the scripts generate no output unless some error or warning condition is encountered. .PP The .B \-N option enables a ``show me'' mode, where the actions are echoed, but not executed, in the style of ``make \-n''. Using .B \-N in conjunction with .B \-V maximizes the diagnostic capabilities for debugging. .SH FILES .TP 10 .B $PCP_PMIECONTROL_PATH the default PCP inference engine control file .br .BR Warning : this file must not be writable by any user other than root. .TP .B $PCP_SYSCONF_DIR/pmie/crontab sample crontab for automated script execution by $PCP_USER (or root) - exists only if the platform does not support the .I /etc/cron.d mechanism. .TP .B $PCP_SYSCONF_DIR/pmie/config.default default .B pmlogger configuration file location for a localhost inference engine, typically generated automatically by .BR pmieconf (1). .TP .BI $PCP_LOG_DIR/pmie/ hostname default location for the pmie log file for the host .I hostname .TP .BI $PCP_LOG_DIR/pmie/ hostname /lock transient lock file to guarantee mutual exclusion during .B pmie administration for the host .I hostname \- if present, can be safely removed if neither .B pmie_daily nor .B pmie_check are running .TP .B $PCP_LOG_DIR/NOTICES PCP ``notices'' file used by .BR pmie (1) and friends .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR chkconfig (1), .BR cron (1), .BR PCPintro (1), .BR pmie (1) .BR pmieconf (1) and .BR pmsocks (1). pcp-3.8.12ubuntu1/man/man1/pmmgr.10000664000000000000000000002324212272262521013422 0ustar '\"! tbl | mmdoc '\"macro stdmacro .\" .\" Copyright (c) 2013-2014 Red Hat, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMMGR 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmmgr\f1 \- pcp daemon manager .SH SYNOPSIS \f3pmmgr\f1 [\f3\-v\f1] [\f3\-c\f1 \f2config-directory\f1] [\f3\-p\f1 \f2polling-interval\f1] [\f3\-l\f1 \f2log-file\f1] .SH DESCRIPTION .B pmmgr manages a collection of PCP daemons for a set of discovered local and remote hosts running the Performance Metrics Collection Daemon (PMCD), according to zero or more configuration directories. It keeps a matching set of .BR pmlogger " and/or " pmie daemons running, and their archives/logs merged/rotated. It supplants the older .BR pmlogger_* " and " pmie_* check/daily management shell scripts. .P pmmgr is largely self-configuring and perseveres despite most run-time errors. pmmgr runs in the foreground until interrupted. When signaled, it will stop its running daemons before exiting. .P A description of the command line options specific to .B pmmgr follows: .TP 5 .B \-c .I directory adds a given configuration directory to pmmgr. pmmgr can supervise multiple different configurations at the same time. Errors in the configuration may be noted to standard error, but pmmgr will fill in missing information with built-in defaults. The default directory is .I $PCP_SYSCONF_DIR/pmmgr .TP .B \-p .I polling-interval sets the host-discovery polling interval to the given number of seconds. The default is 60. .TP .B \-l .I log-file redirects standard output & error to the given log file, which is created anew .TP .B \-v adds more verbose tracing to standard error. .SH CONFIGURATION A .B pmmgr configuration identifies which hosts should be monitored, which daemons should be maintained for them, and what options those daemons should be run with. pmmgr uses a small number of files in a configuration directory, instead of lines in a text file. The individual files carry zero or more lines of 100% pure configuration text, and no comments. (If desired, a configuration may be commented upon with any other file, such as a free-form README.) .SS TARGET SELECTION This set of configuration files identifies where pmmgr should search for pmcd instances, how to uniquely identify them, and where state such as log files should be kept for each. Ideally, a persistent & unique host-id string is computed for each potential target pmcd from specified metric values. This host-id is also used as a subdirectory name for locating daemon data. .TP hostid\-metrics This file contains one or more lines of metric specifications in the format accepted by .IR pmParseMetricSpec . Metrics without instance specifiers mean all instances of that metric. These are used to generate the .IR unique host-id string for each pmcd server that pmmgr discovers. Upon discovery, all the metrics/instances named are queried, string values fetched, and normalized/concatenated into a single hyphenated printable string. The default is the single metric .BR pmcd.hostname , which is sufficient if all the hosts discovered have unique hostname(2). If they don't, you should add other pcp metric specifications to set them apart at your site. The more you add, the longer the host-id string, but the more likely that accidental duplication is prevented. However, it may be desirable for a host-id to also be .IR persistent , so that if the target host goes offline and later returns, the new host-id matches the previous one, because then old and new histories can be joined. This argues against using metrics whose values vary from boot to boot. Some candidate metrics to consider: .IR network.interface.hw_addr ", " network.interface.inet_addr["eth0"] ", " .IR network.interface.ipv6_addr ", " kernel.uname.nodename .\" some others would be nice to have: .\" CPU serial numbers .\" VM uuid .\" DMI serial numbers .TP log\-directory This file contains the path of a directory beneath which the per-host-id subdirectories are to be created by pmmgr. If it is not a full path, it is implicitly relative to the configuration directory itself. The default is .BR $PCP_LOG_DIR/pmmgr/ . .TP target\-host This file contains one or more lines containing pmcd host specifications, as described on the .IR PCPintro (1) man page. Each poll interval, pmmgr will attempt to make a brief .IR pmNewContext connection to the host to check liveness. It is not a problem if more than one specification for the same host is listed, because the host-id processing eliminates duplicates, and chooses an arbitrary specification among them. The default is to target pmcd at .BR local: . .TP target\-discovery This file contains one or more lines containing specifications for the .IR pmDiscoverServices PMAPI call, each of which may map onto a fluctuating set of local or remote pmcd servers. Each poll interval, pmmgr will attempt to rerun discovery with all of the given specifications. Again it is not a problem if more than one specification matches the same actual pmcd. The default value is to do .BR "no discovery" . Consider including .IR avahi to rely on pmcd self-announcements on the local network. .TP log\-subdirectory\-gc This file may contain a time interval specification as per the .IR PCPintro man page. All subdirectories of the log\-directory are presumed to contain data for pmmgr-monitored servers. Those that have not been touched (in the .BR stat/mtime sense) in at least that long, and not associated with a currently monitored target, are deleted entirely. This value should be longer than the longest interval that pmmgr normally recreates archives (such as due to pmmgr restarts, and .BR pmlogmerge intervals). The default value is .BR 90days . .SS PMLOGGER CONFIGURATION This group of configuration options controls a .BR pmlogger daemon for each host. This may include generating its configuration, and managing its archives. .TP pmlogger If and only if this file exists, pmmgr will maintain a .BR pmlogger daemon for each targeted host. This file contains one line of additional space-separated options for the pmie daemon. (pmmgr already adds \-h, \-f, \-r, \-l, and perhaps \-c.) The default is to maintain .BR "no pmlogger" (and no other configuration in this section is processed). .TP pmlogconf If and only if this file exists, pmmgr will run .BR pmlogconf to generate a configuration file for each target pmcd. The file contains one line of space-separated additional options for the pmlogconf program. pmlogconf's generated output file will be stored under the log\-directory/hostid subdirectory. (pmmgr already adds \-c, \-r, and \-h.) The default is .BR "no pmlogconf" , so instead, the pmlogger file above should probably contain a \-c option, to specify a fixed pmlogger configuration. .TP pmlogmerge If and only if this file exists, pmmgr will run .BR pmlogextract to periodically merge together all preexisting log archives for each target pmcd into one. (When pmlogger is started, it always creates a new archive, so in the steady state, there will be one merged archive from history, and one current archive being written-to by pmlogger.) The file may contain a time interval specification as per the .IR PCPintro man page, representing the period at which pmlogger should be temporarily stopped, and archives merged. The default is .BR 24hours . .TP pmlogmerge\-retain If this file exists, pmmgr will set the relative starting time for retaining old archived data. It will be passed to pmlogextract as a negative parameter to \-S. It is interpreted as a request that data older than the given interval should be thrown away. The default is .BR 14days . .SS PMIE CONFIGURATION This group of configuration options controls a .BR pmie daemon for each host. This may include generating a custom configuration. .TP pmie If and only if this file exists, pmmgr will maintain a .BR pmie daemon for each targeted pmcd. This file contains one line of additional space-separated options for the pmie daemon. (pmmgr already adds \-h, \-f, \-l, and perhaps \-c.) The default is to maintain .BR "no pmie" (and no other configuration in this section is processed). .TP pmieconf If and only if this file exists, pmmgr will run .BR pmieconf to generate a configuration file for each target pmcd. The file contains one line of space-separated additional options for the pmieconf program. pmieconf's generated output file will be stored under the log\-directory/hostid subdirectory. (pmmgr already adds \-F, \-c, and \-f.) The default is .BR "no pmieconf" , so instead, the pmie file above should probably contain a \-c option, to specify a fixed pmie configuration. .SH FILES .PD 0 .TP 10 .BI $PCP_SYSCONFIG_DIR/pmmgr/ default configuration directory .TP .BI $PCP_LOG_DIR/pmmgr/ default logging directory .PD .SH BUGS .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parametrize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmlogconf (1), .BR pmlogger (1), .BR pmieconf (1), .BR pmie (1), .BR pmlogreduce (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmdakernel.10000664000000000000000000001115112272262521014416 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH "KERNEL PMDAS" 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaaix\f1, \f3pmdadarwin\f1, \f3pmdafreebsd\f1, \f3pmdalinux\f1, \f3pmdanetbsd\f1, \f3pmdaproc\f1, \f3pmdasolaris\f1, \f3pmdawindows\f1, \f3kernel PMDAs\f1 \- operating system kernel performance metrics domain agents .SH SYNOPSIS \f3$PCP_PMDAS_DIR/aix/pmdaaix\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] .br \f3$PCP_PMDAS_DIR/darwin/pmdadarwin\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] .br \f3$PCP_PMDAS_DIR/freebsd/pmdafreebsd\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] .br \f3$PCP_PMDAS_DIR/linux/pmdalinux\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] .br \f3$PCP_PMDAS_DIR/netbsd/pmdanetbsd\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] .br \f3$PCP_PMDAS_DIR/solaris/pmdasolaris\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] .br \f3$PCP_PMDAS_DIR/windows/pmdawindows\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION Each supported platform has a kernel Performance Metrics Domain Agent (PMDA) which extracts performance metrics from the kernel of that platfrom. A variety of platform-specific metrics are available, with an equally varied set of access mechanisms - typically this involves special system calls, or reading from files in kernel virtual filesystems such as the Linux .I sysfs and .I procfs filesystems. .PP The platform kernel PMDA is one of the most critical components of the PCP installation, and must be as efficient and reliable as possible. In all installations the default kernel PMDA will be installed as a shared library and thus executes directly within the .BR pmcd (1) process. This slightly reduces overheads associated with querying the metadata and values associated with these metrics (no message passing is required). .PP Unlike many other PMDAs, the kernel PMDA exports a number of metric namespace subtrees, such as kernel, network, swap, mem, ipc, filesys, nfs, disk and hinv (hardware inventory). .PP Despite usually running as shared libraries, most installations also include a stand-alone executable for the kernel PMDA. This is to aid profiling and debugging activities, with .BR dbpmda (1) for example. In this case (but not for shared libraries), the following command line options are available: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I [platform].log is written in the current directory of .BR pmcd (1) when .B pmda[platform] is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .SH INSTALLATION Access to the names, help text and values for the kernel performance metrics is available by default - unlike most other agents, no action is required to enable them and they should not be removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMDAS_DIR/[platform]/help default help text file for the the kernel metrics .TP 10 .B $PCP_LOG_DIR/pmcd/pmcd.log default log file for error messages and other information from the kernel PMDA. .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR dbpmda (1) .BR pmcd (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmdalogger.10000664000000000000000000001134012272262521014415 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMDALOGGER 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdalogger\f1 \- log file performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/logger/pmdalogger\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-m\f1 \f2memory\f1] [\f3\-s\f1 \f2interval\f1] [\f3\-U\f1 \f2username\f1] [\f2configfile\f1] .SH DESCRIPTION .B pmdalogger is a configurable log file monitoring Performance Metrics Domain Agent (PMDA). It can be seen as analagous to the .B \-f option to .BR tail (1) and converts each new log line into a performance event. It was the first PMDA to make extensive use of event metrics, which can be consumed by client tools like .BR pmevent (1). .PP The .B logger PMDA exports both event-style metrics reflecting timestamped event records for text logged to a file (or set of files or output from a process), as well as the more orthodox sample-style metrics such as event counts and throughput size values. .PP The PMDA is configured via a .I configfile which contains one line for each source of events (file or process). This file is setup by the Install script described in the later section on ``INSTALLATION'' of the PMDA. .PP A brief description of the .B pmdalogger command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I logger.log is written in the current directory of .BR pmcd (1) when .B pmdalogger is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-m Limit the physical memory used by the PMDA to buffer event records to .I maxsize bytes. As log events arrive at the PMDA, they must be buffered until individual client tools request the next batch since their previous batch of events. The default maximum is 2 megabytes. .TP .B \-s Sets the polling interval for detecting newly arrived log lines. Mirrors the same option from the .BR tail (1) command. .TP .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .SH INSTALLATION If you want access to the names, help text and values for the logger performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/logger # ./Install .in .fi .ft 1 .PP This is an interactive installation process which prompts for each log file path to be monitored (or command to be run), a metric instance name to identify it, and whether access should be restricted (refer to the .B \-x option to .BR pmevent (1) for further details). .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/logger # ./Remove .in .fi .ft 1 .PP .B pmdalogger is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdalogger .TP 10 .B $PCP_PMDAS_DIR/logger/logger.conf default configuration file for the logger metrics .TP 10 .B $PCP_PMDAS_DIR/logger/help default help text file for the logger metrics .TP 10 .B $PCP_PMDAS_DIR/logger/Install installation script for the .B pmdalogger agent .TP 10 .B $PCP_PMDAS_DIR/logger/Remove undo installation script for the .B pmdalogger agent .TP 10 .B $PCP_LOG_DIR/pmcd/logger.log default log file for error messages and other information from .B pmdalogger .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmevent (1), .BR pmcd (1), .BR tail (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmlogger_check.10000664000000000000000000003061012272262501015244 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOGGER_CHECK 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmlogger_check\f1, \f3pmlogger_daily\f1, \f3pmlogger_merge\f1 \- administration of Performance Co-Pilot archive log files .SH SYNOPSIS .B $PCP_BINADM_DIR/pmlogger_check [\f3\-CNsTV\f1] [\f3\-c\f1 \f2control\f1] .br .B $PCP_BINADM_DIR/pmlogger_daily [\f3\-NorV\f1] [\f3\-c\f1 \f2control\f1] [\f3\-k\f1 \f2discard\f1] [\f3\-m\f1 \f2addresses\f1] [\f3\-s\f1 \f2size\f1] [\f3\-t\f1 \f2want\f1] [\f3\-x\f1 \f2compress\f1] [\f3\-X\f1 \f2program\f1] [\f3\-Y\f1 \f2regex\f1] .br .B $PCP_BINADM_DIR/pmlogger_merge [\f3\-fNV\f1] [\f2input-basename\f1 ... \f2output-name\f1] .br .SH DESCRIPTION This series of shell scripts and associated control files may be used to create a customized regime of administration and management for Performance Co-Pilot (see .BR PCPintro (1)) archive log files. .PP .B pmlogger_daily is intended to be run once per day, preferably in the early morning, as soon after midnight as practicable. Its task is to aggregate and rotate one or more sets of PCP archives. After some period, old PCP archives are discarded. This period is 14 days by default, but may be changed using the .B \-k option. Two special values are recognized for the period (\c .IR discard ), namely .B 0 to keep no archives beyond the current one, and .B forever to prevent any archives being discarded. .PP Archive data files can optionally be compressed after some period (\c .IR compress ), to conserve disk space. This is particularly useful for large numbers of .B pmlogger processes under the control of .BR pmlogger_check . The .B \-x option specifies the number of days after which to compress archive data files, and the .B \-X option specifies the program to use for compression \- by default this is .BR bzip2 (1). Use of the .B \-Y option allows a regular expression to be specified causing files in the set of files matched for compression to be omitted \- this allows only the data file to be compressed, and also prevents the program from attempting to compress it more than once. The default .I regex is ".meta$|.index$|.Z$|.gz$|.bz2|.zip$" \- such files are filtered using the .B \-v option to .BR egrep (1). .PP In addition, if the PCP ``notices'' file (\c .BR $PCP_LOG_DIR/NOTICES ) is larger than 20480 bytes, .B pmlogger_daily will rename the file with a ``.old'' suffix, and start a new ``notices'' file. The rotate threshold may be changed from 20480 to .I size bytes using the .B \-s option. .PP Use of the .B \-m option causes .B pmlogger_daily to construct a summary of the ``notices'' file entries which were generated in the last 24 hours, and e-mail that summary to the set of space-separated .IR addresses . This daily summary is stored in the file .BR $PCP_LOG_DIR/NOTICES.daily , which will be empty when no new ``notices'' entries were made in the previous 24 hour period. .PP .B pmlogger_check may be run at any time, and is intended to check that the desired set of .BR pmlogger (1) processes are running, and if not to re-launch any failed loggers. Use of the .B \-s option provides the reverse functionality, allowing the set of .B pmlogger processes to be cleanly shutdown. Use of the .B \-C option queries the system service runlevel information for .BR pmlogger , and uses that to determine whether to start or stop processes. .PP .B pmlogger_merge is a wrapper script for .BR pmlogmerge (1) that merges all of the archive logs matching the .I input-basename arguments, and creates a new archive using .I output-name as the base name for the physical files that constitute an archive log. The .I input-basename arguments may contain meta characters in the style of .BR sh (1). If specified, the .B \-f option causes all of the input files to be removed once the output archive has been created. .PP .B pmlogger_merge is used by .BR pmlogger_daily . .PP To assist with debugging or diagnosing intermittent failures the .B \-t option may be used. This will turn on very verbose tracing (\c .BR \-VV ) and capture the trace output in a file named .BI $PCP_LOG_DIR/pmlogger/daily. datestamp .trace, where .I datestamp is the time .B pmlogger_daily was run in the format YYYYMMDD.HH.MM. In addition, the .I want argument will ensure that trace files created with .B \-t will be kept for .I want days and then discarded. .PP Both .B pmlogger_daily and .B pmlogger_check are controlled by a PCP logger control file that specifies the .B pmlogger instances to be managed. The default control file is .BR $PCP_PMLOGGERCONTROL_PATH , but an alternate may be specified using the .B \-c option. .PP The control file should be customized according to the following rules that define for the current version (1.1) of the control file format. .IP 1. Lines beginning with a ``#'' are comments. .PD 0 parameters of the .IP 2. Lines beginning with a ``$'' are assumed to be assignments to environment variables in the style of .BR sh (1), and all text following the ``$'' will be .BR eval 'ed by the script reading the control file, and the corresponding variable exported into the environment. This is particularly useful to set and export variables into the environment of the administrative scripts, e.g. .br .in +4n .ft CW .nf $ PMCD_CONNECT_TIMEOUT=20 .fi .ft R .in -4n .br .BR Warning : The .B $PCP_PMLOGGERCONTROL_PATH file must not be writable by any user other than root. .br .IP 3. There .B must be a version line of the form: .br .in +4n .ft CW .nf $ version=1.1 .fi .ft R .in -4n .IP 4. There should be one line in the control file for each .B pmlogger instance of the form: .in +4n .ft CW .nf \f2host\f1 \f3y\f1|\f3n\f1 \f3y\f1|\f3n\f1 \f2directory\f1 \f2args\f1 .fi .ft R .in -4n .IP 5. Fields within a line of the control file are separated by one or more spaces or tabs. .IP 6. The .I first field is the name of the host that is the source of the performance metrics for this .B pmlogger instance. .IP 7. The .I second field indicates if this is a .I primary .B pmlogger instance (\c .BR y ) or not (\c .BR n ). Since the primary logger must run on the local host, and there may be at most one primary logger for a particular host, this field can be .B y for at most one .B pmlogger instance, in which case the host name must be the name of the local host. .IP 8. The .I third field indicates if this .B pmlogger instance needs to be started under the control of .BR pmsocks (1) to connect to a .B pmcd through a firewall (\c .B y or .BR n ). .IP 9. The .I fourth field is a directory name. All files associated with this .B pmlogger instance will be created in this directory, and this will be the current directory for the execution of any programs required in the maintenance of those archives. A useful convention is that primary logger archives for the local host with hostname .I myhost are maintained in the directory .BI $PCP_LOG_DIR/pmlogger/ myhost (this is where the default .B pmlogger start-up script in .B $PCP_RC_DIR/pcp will create the archives), while archives for the remote host .I mumble are maintained in .BI $PCP_LOG_DIR/pmlogger/ mumble\fR. .IP 10. All other fields are interpreted as arguments to be passed to .BR pmlogger (1) and/or .BR pmnewlog (1). Most typically this would be the .B \-c option. .PD .PP The following sample control lines specify a primary logger on the local host (\c .IR bozo ), and a non-primary logger to collect and log performance metrics from the host .IR boing . .PP .nf .ft CW $version=1.1 bozo y n $PCP_LOG_DIR/pmlogger/bozo \-c config.default boing n n $PCP_LOG_DIR/pmlogger/boing \-c ./pmlogger.config .ft 1 .fi .PP Typical .BR crontab (5) entries for periodic execution of .B pmlogger_daily and .B pmlogger_check are given in .BR $PCP_SYSCONF_DIR/pmlogger/crontab (unless installed by default in .I /etc/cron.d already) and shown below. .PP .nf .ft CW # daily processing of archive logs 14 0 * * * $PCP_BINADM_DIR/pmlogger_daily # every 30 minutes, check pmlogger instances are running 25,55 * * * * $PCP_BINADM_DIR/pmlogger_check .ft 1 .fi .PP The output from the .BR cron (1) execution of the scripts may be extended using the .B \-V option to the scripts which will enable verbose tracing of their activity. By default the scripts generate no output unless some error or warning condition is encountered. .PP The .B \-N option enables a ``show me'' mode, where the actions are echoed, but not executed, in the style of ``make \-n''. Using .B \-N in conjunction with .B \-V maximizes the diagnostic capabilities for debugging. .PP By default all possible archives will be merged. The .B \-o option reinstates the old behaviour in which only yesterday's archives will be considered as merge candidates. .PP The .B \-T option provides a terser form of output for .B pmlogger_check that is most suitable for a .I pmlogger \&``farm'' where many instances of .I pmlogger are expected to be running. .PP To accommodate the evolution of PMDAs and changes in production logging environments, .B pmlogger_daily is integrated with .BR pmlogrewrite (1) to allow optional and automatic rewriting of archives before merging. If there are global rewriting rules to be applied across all archives mentioned in the control file, then create the directory .B $PCP_SYSCONF_DIR/pmlogrewrite and place any .BR pmlogrewrite (1) rewriting rules in this directory. For rewriting rules that are specific to only one family of archives, use the directory name from the control file (the .I fourth field) and create a file, or a directory, or a symbolic link named .B pmlogrewrite within this directory and place the required rewriting rule(s) in the .B pmlogrewrite file or in files within the .B pmlogrewrite subdirectory. .B pmlogger_daily will choose rewriting rules from the archive directory if they exist, else rewriting rules from .B $PCP_SYSCONF_DIR/pmlogrewrite if that directory exists, else no rewriting is attempted. .PP The .B \-r command line option acts as an over-ride and prevents all archive rewriting with .BR pmlogrewrite (1) independent of the presence of any rewriting rule files or directories. .PP The script .B $PCP_BINADM_DIR/pmlogger_daily could be copied and modified to implement a site-specific procedure for end-of-week and/or end-of-month management for a set of PCP archives. .SH FILES .TP 10 .B $PCP_PMLOGGERCONTROL_PATH the PCP logger control file .br .BR Warning : this file must not be writable by any user other than root. .TP .B $PCP_SYSCONF_DIR/pmlogger/crontab sample crontab for automated script execution by $PCP_USER (or root). Exists only if the platform does not support the /etc/cron.d mechanism. .TP .B $PCP_SYSCONF_DIR/pmlogger/config.default default .B pmlogger configuration file location for the local primary logger, typically generated automatically by .BR pmlogconf (1). .TP .BI $PCP_LOG_DIR/pmlogger/ hostname default location for archives of performance information collected from the host .I hostname .TP .BI $PCP_LOG_DIR/pmlogger/ hostname /lock transient lock file to guarantee mutual exclusion during .B pmlogger administration for the host .I hostname \- if present, can be safely removed if neither .B pmlogger_daily nor .B pmlogger_check are running .TP .BI $PCP_LOG_DIR/pmlogger/ hostname /Latest PCP archive folio created by .BR mkaf (1) for the most recently launched archive containing performance metrics from the host .I hostname .TP .B $PCP_LOG_DIR/NOTICES PCP ``notices'' file used by .BR pmie (1) and friends .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR bzip2 (1), .BR cron (1), .BR egrep (1), .BR PCP (1), .BR pmlc (1), .BR pmlogconf (1), .BR pmlogger (1), .BR pmlogmerge (1), .BR pmlogrewrite (1), .BR pmnewlog (1) and .BR pmsocks (1). pcp-3.8.12ubuntu1/man/man1/pmdasample.10000664000000000000000000001064112272262501014420 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .\" I am variants ... .ds ia sample .ds IA SAMPLE .ds Ia Sample .TH PMDASAMPLE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdasample\f1 \- \*(ia performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/pmda\*(ia\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-i\f1 \f2port\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-p\f1] [\f3\-u\f1 \f2socket\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION .B pmda\*(ia is a \*(ia Performance Metrics Domain Agent (PMDA) which exports a variety of synthetic performance metrics. .PP This PMDA was developed as part of the quality assurance testing for the PCP product, but has other uses, most notably in the development of new PCP clients. .PP The metrics exported by the \*(ia PMDA cover the full range of data types, data semantics, value cardinality, instance domain stability and error conditions found in real PMDAs. .PP A brief description of the .B pmda\*(ia command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-i Expect PMCD to connect to .B pmda\*(ia on the specified TCP/IP port. .I port may be a port number or port name. .TP .B \-l Location of the log file. By default, a log file named .I \*(ia.log is written in the current directory of .BR pmcd (1) when .B pmda\*(ia is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-p Expect PMCD to create a pipe and the connection to .B pmda\*(ia is via standard input and standard output. This is the default connection mode. .TP .B \-u Expect PMCD to connect to .B pmda\*(ia on the Unix domain socket named .IR socket . .TP 5 .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .PP At most one of the options .BR \-i , .B \-p and .B \-u may be specified. .SH INSTALLATION If you want access to the names, help text and values for the \*(ia performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/\*(ia # ./Install .in .fi .ft 1 .PP Note that the installation script also installs the DSO version of the \*(ia PMDA, so there are in fact two PMDAs installed, and two sets of performance metrics, namely .B sample.* and .BR sampledso.* . .PP If you want to undo the installation (and remove both PMDAs), do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/\*(ia # ./Remove .in .fi .ft 1 .PP .B pmda\*(ia is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmda\*(ia .TP 10 .B $PCP_PMDAS_DIR/\*(ia/help default help text file for the \*(ia metrics .TP 10 .B $PCP_PMDAS_DIR/\*(ia/Install installation script for the .B pmda\*(ia agent .TP 10 .B $PCP_PMDAS_DIR/\*(ia/Remove undo installation script for the .B pmda\*(ia agent .TP 10 .B $PCP_LOG_DIR/pmcd/sample.log default log file for error messages and other information from .B pmda\*(ia .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmdasimple (1), .BR pmdatrivial (1), .BR pmdatxmon (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmdalustrecomm.10000664000000000000000000000716212272262521015337 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMDALUSTERCOMM 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdalustrecomm\f1 \- Lustre filesystem comms performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/lustrecomm/pmdalustrecomm\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION .B pmdalustrecomm is a Performance Metrics Domain Agent (PMDA) which extracts performance metrics from the Linux procfs filesystem about the state of various aspects of the Lustre filesystem. .PP The .B lustrecomm PMDA exports metrics that focus on distributed communication in the filesystem, including metrics related to timeouts, network drops, send/recv information and route lengths. However, it also covers the memory use of some of the Lustre filesystem components. .PP A brief description of the .B pmdalustrecomm command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I lustrecomm.log is written in the current directory of .BR pmcd (1) when .B pmdalustrecomm is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .SH INSTALLATION If you want access to the names, help text and values for the lustrecomm performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/lustrecomm # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/lustrecomm # ./Remove .in .fi .ft 1 .PP .B pmdalustrecomm is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdalustrecomm .TP 10 .B $PCP_PMDAS_DIR/lustrecomm/help default help text file for the lustrecomm metrics .TP 10 .B $PCP_PMDAS_DIR/lustrecomm/Install installation script for the .B pmdalustrecomm agent .TP 10 .B $PCP_PMDAS_DIR/lustrecomm/Remove undo installation script for the .B pmdalustrecomm agent .TP 10 .B $PCP_LOG_DIR/pmcd/lustrecomm.log default log file for error messages and other information from .B pmdalustrecomm .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmdbg.10000664000000000000000000000371612272262501013373 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDBG 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdbg\f1 \- translate Performance Co-Pilot debug control flags .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS \f3pmdbg\f1 \f2code\f1 ... .br \f3pmdbg\f1 \f3\-l\f1 .SH DESCRIPTION The components of the Performance Co-Pilot (PCP) use a global vector of bit-fields to control diagnostic and debug output. .PP .B pmdbg with a .B \-l argument prints out the mnemonic and decimal values of all the bit-fields in the debug control vector. .PP In the alternative usage, the .I code arguments are values for the debug vector, and the bit-fields that are enabled by each of these values is listed. .PP Each .I code may be an integer, a hexadecimal value or a hexadecimal value prefixed by either ``0x'' or ``0X''. .PP Most applications using the facilities of the PCP support a .BI \-D N command-line syntax to enable debug control. .B pmdbg is designed to help choose an appropriate value for .IR N . .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmproxy.10000664000000000000000000002272712272262501014023 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMPROXY 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmproxy\f1 \- proxy for performance metrics collector daemon .SH SYNOPSIS \f3pmproxy\f1 [\f3\-C\f1 \f2dirname\f1] [\f3\-f\f1] [\f3\-i\f1 \f2ipaddress\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-L\f1 \f2bytes\f1] [\f3\-p\f1 \f2port\f1[,\f2port\f1 ...] [\f3\-P\f1 \f2passfile\f1] [\f3\-U\f1 \f2username\f1] [\f3\-x\f1 \f2file\f1] .SH DESCRIPTION .B pmproxy acts as a protocol proxy for .BR pmcd (1), allowing Performance Co-Pilot (PCP) monitoring clients to connect to one or more .BR pmcd (1) instances via .BR pmproxy . .PP Normally .B pmproxy is deployed in a firewall domain, or on a ``head'' node of a cluster where the IP (Internet Protocol) address of the hosts where .BR pmcd (1) is running may be unknown to the PCP monitoring clients, although the IP address of the host where .B pmproxy is running is known to these clients. Similarly, the clients may have network connectivity only to the host where .B pmproxy is running, while there is network connectivity from that host to the hosts of interest where .BR pmcd (1) is running. .PP The behaviour of the PCP monitoring clients is controlled by either the .B PMPROXY_HOST environment variable or through the extended hostname specification (see .BR PCPIntro (1) for details). If neither of these mechanisms is used, clients will make their connections directly to .BR pmcd (1). If the proxy hostname syntax is used or .B PMPROXY_HOST is set, then this should be the hostname or IP address of the system where .B pmproxy is running, and the clients will connect to .BR pmcd (1) indirectly through the protocol proxy services of .BR pmproxy. .PP The options to .B pmproxy are as follows. .TP \f3\-C\f1 \f2dirname\f1 Specify the path to the Network Security Services certificate database, for (optional) secure connections. The default is .BR /etc/pki/nssdb . Refer also to the \f3\-P\f1 option. If it does not already exist, this database can be created using the .B certutil utility. This process and other certificate database maintenance information is provided in the .BR PCPIntro (1) manual page and the online PCP tutorials. .TP .B \-f By default .B pmproxy is started as a daemon. The .B \-f option indicates that it should run in the foreground. This is most useful when trying to diagnose problems with establishing connections. .TP \f3\-i\f1 \f2ipaddress\f1 This option is usually only used on hosts with more than one network interface (very common for firewall and ``head'' node hosts where .B pmproxy is most likely to be deployed). If no .B \-i options are specified .B pmproxy accepts PCP client connections on any of its host's IP addresses. The .B \-i option is used to specify explicitly an IP address that PCP client connections should be accepted on. .I ipaddress should be in the standard dotted form (e.g. 100.23.45.6). The .B \-i option may be used multiple times to define a list of IP addresses. When one or more .B \-i options is specified, attempted connections made on any other IP addresses will be refused. .TP \f3\-l\f1 \f2logfile\f1 By default a log file named .I pmproxy.log is written in the current directory. The .B \-l option causes the log file to be written to .I logfile instead of the default. If the log file cannot be created or is not writable, output is written to the standard error instead. .TP \f3\-L\f1 \f2bytes\f1 .IR PDU s received by .B pmproxy from PCP monitoring clients are restricted to a maximum size of 65536 bytes by default to defend against Denial of Service attacks. The .B \-L option may be used to change the maximum incoming .I PDU size. .TP \f3\-P\f1 \f2passfile\f1 Specify the path to a file containing the Network Security Services certificate database password for (optional) secure connections, and for databases that are password protected. Refer also to the \f3\-C\f1 option. When using this option, great care should be exercised to ensure appropriate ownership ("pcp" user, typically) and permissions on this file (0400, so as to be unreadable by any user other than the user running the .B pmproxy process). .TP \f3\-U\f1 \f2username\f1 Assume the identity of .I username before starting to accept incoming packets from PCP monitoring clients. .TP \f3\-x\f1 \f2file\f1 Before the .B pmproxy .I logfile can be opened, .B pmproxy may encounter a fatal error which prevents it from starting. By default, the output describing this error is sent to .B /dev/tty but it may redirected to .IR file . .SH "STARTING AND STOPPING PMPROXY" Normally, .B pmproxy is started automatically at boot time and stopped when the system is being brought down. Under certain circumstances it is necessary to start or stop .B pmproxy manually. To do this one must become superuser and type .PP .ft CS # $PCP_RC_DIR/pmproxy start .ft .PP to start .BR pmproxy , or .PP .ft CS # $PCP_RC_DIR/pmproxy stop .ft .PP to stop .BR pmproxy . Starting .B pmproxy when it is already running is the same as stopping it and then starting it again. .P Normally .B pmproxy listens for PCP client connections on TCP/IP port number 44322 (registered at .IR http://www.iana.org/ ). Either the environment variable .B PMPROXY_PORT .B \-p command line option may be used to specify alternative port number(s) when .B PMPROXY_PORT or the .B \-p command line option may be used to specify alternative port number(s) when .B pmproxy is started; in each case, the specification is a comma-separated list of one or more numerical port numbers. Should both methods be used or multiple .B \-p options appear on the command line, .B pmproxy will listen on the union of the set of ports specified via all .B \-p options and the .B PMPROXY_PORT environment variable. If non-default ports are used with .B pmproxy care should be taken to ensure that .B PMPROXY_PORT is also set in the environment of any client application that will connect to .BR pmproxy , or that the extended host specification syntax is used (see .BR PCPIntro (1) for details). .SH FILES .PD 0 .TP .B PCP_PMPROXYOPTIONS_PATH command line options and environment variable settings for .B pmproxy when launched from .B $PCP_RC_DIR/pmproxy All the command line option lines should start with a hyphen as the first character. This file can also contain environment variable settings of the form "VARIABLE=value". .TP .B \&./pmproxy.log (or .B $PCP_LOG_DIR/pmproxy/pmproxy.log when started automatically) .br All messages and diagnostics are directed here .TP .B /etc/pki/nssdb default Network Security Services (NSS) certificate database directory, used for optional Secure Socket Layer connections. This database can be created and queried using the NSS .B certutil tool, amongst others. .PD .SH ENVIRONMENT In addition to the PCP environment variables described in the .B "PCP ENVIRONMENT" section below, there are several environment variables that influence the interactions between a PCP monitoring client, .B pmcd and .BR pmcd (1). .TP .B PMCD_PORT For the PCP monitoring client this (or the default port number) is passed to .B pmproxy and used to connect to .BR pmcd (1). In the environment of .B pmproxy .B PMCD_PORT is not used. .TP .B PMPROXY_HOST For the PCP monitoring client this is the hostname or IP address of the host where .B pmproxy is running. In recent versions of PCP (since version 3) this has been superseded by the extended hostname syntax (see .BR PCPIntro (1) for details). .TP .B PMPROXY_PORT For the PCP monitoring client this is the port on which .B pmproxy will accept connections. The default is 44322. .TP .BR PMCD_CONNECT_TIMEOUT ", " PMCD_RECONNECT_TIMEOUT " and " PMCD_REQUEST_TIMEOUT (see .BR PCPIntro (1)) For the PCP monitoring client, setting these environment variables will modify the timeouts used for interactions between the client and .BR pmproxy (independent of which .BR pmcd (1) is being used). For .B pmproxy these same environment variables control the timeouts between .B pmproxy and all .BR pmcd (1) instances (independent of which monitoring client is involved). .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmdbg (1), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS If .B pmproxy is already running the message "Error: OpenRequestSocket bind: Address already in use" will appear. This may also appear if .B pmproxy was shutdown with an outstanding request from a client. In this case, a request socket has been left in the TIME_WAIT state and until the system closes it down (after some timeout period) it will not be possible to run .BR pmproxy . .PP In addition to the standard .B PCP debugging flags, see .BR pmdbg (1), .B pmproxy currently uses .B DBG_TRACE_CONTEXT for tracing client connections and disconnections pcp-3.8.12ubuntu1/man/man1/pmprobe.10000664000000000000000000001400212272262501013734 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMPROBE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmprobe\f1 \- lightweight probe for performance metrics .SH SYNOPSIS \f3pmprobe\f1 [\f3\-fIiLVvz\f1] [\f3\-a\f1 \f2archive\f1] [\f3\-h\f1 \f2hostname\f1] [\f3\-K\f1 \f2spec\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-O\f1 \f2time\f1] [\f3\-Z\f1 \f2timezone\f1] [\f2metricname\f1 ...] .SH DESCRIPTION .B pmprobe determines the availability of performance metrics exported through the facilities of the Performance Co-Pilot (PCP). .PP The metrics of interest are named in the .I metricname arguments. If .I metricname is a non-leaf node in the Performance Metrics Name Space (\c .BR pmns (5)), then .B pmprobe will recursively descend the PMNS and report on all leaf nodes. If no .I metricname argument is given, the root of the namespace is used. .PP The output format is spartan and intended for use in wrapper scripts creating configuration files for other PCP tools. By default, there is one line of output per metric, with the metric name followed by a count of the number of available values. Error conditions are encoded as a negative value count (as per the .BR PMAPI (3) protocols, but may be decoded using .BR pmerr (1)) and followed by a textual description of the error. .PP Unless directed to another host by the .B \-h option, .B pmprobe will contact the Performance Metrics Collector Daemon (PMCD) on the local host. .PP The .B \-a option causes .B pmprobe to use the specified archive rather than connecting to a PMCD. The .B \-a and .B \-h options are mutually exclusive. .PP The .B \-L option causes .B pmprobe to use a local context to collect metrics from PMDAs on the local host without PMCD. Only some metrics are available in this mode. The .BR \-a , \-h and .B \-L options are mutually exclusive. .PP Normally .B pmprobe operates on the distributed Performance Metrics Name Space (PMNS), however, if the .B \-n option is specified an alternative local PMNS file is loaded from the file .IR pmnsfile . .PP Other options control the output of additional information when one or more values is available. .TP 5 .B \-f When used with .B \-i or .B \-I the set of instances reported will be all of those known at the source of the performance data. By default the set of reported instances are those for which values are currently available, which may be smaller than the set reported with .BR \-f . .TP .B \-I Report the external identifiers for each instance. The literal string .B PM_IN_NULL is reported for singular metrics. .TP .B \-i Report the internal identifiers for each instance. The values are in decimal and prefixed by ``?''. As a special case, the literal string .B PM_IN_NULL is reported for singular metrics. .TP .B \-K When using the .B \-L option to fetch metrics from a local context, the .B \-K option may be used to control the DSO PMDAs that should be made accessible. The .I spec argument conforms to the syntax described in .BR __pmSpecLocalPMDA (3). More than one .B \-K option may be used. .TP .B \-O When used in conjunction with an archive source of metrics and the .B \-v option the .I time argument defines a time origin at which the metrics should be fetched from the archive. Refer to .BR PCPIntro (1) for a complete description of this option, and the syntax for the .I time argument. .RS .PP When the ``ctime'' format is used for the .I time argument in a .B \-O option, the timezone becomes an issue. The default is to use the local timezone on the system where .B pmprobe is run. The .B \-Z option changes the timezone to .I timezone in the format of the environment variable .B TZ as described in .BR environ (5). The .B \-z option changes the timezone to the local timezone at the host that is the source of the performance metrics, as identified via the .B \-a option. .RE .TP .B \-v Report the value for each instance, as per the formatting rules of .BR pmPrintValue (3). When fetching from an archive, only those instances present in the first archive record for a metric will be displayed; see also the .B \-O option. .PP The .B \-v option is mutually exclusive with either the .B \-I or .B \-i options. .PP The .B \-V option provides a cryptic summary of the number of messages sent and received across the PMAPI interface. .SH EXAMPLES .nf .ft CW $ pmprobe disk.dev .ft CW disk.dev.read 2 disk.dev.write 2 disk.dev.total 2 disk.dev.blkread 2 disk.dev.blkwrite 2 disk.dev.blktotal 2 disk.dev.active 2 disk.dev.response 2 .sp .ft CW $ pmprobe \-I disk.dev.read disk.dev.write disk.all.total .ft CW disk.dev.read 2 "dks0d1" "dks0d2" disk.dev.write 2 "dks0d1" "dks0d2" disk.all.total 1 PM_IN_NULL .sp .ft CW $ pmprobe \-v pmcd.numagents pmcd.version pmcd.control.timeout .ft CW pmcd.numagents 1 9 pmcd.version 1 "2.0 beta-1" pmcd.control.timeout 1 5 .sp .ft CW $ pmprobe \-v disk.dev.total disk.all.total .ft CW disk.dev.total \-1012 Unknown metric name disk.all.total 1 4992466 .fi .ft R .SH FILES .PD 0 .TP 10 .BI $PCP_VAR_DIR/pmns/ * default PMNS specification files .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmdumplog (1), .BR pminfo (1), .BR PMAPI (3), .BR pmErrStr (3), .BR __pmSpecLocalPMDA (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). pcp-3.8.12ubuntu1/man/man1/genpmda.10000664000000000000000000001032512272262501013707 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH GENPMDA 1 "PCP" "Performance Co-Pilot" .SH NAME \f3genpmda\f1 \- Performance Co-Pilot PMDA Generator .SH SYNOPSIS \f3genpmda\f1 [\f3\-d\f1] [\f3\-D\f1 \f2domain\f1] [\f3\-s\f1 \f2stdpmid\f1] [\f3\-t\f1 \f2topdir\f1] [\f3\-n\f1 \f2pmns\f1] [\f3\-o\f1 \f2dir\f1] [\f3\-v\f1] \f3\-i\f1 \f2IAM\f1 \f3\-c\f1 \f2config\f1 .SH DESCRIPTION .B Genpmda is a rapid application development tool for creating new Performance Metrics Domain Agents, see .BR PMDA (3). It provides a very easy and efficient way to extend the Performance Co-pilot (PCP) with new performance metrics without needing to understand the low level details of how PMDAs are constructed. .PP .B Genpmda reads a config file containing an augmented Performance Metrics Name Space, see .BR pmns (5), and automatically generates virtually all of the source code to implement a fully functional PMDA, including the Makefile, name space, support scripts for configuring the new PMDA, and the metrics help text. Fairly simple PMDAs can be automatically generated from the config file without writing any additional code. More complicated PMDAs, e.g. containing multiple instance domains, require only the refresh methods for the instance domains to be written manually. .PP An example of the config file format accepted by .B genpmda is given below. .SH OPTIONS .TP 0 .B "Required options:" .TP 7 .BI "\-c" " config" input \f2config\f1 file, see example below .TP 7 .BI "\-i" " IAM" pmda name \f2IAM\f1, should appear in \f2stdpmid\f1 or the \f3\-D\f1 option must be used to specify a \f2domain\f1. .TP 0 .B "Other options:" .TP 7 .BI "\-d" generate an Install script for a daemon PMDA (default is DSO) .TP 7 .BI "\-t" " topdir" use \f2topdir\f1 in generated GNUmakefile, default \f3../../..\f1 .TP 7 .BI "\-n" " pmns" use \f2pmns\f1 as root of the namespace (default matches \f3\-i\f1 flag) .TP 7 .BI "\-D" " domain" use \f2domain\f1 number in the generated \f3pmns\f1 and \f3domain.h\f1 (if \f3\-s\f1 is not given) .TP 7 .BI "\-s" " stdpmid" path to \f2stdpmid\f1 (default \f3../../pmns/stdpmid\f1) .TP 7 .BI "\-o" " dir" use \f2dir\f1 for generated source code, default \f3./generated\f1 .TP 7 .BI "\-v" print verbose messages about what .B genpmda is doing. .PP Example: Generate an "example" pmda using domain 99: .br \f3genpmda \-D 99 \-v \-i EXAMPLE \-c example.conf\f1 Here is \f2example.conf\f1 config file (for the required \f3\-c\f1 option): .br .in +0.5i .sp .nf example { metric } example.metric { ## metric string ## pmid EXAMPLE:CLUSTER:0 ## indom PM_INDOM_NULL ## type PM_TYPE_STRING ## units PMDA_PMUNITS(0,0,0,0,0,0) ## semantics PM_SEM_DISCRETE ## briefhelptext one line help text for example.metric.string ## helptext long help text for example.metric.string ## helptext This is the second line of the long help text ## helptext and this is the third line. ## fetch function example_string_fetch_callback ## code atom->cp = "hello world"; ## code return 1; ## endmetric } .fi .sp 2 .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .PP .BR PMDA (3), .BR pmns (5), .BR pmcd (1), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS Many, but all are intended to be easily understood. pcp-3.8.12ubuntu1/man/man1/telnet-probe.10000664000000000000000000000435012272262501014675 0ustar '\"macro stdmacro .TH TELNET-PROBE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3telnet-probe\f1 \- lightweight telnet-like port probe .SH SYNOPSIS \f3$PCP_BINADM_DIR/telnet-probe\f1 [\f3\-c\f1] [\f3\-v\f1] \f2host\f1 \f2port\f1 .SH DESCRIPTION .B telnet-probe allows the .BR pmdashping (1) daemons to establish connections to arbitrary local and remote service-providing daemons so that response time and service availability information can be obtained. .PP The required .I host and .I port number arguments have the same meaning as their .BR telnet (1) equivalents. .PP The .B \-c option causes .B telnet-probe to perform a .BR connect (2) only. This skips the .BR read (2) and .BR write (2) exercise that would otherwise be done after connecting (see below). .PP The .B \-v option causes .B telnet-probe to be verbose while operating. .PP Once the telnet connection has been established, .B telnet-probe reads from .I stdin until end-of-file, and writes all the input data to the telnet connection. Next, .B telnet-probe will read from the telnet connection until end-of-file, discarding whatever data it receives. Then .B telnet-probe exits. .PP To operate successfully, the input passed via .B telnet-probe to the remote service must be sufficient to cause the remote service to close the connection when the last line of input has been processed, e.g. ending with ``quit'' when probing SMTP on port 25. .PP By default .B telnet-probe will not produce any output, unless there is an error in which case a diagnostic message can be displayed (in verbose mode only) and the exit status will be non-zero indicating a failure. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH DIAGNOSTICS If .B telnet-probe succeeds, then 0 will be returned. If the attempt to establish a connection fails or is terminated, then a non-zero exit status is returned. .SH SEE ALSO .BR PCPintro (1), .BR pmdashping (1), .BR pmie (1), .BR telnet (1), .BR connect (2), .BR read (2) and .BR write (2). pcp-3.8.12ubuntu1/man/man1/pmerr.10000664000000000000000000000345012272262501013422 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMERR 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmerr\f1 \- translate Performance Co-Pilot error codes into error messages .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS .B pmerr .I code \&... .br .B pmerr \f3\-l\f1 .SH DESCRIPTION .B pmerr accepts standard Performance Co-Pilot (PCP) error codes via the .I code argument(s) and generates the corresponding error text. .PP Each .I code may be an integer, a hexadecimal value or a hexadecimal value prefixed by either ``0x'' or ``0X''. .PP Error codes must be less than zero, so if .I code is a positive number, a warning message is produced, and the negated value is used. .PP The alternative use of the .B \-l option causes all known error codes to be listed, along with their symbolic names and error text. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PMAPI (3), .BR pmErrStr (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmdarpm.10000664000000000000000000000712112272262521013736 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMDARPM 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdarpm\f1 \- RPM packages performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/rpm/pmdarpm\f1 [\f3\-C\f1] [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-r\f1 \f2path\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION .B pmdarpm is a Performance Metrics Domain Agent (PMDA) which extracts performance metrics reflecting the state of the RPM package database managed by .BR rpm (1). .PP The .B rpm PMDA exports metrics that describe each package installed on a system, as well as some cumulative totals. When the RPM database changes the PMDA automatically detects this and uses a background thread to asynchronously refresh its values. .PP A brief description of the .B pmdarpm command line options follows: .TP 5 .B \-C Verify the package iteration code by scanning the RPM database once, then exiting. Only useful for problem diagnosis and testing. .TP .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I rpm.log is written in the current directory of .BR pmcd (1) when .B pmdarpm is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-r Specify an alternate path to the RPM database (default is .IR /var/lib/rpm/Packages ). .TP .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account. .SH INSTALLATION If you want access to the names, help text and values for the rpm performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/rpm # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/rpm # ./Remove .in .fi .ft 1 .PP .B pmdarpm is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdarpm .TP 10 .B $PCP_PMDAS_DIR/rpm/help default help text file for the rpm metrics .TP 10 .B $PCP_PMDAS_DIR/rpm/Install installation script for the .B pmdarpm agent .TP 10 .B $PCP_PMDAS_DIR/rpm/Remove undo installation script for the .B pmdarpm agent .TP 10 .B $PCP_LOG_DIR/pmcd/rpm.log default log file for error messages and other information from .B pmdarpm .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmdaapache.10000664000000000000000000001004112272262521014354 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMDAAPACHE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaapache\f1 \- Apache2 web server performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/apache/pmdaapache\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] [\f3\-S\f1 \f2server\f1] [\f3\-P\f1 \f2port\f1] [\f3\-L\f1 \f2location\f1] .SH DESCRIPTION .B pmdaapache is a Performance Metrics Domain Agent (PMDA) which extracts performance metrics describing the state of an Apache web server. .PP The .B apache PMDA exports metrics that measure the request rate, cumulative request sizes, uptime and various connection states for active clients. .PP This information is obtained by performing a HTTP request to the server status URL, which must be enabled in the .I httpd.conf configuration file. .P .ft CW .nf .in +0.5i ExtendedStatus on SetHandler server-status Order deny,allow Deny from all Allow from localhost .in .fi .ft 1 .PP A brief description of the .B pmdaapache command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I apache.log is written in the current directory of .BR pmcd (1) when .B pmdaapache is started, i.e. .B $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-S Query the Apache status information from the named .I server rather than the local host. .TP .B \-P Query the Apache status information from the given .I port rather than the default (80). .TP .B \-L Specify an alternative .I location for finding the server-status page. .TP .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .SH INSTALLATION If you want access to the names, help text and values for the apache performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/apache # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/apache # ./Remove .in .fi .ft 1 .PP .B pmdaapache is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdaapache .TP 10 .B $PCP_PMDAS_DIR/apache/help default help text file for the apache metrics .TP 10 .B $PCP_PMDAS_DIR/apache/Install installation script for the .B pmdaapache agent .TP 10 .B $PCP_PMDAS_DIR/apache/Remove undo installation script for the .B pmdaapache agent .TP 10 .B $PCP_LOG_DIR/pmcd/apache.log default log file for error messages and other information from .B pmdaapache .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR httpd (8), .BR pmcd (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/dbpmda.10000664000000000000000000003151512272262501013527 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH DBPMDA 1 "PCP" "Performance Co-Pilot" .SH NAME \f3dbpmda\f1 \- debugger for Performance Co-Pilot PMDAs .SH SYNOPSIS \f3dbpmda\f1 [\f3\-ei\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-q\f1 \f2timeout\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION .B dbpmda is an interactive interface to the interactions between a Performance Metric Domain Agent .RB ( PMDA (3)) and the Performance Metric Collector Daemon .RB ( pmcd (1)). This allows PMDAs to be attached, initialized and exercised to test for correctness. .PP .B dbpmda interactively prompts the user for commands, many of which emulate the Protocol Data Units (PDUs) that may be sent by a .BR pmcd (1) process. After running .BR dbpmda , enter the command .B help to get a list of the available commands. The example section below illustrates a session using .B dbpmda to test a PMDA. .PP To simplify repetitive testing of a PMDA, the file .I .dbpmdarc in the current working directory can contain a list of commands that will be executed by .B dbpmda on startup, before the user is prompted to enter further commands interactively. While processing the .I .dbpmdarc file, interactive mode and command echoing are enabled and then reset at the end of the .I .dbpmdarc file (see the .I \-i and .I \-e command line arguments below). .PP If the system supports .BR readline (3) then this will be used to read commands when input is from a tty device, so history and command line editing are available. .PP .B dbpmda accepts the following command line arguments: .TP .B \-e Echo the input to .BR stdout . This is useful when the input is redirected from a file. .TP .B \-i Emulate interactive behavior and prompt for new commands, even if standard input is not a tty device. .TP \f3\-n\f1 \f2pmnsfile\f1 Normally .B dbpmda operates on the distributed Performance Metrics Name Space (PMNS), however if the .B \-n option is specified an alternative local PMNS is loaded from the file .IR pmnsfile . .TP \f3\-q\f1 \f2timeout\f1 The pmcd to agent version exchange protocol (new in PCP 2.0 - introduced to provide backward compatibility) uses this timeout to specify how long \f3dbpmda\f1 should wait before assuming that no version response is coming from an agent. If this timeout is reached, the agent is assumed to be an agent which does not understand the PCP 2.0 protocol. The default timeout interval is five seconds, but the .B \-q option allows an alternative timeout interval (which must be greater than zero) to be specified. The unit of time is seconds. .TP \f3\-U\f1 \f2username\f1 User account under which to run .BR dbpmda . .PP As there are no timeout constraints on a PMDA while using .B dbpmda (as compared to .BR pmcd (1)), another debugger like .BR gdb (1) can be used on the PMDA process once it has been attached to .BR dbpmda . .SH EXAMPLE Below is a .B dbpmda session using the .I simple PMDA. A .B \.dbpmdarc file is used to set the debugging flag, open the PMDA and display the current status of the debugger: .PP .nf .ft CW .in +0.5i $ cat .dbpmdarc debug libpmda open dso pmda_simple.so simple_init 253 status .fi .in .PP When .B dbpmda is run, the commands in the .B \.dbpmdarc file are executed first: .PP .nf .ft CW .in +0.5i $ dbpmda \&.dbpmdarc> debug libpmda \&.dbpmdarc> open dso pmda_simple.so simple_init 253 [Fri Sep 19 10:19:55] dbpmda(11651) Debug: pmdaInit: PMDA simple DSO: Metric 0.0.1(1) matched to indom 253.0(0) [Fri Sep 19 10:19:55] dbpmda(11651) Debug: pmdaInit: PMDA simple DSO: help file $PCP_PMDAS_DIR/simple/help opened [Fri Sep 19 10:19:55] dbpmda(11651) Info: name = simple DSO [Fri Sep 19 10:19:55] dbpmda(11651) Info: domain = 253 [Fri Sep 19 10:19:55] dbpmda(11651) Info: num metrics = 4 [Fri Sep 19 10:19:55] dbpmda(11651) Info: num indom = 1 [Fri Sep 19 10:19:55] dbpmda(11651) Info: direct map = 1 \&.dbpmdarc> status Namespace: (default) PMDA: ./pmda_simple.so Connection: dso DSO Interface Version: 2 PMDA PMAPI Version: 2 pmDebug: 32768 ( libpmda ) Timer: off Getdesc: off Dump Instance Profile state=INCLUDE, 0 profiles \&.dbpmdarc> .fi .in .PP To examine the metric and instance descriptors, the .B desc and .B instance commands can be used. Metrics may be identified either by name, or using the ``dotted'' notation to specify the domain, cluster and item fields of a PMID. Instance domains must be identified using a ``dotted'' notation to specify the domain and serial fields. The syntax for most commands will be displayed if the command is given without any arguments: .PP .nf .ft CW .in +0.5i dbpmda> desc 253.0.0 PMID: 253.0.0 Data Type: 32-bit unsigned int InDom: PM_INDOM_NULL 0xffffffff Semantics: instant Units: none dbpmda> instance instance indom# [ number | name | "name" ] dbpmda> instance 253.0 pmInDom: 253.0 [ 0] inst: 0 name: "red" [ 1] inst: 1 name: "green" [ 2] inst: 2 name: "blue" .fi .in .PP To test the most important component of a PMDA, the .BR fetch , it is often useful to determine the time it takes the PMDA to respond. The .B timer may be turned on before giving a .BR fetch : .PP .nf .ft CW .in +0.5i dbpmda> timer on dbpmda> fetch simple.numfetch 253.0.1 PMID(s): 253.0.0 253.0.1 pmResult dump from 0x100078e0 timestamp: 0.000000 11:00:00.000 numpmid: 2 253.0.0 (simple.numfetch): numval: 1 valfmt: 0 vlist[]: value 1 1.4012985e-45 0x1 253.0.1 (simple.color): numval: 3 valfmt: 0 vlist[]: inst [0 or ???] value 1 1 1.4012985e-45 0x1 inst [1 or ???] value 101 1.4153114e-43 0x65 inst [2 or ???] value 201 2.8166099e-43 0xc9 Timer: 0.003921 seconds dbpmda> timer off .fi .in .PP The integer, floating point and hex translations of the values in the .I pmResult structure are dumped if .B getdesc is set to .B off (the default). Setting .B getdesc to .B on would result in only integer values being dumped in the above fetch as the descriptor describes the metrics of 32-bit unsigned integers. .PP The simple PMDA also supports the .B store operation which can be tested with subsequent .B fetch commands: .PP .nf .ft CW .in +0.5i dbpmda> store simple.numfetch "42" PMID: 253.0.0 Getting description... Getting Result Structure... 253.0.0: 2 -> 42 dbpmda> fetch simple.numfetch PMID(s): 253.0.0 pmResult dump from 0x100078e0 timestamp: 0.000000 11:00:00.000 numpmid: 1 253.0.0 (simple.numfetch): numval: 1 valfmt: 0 vlist[]: value 43 .fi .in .PP A .B profile can be specified for each instance domain which includes all, some or no instances: .PP .nf .ft CW .in +0.5i dbpmda> help profile profile indom# [ all | none ] profile indom# [ add | delete ] number For the instance domain specified, the profile may be changed to include 'all' instances, no instances, add an instance or delete an instance. dbpmda> profile 253.0 none dbpmda> getdesc on dbpmda> fetch 253.0.1 PMID(s): 253.0.1 pmResult dump from 0x100078e0 timestamp: 0.000000 11:00:00.000 numpmid: 1 253.0.1 (simple.color): No values returned! dbpmda> profile 253.0 add 2 dbpmda> fetch 253.0.1 PMID(s): 253.0.1 pmResult dump from 0x100078e0 timestamp: 0.000000 11:00:00.000 numpmid: 1 253.0.1 (simple.color): numval: 1 valfmt: 0 vlist[]: value 202 dbpmda> profile 253.0 add 0 dbpmda> fetch 253.0.1 PMID(s): 253.0.1 pmResult dump from 0x100078e0 timestamp: 0.000000 11:00:00.000 numpmid: 1 253.0.1 (simple.color): numval: 2 valfmt: 0 vlist[]: inst [0 or ???] value 2 inst [2 or ???] value 203 dbpmda> status PMDA = pmda_simple.so Connection = dso pmDebug = 32768 ( libpmda ) Timer = off Dump Instance Profile state=INCLUDE, 1 profiles Profile [0] indom=1061158913 [253.0] state=EXCLUDE 2 instances Instances: [2] [0] dbpmda> quit .fi .PP The .B watch command (usage: .B watch .I filename ) opens an xwsh window which tails the specified log file. This window must be closed by the user when no longer required. .PP The .B wait command is equivalent to .B sleep (1) and takes a single integer argument. .PP The introduction of dynamic subtrees in the PMNS and PMDA_INTERFACE_4 in .I libpcp_pmda has led to additional commands being supported in .B dbpmda to exercise the associated dynamic PMNS services. The examples below are based on the .I sample PMDA. .PP .nf .ft CW .in +0.5i $ dbpmda dbpmda> open pipe /var/lib/pcp/pmdas/sample/pmdasample \-d 29 dbpmda> Start pmdasample PMDA: /var/lib/pcp/pmdas/sample/pmdasample \-d 29 dbpmda> children sample.secret Metric: sample.secret non-leaf foo leaf bar dbpmda> traverse sample.secret.foo Metric: sample.secret.foo sample.secret.foo.bar.max.redirect sample.secret.foo.one sample.secret.foo.two sample.secret.foo.bar.three sample.secret.foo.bar.four sample.secret.foo.bar.grunt.five sample.secret.foo.bar.grunt.snort.six sample.secret.foo.bar.grunt.snort.huff.puff.seven dbpmda> pmid sample.secret.foo.bar.four Metric: sample.secret.foo.bar.four 29.0.1004 dbpmda> name 29.0.1006 PMID: 29.0.1006 sample.secret.foo.bar.grunt.snort.six .fi .in .PP The .B children command returns the next name component for all the direct descendants of a node within a dynamic subtree of the PMNS. The related .B traverse command returns the full metric names for all leaf nodes in the PMNS below the specified non-leaf node in a dynamic subtree of the PMNS. .PP The .B name and .B pmid commands exercise the translation of metric names to PMIDs (and vice versa) for metrics within a dynamic subtree of the PMNS. .PP If the commands .BR children , .BR traverse , .B pmid or .B name are used with a PMDA that is .B not using PMDA_INTERFACE_4 or with performance metric names that are not part of a dynamic subtree of the PMNS, then the PMDA would be expected to return errors (PM_ERR_NAME or PM_ERR_PMID) to reflect the fact that the operation is in error (outside a dynamic subtree of the PMNS it is .BR pmcd (1) and not the PMDA that is responsible for implementing these functions). .PP Client authentication mechanisms have been incorporated into the PMCS, providing per-user (and per-connection) information that is available to PMDAs. A PMDA using PMDA_INTERFACE_6 or later in .I libpcp_pmda is able to make use of the "attribute" method to gain visibility into these authenticated connections, with access to information including user and group identifiers, user name, and so on. The need to exercise and debug this interface has led to a new .B dbpmda command. The following example is based on the .I sample PMDA. .PP .nf .ft CW .in +0.5i $ dbpmda dbpmda> open pipe pmdasample \-D AUTH \-l logfile dbpmda> Start pmdasample PMDA: pmdasample \-D AUTH \-l logfile dbpmda> attr "username" "tanya" Attribute: username=tanya Success dbpmda> attr 11 "0" Attribute: userid=0 Success dbpmda> .fi .in .PP The .B attr command passes connection attributes (PCP_ATTR keys) and their values into a PMDA in much the same way that PMCD would for a client connection. .B dbpmda always passes a client context identifier of zero, and while no validity checking on values is performed only recognised attributes can be set. .PP In the example above the .I AUTH debug flag is set for the PMDA, which uses this in its attribute callback and records each attribute and value pair sent to it in its .IR logfile . .PP Note that authentication checks have already been performed by PMCD by the time a PMDA is presented with these attributes, so no further verification is necessary by the PMDA. .SH CAVEATS A value cannot be stored into metrics of type .B PM_TYPE_AGGREGATE or .BR PM_TYPE_EVENT . .PP .B dbpmda uses .BR fork (2) and .BR exec (2) to attach to daemon PMDAs. .B dbpmda makes no attempt to detect the termination of the daemon PMDA process, so it is possible for a PMDA to exit unexpectedly without any notification. However, any further communication attempts with the PMDA will result in errors which will indicate that the PMDA is no longer responding. .SH FILES .TP 10 .I ./.dbpmdarc List of commands to do on startup. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR gdb (1), .BR pmcd (1), .BR pmdbg (1), .BR exec (2), .BR fork (2), .BR PMAPI (3), .BR PMDA (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmsocks.10000664000000000000000000002037512272262501013761 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMSOCKS 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmsocks\f1 \- shell wrapper for performance monitoring across firewalls .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSYS \f3pmsocks\f1 \f2path\f1 [\f2args\f1 ...] .SH DESCRIPTION .B pmsocks allows Performance Co-Pilot (PCP) clients running on hosts located on the internal side of a TCP/IP firewall to monitor remote hosts on the other side of the firewall. This assumes the firewall has been configured with a compliant .B sockd daemon and the necessary access controls are satisfied. .SH "CONFIGURATION" .B pmsocks uses the .BR tsocks (5) library, which is not included with PCP. You can get .B tsocks from .IR http://www.progsoc.uts.edu.au/~delius/ . .SH "IRIX CONFIGURATION" On IRIX, .B pmsocks is simply a shell wrapper that sets the appropriate environment variables and then executes the .I path program with .I args arguments (if any). .B pmsocks works by setting the .B _RLD_LIST environment variable (see .BR rld (1)) to load a dynamic shared library (see .BR dso (5)) containing stubs for ``socksified'' network library functions; This ``socksified'' library is installed at .IR /usr/pcp/lib/libpcp_socks.so . .PP There are a number of conditions required for this to be successful and the user is strongly advised to read this whole manual page (in particular the .B CAVEAT section below) before attempting to use .BR pmsocks . .PP When .B pmsocks is installed, the .I /etc/pcp_socks.conf configuration file is also installed with minimum default settings. These settings specify that socket connections to the local host should be made directly, without contacting any socks server daemon. This is necessary so that PCP clients will be able to establish a local connection to the .BR X (1) server, and use PCP connections, possibly via a .B sockd daemon, to monitor remote hosts. In the present implementation of .BR pmsocks , non-direct connections to the .BR X (1) server do not work, hence if the display is remote, then the remote host must be on the same side of the firewall and .I /etc/pcp_socks.conf must be configured to connect directly to that host. .PP The format of .I /etc/pcp_socks.conf is identical to .IR /etc/socks.conf as documented in the .I "CSTC-4.2" socks distribution. This distribution may be obtained via information contained in the socks FAQ at .ce 1 ftp://coast.cs.purdue.edu/pub/tools/unix/socks/ .PP If other socks clients are being used, then it is generally safe to remove .I /etc/pcp_socks.conf and instead make a symbolic link to .IR /etc/socks.conf . The file formats are identical. .PP The default configuration should be customized to suit the local environment so that connections to hosts located on the same side of the firewall as the local host do not use the socks daemon unnecessarily. The default configuration is .sp 1 .in 1i direct LOCALHOSTNAME 255.255.255.255 # direct localhost .br sockd 0.0.0.0 0.0.0.0 # contact sockd everywhere else .in .sp 1 Note that the string .B LOCALHOSTNAME is dynamically substituted at run time with the name of the local host, as obtained by a call to .BR gethostname (2). Assuming the real IP address of the local host is .B 1.2.3.4 and that a normal class-c subnet is used locally, the most common customization would be to specify direct connections for all hosts on the local subnet, by inserting another ``direct'' line as follows: .sp 1 .in 1i direct LOCALHOSTNAME 255.255.255.255 # direct localhost .br direct 1.2.3.0 255.255.255.0 # direct on local subnet .br sockd 0.0.0.0 0.0.0.0 # contact sockd everywhere else .in .PP The order of lines is important \- the first line matching the requested destination IP address during a .BR connect (2) call (after the requested IP address has been masked by the third parameter of the .IR /etc/pcp_socks.conf line), specifies via the first parameter whether to contact the socks daemon or whether to attempt a direct connection. .SH "IRIX ENVIRONMENT VARIABLES" There are several environment variables used by .B pmsocks as follows: .TP 10 .B SOCKS_SERVER Specifies the host name or IP address of the host running the .B sockd daemon. Usually this is the name of the firewall host. .TP 10 .B SOCKS_PORT The TCP/IP port to use when contacting .B sockd on the .B SOCKS_SERVER host. The default is .BR 1080 . .TP 10 .B SOCKS_NS The host name of the name server to use, usually to resolve the IP address of .BR SOCKS_SERVER . .TP 10 .B SOCKS_DEBUG If present in the environment, .B libpcp_socks will print debugging information to the .I stderr stream. There are only two levels of debugging, on or off. This is only really useful for the developers because the debugging information assumes knowledge of the .B libpcp_socks source code. .TP 10 .B SOCKS_BANNER If this is set, whenever a client calls .B libpcp_socks it will echo a message to .I stdout containing version information. This can be useful to check .B libpcp_socks is working in the absence of verbose logging. .TP 10 .B _RLD_LIST .B pmsocks sets this to exactly .B /usr/pcp/lib/libpcp_socks.so:DEFAULT .br It is strongly recommended this NOT be set in the environment of interactive shells. .TP 10 .B PMCD_CONNECT_TIMEOUT Specifies the time-out, in seconds, for connections to .BR pmcd (1). When using .BR pmsocks , this may need to be increased from the default (5 seconds) due to the additional delays introduced as a result of using .BR sockd . See .BR PMAPI (3) for further details about this variable. .SH CAVEAT The following notes should be considered carefully: .TP 5 0) Because .B sockd can only handle TCP/IP sockets, .B pmsocks never attempts to use .B sockd for sockets of type .B SOCK_DGRAM or if the .B domain parameter in a call to .BR socket (2) is .B PF_UNIX (unix domain sockets should never need to use .B sockd anyway). .TP 5 1) Some firewall products do not support ``socksified'' applications, and in these cases, .B pmsocks cannot be used. In this case, it will be necessary to configure the firewall to allow connections through the firewall for the PMCD communications port, typically tcp/4321. .TP 5 2) The PCP protocol is TPC/IP-based and works with the socks protocol, but connections which use UDP/DATAGRAM sockets or remote X11 connections via .B sockd may not work. If the remote display host is on the same side of the firewall as the application, this may be circumvented by configuring the remote display host to use direct connections - see above. Also, using X11 display options which use shared memory may hang the X server when used with .BR pmsocks . .TP 5 3) If the .B pmsocks configuration file is not present, then .B pmsocks will exit with an error message. .TP 5 4) .B pmsocks uses the locally configured name server or resolver (see .BR resolver (5)) to resolve host names to IP addresses. This may or may not be capable of resolving host names on the other side of the firewall. .TP 5 5) When used over a WAN, often the .B sockd daemon will be a long way from the application. This may result in PCP client connections timing out before connecting to the remote .BR pmcd . If this is occurring, set the environment variable .B PMCD_CONNECT_TIMEOUT to a higher value than the default (5 seconds). Refer to .BR PMAPI (3) for further details about this variable. .TP 5 6) When using .B pmsocks to connect to .BR pmcd (1), but .I "``Connection Refused''" error messages are returned, it is not immediately obvious whether .BR pmcd (1) is returning the error or .BR sockd . .SH "COPYRIGHT NOTICE" .B tsocks is covered by the GPL license and is copyright Shaun Clowes (delius@progsoc.org). .SH "FILES" .TP 10 .B /etc/tsocks.conf configuration file .SH "SEE ALSO" .BR pmcd (1), .BR pminfo (1), .BR pmlogger (1), .BR pmval (1), .BR X (1), .BR PMAPI (3), .BR resolver (5), and .BR tsocks (5). pcp-3.8.12ubuntu1/man/man1/pmlogrewrite.10000664000000000000000000005575312272262501015032 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2011 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOGREWRITE 1 "" "Performance Co-Pilot" .SH NAME \f3pmlogrewrite\f1 \- rewrite Performance Co-Pilot archives .SH SYNOPSIS \f3$PCP_BINADM_DIR/pmlogrewrite\f1 [\f3\-Cdiqsvw \f1] [\f3\-c\f1 \f2config\f1] \f2inlog\f1 [\f2outlog\f1] .SH DESCRIPTION .de KW \\f(BI\\$1\\fP\\$2 .. .B pmlogrewrite reads a Performance Co-Pilot (PCP) archive log identified by .I inlog and creates a PCP archive log in .IR outlog . Under normal usage, the .B \-c option will be used to nominate a configuration file or files that contains specifications (see the .B "REWRITING RULES SYNTAX" section below) that describe how the data and metadata from .I inlog should be transformed to produce .IR outlog . .PP The typical uses for .B pmlogrewrite would be to accommodate the evolution of Performance Metric Domain Agents (PMDAs) where the names, metadata and semantics of metrics and their associated instance domains may change over time, e.g. promoting the type of a metric from a 32-bit to a 64-bit integer, or renaming a group of metrics. Refer to the .B EXAMPLES section for some additional use cases. .PP .B pmlogrewrite is most useful where PMDA changes, or errors in the production environment, result in archives that cannot be combined with .BR pmlogextract (1). By pre-processing the archives with .B pmlogrewrite the resulting archives may be able to be merged with .BR pmlogextract (1). .PP The input .I inlog must be a PCP archive log created by .BR pmlogger (1), or possibly one of the tools that read and create PCP archives, e.g. .BR pmlogextract (1) and .BR pmlogreduce (1). .PP If no .B \-c option is specified, then the default behavior simply creates .I outlog as a copy of .IR inlog . This is a little more complicated than .BR cat (1), as each PCP archive is made up of several physical files. .PP While .B pmlogrewrite may be used to repair some data consistency issues in PCP archives, there is also a class of repair tasks that cannot be handled by .B pmlogrewrite and .BR pmloglabel (1) may be a useful tool in these cases. .SH COMMAND LINE OPTIONS The command line options for .B pmlogrewrite are as follows: .TP 7 .B \-C Parse the rewriting rules and quit. .I outlog is not created. When .B \-C is specified, this also sets .B \-v and .B \-w so that all warnings and verbose messages are displayed as .I config is parsed. .TP 7 .BI \-c " config" If .I config is a file or symbolic link, read and parse rewriting rules from there. If .I config is a directory, then all of the files or symbolic links in that directory (excluding those beginning with a period ``.'') will be used to provide the rewriting rules. Multiple .B \-c options are allowed. .TP 7 .B \-d Desperate mode. Normally if a fatal error occurs, all trace of the partially written PCP archive .I outlog is removed. With the .B \-d option, the partially created .I outlog archive log is not removed. .TP 7 .B \-i Rather than creating .IR outlog , .I inlog is rewritten in place when the .B \-i option is used. A new archive is created using temporary file names and then renamed to .I inlog in such a way that if any errors (not warnings) are encountered, .I inlog remains unaltered. .TP 7 .B \-q Quick mode, where if there are no rewriting actions to be performed (none of the global data, instance domains or metrics from .I inlog will be changed), then .B pmlogrewrite will exit (with status 0, so success) immediately after parsing the configuration file(s) and .I outlog is not created. .TP 7 .B \-s When the ``units'' of a metric are changed, if the dimension in terms of space, time and count is unaltered, then the scaling factor is being changed, e.g. BYTE to KBYTE, or MSEC\u\s-3-1\s0\d to USEC\u\s-3-1\s0\d, or the composite MBYTE.SEC\u\s-3-1\s0\d to KBYTE.USEC\u\s-3-1\s0\d. The motivation may be (a) that the original metadata was wrong but the values in .I inlog are correct, or (b) the metadata is changing so the values need to change as well. The default .B pmlogrewrite behaviour matches case (a). If case (b) applies, then use the .B \-s option and the values of all the metrics with a scale factor change in each result will be rescaled. For finer control over value rescaling refer to the .KW RESCALE option for the .KW UNITS clause of the metric rewriting rule described below. .TP 7 .BI \-v Increase verbosity of diagnostic output. .TP 7 .BI \-w Emit warnings. Normally .B pmlogrewrite remains silent for any warning that is not fatal and it is expected that for a particular archive, some (or indeed, all) of the rewriting specifications may not apply. For example, changes to a PMDA may be captured in a set of rewriting rules, but a single archive may not contain all of the modified metrics nor all of the modified instance domains and/or instances. Because these cases are expected, they do not prevent .B pmlogrewrite executing, and rules that do not apply to .I inlog are silently ignored by default. Similarly, some rewriting rules may involve no change because the metadata in .I inlog already matches the intent of the rewriting rule to correct data from a previous version of a PMDA. The .B \-w flag forces warnings to be emitted for all of these cases. .PP The argument .I outlog is required in all cases, except when .B \-i is specified. .SH REWRITING RULES SYNTAX A configuration file contains zero or more rewriting rules as defined below. .PP Keywords and special punctuation characters are shown below in .KW bolditalic font and are case-insensitive, so .KW METRIC , .KW metric and .KW Metric are all equivalent in rewriting rules. .PP The character ``#'' introduces a comment and the remainder of the line is ignored. Otherwise the input is relatively free format with optional white space (spaces, tabs or newlines) between lexical items in the rules. .PP A .B global rewriting rule has the form: .PP .KW GLOBAL .KW { .I globalspec \&... .KW } .PP where .I globalspec is zero or more of the following clauses: .RS +4n .PP .KW HOSTNAME .KW -> .I hostname .RS +4n .PP Modifies the label records in the .I outlog PCP archive, so that the metrics will appear to have been collected from the host .IR hostname . .RE .PP .KW TIME .KW -> .I delta .RS +4n .PP Both metric values and the instance domain metadata in a PCP archive carry timestamps. This clause forces all the timestamps to be adjusted by .IR delta , where .I delta is an optional sign ``+'' (the default) or ``\-'', an optional number of hours followed by a colon ``:'', an optional number of minutes followed by a colon ``:'', a number of seconds, an optional fraction of seconds following a period ``.''. The simplest example would be ``30'' to increase the timestamps by 30 seconds. A more complex example would be ``\-23:59:59.999'' to move the timestamps backwards by one millisecond less than one day. .RE .PP .KW TZ .KW -> \f(BI"\fP\fItimezone\fP\f(BI"\fP .RS +4n .PP Modifies the label records in the .I outlog PCP archive, so that the metrics will appear to have been collected from a host with a local timezone of .IR timezone . .I timezone must be enclosed in quotes, and should conform to the valid timezone syntax rules for the local platform. .RE .RE .PP An .B indom rewriting rule modifies an instance domain and has the form: .PP .KW INDOM \fIdomain\fP\f(BI.\fP\fIserial\fP .KW { .I indomspec \&... .KW } .PP where .I domain and .I serial identify one or more existing instance domains from .I inlog \- typically .I domain would be an integer in the range 1 to 510 and .I serial would be an integer in the range 0 to 4194304. .PP As a special case .I serial could be an asterisk ``*'' which means the rule applies to every instance domain with a domain number of .IR domain . .PP If a designated instance domain is not in .I inlog the rule has no effect. .PP The .I indomspec is zero or more of the following clauses: .RS +4n .PP .KW INAME "\fIoldname\fP" .KW -> "\fInewname\fP" .RS +4n .PP The instance identified by the external instance name .I oldname is renamed to .IR newname . Both .I oldname and .I newname must be enclosed in quotes. .PP As a special case, the new name may be the keyword .KW DELETE (with no quotes), and then the instance .I oldname will be expunged from .I outlog which removes it from the instance domain metadata and removes all values of this instance for all the associated metrics. .PP If the instance names contain any embedded spaces then special care needs to be taken in respect of the PCP instance naming rule that treats the leading non-space part of the instance name as the unique portion of the name for the purposes of matching and ensuring uniqueness within an instance domain, refer to .BR pmdaInstance (3) for a discussion of this issue. .PP As an illustration, consider the hypothetical instance domain for a metric which contains 2 instances with the following names: .RS +4 .ft CW .nf red eek urk .fi .ft P .RE .PP Then some possible .KW INAME clauses might be: .TP +10n \f(CW"eek" -> "yellow like a flower"\fP Acceptable, .I oldname "eek" matches the "eek urk" instance. .TP +10n \f(CW"red" -> "eek"\fP Error, .I newname "eek" matches the existing "eek urk" instance. .TP +10n \f(CW"eek urk" -> "red of another hue"\fP Error, .I newname "red of another hue" matches the existing "red" instance. .RE .PP .KW INDOM .KW -> \fInewdomain\fP\f(BI.\fP\fInewserial\fP .RS +4n .PP Modifies the metadata for the instance domain and every metric associated with the instance domain. As a special case, .I newserial could be an asterisk ``*'' which means use .I serial from the .B indom rewriting rule, although this is most useful when .I serial is also an asterisk. So for example: .RS +4n .ft CW indom 29.* { indom -> 109.* } .ft P .RE will move all instance domains from domain 29 to domain 109. .RE .PP .KW INDOM .KW -> .KW DUPLICATE \fInewdomain\fP\f(BI.\fP\fInewserial\fP .RS +4n .PP A special case of the previous .KW INDOM clause where the instance domain is a duplicate copy of the \fIdomain\fP\f(BI.\fP\fIserial\fP instance domain from the .I indom rewriting rule, and then any mapping rules are applied to the copied \fInewdomain\fP\f(BI.\fP\fInewserial\fP instance domain. This is useful when a PMDA is split and the same instance domain needs to be replicated for domain \fIdomain\fP and domain \fInewdomain\fP. So for example if the metrics .I foo.one and .I foo.two are both defined over instance domain 12.34, and .I foo.two is moved to another PMDA using domain 27, then the following rewriting rules could be used: .RS +4n .ft CW indom 12.34 { indom -> duplicate 27.34 } .br metric foo.two { indom -> 27.34 pmid -> 27.*.* } .ft P .RE .RE .PP .KW INST \fIoldid\fP .KW -> \fInewid\fP .RS +4n .PP The instance identified by the internal instance identifier .I oldid is renumbered to .IR newid . Both .I oldid and .I newid are integers in the range 0 to 2\u\s-331\s0\d-1. .PP As a special case, .I newid may be the keyword .KW DELETE and then the instance .I oldid will be expunged from .I outlog which removes it from the instance domain metadata and removes all values of this instance for all the associated metrics. .RE .RE .PP A .B metric rewriting rule has the form: .PP .KW METRIC .I metricid .KW { .I metricspec \&... .KW } .PP where .I metricid identifies one or more existing metrics from .I inlog using either a metric name, or the internal encoding for a metric's PMID as \fIdomain\fP\f(BI.\fP\fIcluster\fP\f(BI.\fP\fIitem\fP. In the latter case, typically .I domain would be an integer in the range 1 to 510, .I cluster would be an integer in the range 0 to 4095, and .I item would be an integer in the range 0 to 1023. .PP As special cases .I item could be an asterisk ``*'' which means the rule applies to every metric with a domain number of .I domain and a cluster number of .IR cluster , or .I cluster could be an asterisk which means the rule applies to every metric with a domain number of .I domain and an item number of .IR item , or both .I cluster and .I item could be asterisks, and rule applies to every metric with a domain number of .IR domain . .PP If a designated metric is not in .I inlog the rule has no effect. .PP The .I metricspec is zero or more of the following clauses: .RS +4n .PP .KW DELETE .RS +4n .PP The metric is completely removed from .IR outlog , both the metadata and all values in results are expunged. .RE .PP .KW INDOM .KW -> \fInewdomain\fP\f(BI.\fP\fInewserial\fP [ .I pick ] .RS +4n .PP Modifies the metadata to change the instance domain for this metric. The new instance domain must exist in .IR outlog . .PP The optional .I pick clause may be used to select one input value, or compute an aggregate value from the instances in an input result, or assign an internal instance identifier to a single output value. If no .I pick clause is specified, the default behaviour is to copy all input values from each input result to an output result, however if the input instance domain is singular (indom .BR PM_INDOM_NULL ) then the one output value must be assigned an internal instance identifier, which is 0 by default, unless over-ridden by a .KW INST or .KW INAME clause as defined below. .PP The choices for .I pick are as follows: .TP +12n \f(BIOUTPUT FIRST\fP choose the value of the first instance from each input result .TP +12n \f(BIOUTPUT LAST\fP choose the value of the last instance from each input result .TP +12n \f(BIOUTPUT INST\fP \fIinstid\fP choose the value of the instance with internal instance identifier .I instid from each result; the sequence of rewriting rules ensures the .KW OUTPUT processing happens before instance identifier renumbering from any associated .B indom rule, so .I instid should be one of the internal instance identifiers that appears in .I inlog .TP +12n \f(BIOUTPUT INAME\fP "\fIname\fP" choose the value of the instance with .I name for its external instance name from each result; the sequence of rewriting rules ensures the .KW OUTPUT processing happens before instance renaming from any associated .B indom rule, so .I name should be one of the external instance names that appears in .I inlog .TP +12n \f(BIOUTPUT MIN\fP choose the smallest value in each result (metric type must be numeric and output instance will be 0 for a non-singular instance domain) .TP +12n \f(BIOUTPUT MAX\fP choose the largest value in each result (metric type must be numeric and output instance will be 0 for a non-singular instance domain) .TP +12n \f(BIOUTPUT SUM\fP choose the sum of all values in each result (metric type must be numeric and output instance will be 0 for a non-singular instance domain) .TP +12n \f(BIOUTPUT AVG\fP choose the average of all values in each result (metric type must be numeric and output instance will be 0 for a non-singular instance domain) .PP If the input instance domain is singular (indom .BR PM_INDOM_NULL ) then independent of any .I pick specifications, there is at most one value in each input result and so .KW FIRST , .KW LAST , .KW MIN , .KW MAX , .KW SUM and .KW AVG are all equivalent and the output instance identifier will be 0. .PP In general it is an error to specify a rewriting action for the same metadata or result values more than once, e.g. more than one .KW INDOM clause for the same instance domain. The one exception is the possible interaction between the .KW INDOM clauses in the .B indom and .B metric rules. For example the metric .I sample.bin is defined over the instance domain 29.2 in .I inlog and the following is acceptable (albeit redundant): .RS +4n .ft CW .nf indom 29.* { indom -> 109.* } metric sample.bin { indom -> 109.2 } .fi .ft P .RE However the following is an error, because the instance domain for .I sample.bin has two conflicting definitions: .RS +4n .ft CW .nf indom 29.* { indom -> 109.* } metric sample.bin { indom -> 123.2 } .fi .ft P .RE .RE .PP .KW INDOM .KW -> .KW NULL [ .I pick ] .RS +4n .PP The metric (which must have been previously defined over an instance domain) is being modified to be a singular metric. This involves a metadata change and collapsing all results for this metric so that multiple values become one value. .PP The optional .I pick part of the clause defines how the one value for each result should be calculated and follows the same rules as described for the non-NULL .KW INDOM case above. .PP In the absence of .IR pick , the default is .KW "OUTPUT FIRST" . .RE .PP .KW NAME .KW -> .I newname .RS +4n .PP Renames the metric in the PCP archive's metadata that supports the Performance Metrics Name Space (PMNS). .I newname should not match any existing name in the archive's PMNS and must follow the syntactic rules for valid metric names as outlined in .BR pmns (5). .RE .PP .KW PMID .KW -> \fInewdomain\fP\f(BI.\fP\fInewcluster\fP\f(BI.\fP\fInewitem\fP .RS +4n .PP Modifies the metadata and results to renumber the metric's PMID. As special cases, .I newcluster could be an asterisk ``*'' which means use .I cluster from the .B metric rewriting rule and/or .I item could be an asterisk which means use .I item from the .B metric rewriting rule. This is most useful when .I cluster and/or .I item is also an asterisk. So for example: .RS +4n .ft CW metric 30.*.* { pmid -> 123.*.* } .ft P .RE will move all metrics from domain 30 to domain 123. .RE .PP .KW SEM .KW -> .I newsem .RS +4n .PP Change the semantics of the metric. .I newsem should be the XXX part of the name of one of the .B PM_SEM_XXX macros defined in or .BR pmLookupDesc (3), e.g. .KW COUNTER for .BR PM_TYPE_COUNTER . .PP No data value rewriting is performed as a result of the .KW SEM clause, so the usefulness is limited to cases where a version of the associated PMDA was exporting incorrect semantics for the metric. .BR pmlogreduce (1) may provide an alternative in cases where re-computation of result values is desired. .RE .PP .KW TYPE .KW -> .I newtype .RS +4n .PP Change the type of the metric which alters the metadata and may change the encoding of values in results. .I newtype should be the XXX part of the name of one of the .B PM_TYPE_XXX macros defined in or .BR pmLookupDesc (3), e.g. .KW FLOAT for .BR PM_TYPE_FLOAT . .PP Type conversion is only supported for cases where the old and new metric type is numeric, so .BR PM_TYPE_STRING , .B PM_TYPE_AGGREGATE and .B PM_TYPE_EVENT are not allowed. Even for the numeric cases, some conversions may produce run-time errors, e.g. integer overflow, or attempting to rewrite a negative value into an unsigned type. .RE .PP .KW UNITS .KW -> .I newunits [ .KW RESCALE ] .RS +4n .PP .I newunits is six values separated by commas. The first 3 values describe the dimension of the metric along the dimensions of space, time and count; these are integer values, usually 0, 1 or \-1. The remaining 3 values describe the scale of the metric's values in the dimensions of space, time and count. Space scale values should be 0 (if the space dimension is 0), else the XXX part of the name of one of the .B PM_SPACE_XXX macros, e.g. .KW KBYTE for .BR PM_TYPE_KBYTE . Time scale values should be 0 (if the time dimension is 0), else the XXX part of the name of one of the .B PM_TIME_XXX macros, e.g. .KW SEC for .BR PM_TIME_SEC . Count scale values should be 0 (if the time dimension is 0), else .KW ONE for .BR PM_COUNT_ONE . .PP The .BR PM_SPACE_XXX , .B PM_TIME_XXX and .B PM_COUNT_XXX macros are defined in or .BR pmLookupDesc (3). .PP When the scale is changed (but the dimension is unaltered) the optional keyword .KW RESCALE may be used to chose value rescaling as per the .B \-s command line option, but applied to just this metric. .RE .PP When changing the domain number for a metric or instance domain, the new domain number will usually match an existing PMDA's domain number. If this is not the case, then the new domain number should not be randomly chosen; consult .B $PCP_VAR_DIR/pmns/stdpmid for domain numbers that are already assigned to PMDAs. .SH EXAMPLES .PP To promote the values of the per-disk IOPS metrics to 64-bit to allow aggregation over a long time period for capacity planning, or because the PMDA has changed to export 64-bit counters and we want to convert old archives so they can be processed alongside new archives. .RS +4 .ft CW .nf metric disk.dev.read { type -> U64 } metric disk.dev.write { type -> U64 } metric disk.dev.total { type -> U64 } .fi .ft P .RE .PP The instances associated with the load average metric .B kernel.all.load could be renamed and renumbered by the rules below. .RS +4 .ft CW .nf # for the Linux PMDA, the kernel.all.load metric is defined # over instance domain 60.2 indom 60.2 { inst 1 -> 60 iname "1 minute" -> "60 second" inst 5 -> 300 iname "5 minute" -> "300 second" inst 15 -> 900 iname "15 minute" -> "900 second" } .fi .ft P .RE .PP If we decide to split the ``proc'' metrics out of the Linux PMDA, this will involve changing the domain number for the PMID of these metrics and the associated instance domains. The rules below would rewrite an old archive to match the changes after the PMDA split. .RS +4 .ft CW .nf # all Linux proc metrics are in 7 clusters metric 60.8.* { pmid -> 123.*.* } metric 60.9.* { pmid -> 123.*.* } metric 60.13.* { pmid -> 123.*.* } metric 60.24.* { pmid -> 123.*.* } metric 60.31.* { pmid -> 123.*.* } metric 60.32.* { pmid -> 123.*.* } metric 60.51.* { pmid -> 123.*.* } # only one instance domain for Linux proc metrics indom 60.9 { indom -> 123.0 } .fi .ft P .RE .SH FILES .PD 0 For each of the .I inlog and .I outlog archive logs, several physical files are used. .TP 10 \f2archive\f3.meta metadata (metric descriptions, instance domains, etc.) for the archive log .TP \f2archive\f3.0 initial volume of metrics values (subsequent volumes have suffixes .BR 1 , .BR 2 , \&...). .TP \f2archive\f3.index temporal index to support rapid random access to the other files in the archive log. .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmdaInstance (3), .BR pmdumplog (1), .BR pmlogger (1), .BR pmlogextract (1), .BR pmloglabel (1), .BR pmlogreduce (1), .BR pmLookupDesc (3), .BR pmns (5), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS All error conditions detected by .B pmlogrewrite are reported on .I stderr with textual (if sometimes terse) explanation. .PP Should the input archive log be corrupted (this can happen if the .B pmlogger instance writing the log suddenly dies), then .B pmlogrewrite will detect and report the position of the corruption in the file, and any subsequent information from that archive log will not be processed. .PP If any error is detected, .B pmlogrewrite will exit with a non-zero status. pcp-3.8.12ubuntu1/man/man1/collectl2pcp.10000664000000000000000000000444012272262501014663 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH COLLECTL2PCP 1 "PCP" "Performance Co-Pilot" .SH NAME \f3collectl2pcp\f1 \- import collectl data to a PCP archive .SH SYNOPSIS \f3collectl2pcp\f1 [\f3\-F\f1] [\f3\-v\f1] [\f3\-?\f1] \f2file\f1 [\f2file\f1 ...] \f2archive\f1 .SH DESCRIPTION .B collectl2pcp reads raw .BR collectl (1) data from each \f2file\f1 and creates a new PCP archive with basename \f2archive\f1. Each input \f2file\f1 may be gzipped (with \f3.gz\f1 suffix). The PCP \f2archive\f1 and at least one input \f2file\fP are required arguments. .PP The options to .B collectl2pcp are as follows. .TP \f3\-F\f1 Overwrite \f2archive\fP (and the index and meta files) if it already exists. .TP \f3\-v\f1 Report progress and errors verbosely. This also reports a count of unsupported metric data in the .BR collectl (1) input file(s), which is normally silently skipped. .TP \f2file\f1 [\f2file\f1 ...] These are the .BR collectl (1) input files. If more than one is given, they must contain data for the same host and be given in time-stamp chronological order on the command line. Note that when .BR collectl (1) is run as a service, it normally creates files with date based names that will sort chronologically (e.g. \f3/var/log/collectl/*.gz\f1 will be sorted correctly). .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR collectl (1), .BR pmcollectl (1), .BR PCPIntro (1), .BR LOGIMPORT (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). pcp-3.8.12ubuntu1/man/man1/pmstat.10000664000000000000000000002033012272262501013601 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMSTAT 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmstat\f1 \- high-level system performance overview .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS \f3pmstat\f1 [\f3\-gLlPxz\f1] [\f3\-A\f1 \f2align\f1] [\f3\-a\f1 \f2archive\f1] [\f3\-h\f1 \f2host\f1] [\f3\-H\f1 \f2file\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-O\f1 \f2offset\f1] [\f3\-p\f1 \f2port\f1] [\f3\-S\f1 \f2starttime\f1] [\f3\-s\f1 \f2samples\f1] [\f3\-T\f1 \f2endtime\f1] [\f3\-t\f1 \f2interval\f1] [\f3\-Z\f1 \f2timezone\f1] .SH DESCRIPTION .B pmstat provides a one line summary of system performance every .I interval unit of time (the default is 5 seconds). .B pmstat is intended to monitor system performance at the highest level, after which other tools may be used to examine subsystems in which potential performance problems may be observed in greater detail. .P Multiple hosts may be monitored by supplying more than one host with multiple .B \-h flags (for live monitoring) or by providing a name of the hostlist file, where each line contain one host name, with .B \-H, or multiple .B \-a flags (for retrospective monitoring from an archive). .P The .B \-t option may be used to change the default reporting .IR interval . The .I interval argument follows the syntax described in .BR PCPIntro (1), and in the simplest form may be an unsigned integer (the implied units in this case are seconds). .PP By default, .B pmstat fetches metrics by connecting to the Performance Metrics Collector Daemon (PMCD) on the local host. If the .B \-L option is specified, then .BR pmcd (1) is bypassed, and metrics are fetched from PMDAs on the local host using the standalone .B PM_CONTEXT_LOCAL variant of .BR pmNewContext (3). When the .B \-h option is specified, .B pmstat connects to the .BR pmcd (1) on .I host and fetches metrics from there. As mentioned above, multiple hosts may be monitored by supplying multiple .B \-h flags. .PP Alternatively, if the .B \-a option is used, the metrics are retrieved from the Performance Co-Pilot archive log files identified by the base name .IR archive . Multiple archives may be replayed by supplying multiple .B \-a flags. When the .B \-a flag is used, the .B \-P flag may also be used to pause the output after each interval. .PP Standalone mode can only connect to the local host, using an archive implies a host name, and nominating a host precludes using an archive, so the options .BR \-L , .B \-a and .B \-h are mutually exclusive. .PP Normally .B pmstat operates on the default Performance Metrics Name Space (PMNS), however if the .B \-n option is specified an alternative namespace is loaded from the file .IR pmnsfile . .PP If the .B \-s the option is specified, .I samples defines the number of samples to be retrieved and reported. If .I samples is 0 or .B \-s is not specified, .B pmstat will sample and report continuously \- this is the default behavior. .PP When processing an archive, .B pmstat may relinquish its own timing control, and operate as a ``slave'' of a .BR pmtime (1) process that uses a GUI dialog to provide timing control. In this case, either the .B \-g option should be used to start .B pmstat as the sole slave of a new .BR pmtime (1) instance, or .B \-p should be used to attach .B pmstat to an existing .BR pmtime (1) instance via the IPC channel identified by the port argument. .PP The .BR \-S , .BR \-T , .BR \-O and .B \-A options may be used to define a time window to restrict the samples retrieved, set an initial origin within the time window, or specify a ``natural'' alignment of the sample times; refer to .BR PCPIntro (1) for a complete description of these options. .PP The .B \-l option prints the last 7 characters of a hostname in summaries involving more than one host (when more than one .B \-h option has been specified on the command line). .PP The .B \-x option (extended CPU metrics) causes two additional CPU metrics to be reported, namely wait for I/O ("wa") and virtualisation steal time ("st"). .PP The output from .B pmstat is directed to standard output, and the columns in the report are interpreted as follows: .PP .TP 10 .B loadavg The .I "1 minute" load average. .TP .B memory The \f3swpd\fP column indicates average swap space used during the interval, in Kbytes. The \f3free\fP column indicates average free memory during the interval, in Kbytes. The \f3buff\fP column indicates average buffer memory in use during the interval, in Kbytes. The \f3cache\fP column indicates average cached memory in use during the interval, in Kbytes. .RS .PP If the values become large, they are reported as Mbytes .BR "" ( m " suffix)" or Gbytes .BR "" ( g " suffix)." .RE .TP .B swap The metrics in this area of the kernel instrumentation are of varying value. We try to report the average number of \f3pages\fP that are paged in (\f3pi\fP) and out (\f3po\fP) per second during the interval. If the corresponding page swapping metrics are unavailable, we report the average rate per second of swap \f3operations\fP in (\f3si\fP) and out (\f3so\fP) during the interval. It is normal for the ``in'' values to be non-zero, but the system is suffering memory stress if the ``out'' values are non-zero over an extended period. .RS .PP If the values become large, they are reported as thousands of operations per second .BR "" ( K " suffix)" or millions of operations per second .BR "" ( M " suffix)." .RE .TP .B io The \f3bi\fP and \f3bo\fP columns indicate the average rate per second of block input and block output operations (respectfully) during the interval. Unless all file systems have a 1 Kbyte block size, these rates do not directly indicate Kbytes transferred. .RS .PP If the values become large, they are reported as thousands of operations per second .BR "" ( K " suffix)" or millions of operations per second .BR "" ( M " suffix)." .RE .TP .B system Interrupt rate (\f3in\fP) and context switch rate (\f3cs\fP). Rates are expressed as average operations per second during the interval. Note that the interrupt rate is normally at least .I HZ (the clock interrupt rate, usually 100) interrupts per second. .RS .PP If the values become large, they are reported as thousands of operations per second .BR "" ( K " suffix)" or millions of operations per second .BR "" ( M " suffix)." .RE .TP .B cpu Percentage of CPU time spent executing user and "nice user" code (\f3us\fP), system and interrupt processing code (\f3sy\fP), idle loop (\f3id\fP). .P If any values for the associated performance metrics are unavailable, the value appears as ``?'' in the output. .PP By default, .B pmstat reports the time of day according to the local timezone on the system where .B pmstat is run. The .B \-Z option changes the timezone to .I timezone in the format of the environment variable .B TZ as described in .BR environ (5). The .B \-z option changes the timezone to the local timezone at the host that is the source of the performance metrics, as identified via either the .B \-h or .B \-a options. .SH FILES .PD 0 .TP 10 .BI $PCP_VAR_DIR/pmns/ * default PMNS specification files .TP .BI $PCP_SYSCONF_DIR/pmlogger/config.pmstat .BR pmlogger (1) configuration for creating an archive suitable for replay with .B pmstat .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmclient (1), .BR pmtime (1), .BR PMAPI (3), .BR pmNewContext (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS All are generated on standard error, and are intended to be self-explanatory. pcp-3.8.12ubuntu1/man/man1/pmdasimple.10000664000000000000000000001132212272262501014425 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .\" I am variants ... .ds ia simple .ds IA SIMPLE .ds Ia Simple .TH PMDASIMPLE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdasimple\f1 \- \*(ia performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/\*(ia/pmda\*(ia\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-i\f1 \f2port\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-p\f1] [\f3\-u\f1 \f2socket\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION .B pmda\*(ia is a \*(ia Performance Metrics Domain Agent (PMDA) which exports a small number of synthetic performance metrics. .PP The \*(ia PMDA is shipped as source code and is designed to be an aid for PMDA developers. In terms of code size and features, it is more complex than the trivial PMDA, about the same as the txmon PMDA and less complex than the sample PMDA. The source for the \*(ia PMDA is a good template from which production, customized PMDAs can be developed. .PP A brief description of the .B pmda\*(ia command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-i Expect PMCD to connect to .B pmda\*(ia on the specified TCP/IP port. .I port may be a port number or port name. .TP .B \-l Location of the log file. By default, a log file named .I \*(ia.log is written in the current directory of .BR pmcd (1) when .B pmda\*(ia is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-p Expect PMCD to create a pipe and the connection to .B pmda\*(ia is via standard input and standard output. This is the default connection mode. .TP .B \-u Expect PMCD to connect to .B pmda\*(ia on the Unix domain socket named .IR socket . .TP 5 .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .PP At most one of the options .BR \-i , .B \-p and .B \-u may be specified. .SH INSTALLATION If you want access the names, help text and values for the \*(ia performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/\*(ia # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/\*(ia # ./Remove .in .fi .ft 1 .PP .B pmda\*(ia is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmda\*(ia .TP .B $PCP_PMDAS_DIR/\*(ia/help default help text file for the \*(ia metrics .TP .B $PCP_PMDAS_DIR/\*(ia/Install installation script for the .B pmda\*(ia agent .TP .B $PCP_PMDAS_DIR/\*(ia/Remove undo installation script for the .B pmda\*(ia agent .TP .B $PCP_PMDAS_DIR/\*(ia/simple.conf configuration file for the dynamic instance domain that underlies the .B simple.now performance metric. For a description, refer to the help text file, or run the command .sp 0.5v .ft CW $ pminfo \-T simple.now .ft P .sp 0.5v .TP .B $PCP_PMDAS_DIR/\*(ia/*.pmda_simple.so The DSO version of the PMDA. The same source is used to create both the DSO and the daemon versions of the \*(ia PMDA, and one or the other may be installed as part of the dialog in the .B Install script. .TP .B $PCP_LOG_DIR/pmcd/simple.log default log file for error messages and other information from .B pmda\*(ia .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmdasample (1), .BR pmdatrivial (1), .BR pmdatxmon (1), .BR PMDA (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmdacisco.10000664000000000000000000002114212272262501014235 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDACISCO 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdacisco\f1 \- Cisco router performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/cisco/pmdacisco\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] [\f3\-P\f1 \f2password\f1] [\f3\-r\f1 \f2refresh\f1] [\f3\-s\f1 \f2prompt\f1] [\f3\-M\f1 \f2username\f1] [\f3\-x\f1 \f2port\f1] \f2host:interface-spec\f1 [...] .br \f3$PCP_PMDAS_DIR/cisco/parse\f1 [options] \f2host:interface-spec\f1 [...] .br \f3$PCP_PMDAS_DIR/cisco/probe\f1 [\f3\-P\f1 \f2password\f1] [\f3\-s\f1 \f2prompt\f1] [\f3\-U\f1 \f2username\f1] [\f3\-x\f1 \f2port\f1] \f2host\f1 .SH DESCRIPTION .B pmdacisco is a Performance Metrics Domain Agent (PMDA) which extracts performance metrics from one or more Cisco routers. .PP A brief description of the .B pmdacisco command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP 5 .B \-l Location of the log file. By default, a log file named .I cisco.log is written in the current directory of .BR pmcd (1) when .B pmdacisco is started, i.e. .IR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP 5 .B \-P By default, it is assumed that no user-level password is required to access the Cisco's telnet port. If user-level passwords have been enabled on the Ciscos, then those passwords must be specified to .BR pmdacisco . If specified with the .B \-P option, .I password will be used as the default user-level password for all Ciscos. See also the INTERFACE IDENTIFICATION section below. .TP 5 .B \-r .B pmdacisco will refresh the current values for all performance metrics by contacting each Cisco router once every .I refresh seconds. The default .I refresh is 120 seconds. .TP 5 .B \-s The Cisco command prompt ends with the string .IR prompt . The default value is ``>''. The only way .B pmdacisco can synchronize the sending of commands and the parsing of output is by recognizing .I prompt as a unique string that comes at the end of all output, i.e. as the command prompt when waiting for the next command. .TP 5 .B \-U By default, it is assumed that no username login is required to access the Cisco's telnet port. If username login has been enabled on the Ciscos, then the corresponding usernames must be specified to .BR pmdacisco . If specified with the .B \-U option, .I username will be used as the default username login for all Ciscos. See also the INTERFACE IDENTIFICATION section below. .TP 5 .B \-M User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .TP 5 .B \-x Connect to the Cisco via TCP port number .I port rather than the default 23 for a telnet connection. .PP For each interface, once the telnet connection is established, .B pmdacisco is willing to wait up to 5 seconds for the Cisco to provide a new snapshot of the requested information. If this does not happen, the telnet connection is broken and no values are returned. This prevents .B pmdacisco tying up the Cisco's telnet ports waiting indefinitely when the response from the router is not what is expected, e.g. if the format of the ``show int'' output changes, or the command is in error because an interface is no longer configured on the router. .SH INTERFACE IDENTIFICATION As each Cisco router can support multiple network interfaces and/or multiple communications protocols, it is necessary to tell .B pmdacisco which interfaces are to be monitored. .PP The .I host:interface-spec arguments on the command line define a particular interface on a particular Cisco router. .I host should be a hostname or a ``dot-notation'' IP address that identifies the telnet port of a particular Cisco router. There are several components of the .I interface-spec as follows. .TP protocol One of the abbreviations .BR a , .BR B , .BR E , .BR e , .BR f , .BR G , .BR h , .B s or .B Vl respectively for ATM, BRI (ISDN), FastEthernet, Ethernet, FDDI, GigabitEthernet, HSSI, serial or Vlan. .TP interface Depending on the model of the Cisco, this will either be an integer, e.g.\& .BR s0 , or an integer followed by a slash (``/'') followed by a subinterface identification in one of a variety of syntactic forms, e.g.\& .BR e1/0 , .B G0/0/1 or .BR s4/2.1 . .RS .P To discover the valid interfaces on a particular Cisco, connect to the telnet port (using .BR telnet (1)) and enter the command "show int" and look for the interface identifiers following the keywords ``Ethernet'', ``Fddi'', ``Serial'', etc. .P Alternatively run the .BR probe command. .RE .TP username If there is a username login, and it is different to the default (see .B \-U above), it may be optionally specified here by appending \&``@'' and the username to the end of .IR interface-spec . .TP password If there is a user-level password, and it is different to the default (see .B \-P above), it may be optionally specified here by appending a question mark (``?'') and the password to the end of .IR interface-spec . .TP prompt If the Cisco command prompt is different to the default (see .B \-s above), it may be optionally specified here by appending an exclamation mark (``!'') and the prompt to the end of .IR interface-spec . .PP The following are examples of valid .I interface-spec arguments. .in +1i .nf my-router:e1/2 123.456.789.0:s0 wancisco:f2/3?trust_me somecisco:G1/0!myprompt cisco34.foo.bar.com:e2?way2cool mycisco:s2/2.1@mylogin yourcisco:E0/0@yourlogin?yourpassword mycisco:E0/0@mylogin?mypassword!myprompt .fi .in .SH HELPER UTILITIES The .B probe command may be used to discover the names of all interfaces for a particular Cisco router identified by .IR host . The .BR \-P argument is the same as for .BR pmdacisco . .PP The .B parse command takes exactly the same arguments as .BR pmdacisco , but executes outside the control of any .BR pmcd (1) and so may be used to diagnose problems with handling a particular Cisco router and/or one of its interfaces. .PP Additional diagnostic verbosity may be produced using the .B "\-D appl0,appl1,appl2" command line option. .B appl0 logs connect and disconnect events, login progress, high-level flow of control and extracted statistics. .B appl1 traces all commands sent to the Cisco device. .B appl2 logs tokenizing and parsing of the output from the Cisco device. Diagnostics are generated on standard error as each sample is fetched and parsed. .SH INSTALLATION If you want access to the names, help text and values for the Cisco performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/cisco # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/cisco # ./Remove .in .fi .ft 1 .PP .B pmdacisco is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdacisco .TP 10 .B $PCP_PMDAS_DIR/cisco/help default help text file for the Cisco metrics .TP 10 .B $PCP_PMDAS_DIR/cisco/Install installation script for the .B pmdacisco agent .TP 10 .B $PCP_PMDAS_DIR/cisco/Remove undo installation script for the .B pmdacisco agent .TP 10 .B $PCP_LOG_DIR/pmcd/cisco.log default log file for error messages and other information from .B pmdacisco .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmcd (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmwtf.10000664000000000000000000001036312272262501013433 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMWTF 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmwtf\f1 \- compares archives and report significant differences .SH SYNOPSIS \f3pmwtf\f1 [\f3\-dz\f1] [\f3\-p\f1 \f2precision\f1] [\f3\-q\f1 \f2thres\f1] [\f3\-S\f1 \f2starttime\f1] [\f3\-T\f1 \f2endtime\f1] [\f3\-B\f1 \f2starttime\f1] [\f3\-E\f1 \f2endtime\f1] [\f3\-x\f1 \f2metric\f1] [\f3\-X\f1 \f2file\f1] [\f3\-Z\f1 \f2timezone\f1] \f2archive1\f1 [\f2archive2\f1] .SH DESCRIPTION .B pmwtf compares the average values for every metric in either one or two archives, in a given time window, for changes that are likely to be of interest when searching for performance regressions. .PP The archive log has the base name .I archive and must have been previously created using .BR pmlogger (1). The .BR pmlogsummary (1) utility is used to obtain the average values used for comparison. .PP There are two sorts of invocation of the tool: with either one or two archives. .PP In the first case, the only sensible command line requires use of all four time window arguments. These are specified using the same time window format described in .BR PCPIntro (1), and are .B \-S and .B \-T for the start and end times of the first time window of interest in the archive, and .B \-B and .B \-E for the start and end times of the second time window of interest. .PP In the second case, with two archives, the .B \-B and .B \-E options might be unnecessary. This might be the case, for example, when comparing the same time window of two consecutive days (usually two separate archives), or a time window on the same day of different weeks. .PP In either case, .B pmwtf produces a sorted summary of those metrics in the specified window whose values have deviated the most from a minimal threshold. The level of deviation is calculated by dividing the average value of each metric in both logs, and then calculating whether the ratio falls outside of a range considered normal. This ratio can be adjusted using the .B \-q option, and by default it is 2 (i.e. report all metrics with average values that have more than doubled in the two time windows or more than halved in the two time windows). .PP Should any metrics be present in one window but missing from the other, a diagnostic will be displayed listing each missing metric and the archive from which it was missing. .PP The remaining options control the specific information to be reported. Metrics with counter semantics are converted to rates before being evaluated. .TP 5 .B \-p Print all floating point numbers with .I precision digits after the decimal place. .TP .B \-x Compare each metric in each archive in the time windows specified to a given .BR egrep (1) pattern, excluding those that match from the report output. .TP .B \-X Allows a .IR file to be specified which containing .BR egrep (1) patterns which are applied to the metric names to optionally exclude some from the report. .TP .B \-z Use the local timezone from the given archives. .TP .B \-Z Changes the timezone in the archive labels to .I timezone in the format of the environment variable .B TZ as described in .BR environ (5). .PP .SH FILES .PD 0 .TP 10 .BI $PCP_LOG_DIR/pmlogger/ hostname Default directory for PCP archives containing performance metric values collected from the host .IR hostname . .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmlogger (1), .BR pmlogsummary (1), .BR egrep (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmgenmap.10000664000000000000000000001321312272262501014077 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMGENMAP 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmgenmap\f1 \- generate C code to simplify handling of performance metrics .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS \f3pmgenmap\f1 [\f2infile\f1] .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Given one or more lists of metric names in .I infile or on standard input, .B pmgenmap generates C declarations and .BR cpp (1) macros suitable for use across the Performance Metrics Programming Interface (PMAPI) on standard output. .PP The declarations produced by .B pmgenmap simplify the coding for client applications using the PMAPI. .PP The input should consist of one or more lists of metric names of the form .PP .ft CW .nf .in +0.5i listname { metricname1 symbolname1 metricname2 symbolname2 ... } .in .fi .ft 1 .PP which will generate C and .BR cpp (1) declarations of the form .PP .ft CW .nf .in +0.5i char *listname[] = { #define symbolname1 0 "metricname1", #define symbolname2 1 "metricname2", ... }; .in .fi .ft 1 .PP The array declarations produced are suitable as parameters to .BR pmLookupName (3) and the .BR #define d constants may be used to index the .CW vset s in the .CW pmResult structure returned by a .BR pmFetch (3) call. .PP Obviously, .CW listname must conform to the C identifier naming rules, each .CW symbolname must conform to the .BR cpp (1) macro naming rules, and each .CW metricname is expected to be a valid performance metrics name (see .BR pmns (5) for more details). .PP The input may include .BR sh -style comment lines, i.e. with a `\f3#\f1' as the first non-blank character of a line, and these are translated on output to either single line or multi-line C comments in the K&R style. For example, the input: .PP .ft CW .nf .in +0.5i # leading block of multi-line comments # initialization group foo { a.b.c ONE d.e.f.g TWO # embedded block of multi-lines # comments and boring pad text xx.yy.zz THREE } # trailing single line comment .in .fi .ft 1 .PP Produces the output: .PP .ft CW .nf .in +0.5i /* * leading block of multi-line comments * initialization group */ char *foo[] = { #define ONE 0 "a.b.c", #define TWO 1 "d.e.f.g", /* * embedded block of multi-lines * comments and boring pad text */ #define THREE 2 "xx.yy.zz", }; /* trailing single line comment */ .in .fi .ft 1 .SH EXAMPLE For brevity we have removed the error handling code, and assumed the chosen metrics do not have multiple values. .PP The input file .PP .ft CW .nf .in +0.5i mystats { kernel.percpu.cpu.idle IDLE kernel.percpu.cpu.sys SYS kernel.percpu.cpu.user USER hinv.ncpu NCPU } .in .fi .ft 1 .PP produces the following C code, suitable for .BR #include -ing .PP .ft CW .nf .in +0.5i /* * Performance Metrics Name Space Map * Built by pmgenmap from the file * mystats.metrics * on Wed Dec 28 19:44:17 EST 1994 * * Do not edit this file! */ char *mystats[] = { #define IDLE 0 "kernel.percpu.cpu.idle", #define SYS 1 "kernel.percpu.cpu.sys", #define USER 2 "kernel.percpu.cpu.user", #define NCPU 3 "hinv.ncpu", }; .in .fi .ft 1 .PP Using the code generated by .BR pmgenmap , we are now able to easily obtain metrics from the Performance Metrics Collection Subsystem (PMCS) as follows: .PP .ft CW .nf .in +0.5i #define MAX_PMID 4 int trip = 0; int numpmid = sizeof(mystats)/sizeof(mystats[0]); double duration; pmResult *resp; pmResult *prev; pmID pmidlist[MAX_PMID]; pmNewContext(PM_CONTEXT_HOST, "localhost"); pmLookupName(numpmid, mystats, pmidlist); pmFetch(numpmid, pmidlist, &resp); printf("%d CPUs: %d usr %d sys %d idle\n", resp->vset[NCPU]->vlist[0].value.lval, resp->vset[USER]->vlist[0].value.lval, resp->vset[SYS]->vlist[0].value.lval, resp->vset[IDLE]->vlist[0].value.lval); .in .fi .ft 1 .PP Some calls to ensure portability have been removed from the code above for the sake of clarity \- the example above should not be used as a template for programming. In particular, the raw values of the metrics were used when .BR pmLookupDesc (3) should have been called to determine the semantics of each metric. .PP More complete examples that demonstrate the use of .B pmgenmap which may be used as a basis for program development are included in the PCP demos, e.g. .IR $PCP_DEMOS_DIR/pmclient . .SH FILES .PD 0 .TP 10 .BI $PCP_VAR_DIR/pmns/ * default PMNS specification files .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR cpp (1), .BR PMAPI (3), .BR pmFetch (3), .BR pmLookupName (3), .BR pmNewContext (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). pcp-3.8.12ubuntu1/man/man1/pmdamounts.10000664000000000000000000000724512272262521014474 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMDAMOUNTS 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdamounts\f1 \- filesystem mounts performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/mounts/pmdamounts\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION .B pmdamounts is a simple Performance Metrics Domain Agent (PMDA) which monitors availability of a given set of filesystem mounts. .PP The .B mounts PMDA exports metrics that reflect whether the configured filesystems are mounted ("up") or not. The list of mount points to monitor is specified via the .I $PCP_PMDAS_DIR/mounts/mounts.conf file which simply contains one line for each mount point. .PP Note that the platform kernel PMDA exports a more extensive set of filesystem metrics for every mounted filesystem \- this PMDA is primarily intended for availability monitoring using the .I mounts.up metric. .PP A brief description of the .B pmdamounts command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I mounts.log is written in the current directory of .BR pmcd (1) when .B pmdamounts is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .SH INSTALLATION If you want access to the names, help text and values for the mounts performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/mounts # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/mounts # ./Remove .in .fi .ft 1 .PP .B pmdamounts is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdamounts .TP 10 .B $PCP_PMDAS_DIR/mounts/help default help text file for the mounts metrics .TP 10 .B $PCP_PMDAS_DIR/mounts/Install installation script for the .B pmdamounts agent .TP 10 .B $PCP_PMDAS_DIR/mounts/Remove undo installation script for the .B pmdamounts agent .TP 10 .B $PCP_LOG_DIR/pmcd/mounts.log default log file for error messages and other information from .B pmdamounts .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmdajbd2.10000664000000000000000000001015212272262521013757 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMDAJBD2 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdajbd2\f1 \- journal block device (JBD) performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/jbd2/pmdajbd2\f1 [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-j\f1 \f2path\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION .B pmdajbd2 is a Performance Metrics Domain Agent (PMDA) which extracts performance metrics from the Journal Block Device subsystem (version 2) in the Linux kernel. These metrics are exported by the kernel in procfs files, one file per block device. The JBD2 subsystem is used by several filesystems including ext3, ext4 and ocfs2. .PP The .B jbd2 PMDA exports metrics that measure detailed journal transaction information, such as time spent waiting and locked, request rates, blocks used and so on. .PP A brief description of the .B pmdajbd2 command line options follows (these are only relevant when running the PMDA as a daemon, and not as a shared library): .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, when running as a daemon a log file named .I jbd2.log is written in the current directory of when .B pmdajbd2 is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. When running in shared library mode, and diagnostic information will be written into the .B pmcd log file, namely .BR $PCP_LOG_DIR/pmcd/pmcd.log . .TP .B \-j Allows an alternate path to the jbd2 statistics files to be specified. The default path is .IR /proc/fs/jbd2 . .TP .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .SH INSTALLATION This PMDA is installed by default and in the shared library mode (rather than as a separate daemon to .BR pmcd (1)). Thus, the names, help text and values for the jbd2 performance metrics should always be available. .PP If you do not use these metrics you can remove this PMDA, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/jbd2 # ./Remove .in .fi .ft 1 .PP If you want to enable the installation again, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/jbd2 # ./Install .in .fi .ft 1 .PP .B pmdajbd2 is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdajbd2 .TP 10 .B $PCP_PMDAS_DIR/jbd2/help default help text file for the jbd2 metrics .TP 10 .B $PCP_PMDAS_DIR/jbd2/Install installation script for the .B pmdajbd2 agent .TP 10 .B $PCP_PMDAS_DIR/jbd2/Remove undo installation script for the .B pmdajbd2 agent .TP 10 .B $PCP_LOG_DIR/pmcd/jbd2.log default log file for error messages and other information from .B pmdajbd2 .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmie2col.10000664000000000000000000000660512272262501014014 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIE2COL 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmie2col\f1 \- convert pmie output to multi-column format .SH SYNOPSIS \f3pmie2col\f1 [\f3\-d\f1 \f2delimiter\f1] [\f3\-p\f1 \f2precision\f1] [\f3\-w\f1 \f2width\f1] .de EX .in +0.5i .ie t .ft CB .el .ft B .ie t .sp .5v .el .sp .ta \\w' 'u*8 .nf .. .de EE .fi .ie t .sp .5v .el .sp .ft R .in .. .SH DESCRIPTION .B pmie2col is a simple tool that converts output from .BR pmie (1) into regular column format. Each column is 7 characters wide (by default, may be changed with the .B \-w option) with a single space between columns. That single space can be substituted with an alternate delimiter using the .B \-d option (this is useful for importing the data into a spreadsheet, for example). .PP The precision of the tabulated values from .B pmie can be specified with the .B \-p option (default is 2 decimal places). This option can and will override any width setting in order to present the requested precision. .PP The .BR pmie (1) configuration must follow these rules: .IP (1) Each .BR pmie (1) expression is of the form ``NAME = expr;''. NAME will be used as the column heading, and must contain no white space, although special characters can be escaped by enclosing NAME in single quotes. .IP (2) The ``expr'' must be a valid .BR pmie (1) expression that produces a singular value. .PP In addition, .BR pmie (1) must be run with the .B \-v command line option. .PP It is also possible to use the .B \-e command line to .BR pmie (1) and output lines will be prefixed by a timestamp. .SH EXAMPLE .PP Given this .BR pmie (1) configuration file .IR (config) : .EX loadav = kernel.all.load #'1 minute'; \&'%usr' = kernel.all.cpu.user; \&'%sys' = kernel.all.cpu.sys; \&'%wio' = kernel.all.cpu.wait.total; \&'%idle' = kernel.all.cpu.idle; \&'max-iops' = max_inst(disk.dev.total); .EE Then this command pipeline: .EX $ pmie \-v \-t 5 ). .PP A similar convention is used for trimming the amount of information displayed for running .B pmie instances, where configuration files below .B $PCP_VAR_DIR/config will be displayed in truncated form. .SH FILES .PD 0 .TP 10 .B $PCP_SYSCONF_DIR/pmlogger/config.pcp .B pmlogger configuration file for collecting all of the metrics required by .BR pcp . .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmie (1), .BR pmlogger (1), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .B pcp will terminate with an exit status of .B 1 if .B pmcd on the target host could not be reached or the archive could not be opened, or .B 2 for any other error. pcp-3.8.12ubuntu1/man/man1/pmnewlog.10000664000000000000000000001756012272262501014134 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNEWLOG 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmnewlog\f1 \- stop and restart archive logging for PCP performance metrics .SH SYNOPSIS \f3$PCP_BINADM_DIR/pmnewlog\f1 [\f3\-a\f1 \f2accessfile\f1] [\f3\-C\f1 \f2saveconfig\f1] [\f3\-c\f1 \f2configfile\f1] [\f3\-N\f1] [\f3\-n\f1 \f2pmnsfile\f1] [\f3\-P\f1] [\f3\-p\f1 \f2pid\f1] [\f3\-s\f1] [\f3\-V\f1] [\f2other pmlogger options\f1] \f2archive\f1 .SH DESCRIPTION .B pmnewlog may be used to stop and restart a running instance of .BR pmlogger (1). This is most useful for managing multiple sets of Performance Co-Pilot (PCP) archive logs. These archive logs record the history of performance metric values that may be ``played back'' by other PCP tools, and they form the basis of the VCR paradigm and retrospective performance analysis services common to the PCP toolkit. .PP In normal usage, .B pmnewlog would be executed by .BR cron (1) in the wee hours to terminate one PCP archive log and start another, i.e. to perform log rotation. .PP Even more common, would be the execution of .B pmnewlog from the PCP archive management script .BR pmlogger_daily (1). In this case, direct end-user execution of .B pmnewlog is most unlikely. .PP The mandatory argument .I archive is the base name for the physical files that will constitute the new archive log. .PP The .B pmlogger instance to be stopped and restarted must be running on the same system as .B pmnewlog and is either the primary logger (the default) or the logger with .I pid as specified by the .B \-p option. .PP If the .B \-n option is specified, then .B pmnewlog will use the namespace in the .IR pmnsfile , rather than the default Performance Metrics Name Space (PMNS). .PP If no .B \-c option is specified, .B pmnewlog will use .BR pmlc (1) to connect to the running .BR pmlogger (1) and so determine all those metrics and instances that are subject to .B mandatory logging or .B advisory on logging, and the associated logging frequencies. This information is used to synthesize a new .BR pmlogger (1) configuration file. If the .B \-n option is specified, it will also be used for these interactions with .BR pmlc (1). .PP If the .B \-c option is specified, .BR pmlogger (1) will be restarted with .I configfile as the configuration file. Normally .I configfile would be the same configuration file used to start .BR pmlogger (1) in the first place, however note that since .BR pmlogger (1) is restarted, any changes to the logging status made using .BR pmlc (1) will be lost, unless these have also been reflected in changes to .IR configfile . .PP If .I configfile does not exist, then a search is made in the directory .I $PCP_SYSCONF_DIR/pmlogger for a file of the same name, and if found that file is used, e.g. if .I config.mumble does not exist in the current directory and the file .I $PCP_SYSCONF_DIR/pmlogger/config.mumble does exist, then .B "\-c config.mumble" and .B "\-c $PCP_SYSCONF_DIR/pmlogger/config.mumble" are equivalent. .PP Access controls specifications for the new .BR pmlogger (1) instance may optionally be provided via the .B \-a option. The contents of .I accessfile should start with the literal token .B [access] and conform to the syntax of the access controls section as described for .BR pmlogger (1). .PP The .B \-C option may be used to save the configuration file that .B pmnewlog passes to the newly launched .BR pmlogger (1). .PP If the .BR pmlogger (1) instance needs to be started under the control of .BR pmsocks (1) to connect to a .B pmcd through a firewall, the .B \-s option may be used. .PP The .B \-V option enables verbose reporting of the activity. By default no output is generated unless some error or warning condition is encountered. .PP The .B \-N option enables a ``show me'' mode, where the actions are echoed, but not executed, in the style of ``make \-n''. Using .B \-N in conjunction with .B \-V maximizes the diagnostic capabilities for debugging. .PP The .I other pmlogger options are as described for .BR pmlogger (1). Note that .B pmnewlog does .B not support the following options of .BR pmlogger (1). .TP \fB\-h\fR \fIhost\fR .B pmnewlog determines the host to which the new .BR pmlogger (1) should connect based upon the current host connection for the old .BR pmlogger (1). .TP \fB\-s\fR \fIsamples\fR The new .BR pmlogger (1) is expected to be long running, and the .B \-s option of .B pmnewlog takes precedence. .TP \fB\-T\fR \fIruntime\fR The new .BR pmlogger (1) is expected to be long running .TP \fB\-V\fR \fIversion\fR The new .B pmlogger will always create the latest version PCP archive format, and the .B \-V option of .B pmnewlog takes precedence. .TP \fB\-x\fR \fIfd\fR The launched .B pmlogger cannot be controlled by .BR pmRecordControl (3). .SH EXAMPLE The following .BR sh (1) script could be executed by root via .BR cron (1) to start a new set of archive logs for the primary logger each evening. A more complete version of this script may be found in .IR $PCP_BINADM_DIR/pmlogger_daily , and is documented in the manual page for .BR pmlogger_daily (1). .PP .in +8n .nf .ft CW #!/bin/sh # start new logs for PCP primary logger on this host # standard place for logs LOGDIR=$PCP_LOG_DIR/pmlogger/`hostname` # each new log is named yymmdd.hh.mm LOGNAME=`date "+%Y%m%d.%H.%M"` # do it [ ! \-d $LOGDIR ] && mkdir \-p $LOGDIR cd $LOGDIR $PCP_BINADM_DIR/pmnewlog \-l $LOGDIR/pmlogger.log $LOGDIR .ft R .fi .in -8n .SH FILES .PD 0 .TP 10 \f2archive\f3.meta metadata (metric descriptions, instance domains, etc.) for the archive log .TP \f2archive\f3.0 initial volume of metrics values (subsequent volumes have suffixes .BR 1 , .BR 2 , \&...) .TP \f2archive\f3.index temporal index to support rapid random access to the other files in the archive log .TP .B $PCP_BINADM_DIR/pmlogger_daily sample script to rotate archives for a number of loggers .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmdumplog (1), .BR pmlc (1), .BR pmlogger (1), .BR pmlogger_daily (1), .BR pmsocks (1), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS Due to the precious nature of the archive logs, .B pmnewlog is rather paranoid in its checking and validation, and will try very hard to ensure that an appropriately configured .BR pmlogger (1) can be restarted, before terminating the existing .BR pmlogger (1). .PP As a consequence of this checking, .B pmnewlog tends to generate rather verbose error and warning messages. .SH CAVEATS If no .I configfile is specified, the method for synthesizing a configuration file using a .BR pmlc (1) connection to the existing .BR pmlogger (1) is, of necessity, incomplete. In particular, for metrics with dynamic underlying instance domains, it is not possible to identify a configuration that logs .B all instances of a metric all of the time, so rather the synthesized configuration file requests the continued logging of the set of instances that exist at the time .BR pmlogger (1) is interrogated by .BR pmnewlog . .PP If this situation is a concern, a fixed configuration file should be used, and passed to .B pmnewlog via the .B \-c option. pcp-3.8.12ubuntu1/man/man1/pmatop.10000664000000000000000000001345512272262501013603 0ustar .TH PMATOP 1 "PCP" "Performance Co-Pilot" .SH NAME .B pmatop \- System & Process Monitor .SH SYNOPSIS Interactive usage: .P .B pmatop [\-g|\-m] [\-L linelen] [\-h host] [ .I interval [ .I samples ]] .P Writing and reading raw logfiles: .P .B pmatop \-w .I rawfile [ .I interval [ .I samples ]] .br .B pmatop \-r [ .I rawfile ] [\-g|\-m] [\-L linelen] [\-h host] .SH DESCRIPTION The program .I pmatop is an interactive monitor to view the load on a Linux system. It shows the occupation of the most critical hardware resources (from a performance point of view) on system level, i.e. cpu, memory, disk and network. By default metrics from the local host are displayed, but a different host may be specified with the .I [-h host] option. It is modeled after .BR atop (1) and provides a showcase for the variety of data available via .BR pmcd (1). .br .PP Every .I interval (default: 10 seconds) information is shown about the resource occupation on system level (cpu, memory, disks and network layers), followed by a list of processes which have been active during the last interval If the list of active processes does not entirely fit on the screen, only the top of the list is shown. .br The intervals are repeated till the number of .I samples (specified as command argument) is reached, or till the key 'q' is pressed in interactive mode. .PP When .I pmatop is started, it checks whether the standard output channel is connected to a screen, or to a file/pipe. In the first case it produces screen control codes (via the ncurses library) and behaves interactively; in the second case it produces flat ASCII-output. .PP In interactive mode, the output of .I pmatop scales dynamically to the current dimensions of the screen/window. .PP Furthermore in interactive mode the output of .I pmatop can be controlled by pressing particular keys. However it is also possible to specify such key as .B flag on the command line. In that case .I pmatop switches to the indicated mode on beforehand; this mode can be modified again interactively. Specifying such key as flag is especially useful when running .I pmatop with output to a pipe or file (non-interactively). These flags are the same as the keys that can be pressed in interactive mode (see section INTERACTIVE COMMANDS). .SH OUTPUT FORMAT The output of .I pmatop consists of system level and process level information. The system level information consists of the following output lines: .PP .TP 5 .B PRC Process and thread level totals. .br This line contains the total cpu time consumed in system mode (`sys') and in user mode (`user'), the total number of processes present at this moment (`#proc'), `sleeping interruptible' (`#tslpi') and `sleeping uninterruptible' (`#tslpu'), and the number of zombie processes (`#zombie'). .PP .TP 5 .B CPU The occupation percentage of this process related to the available capacity for this resource on system level. .br This line contains the total CPU usage in system mode, in user mode, in irq mode, in idle mode, and in wait mode. The .B cpu lines contain this information on a per cpu basis. .PP .TP 5 .B CPL This line contains load average information for the last minute, five minutes, and fifteen minutes. Also the number of context switches and the number of device interrupts. .PP .TP 5 .B MEM This line contains the size of physical memory, free memory, page cache, buffer cache, and slab. .PP .TP 5 .B SWP This line contains the size of swap, free swap, committed space, and committed space limit. .PP .TP 5 .B PAG This line contains the number of page scans, allocstalls, swapins, and swapouts. .PP .TP 5 .B LVM/MDD/DSK For every logical volume/multiple device/hard disk one line is shown containing the nàme, number of reads, and number of writes. .PP .TP 5 .B NET The first line is for the upper TCP/IP layer and contains the number of packets received, packets transmitted, packets received. The next line is one per network interface and contains the number of packets received and number of packets transmitted. .PP .TP 5 .B PROCESS The remaining lines are one line per process and can be controlled as described below. .SH INTERACTIVE COMMANDS When running .I pmatop interactively (no output redirection), keys can be pressed to control the output. .PP .TP 5 .B g Show generic output (default). Per process the following fields are shown in case of a window-width of 80 positions: process-id, cpu consumption during the last interval in system- and user mode, the virtual and resident memory growth of the process. The subsequent columns are the username, number of threads in the thread group, the status and exit code are shown. .br The last columns contain the state, the occupation percentage for the chosen resource (default: cpu) and the process name. When more than 80 positions are available, other information is added. .PP .TP 5 .B m Show memory related output. Per process the following fields are shown in case of a window-width of 80 positions: process-id, minor and major memory faults, size of virtual shared text, total virtual process size, total resident process size, virtual and resident growth during last interval, memory occupation percentage and process name. When more than 80 positions are available, other information is added. .PP Miscellaneous interactive commands: .PP .TP 5 .B ? Request for help information (also the key 'h' can be pressed). .PP .TP 5 .B z The pause key can be used to freeze the current situation in order to investigate the output on the screen. While .I pmatop is paused, the keys described above can be pressed to show other information about the current list of processes. Whenever the pause key is pressed again, pmatop will continue with a next sample. .PP .SH "SEE ALSO" .BR PCPIntro (1), .BR collectl (1), .BR perl (1), .BR python (1), .BR pmlogger (1), .BR pmcd (1), .BR pmprobe (1), .BR pmval (1), .BR PMAPI (3), and .BR pcp.conf (4). pcp-3.8.12ubuntu1/man/man1/pmwebd.10000664000000000000000000002045612272262501013560 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMWEBD 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmwebd\f1 \- bridge client PMAPI to HTTP .SH SYNOPSIS \f3pmwebd\f1 [\f3\-p\f1 \f2port\f1] [\f3\-4\f1] [\f3\-6\f1] [\f3\-t\f1 \f2timeout\f1] [\f3\-R\f1 \f2resdir\f1] [\f3\-c\f1 \f2number\f1] [\f3\-h\f1 \f2hostname\f1] [\f3\-a\f1 \f2archive\f1] [\f3\-L\f1] [\f3\-N\f1] [\f3\-K\f1 \f2spec\f1] [\f3\-A\f1 \f2archdir\f1] [\f3\-f\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-U\f1 \f2username\f1] [\f3\-x\f1 \f2file\f1] [\f3\-v\f1] [\f3\-?\f1] .\" see also ../../src/pmwebapi/main.c options[] et al. .SH DESCRIPTION .B pmwebd is a long-running network daemon. It binds a subset of the Performance Co-Pilot (PCP) client API (PMAPI) to RESTful web applications using the HTTP (PMWEBAPI) protocol. Web clients request a URI with the prefix .B /pmapi to access the bindings. pmwebd creates dynamic PCP contexts as requested by a dynamic pool of remote clients, and maintains them as long as the clients regularly reconnect to request PMAPI operations. Otherwise, PCP contexts are closed after a timeout. Permanent contexts may be requested on the command line. .PP In addition to the API binding, pmwebd may be optionally configured as a simple HTTP file server, in order to feed the web application itself to a web browser. URIs not matching the .B /pmapi prefix are mapped to files under the configured resource directory, if the \f3\-R\f1 option was given. .PP The options to .B pmwebd are as follows. .TP \f3\-p\f1 \f2port\f1 Set the TCP port number on which pmwebd will listen for HTTP requests. The default is 44323. .TP \f3\-4\f1 or \f3\-6\f1 Listen only on IPv4 or IPv6. By default, pmwebd will listen on both protocols, if possible. .TP \f3\-R\f1 \f2resdir\f1 Activate file serving beneath the given resource directory. All regular files there may be read & transcribed to remote clients. By default, file serving is disabled. .TP \f3\-t\f1 \f2timeout\f1 Set the maximum timeout (in seconds) after the last operation on a web context, before it is closed by pwmebd. A smaller timeout may be requested by the web client. .TP \f3\-c\f1 \f2number\f1 Reset the next PMWEBAPI permanent context identifier as given. The default is 1. .TP \f3\-h\f1 \f2hostname\f1 or \f3\-a\f1 \f2archive\f1 or \f3\-L\f1 Assign the next permanent PMWEBAPI context identifier to a PMAPI connection to the given host (with an extended syntax as given in .BR PCPIntro (1)), or archive file, or the PM_CONTEXT_LOCAL. .TP \f3\-A\f1 \f2archdir\f1 Limit remote new-context requests for archives to beneath the given directory. By default, only files beneath the initial working directory may be accessed. .TP \f3\-N\f1 Disable creation of new PMWEBAPI contexts via HTTP requests, leaving only permanent ones accessible. .TP \f3\-K\f1 \f2spec\f1 When fetching metrics from a local context, the .B \-K option may be used to control the DSO PMDAs that should be made accessible. The .I spec argument conforms to the syntax described in .BR __pmSpecLocalPMDA (3). More than one .B \-K option may be used. .TP \f3\-f\f1 By default .B pmwebd is started as a daemon. The .B \-f option indicates that it should run in the foreground. This is most useful when trying to diagnose problems with establishing connections. .TP \f3\-l\f1 \f2logfile\f1 By default a log file named .I pmwebd.log is written in the current directory. The .B \-l option causes the log file to be written to .I logfile instead of the default. If the log file cannot be created or is not writable, output is written to the standard error instead. .TP \f3\-U\f1 \f2username\f1 Assume the identity of .I username before starting to accept incoming requests from web clients. .TP \f3\-x\f1 \f2file\f1 Before the .B pmwebd .I logfile can be opened, .B pmwebd may encounter a fatal error which prevents it from starting. By default, the output describing this error is sent to .B /dev/tty but it may redirected to .IR file . .TP \f3\-v\f1 Increase the verbosity of the .B pmwebd program as it logs to its standard error. .TP \f3\-?\f1 Show pmwebd invocation help and exit. .SH SECURITY .PP The current release of pmwebd is suitable for direct exposure to trusted networks only, due to several security limitations. Most or all of these limitations may be worked around by use of a web application firewall (for example, an Apache HTTPD proxy), which would add the constraints and capabilities absent within pmwebd. Such configuration is beyond the scope of this document. .TP encryption/confidentiality The pmwebd program is does not currently support HTTPS (SSL/TLS), so the HTTP traffic is not protected against network-level attacks. .TP authentication The PMAPI layer does not possess a mandatory authentication mechanism, so any remote connection can access any metric exposed by suchly connected PMAPI contexts. However, a new host-context string may use authentication clauses of the longer host URLs, for example .IR pcps://hostname?method=plain&user=userid&pass=password . .TP inbound admission control The pmwebd program does not impose ACLs on the origin or rate of its incoming requests. It may be possible for some clients to starve others. .TP outbound admission control The pmwebd program does not impose ACLs on outbound connections when a new PMAPI context is created for a remote third-party PMCD. For an archive type context, the files must be located under the pmwebd current directory, or another directory specified by .BR \-A . One may entirely disable remotely specified PMAPI context creation using the .B \-N option; in this case, specify a static set of contexts using the .B \-h ", " \-a ", and/or " \-L " options." You may assign them arbitrary context numbers with the .B \-c option. .TP context ownership Authenticated PCP contexts are protected by requiring the same HTTP PLAIN/simple userid/password credentials for related /pmapi requests. However, unauthenticated contexts for different web clients are kept distinct only by the assignment of large pseudorandom identifiers. It may be possible to find these by brute-force search or other techniques, thereby letting a web client impersonate another. For more privacy of the permanent contexts, use the .B \-c option to reset their starting web context identifiers to a number much different from 1. On the other hand, context ownership is not that precious, since there exist no state-destructive operations for them, except perhaps instance profile settings. .SH "STARTING AND STOPPING PMWEBD" Normally, .B pmwebd is started automatically at boot time and stopped when the system is being brought down. Under certain circumstances it is necessary to start or stop .B pmwebd manually. To do this one must become superuser and type .PP .ft CS # $PCP_RC_DIR/pmwebd start .ft .PP to start .BR pmwebd , or .PP .ft CS # $PCP_RC_DIR/pmwebd stop .ft .PP to stop .BR pmwebd . Starting .B pmwebd when it is already running is the same as stopping it and then starting it again. .SH FILES .PD 0 .TP .B PCP_PMWEBDOPTIONS_PATH command line options and environment variable settings for .B pmwebd when launched from .B $PCP_RC_DIR/pmwebd All the command line option lines should start with a hyphen as the first character. This file can also contain environment variable settings of the form "VARIABLE=value". .TP .B \&./pmwebd.log (or .B $PCP_LOG_DIR/pmwebd/pmwebd.log when started automatically) .br All messages and diagnostics are directed here .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR PMAPI (3), .BR PMWEBAPI (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). pcp-3.8.12ubuntu1/man/man1/pmlogreduce.10000664000000000000000000001655512272262501014615 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOGREDUCE 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmlogreduce\f1 \- temporal reduction of Performance Co-Pilot archives .SH SYNOPSIS \f3$PCP_BINADM_DIR/pmlogreduce\f1 [\f3\-z\f1] [\f3\-A\f1 \f2align\f1] [\f3\-S\f1 \f2starttime\f1] [\f3\-s\f1 \f2samples\f1] [\f3\-T\f1 \f2endtime\f1] [\f3\-t\f1 \f2interval\f1] [\f3\-v\f1 \f2volsamples\f1] [\f3\-Z\f1 \f2timezone\f1] \f2input\f1 \f2output\f1 .SH DESCRIPTION .B pmlogreduce reads one Performance Co-Pilot (PCP) archive identified by .I input (this must be a PCP archive created by .BR pmlogger (1), .BR pmlogextract (1) or .BR pmlogreduce (1)), and creates a temporally reduced PCP archive in .IR output . The data reduction involves statistical and temporal reduction of samples with an output sampling interval defined by the .B \-t option in the .I output archive (independent of the sampling intervals in the .I input archive), and is further controlled by other command line arguments. .PP For some metrics, temporal data reduction is not going to be helpful, so for metrics with types .B PM_TYPE_AGGREGATE or .BR PM_TYPE_EVENT , a warning is issued if these metrics are found in .I input and they will be skipped and not appear in the .I output archive. .SH COMMAND LINE OPTIONS The command line options for .B pmlogreduce are as follows: .PP .TP 7 .BI \-A " align" Specify a ``natural'' alignment of the output sample times; refer to .BR PCPIntro (1). .PP .TP 7 .BI \-S " starttime" Define the start of a time window to restrict the samples retrieved from the .I input archive; refer to .BR PCPIntro (1). .PP .TP 7 .BI \-s " samples" The argument .I samples defines the number of samples to be written to .IR output . If .I samples is 0 or .B -s is not specified, .B pmlogreduce will sample until the end of the PCP archive, or the end of the time window as specified by .BR -T , whichever comes first. The .B -s option will override the .B -T option if it occurs sooner. .PP .TP 7 .BI \-T " endtime" Define the termination of a time window to restrict the samples retrieved from the .I input archive; refer to .BR PCPIntro (1). .PP .TP 7 .BI \-v " volsamples" The .I output archive is potentially a multi-volume data set, and the .B \-v option causes .B pmlogreduce to start a new volume after .I volsamples log records have been written to the .I output archive. .RS 7 .PP Independent of any .B \-v option, each volume of an archive is limited to no more than 2^31 bytes, so .I pmlogreduce will automatically create a new volume for the archive before this limit is reached. .RE .PP .TP 7 .BI \-t " interval" Consecutive samples in the .I output archive will appear with a time delta defined by .IR interval ; refer to .BR PCPIntro (1). Note the default value is 600 (seconds, i.e. 10 minutes). .PP .TP 7 .BI \-Z " timezone" Use .I timezone when displaying the date and time, or interpreting the .B \-S and .B \-T options. .I Timezone is in the format of the environment variable .B TZ as described in .BR environ (5). .PP .TP 7 .B \-z Use the local timezone of the host from the .I input archive when displaying the date and time, or interpreting the .B \-S and .B \-T options. The default is to initially use the timezone of the local host. .SH DATA REDUCTION .PP The statistical and temporal reduction follows the following rules: .TP 4m 1. Consecutive records from .I input are read without interpolation, and at most one output record is written for each .IR interval , summarizing the performance data over that period. .TP 4m 2. If the semantics of a metric indicates it is .B instantaneous or .B discrete then .I output value is computed as the arithmetic mean of the observations (if any) over each .IR interval . .TP 4m 3. If the semantics of a metric indicates it is a .B counter then the following transformations are applied: .RS +4m .nr PD 0 .TP 4m a) Metrics with 32-bit precision are promoted to 64-bit precision. .TP 4m b) Any counter wrap (overflow) is noted, and appropriate adjustment made in the value of the metric over each .IR interval . This will be correct in the case of a single counter wrap, but will silently .B underestimate in the case where more than one counter wrap occurs between consecutive observations in the .I input archive, and silently .B overestimate in the case where a counter is reset occurs between consecutive observations in the .I input archive; unfortunately these situations cannot be detected, but are believed to be rare events for the sort of production monitoring environments where .B pmlogreduce is most likely to be deployed. .RE .PD .TP 4m 4. Any changes in instance domains, and indeed all metadata, is preserved. .TP 4m 5. Any ``mark'' records in the .I input archive (as created by .BR pmlogextract (1)) will be preserved in the .I output archive, so periods where no data is available are maintained, and data interpolation will .B not occur across these periods when the .I output archive is subsequently processed with PCP applications. .SH FILES .PD 0 For each of the .I input and .I output archives, several physical files are used. .TP 10 \f2archive\f3.meta metadata (metric descriptions, instance domains, etc.) for the archive log .TP \f2archive\f3.0 initial volume of metrics values (subsequent volumes have suffixes .BR 1 , .BR 2 , \&...) \- for .I input these files may have been previously compressed with .BR bzip2 (1) or .BR gzip (1) and thus may have an additional .B .bz2 or .B .gz suffix. .TP \f2archive\f3.index temporal index to support rapid random access to the other files in the archive log. .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmdumplog (1), .BR pmlc (1), .BR pmlogextract (1), .BR pmlogger (1), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS All error conditions detected by .B pmlogreduce are reported on .I stderr with textual (if sometimes terse) explanation. .PP Should the .I input archive be corrupted (this can happen if the .B pmlogger instance writing the archive suddenly dies), then .B pmlogreduce will detect and report the position of the corruption in the file, and any subsequent information from the .I input archive will not be processed. .PP If any error is detected, .B pmlogreduce will exit with a non-zero status. .SH CAVEATS .PP The preamble metrics (pmcd.pmlogger.archive, pmcd.pmlogger.host, and pmcd.pmlogger.port), which are automatically recorded by .B pmlogger at the start of the archive, may not be present in the archive output by .BR pmlogreduce . These metrics are only relevant while the archive is being created, and have no significance once recording has finished. pcp-3.8.12ubuntu1/man/man1/pmnsadd.10000664000000000000000000000775412272262501013736 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNSADD 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmnsadd\f1 \- add new names to the Performance Co-Pilot PMNS .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS .B $PCP_BINADM_DIR/pmnsadd [\f3\-d\f1] [\f3\-n\f1 \f2namespace\f1] .I file .SH DESCRIPTION .BR pmnsmerge (1) performs the same function as .B pmnsadd and is faster, more robust and more flexible. It is therefore recommended that .BR pmnsmerge (1) be used instead. .PP .B pmnsadd adds subtree(s) of new names into a Performance Metrics Name Space (PMNS), as used by the components of the Performance Co-Pilot (PCP). .P Normally .B pmnsadd operates on the default Performance Metrics Namespace (PMNS), however if the .B \-n option is specified an alternative namespace is used from the file .IR namespace . .PP The default PMNS is found in the file .I $PCP_VAR_DIR/pmns/root unless the environment variable .B PMNS_DEFAULT is set, in which case the value is assumed to be the pathname to the file containing the default PMNS. .PP The new names are specified in the .IR file , arguments and conform to the syntax for PMNS specifications, see .BR pmns (5). There is one PMNS subtree in each .IR file , and the base PMNS pathname to the inserted subtree is identified by the first group named in each .IR file , e.g. if the specifications begin .P .sp 0.5v .in +1i .ft CW .nf myagent.foo.stuff { mumble 123:45:1 fumble 123:45:2 } .fi .ft 1 .in -1i .sp 0.5v .P then the new names will be added into the PMNS at the non-leaf position identified by .ft CW myagent.foo.stuff\c .ft 1 , and following all other names with the prefix .ft CW myagent.foo\c .ft 1 \&. .PP The new names must be contained within a single subtree of the namespace. If disjoint subtrees need to be added, these must be packaged into separate files and .B pmnsadd used on each, one at a time. .PP All of the files defining the PMNS must be located within the directory that contains the root of the PMNS, this would typically be .B $PCP_VAR_DIR/pmns for the default PMNS, and this would typically imply running .B pmnsadd as root. .PP As a special case, if .I file contains a line that begins .ft CW root { .ft R then it is assumed to be a complete PMNS that needs to be merged, so none of the subtree extraction and rewriting is performed and .I file is handed directly to .BR pmnsmerge (1). .PP Provided some initial integrity checks are satisfied, .B pmnsadd will update the PMNS using .BR pmnsmerge (1) \- if this fails for any reason, the original namespace remains unchanged. .PP The .B \-d option allows the resultant PMNS to optionally contain duplicate PMIDs with different names in the PMNS. By default this condition is considered an error. .SH CAVEAT Once the writing of the new .I namespace file has begun, the signals SIGINT, SIGHUP and SIGTERM will be ignored to protect the integrity of the new files. .SH FILES .PD 0 .IP \f2$PCP_VAR_DIR/pmns/root\f1 2.5i the default PMNS, when then environment variable .B PMNS_DEFAULT is unset .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmnsdel (1), .BR pmnsmerge (1), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). pcp-3.8.12ubuntu1/man/man1/pmconfig.10000664000000000000000000000347412272262501014105 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2009 Aconex. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMCONFIG 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmconfig\f1 \- Performance Co-Pilot configuration parameters .SH SYNOPSIS \f3$PCP_BINADM_DIR/pmconfig\f1 [\f3\-a\f1|\f3-l\f1] [\f3\-L\f1] [\f3\-s\f1] [\f2name ...\f1] .SH DESCRIPTION .B pmconfig displays the values for some or all configuration parameters of the local Performance Co-Pilot toolkit installation. .PP The .B \-L option may be used to change the default reporting mode so that the capabilities of the PCP library are reported, rather than the PCP environment. .PP In the default operating mode, .B pmconfig is often used in conjunction with the .B $PCP_DIR environment variable to setup scripts running under the Windows operating system, where the filesystem hierarchy is very different to the of Linux/UNIX-based operating systems. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmGetConfig (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmlogconf.10000664000000000000000000002065512272262501014267 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOGCONF 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmlogconf\f1 \- create/edit a pmlogger configuration file .SH SYNOPSIS \f3$PCP_BINADM_DIR/pmlogconf\f1 [\f3\-cqrv\f1] [\f3\-d\f2 groupsdir\f1] [\f3\-h\f2 hostname\f1] \f2configfile\f1 .SH DESCRIPTION .B pmlogconf may be used to create and modify a generic configuration file for the PCP archive logger, .BR pmlogger (1). .PP If .I configfile does not exist, .B pmlogconf will create a generic configuration file with a default set of enabled metrics and logging intervals. .PP Once created, .I configfile may be used with the .B \-c option to .BR pmlogger (1) to select performance metrics and specify logging intervals for a PCP archive. .PP If .I configfile does exist, .B pmlogconf will prompt for input from the user to enable or disable groups of related performance metrics and to control the logging interval for each enabled group. .PP Group selection requires a simple .B y (yes) or .B n (no) response to the prompt .BR "Log this group?" . .PP Other responses at this point may be used to select additional control functions as follows: .IP \fBm\fP 10n Report the names of the metrics in the current group. .IP \fBq\fP 10n Finish with group selection (quit) and make no further changes to this group or any subsequent group. .IP \fB/\fIpattern\fP 10n Make no change to this group but search for a group containing .I pattern in the description of the group or the names of the associated metrics. .PP A logging interval is specified by responding to the .B "Logging interval?" prompt with the keywords .B once or .B default or a valid .BR pmlogger (1) interval specification of the form ``\c .B every .IR "N timeunits" '' or simply ``\c .I "N timeunits" '' (the .B every is optional) where .I N is an unsigned integer and .I timeunits is one of the keywords .BR msec , .BR millisecond , .BR sec , .BR second , .BR min , .BR minute , .BR hour or the plural form of one of the keywords. .PP When run from automated logging setup processes, the .B \-c option is used to add a message and timestamp indicating this fact. This option is not appropriate for interactive use of the tool. .PP The .B \-q option suppresses the logging interval dialog and preserves the current interval from .IR configfile . .PP More verbose output may be enabled with the .B \-v option. .SH "SETUP GROUP FILES" When an initial .I configfile is created, the default specifications come from a set of group files below the .I groupsdir specified with the .B \-d option (the default .I groupsdir is .B $PCP_VAR_DIR/config/pmlogconf which is most commonly correct, so the .B \-d option is rarely used in practice). .PP The directory structure below .I groupsdir is arbitrary as all regular files will be found by recursive descent and considered, so add-on products and PMDA developers can easily extend the available defaults to .B pmlogconf by adding new directories and/or group files below .IR groupsdir . .PP These group files are processed in the following ways: .IP \(bu 3n When a new .I configfile is created, all group files are processed. .IP \(bu 3n Whenever .B pmlogconf is run with an existing .IR configfile , .I groupsdir is traversed to see if any new groups have been defined and should be considered for inclusion in .IR configfile . .IP \(bu 3n When .B pmlogconf processes a group in .I configfile that is enabled, the list of metrics associated with the group is taken from the group file (and replaces any previous list of metrics associated with this group in .IR configfile ). .IP \(bu 3n When the .B \-r (reprobe) command line option is specified, every group (not just newly discovered ones) is reprocessed to see if it should be considered for inclusion in .IR configfile . .PP Each group file is structured as follows: .IP \(bu 3n The first line must contain .B #pmlogconf-setup 2.0 .IP \(bu 3n Other lines beginning with .B # are treated as comments. .IP \(bu 3n Blank lines are ignored. .IP \(bu 3n One or more lines starting with the keyword .B ident are used to provide the human-readable description of the group. .IP \(bu 3n Non-blank lines beginning with white space define metrics to be associated with this group, one per line. Each metric specification follows the rules for a .BR pmlogger (1) configuration, namely either the name of a non-leaf node in the PMNS (implying all descendent names in the PMNS), or the name of a leaf node in the PMNS optionally followed by one or more instance names enclosed by ``['' and ``]''. .IP \(bu 3n A control line starting with one of the keywords .B probe or .B force must be present. .IP \(bu 3n An optional logging interval control line begins with the keyword .B delta followed by one of the .BR pmlogger (1) interval specification described above. .IP \(bu 3n .B probe control lines have the format: .RS 3n .br .ce \fBprobe\fR \fImetric\fR [\fIcondition\fR [\fIstate_rule\fR] ] .br where .I metric is the name of a PCP metric (must be a leaf node in the PMNS and no instance specification is allowed) and the optional .I condition is the keyword .B exists (true if .I metric exists, i.e. is defined in the PMNS) or the keyword .B values (true if .I metric exists in the PMNS and has one or more current values) or an expression of the form .br .ce \fIop\fR \fIval\fR where .I op is one of the .BR awk (1) operators (\fB==\fR, \fB!=\fR, \fB>\fR, \fB>=\fR, \fB<\fR, \fB<=\fR, \fB~\fR (regular expression match) or \fB!~\fR (negated regular expression match)) and .I val is a value (arbitrary sequence of characters, excluding a space) and the .I condition is true if there is some instance of .I metric that makes the expression true. .PP If the .I condition is missing, the default is .BR exists . .PP When an explicit .I condition is provided, there may also be an optional .I state_rule of the form .br .ce \fB?\fR \fItrue_state\fR \fB:\fR \fIfalse_state\fR where .I true_state (applies if .I condition is true) and .I false_state (applies if .I condition is false) are both taken from the keywords .B include (include and enable the group and the associated metrics in .IR configfile ), .B available (include and disable the group in .I configfile \- a user action of .B y as described above is needed to enable the group and add the associated metrics into .IR configfile ) or .B exclude (the group is not considered for inclusion in .IR configfile ). .PP The default .I state_rule is .br .ce .ft B ? available : exclude .ft R .RE .IP \(bu 3n .B force control lines begin with the keyword .B force followed by one of the states defined above, so one of the actions .BR include , .B exclude or .B available is applied unconditionally to the group. .PP Probing is only done when a new group is being added to .I configfile or when the .B \-r command line option is specified. The evaluation of the probing conditions is done by contacting .BR pmcd (1) on .I hostname (defaults to local:). .SH EXAMPLE The following group file demonstrates all of the supported syntactic elements. .PP .ft CW .nf #pmlogconf-setup 2.0 ident Example group file ident ... more description delta 1 minute probe sample.secret.foo.one values ? include : exclude sample.secret.foo.one sample.secret.foo.bar # non-leaf in the PMNS sample.colour [ red green ] .fi .ft .SH MIGRATION The current version of .B pmlogconf (2.0) supports a slightly different format for .I configfile compared to earlier versions. If an old version .I configfile is presented to .B pmlogconf it will be converted to the new format. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmcd (1), .BR pmlogger (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmdasystemd.10000664000000000000000000001054112272262521014630 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMDASYSTEMD 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdasystemd\f1 \- systemd performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/systemd/pmdasystemd\f1 [\f3\-f\f1] [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-m\f1 \f2memory\f1] [\f3\-s\f1 \f2interval\f1] [\f3\-U\f1 \f2username\f1] .SH DESCRIPTION .B pmdasystemd is a systemd log file monitoring Performance Metrics Domain Agent (PMDA). It can be seen as analagous to the .B \-f option to .BR journalctl (1) and converts each new log line into a performance event, suitable for consumption by .BR PMAPI (3) client tools like .BR pmevent (1). .PP The .B systemd PMDA exports both event-style metrics reflecting timestamped event records for messages logged to the system logs, as well as the more orthodox sample-style metrics such as message counts and throughput size values. .PP A brief description of the .B pmdasystemd command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-f Disables per-uid/gid record filtering. By default the user and group credentials will be used to filter log records returned to the client tool, preventing information exposure to arbitrary users. This option disables that, so use only with extreme caution. .TP .B \-l Location of the log file. By default, a log file named .I systemd.log is written in the current directory of .BR pmcd (1) when .B pmdasystemd is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-m Limit the physical memory used by the PMDA to buffer event records to .I maxsize bytes. As log events arrive at the PMDA, they must be buffered until individual client tools request the next batch since their previous batch of events. The default maximum is 2 megabytes. .TP .B \-s Sets the polling interval for detecting newly arrived log lines. Mirrors the same option from the .BR tail (1) command. .TP .B \-U User account under which to run the agent. The default is the "adm" user account. .SH INSTALLATION If you want access to the names, help text and values for the systemd performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/systemd # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/systemd # ./Remove .in .fi .ft 1 .PP .B pmdasystemd is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdasystemd .TP 10 .B $PCP_PMDAS_DIR/systemd/help default help text file for the systemd metrics .TP 10 .B $PCP_PMDAS_DIR/systemd/Install installation script for the .B pmdasystemd agent .TP 10 .B $PCP_PMDAS_DIR/systemd/Remove undo installation script for the .B pmdasystemd agent .TP 10 .B $PCP_LOG_DIR/pmcd/systemd.log default log file for error messages and other information from .B pmdasystemd .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pmevent (1), .BR journalctl (1), .BR tail (1), .BR PMAPI (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmhostname.10000664000000000000000000000373412272262501014455 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMHOSTNAME 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmhostname\f1 \- report hostname .\" literals use .B or \f3 .\" arguments use .I or \f2 .SH SYNOPSIS .B $PCP_BINADM_DIR/pmhostname [\fIhostname\fR] .SH DESCRIPTION .B pmhostname reports the name of the host .I hostname as returned by .BR gethostbyname (3N). .PP If .I hostname is not specified, then the local host name is retrieved using .BR gethostname (2) and this is than passed to .BR gethostbyname (3N). .PP .B pmhostname provides a service for shell scripts that mimics the logic formerly used by Performance Co-Pilot applications when trying to determine the official name of a host. PCP applications no longer use DNS-based heuristics, and therefore this command is .IR deprecated . .PP If .BR gethostbyname (3N) fails, the input host name (either .I hostname or the result from calling .BR gethostname (2)) is reported. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR named (1), .BR nsd (1), .BR nslookup (1), .BR gethostname (2), .BR gethostbyname (3N), .BR pcp.conf (5), .BR pcp.env (5) and .BR resolver (5). pcp-3.8.12ubuntu1/man/man1/mkaf.10000664000000000000000000001040312272262501013207 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH MKAF 1 "PCP" "Performance Co-Pilot" .SH NAME \f3mkaf\f1 \- create a Performance Co-Pilot archive folio .SH SYNOPSIS \f3$PCP_BINADM_DIR/mkaf\f1 [\f2findopts\f1] \f2filename\f1 ... .SH DESCRIPTION A collection of one or more Performance Co-Pilot (see .BR PCPIntro (1)) archive logs may be combined with .B mkaf to produce a PCP archive folio and the associated archive folio control file. Some PCP tools use .B mkaf to create archive folios, e.g. the ``record'' facility in the .BR pmchart (1) and .BR pmview (1) tools, to facilitate playback with .BR pmafm (1). .PP .B mkaf processes each .I filename argument, and if this is a component file from a PCP archive that archive is added to the folio. .PP If .I filename is a directory, then this is searched recursively using .BR find (1). Any .I filename argument beginning with a ``\-'' is assumed to be a .BR find (1) command line option .RI ( findopts ); the default is .B -follow if no .I findopts are specified. .PP The first named archive in the folio is assumed to be associated with the default host for any tool that tries to replay multiple archives from the folio. .PP The folio control file is written to standard output, and has the following format. .IP 1. 3n The first line contains the word .BR PCPFolio . .IP 2. The second line contains the tag .B Version: followed by the format version number (currently 1). .IP 3. For subsequent lines, blank lines and lines beginning with ``#'' are ignored. .IP 4. The line beginning with the tag .B Created: documents where and when the folio was created. .IP 5. The line beginning with the tag .B Creator: identifies the tool which created the folio (and is assumed to know how to replay the archive folio). If present, the second argument is the name of a configuration file that the creator tool could use to replay the archive folio, e.g. with the .B replay command for .BR pmafm (1). In the case of .B mkaf (unlike .BR pmchart (1) or .BR pmview (1)) there is no knowledge of the contents of the archives, so the ``creator'' cannot replay the archive, however .BR pmchart (1) is able to replay any archive, and so this tool is identified as the .B Creator: for archive folios created by .BR mkaf (1). .IP 6. This is then followed by one or more lines beginning with the tag .B Archive: followed by the hostname and base name of the archive. .PP For example .ti +5n $ mkaf mydir/gonzo .br might produce the following folio control file. .PP .ft CW .nf PCPFolio Version: 1 # use pmafm(1) to process this PCP archive folio # Created: on gonzo at Tue Jul 2 03:35:54 EST 1996 Creator: pmchart # Host Basename # Archive: gonzo mydir/gonzo/960627 Archive: gonzo mydir/gonzo/960628 Archive: gonzo mydir/gonzo/960629 Archive: gonzo mydir/gonzo/960630 Archive: gonzo mydir/gonzo/960701 Archive: gonzo mydir/gonzo/960701.00.10 Archive: gonzo mydir/gonzo/960701.05.25 Archive: gonzo mydir/gonzo/960702.00.10 .ft .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR find (1), .BR PCPIntro (1), .BR pmafm (1), .BR pmchart (1), .BR pmview (1), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS Some informational messages, warnings and pathological conditions are reported on standard error. pcp-3.8.12ubuntu1/man/man1/pmiestatus.10000664000000000000000000000277612272262501014505 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Max Matveev. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIESTATUS 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmiestatus\f1 \- display information from pmie stats file .SH SYNOPSIS \f3pmiestatus\f1 \f2statsfile\f1 [\f2...\f1] .SH DESCRIPTION .B pmiestatus displays information used to identify a running \f3pmie\f1 process. It is mostly used by \f3pmie_check\f1 and \f3pmie_daily\f1 when they hunt for instances of \f3pmie\f1 to check against the control file. .SH FILES .PD 0 .TP 10 .BI $PCP_TMP_DIR/pmie/ * pmie stats files .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR pmie (1), .BR pmie_check (1), .BR pmie_daily (1), .BR pcp.conf (5), and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmdamailq.10000664000000000000000000001144612272262501014246 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAMAILQ 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdamailq\f1 \- mail queue performance metrics domain agent (PMDA) .SH SYNOPSIS \f3$PCP_PMDAS_DIR/mailq/pmdamailq\f1 [\f3\-b\f1 \f2binlist\f1] [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-r\f1 \f2regex\f1] [\f3\-U\f1 \f2username\f1] [\f2queuedir\f1] .SH DESCRIPTION .B pmdamailq is a Performance Metrics Domain Agent (PMDA) which extracts performance metrics describing the state of the e-mail queues managed by .BR sendmail (1) and other mail transfer agents. .PP The .B mailq PMDA exports metrics that measure the total number of entries in the mail queue, and the subtotals for entries that have been queued for various time periods. .PP A brief description of the .B pmdamailq command line options follows: .TP 5 .B \-b The .I binlist argument specifies a list of delay thresholds used to ``bin'' the entries in the queue into a a histogram based on how long the entry has been in the mail queue. The default thresholds are: 1 hour, 4 hours, 8 hours, 1 day, 3 days and 7 days. The entries in .I binlist are comma separated time intervals, using the syntax described in .BR PCPIntro (1) for an update or reporting interval, e.g. the default list could be specified using the value .BR "1hr,4hrs,8hrs,1day,3days,7days" . .RS .PP Values in .I binlist are assumed to be in ascending order, and mail items in the queue less than the first threshold are binned into a special bin labeled ``recent''. .RE .TP .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP .B \-l Location of the log file. By default, a log file named .I mailq.log is written in the current directory of .BR pmcd (1) when .B pmdamailq is started, i.e. .B $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP .B \-r Use an extended regular expression to match file names in the mail queue directory, rather than assuming all "df" prefixed files in the directory are mail files (the "df" prefix is the .B sendmail convention, but this convention is not followed by other mail daemons). The .I regex pattern specified should conform to the POSIX format described in .BR regex (3), and it describes file names that should be considered mail. .TP 5 .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .PP The optional .I queuedir argument defines the directory in which .B pmdamailq expects to find the mail queue. The default is .BR /var/spool/mqueue . .SH INSTALLATION If you want access to the names, help text and values for the mailq performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/mailq # ./Install .in .fi .ft 1 .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/mailq # ./Remove .in .fi .ft 1 .PP .B pmdamailq is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdamailq .TP 10 .B $PCP_PMDAS_DIR/mailq/help default help text file for the mailq metrics .TP 10 .B $PCP_PMDAS_DIR/mailq/Install installation script for the .B pmdamailq agent .TP 10 .B $PCP_PMDAS_DIR/mailq/Remove undo installation script for the .B pmdamailq agent .TP 10 .B $PCP_LOG_DIR/pmcd/mailq.log default log file for error messages and other information from .B pmdamailq .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR PCPIntro (1), .BR pmcd (1), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man1/pmdabash.10000664000000000000000000001460012272262501014053 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2012 Nathan Scott. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDABASH 1 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdabash\f1 \- Bourne-Again SHell trace performance metrics domain agent .SH SYNOPSIS \f3$PCP_PMDAS_DIR/bash/pmdabash\f1 [\f3\-C\f1] [\f3\-d\f1 \f2domain\f1] [\f3\-l\f1 \f2logfile\f1] [\f3\-I\f1 \f2interval\f1] [\f3\-t\f1 \f2timeout\f1] [\f3\-U\f1 \f2username\f1] \f2configfile\f1 .br .SH DESCRIPTION .B pmdabash is an experimental Performance Metrics Domain Agent (PMDA) which exports "xtrace" events from a traced .BR bash (1) process. This includes the command execution information that would usually be sent to standard error with the .BR "set -x" option to the shell. .PP Event metrics are exported showing each command executed, the function name and line number in the script, and a timestamp. Additionally, the process identifier for the shell and its parent process are exported. .PP This requires .B bash version 4 or later. .PP A brief description of the .B pmdabash command line options follows: .TP 5 .B \-d It is absolutely crucial that the performance metrics .I domain number specified here is unique and consistent. That is, .I domain should be different for every PMDA on the one host, and the same .I domain number should be used for the same PMDA on all hosts. .TP 5 .B \-l Location of the log file. By default, a log file named .I bash.log is written in the current directory of .BR pmcd (1) when .B pmdabash is started, i.e. .BR $PCP_LOG_DIR/pmcd . If the log file cannot be created or is not writable, output is written to the standard error instead. .TP 5 .B \-s Amount of time (in seconds) between subsequent evaluations of the shell trace file descriptor(s). The default is 2 seconds. .PP .TP 5 .B \-m Maximum amount of memory to be allowed for each event queue (one per traced process). The default is 2 megabytes. .TP 5 .B \-U User account under which to run the agent. The default is the unprivileged "pcp" account in current versions of PCP, but in older versions the superuser account ("root") was used by default. .PP .SH INSTALLATION In order for a host to export the names, help text and values for the bash performance metrics, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/bash # ./Install .in .fi .ft 1 .PP As soon as an instrumented shell script (see INSTRUMENTATION selection below) is run, with tracing enabled, new metric values will appear - no further setup of the agent is required. .PP If you want to undo the installation, do the following as root: .PP .ft CW .nf .in +0.5i # cd $PCP_PMDAS_DIR/bash # ./Remove .in .fi .ft 1 .PP .B pmdabash is launched by .BR pmcd (1) and should never be executed directly. The Install and Remove scripts notify .BR pmcd (1) when the agent is installed or removed. .SH INSTRUMENTATION In order to allow the flow of event data between a .BR bash (1) script and .BR pmdabash , the script should take the following actions: .PP .ft CW .nf .in +0.5i #!/bin/sh source $PCP_DIR/etc/pcp.sh pcp_trace on $@ # enable tracing echo "awoke, $count" pcp_trace off # disable tracing .in .fi .ft 1 .PP The tracing can be enabled and disabled any number of times by the script. On successful installation of the agent, several metrics will be available: .PP .ft CW .nf .in +0.5i $ pminfo bash bash.xtrace.numclients bash.xtrace.maxmem bash.xtrace.queuemem bash.xtrace.count bash.xtrace.records bash.xtrace.parameters.pid bash.xtrace.parameters.parent bash.xtrace.parameters.lineno bash.xtrace.parameters.function bash.xtrace.parameters.command .in .fi .ft 1 .PP When an instrumented script is running, the generation of event records can be verified using the .BR pmevent (1) command, as follows: .PP .ft CW .nf .in +0.5i $ pmevent \-t 1 \-x '' bash.xtrace.records host: localhost samples: all bash.xtrace.records["4538 ./test-trace.sh 1 2 3"]: 5 event records 10:00:05.000 --- event record [0] flags 0x19 (point,id,parent) --- bash.xtrace.parameters.pid 4538 bash.xtrace.parameters.parent 4432 bash.xtrace.parameters.lineno 43 bash.xtrace.parameters.command "true" 10:00:05.000 --- event record [1] flags 0x19 (point,id,parent) --- bash.xtrace.parameters.pid 4538 bash.xtrace.parameters.parent 4432 bash.xtrace.parameters.lineno 45 bash.xtrace.parameters.command "(( count++ ))" 10:00:05.000 --- event record [2] flags 0x19 (point,id,parent) --- bash.xtrace.parameters.pid 4538 bash.xtrace.parameters.parent 4432 bash.xtrace.parameters.lineno 46 bash.xtrace.parameters.command "echo 'awoke, 3'" 10:00:05.000 --- event record [3] flags 0x19 (point,id,parent) --- bash.xtrace.parameters.pid 4538 bash.xtrace.parameters.parent 4432 bash.xtrace.parameters.lineno 47 bash.xtrace.parameters.command "tired 2" 10:00:05.000 --- event record [4] flags 0x19 (point,id,parent) --- bash.xtrace.parameters.pid 4538 bash.xtrace.parameters.parent 4432 bash.xtrace.parameters.lineno 38 bash.xtrace.parameters.function "tired" bash.xtrace.parameters.command "sleep 2" .in .fi .ft 1 .SH FILES .PD 0 .TP 10 .B $PCP_PMCDCONF_PATH command line options used to launch .B pmdabash .TP 10 .B $PCP_PMDAS_DIR/bash/help default help text file for the bash metrics .TP 10 .B $PCP_PMDAS_DIR/bash/Install installation script for the .B pmdabash agent .TP 10 .B $PCP_PMDAS_DIR/bash/Remove undo installation script for .B pmdabash .TP 10 .B $PCP_LOG_DIR/pmcd/bash.log default log file for error messages and other information from .B pmdabash .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .B /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). .SH SEE ALSO .BR bash (1), .BR pmevent (1) and .BR pmcd (1). pcp-3.8.12ubuntu1/man/man3/0000775000000000000000000000000012272262617012223 5ustar pcp-3.8.12ubuntu1/man/man3/pmdatrace.30000664000000000000000000002606212272262501014245 0ustar '\"! tbl | mmdoc '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDATRACE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmtracebegin\f1, \f3pmtraceend\f1, \f3pmtraceabort\f1, \f3pmtracepoint\f1, \f3pmtraceobs\f1, \f3pmtracecounter\f1, \f3pmtracestate\f1, \f3pmtraceerrstr\f1 \- application-level performance instrumentation services .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmtracebegin(const char *\fItag\fP); int pmtraceend(const char *\fItag\fP); int pmtraceabort(const char *\fItag\fP); int pmtracepoint(const char *\fItag\fP); int pmtraceobs(const char *\fItag\fP, double \fIvalue\fP); int pmtracecounter(const char *\fItag\fP, double \fIvalue\fP); char *pmtraceerrstr(int \fIcode\fP); int pmtracestate(int \fIflags\fP); .fi .sp cc ... \-lpcp_trace .ft 1 .SH "FORTRAN SYNOPSIS" .ft 3 .nf character*(*) \fItag\fP integer \fIcode\fP integer \fIflags\fP integer \fIstate\fP character*(*) \fIestr\fP real*8 \fIvalue\fP .fi .sp .nf \fIcode\fP = pmtracebegin(\fItag\fP) \fIcode\fP = pmtraceend(\fItag\fP) \fIcode\fP = pmtraceabort(\fItag\fP) \fIcode\fP = pmtracepoint(\fItag\fP) \fIcode\fP = pmtraceobs(\fItag\fP, \fIvalue\fP) \fIcode\fP = pmtracecounter(\fItag\fP, \fIvalue\fP) pmtraceerrstr(\fIcode\fP, \fIestr\fP) \fIstate\fP = pmtracestate(\fIflags\fP) .fi .sp .nf f77 ... \-lpcp_trace \f1or\f3 f90 ... \-lpcp_trace .fi .ft 1 .SH "JAVA SYNOPSIS" .ft 3 .nf .sp import sgi.pcp.trace; .sp .nf int trace.pmtracebegin(String \fItag\fP); int trace.pmtraceend(String \fItag\fP); int trace.pmtraceabort(String \fItag\fP); int trace.pmtracepoint(String \fItag\fP); int trace.pmtraceobs(String \fItag\fP, double \fIvalue\fP); int trace.pmtracecounter(String \fItag\fP, double \fIvalue\fP); String trace.pmtraceerrstr(int \fIcode\fP); int trace.pmtracestate(int \fIflags\fP); .fi .sp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. The .I pcp_trace library functions provide a mechanism for identifying sections of a program as transactions or events for use by the trace Performance Metrics Domain Agent (refer to .BR pmdatrace (1) and .BR PMDA (3)). .PP The monitoring of transactions using the Performance Co-Pilot (PCP) infrastructure is initiated through a call to .BR pmtracebegin . Time will be recorded from the end of each .B pmtracebegin call to the start of the following call to .BR pmtraceend , where the same \f2tag\f1 identifier is used in both calls. Following from this, no visible recording will occur until at least one call to .B pmtraceend is made referencing a \f2tag\f1 previously used in a call to .BR pmtracebegin . .PP A transaction which is currently in progress can be cancelled by calling .BR pmtraceabort . No transaction data gathered for that particular transaction will be exported, although data from previous and subsequent successful transactions with that .I tag name are still exported. This is most useful when an error condition arises during transaction processing and the transaction does not run to completion. .PP The \f2tag\f1 argument to .BR pmtracebegin , .B pmtraceend and .B pmtraceabort is used to uniquely identify each transaction within the .I pcp_trace library and later by the trace PMDA as the instance domain identifiers for the transaction performance metrics which it exports. These routines are most useful when used around blocks of code which are likely to be executed a number of times over some relatively long time period (in a daemon process, for example). .PP .B pmtracebegin has two distinct roles \- firstly as the initiator of a new transaction, and secondly as a mechanism for setting a new start time. Similarly, .B pmtraceend is used to register a new \f2tag\f1 and its initial state with the trace PMDA, or alternatively to update the statistics which the PMDA currently associates with the given \f2tag\f1. .PP A second form of program instrumentation can be obtained from .BR pmtracepoint . This is a simpler form of monitoring as it exports only the number of times that a particular point in a program has been passed. This differs to the transaction monitoring offered by .B pmtracebegin and .BR pmtraceend , which exports a running count of successful transaction completions as well as statistics on the time interval between the start and end points of each transaction. This function is most useful when start and end points are not well defined. Examples of this would be when the code branches in such a way that a transaction cannot be clearly identified, or when processing does not follow a transactional model, or the desired instrumentation is akin to event rates rather than event service times. .PP The .BR pmtraceobs and .BR pmtracecounter functions have similar semantics to .BR pmtracepoint , but also allow an arbitrary numeric \f2value\f1 to be passed to the trace PMDA. The most recent \f2value\f1 for each \f2tag\f1 is then immediately available from the PMDA. The only difference between .BR pmtraceobs and .BR pmtracecounter is that the value exported via .BR pmtracecounter is assumed to be a monotonically increasing counter value (e.g. the number of bytes read from a socket), whereas the value exported via .BR pmtraceobs can be any value at all. .PP .B pmtracestate allows the application to set state \f2flags\f1 which are honoured by subsequent calls to the \f2pcp_trace\f1 library routines. There are currently two types of flag \- debugging flags and the asynchronous protocol flag. A single call may specify a number of \f2flags\f1 together, combined using a (bitwise) logical OR operation, and overrides the previous state setting. .PP The debugging flags to .B pmtracestate cause \f2pcp_trace\f1 to print diagnostic messages on the standard output stream at important processing points. The default protocol used between the trace PMDA and individual \f2pcp_trace\f1 client applications is a synchronous protocol, which allows for dropped connections to be reestablished at a later stage should this become possible. An asynchronous protocol is also available which does not provide the reconnection capability, but which does away with much of the overhead inherent in synchronous communication. This behaviour can be toggled using the .B pmtracestate call, but must be called before other calls to the library. This differs to the debugging state behaviour, which can be altered at any time. .B pmtracestate returns the previous state (setting prior to being called). .PP The following table describes each of the .B pmtracestate \f2flags\f1 - examples of the use of these flags in each supported language are given in the demo applications (refer to the ``FILES'' section below). .TS box,center; cf(R) | cf(R) lf(CW) | lf(R). State Flags Semantics _ 0 NONE Synchronous PDUs and no diagnostics (default) 1 API Shows processing just below the API (debug) 2 COMMS Shows network-related activity (debug) 4 PDU Shows app<->PMDA IPC traffic (debug) 8 PDUBUF Shows internal IPC buffer management (debug) 16 NOAGENT No PMDA communications at all (debug) 32 ASYNC Use the asynchronous PDU protocol (control) .TE .PP Should any of the .I pcp_trace library functions return a negative value, an error has occurred. This can be diagnosed further using the .B pmtraceerrstr routine, which takes the negative return value as its \f2code\f1 argument, and in the C-callable interface returns a pointer to the associated error message. This points into a static error table, and should therefore not be passed to .BR free (3). The Fortran-callable interface has a slightly different syntax, requiring the destination character array to be passed in as the second argument. The Java-callable interface returns a UTF-8 string, created using the JNI (Java Native Interface) routine .BR NewStringUTF . .SH ENVIRONMENT The .I pcp_trace routines communicate with the trace PMDA via a socket connection, which by default uses TCP/IP port number 4323. This can be over-ridden by setting \f3PCP_TRACE_PORT\f1 to a different port number when the application is started. The host where the trace PMDA is running is by default the localhost, but this can be changed using \f3PCP_TRACE_HOST\f1. When attempting to connect to a remote trace PMDA, after some specified time interval has elapsed, the connection attempt will be aborted and an error status will be returned. The default timeout interval is 3 seconds, and this can be modified by setting \f3PCP_TRACE_TIMEOUT\f1 in the environment to a real number of seconds for the desired timeout. This is most useful in cases where the remote host is at the end of a slow network, requiring longer latencies to establish the connection correctly. .SH NOTES The \f2pcp_trace\f1 Java class interface has been developed and verified using version 1.1 of the Java Native Interface (JNI) specification. .SH FILES .TP 10 .B $PCP_DEMOS_DIR/trace/*.c Sample C programs and source for .BR pmtrace (1). Use .BR make (1) to build these programs. .TP .B $PCP_DEMOS_DIR/trace/fapp1.f Sample Fortran program. Call `make fortran77' or `make fortran90' to build this program. .TP .B $PCP_DEMOS_DIR/trace/japp1.java Sample Java program. `make java' builds the java class file. .TP .B /usr/java/classes/sgi/pcp/trace.java Java trace class definition. .PD .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .IR pmGetConfig (3) function. .SH SEE ALSO .B file:$PCP_DOC_DIR/Tutorial/trace.html, .B pcp.man.tutorial, Provided the, .BR make (1), .BR pmcd (1), .BR pmdatrace (1), .BR pmprobe (1), .BR pmtrace (1), Relevant information is also available from the on-line PCP Tutorial, subsystem from the PCP images has been installed, access the URL and from your web browser. .SH DIAGNOSTICS A negative return value from a \f2pcp_trace\f1 function indicates that an error has occurred \- if this is the case, the return value can be passed to .B pmtraceerrstr to obtain the associated error message. .PP Success is indicated by a return value of zero. .PP .B pmtracestate also returns an integer representing the state \f2flags\f1 which were set prior to the call. .SH CAVEAT .P Applications that use .BR gethostbyname (3N) should exercise caution because the static fields in .I "struct hostent" may not be preserved across some .I pcp_trace calls. In particular, .BR pmtracebegin , .BR pmtraceend , .BR pmtracepoint , .BR pmtracecounter , and .B pmtraceobs may all call .BR gethostbyname (3N) internally. pcp-3.8.12ubuntu1/man/man3/pmdupcontext.30000664000000000000000000000316612272262501015037 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDUPCONTEXT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmDupContext\f1 \- duplicate a PMAPI context .SH "C SYNOPSIS" .ft 3 #include .sp int pmDupContext(void); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION An application using the Performance Metrics Application Programming Interface (PMAPI) may manipulate several concurrent contexts, each associated with a source of performance metrics, e.g. \c .BR pmcd (1) on some host, or an archive log of performance metrics as created by .BR pmlogger (1). .PP Calling .B pmDupContext will replicate the current PMAPI context, returning a handle for the new context that may be used with subsequent calls to .BR pmUseContext (3). .PP Once created, the duplicated context and the original context have independent existence, and so their instance profiles and collection time (relevant only for archive contexts) may be independently varied. .PP The newly replicated context becomes the current context. .SH SEE ALSO .BR PMAPI (3), .BR pmNewContext (3) and .BR pmUseContext (3). pcp-3.8.12ubuntu1/man/man3/mmv_stats_init.30000664000000000000000000000772312272262501015350 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" Copyright (c) 2009 Max Matveev. .\" Copyright (c) 2009 Aconex. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH MMV_STATS_INIT 3 "" "Performance Co-Pilot" .SH NAME \f3mmv_stats_init\f1 - create and initialize Memory Mapped Value file .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n void *mmv_stats_init(const char *\fIname\fP, int \fIcluster\fP, mmv_stats_flags_t\ \fIflags\fP, const\ mmv_metric_t\ *\fIstats\fP, int\ \fInstats\fP, mmv_indom_t\ *\fIindoms\fP, int\ \fInindoms\fP); .sp .in .hy .ad cc ... \-lpcp_mmv \-lpcp .ft 1 .SH DESCRIPTION .P \f3mmv_stats_init\f1 creates and initializes the content of the \f2MMV\f1(5) file, returning a handle that is used in subsequent MMV API calls. .P \f3mmv_stats_stop\f1 performs an orderly shutdown of the mapping handle returned by an earlier initialization call. .P The file is created in the $PCP_TMP_DIR/mmv directory, \f2name\f1 argument is expected to be a basename of the file, not the full path. The metadata content of the file does not change after the file has been created. .P The old file is removed unconditionally unless there was an error. .P \f2cluster\f1 is the preferred MMV PMDA cluster ID to be used for the metrics originating from this call to \f3mmv_stats_init\f1. The \f2flags\f1 provide additional control over the behaviour of the MMV PMDA - e.g. use of MMV_FLAG_PROCESS will ensure values are only exported when the instrumented application is running \- this is verified on each request for new values. .P \f2stats\f1 is the array of \f3mmv_metric_t\f1 elements of length \f2nstats\f1. Each element of the array describes one PCP metric. .P .nf typedef struct { char name[MMV_NAMEMAX]; /* Name of the metric */ __uint32_t item; /* Item component of PMID */ mmv_metric_type_t type; /* Type of the metric */ mmv_metric_sem_t semantics; /* Semantics of the metric */ pmUnits dimension; /* Dimensions (TIME,SPACE,etc) */ __uint32_t indom; /* Instance domain identifier */ char *shorttext; /* Optional, one-line help */ char *helptext; /* Optional, full help text */ } mmv_metric_t; .fi .P If \f3indom\f1 is not zero and not PM_INDOM_NULL, then the metric has multiple values and there must be a corresponding \f2indom\f1 entry in the \f2indom\f1 list (uniquely identified by \f3serial\f1 number). .P The \f2stats\f1 array cannot contain any elements which have no name - this is considered an error and no metrics will be exported in this case. .P \f2indoms\f1 is the array of \f3mmv_indom_t\f1 elements of length \f2nindoms\f1. Each element of the array describes one PCP instance domain. .P .nf typedef struct { __int32_t internal; char external[MMV_NAMEMAX]; } mmv_instances_t; typedef struct { __uint32_t serial; /* Unique serial number */ __uint32_t count; /* Number of instances */ mmv_instances_t *instances; /* Internal/external IDs */ char *shorttext; /* Short help text */ char *helptext; /* Long help text */ } mmv_indom_t; .fi .P .SH RETURNS The function returns the address of the memory mapped region on success or NULL on failure. .SH SEE ALSO .BR mmv_inc_value (3), .BR mmv_lookup_value_desc (3) and .BR mmv (5). pcp-3.8.12ubuntu1/man/man3/pmwebapi.30000664000000000000000000001476612272262501014121 0ustar '\" t macro stdmacro .\" .\" Copyright (c) 2013 Red Hat, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMWEBAPI 3 "PCP" "Performance Co-Pilot" .SH NAME \f3PMWEBAPI\f1 \- introduction to the Performance Metrics Web Application Programming Interface .de SAMPLE .br .RS .nf .nh .. .de ESAMPLE .hy .fi .RE .. .SH OVERVIEW The PMWEBAPI interface is a binding of a subset of the PMAPI to the web. It uses HTTP as transport, REST as organizational style for request/parameter encoding (the GET and POST methods are interchangeable), and JSON as response encoding. A context identifier is used as a persistent way to refer to PMAPI contexts across related web requests. These context identifiers expire after a configurable period of disuse. Errors generally result in HTTP-level error responses. .SH CONTEXT CREATION: pmNewContext To create a new web context identifier, a web client invokes: .TP .B /pmapi/context?local=ANYTHING Creates a PM_CONTEXT_LOCAL PMAPI context. .TP .B /pmapi/context?hostname=STRING .TP .B /pmapi/context?hostspec=STRING Creates a PM_CONTEXT_HOST PMAPI context with the given host name and/or extended specification. If the host specification contains a userid/password combination, then the corresponding pmapi context operations will require HTTP Basic authentication credentials with matching userid/password. .TP .B /pmapi/context?archivefile=ARCHIVE Creates a PM_CONTEXT_ARCHIVE PMAPI context with the given file name. .PP In addition, the web client may add the parameter .B &polltimeout=MMMM for a maximum interval (in seconds) between expected accesses to the given context. This value is limited by pmwebd configuration, and is a courtesy to allow pmwebd to free up memory earlier in case of sudden web application shutdown. If successful, the response from these requests is a JSON document of the form: .SAMPLE { "context" : NNNNN } .ESAMPLE The number (a 32-bit unsigned decimal) is then used in all later operations. .SH PMAPI OPERATIONS The general form of the requests is as follows: .B /pmapi/NNNNN/OPERATION where .TP .B /pmapi is the fixed prefix for all PMWEBAPI operations, .TP .B NNNNN is a PMWEBAPI context number returned from a context-creation call, or assigned permanently at pmwebd startup, and .TP .B OPERATION?PARAM1=VALUE2&PARAM2=VALUE2 identifies the operation and its URL-encoded parameters. Some parameters may be optional. .SS METRIC METADATA: pmLookupName, pmLookupDesc, pmTraversePMNS_r The general form of the requests is as follows: .TP .B /pmapi/NNNNN/_metric Traverse the entire PMNS. .TP .B /pmapi/NNNNN/_metric?prefix=NAME Traverse the subtree of PMNS with the prefix NAME. .PP The response is a JSON document that provides the metric metadata as an array. For example: .SAMPLE { "metrics": [ { "name":"foo.bar", "pmID":PPPP, "indom":DDDD, "type":"32", "sem":"instant", "units":"MHz", "text-oneline":"foo bar", "text-help":"blah blah blah" }, { "name":"foo.bar2", ... } ... ] } .ESAMPLE Most of the fields are self-explanatory. .TP PPPP the PMID .TP DDDD the instance domain .TP type from pmTypeStr .TP units from pmUnitsStr .TP sem an abbreviation of the metric semantic: .TS l l. PM_SEM_COUNTER "counter" PM_SEM_INSTANT "instant" PM_SEM_DISCRETE "discrete" .TE .SS METRIC VALUE: pmFetch The general form of the requests is as follows: .TP .B /pmapi/NNNNN/_fetch?names=NAME1,NAME2 Fetch current values for given named metrics. .TP .B /pmapi/NNNNN/_fetch?pmids=PPPP1,PPPP2 Fetch current values for given PMIDs. .PP The response is a JSON document that provides the values for all requested metrics, for all their instances. .SAMPLE { "timestamp": { "s":SEC, "us":USEC }, "values": [ { "pmid":PPPP1, "name":"NAME1", "instances:" [ { "instance":IIII1, "value":VALUE1 } { "instance":IIII2, "value":VALUE2 } ... ] }, { "pmid":PPPP2, "name":"NAME2", ... } ... ] } .ESAMPLE Most of the fields are self-explanatory. Numeric metric types are represented as JSON integer or floating-point values. Strings are passed verbatim, except that non-ASCII values are replaced with a Unicode 0xFFFD REPLACEMENT CHARACTER code. Event type metrics are not currently supported. .SS INSTANCE DOMAINS METADATA: pmGetInDom, pmNameInDom, pmLookupInDom The general form of the requests is as follows: .TP .B /pmapi/NNNN/_indom?indom=DDDD List instances of the given instance domain. .TP .B /pmapi/NNNN/_indom?name=NAME List instances of the instance domain belonging to the named metric. .PP In addition, either query may be suffixed with: .TP .B &instance=IIII,JJJJ Restrict listings to given instance code numbers. .TP .B &iname=INAME1,INAME2 Restrict listings to given instance names. .PP The response is a JSON document that provides the metric metadata as an array. For example: .SAMPLE { "indom":DDDD, "instances": [ { "instance":IIII, "name":"INAME" } ... ] } .ESAMPLE .SS INSTANCE PROFILE: pmAddProfile, pmDelProfile .TP .B /pmapi/NNNN/_profile_reset? These are not currently supported. .TP .B /pmapi/NNNN/_profile_reset?indom=DDDD These are not currently supported. .TP .B /pmapi/NNNN/_profile_add?indom=DDDD&instance=IIII,JJJJ These are not currently supported. .TP .B /pmapi/NNNN/_profile_add?indom=DDDD&iname=IIII,JJJJ These are not currently supported. .TP .B /pmapi/NNNN/_profile_del?indom=DDDD&instance=JJJJ These are not currently supported. .TP .B /pmapi/NNNN/_profile_del?indom=DDDD&iname=INAME1,INAME2 These are not currently supported. .SS DERIVED METRICS: pmRegisterDerived .TP .B /pmapi/NNNNN/_derive?name=NAME&expr=EXPRESSION These are not currently supported. .SS CONTEXT COPY: pmDupContext .TP .B /pmapi/NNNNN/copy These are not currently supported. .SS CONTEXT CLOSE: pmDestroyContext .TP .B /pmapi/NNNNN/destroy This is not likely to be supported, as it is destructive and would offer a tempting target to brute-force attackers. Instead, the pmwebd timeout is used to automatically free unused contexts. .SH SEE ALSO .BR PCPIntro (1), .BR PCPIntro (3), .BR pmwebd (3), and .BR PMAPI (3) pcp-3.8.12ubuntu1/man/man3/pmdaeventarray.30000664000000000000000000001452612272262501015331 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAEVENTARRAY 3 "PCP" "Performance Co-Pilot" .SH NAME .ad l \f3pmdaEventNewArray\f1, \f3pmdaEventResetArray\f1, \f3pmdaEventReleaseArray\f1, \f3pmdaEventAddRecord\f1, \f3pmdaEventAddMissedRecord\f1, \f3pmdaEventAddParam\f1, \f3pmdaEventGetAddr\f1 \- utilities for PMDAs to build packed arrays of event records .br .ad .SH "C SYNOPSIS" .ft 3 .nf #include #include #include .fi .sp .ad l .hy 0 .in +8n .ti -8n int pmdaEventNewArray(void); .br .ti -8n int pmdaEventResetArray(int \fIidx\fP); .br .ti -8n int pmdaEventReleaseArray(int \fIidx\fP); .br .ti -8n int pmdaEventAddRecord(int \fIidx\fP, struct timeval *\fItp\fP, int\ \fIflags\fP); .br .ti -8n int pmdaEventAddMissedRecord(int \fIidx\fP, struct timeval *\fItp\fP, int\ \fInmissed\fP); .br .ti -8n int pmdaEventAddParam(int \fIidx\fP, pmID \fIpmid\fP, int \fItype\fP, pmAtomValue\ *\fIavp\fP); .br .ti -8n pmEventArray *pmdaEventGetAddr(int \fIidx\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. A Performance Metrics Domain Agent (PMDA) that wishes to export event records (or trace records) is encouraged to use a metric of type .B PM_TYPE_EVENT to encode a group of event records into a single packed array. .PP The packed array of event records format is defined in .I and consists of a .B pmEventArray structure, containing a variable number of .B pmEventRecord structures, each of which contains a variable number of .B pmEventParameter structures, which in turn may contain a variable length value for each parameter of each event record. .PP The routines described here are designed to assist the PMDA developer in building a packed array of event records, and managing all of the memory allocations required to hold each instance of an array of event records in a contiguous buffer. Normal use would be as part of PMDA's .B pmdaFetchCallBack method. .PP .B pmdaEventNewArray is used to create a new event array. The return value is a small integer that is used as the .I idx parameter to the other routines to identify a specific event array. If needed, a PMDA can create and use multiple event arrays. .PP To start a new cycle and refill an event array from the beginning, call .BR pmdaEventResetArray . .PP If the PMDA has finished with an event array, .B pmdaEventReleaseArray may be used to release the underlying storage and ``close'' the event array so that subsequent attempts to use .I idx will return .BR PM_ERR_NOCONTEXT . .PP To start a new event record, use .BR pmdaEventAddRecord . The timestamp for the event record is given via .I tp and the .I flags parameter may be used to set the control field that determines the type of the event record \- .I flags may be the bit-wise ``or'' of one or more of the .B PM_EVENT_FLAG_* values defined in .I (but note that .B PM_EVENT_FLAG_MISSED should not be used in this context). .PP If event records have been missed, either because the PMDA cannot keep up or because the PMAPI client cannot keep up, then .B pmdaEventAddMissedRecord may be used. .I idx and .I tp have the same meaning as for .B pmdaEventAddRecord and .I nmissed is the number of event records that have been missed at this point in the time-series of event records. .B pmdaEventAddMissedRecord may be called multiple times for a single batch of event records if there are more than one ``missed event record'' episode. .PP Once an event record has been started by calling .BR pmdaEventAddRecord , one or more event parameters may be added using .BR pmdaEventAddParam . The .I pmid and .I type parameters decribe the PMID of the parameter and the data type (one of the .B PM_TYPE_* values from .IR ) of the value that is passed via .IR avp . .I type should one where the size of the value is implied by the .I type or by the length of a string value (for .BR PM_TYPE_STRING ) or encoded within .I avp->vbp (for .BR PM_TYPE_AGGREGATE ). .PP Once the packed array has been constructed, .B pmdaEventGetAddr should be used to initialize the .B ea_type and .B ea_len fields at the start of the .B pmEventArray and return the base address of the event array that is assigned to the .B vp field of the .B pmAtomValue structure that the .B pmdaFetchCallBack method should return. .SH EXAMPLE The following skeletal code shows how these routines might be used. .PP .ft CW .ps -1 .nf int sts; int myarray; int first = 1; pmEventArray eap; if (first) { first = 0; if ((myarray = pmdaEventNewArray()) < 0) { // report error and fail } } pmdaEventResetArray(myarray); // loop over all event records to be exported \&... { struct timeval stamp; int flags; // establish timestamp and set flags to 0 or some combination // of PM_EVENT_FLAG_POINT, PM_EVENT_FLAG_START, PM_EVENT_FLAG_ID, // etc if ((sts = pmdaEventAddRecord(myarray, &stamp, flags)) < 0) { // report error and fail } // loop over all parameters for this event record ... { pmID pmid; int type; pmAtomValue atom; // construct pmid, type and atom for the parameter and // its value if ((sts = pmdaEventAddParam(myarray, pmid, type, &atom)) < 0) { // report error and fail } } // if some event records were missed (could be at the start // of the exported set, or at the end, or in the middle, or // a combination of multiple missed record episodes) ... { int nmiss; struct timeval stamp; if ((sts = pmdaEventAddMissedRecord(myarray, &stamp, nmiss)) < 0) { // report error and fail } } } // finish up eap = pmdaEventGetAddr(myarray); .fi .ps .ft .SH SEE ALSO .BR pmdaEventNewQueue (3), .BR pmdaEventNewClient (3), .BR PMDA (3) and .BR pmEventFlagsStr (3). pcp-3.8.12ubuntu1/man/man3/pmiwrite.30000664000000000000000000000345412272262501014145 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIWRITE 3 "" "Performance Co-Pilot" .SH NAME \f3pmiWrite\f1 \- flush data to a LOGIMPORT archive .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmiWrite(int \fIsec\fP, int \fIusec\fP); .sp cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp pmiWrite($\fIsec\fP, $\fIusec\fP); .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiWrite forces accumulated data values out to the PCP archive. .PP The data values and associated metadata have previously been built up using calls to .BR pmiAddMetric (3), .BR pmiAddInstance (3), .BR pmiPutValue (3) and .BR pmiPutValueHandle (3). .PP The current set of data values and any new metadata is written to the archive with a timestamp of .I sec and .I usec in the source timezone of the archive, see .BR pmiSetTimezone (3). .SH DIAGNOSTICS .B pmiWrite returns zero on success else a negative value that can be turned into an error message by calling .BR pmiErrStr (3). .SH SEE ALSO .BR LOGIMPORT (3), .BR pmiAddInstance (3), .BR pmiAddMetric (3), .BR pmiErrStr (3), .BR pmiPutValue (3), .BR pmiPutValueHandle (3) and .BR pmiSetTimezone (3). pcp-3.8.12ubuntu1/man/man3/pmreconnectcontext.30000664000000000000000000000734412272262501016231 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMRECONNECTCONTEXT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmReconnectContext\f1 \- reconnect to a PMAPI context .SH "C SYNOPSIS" .ft 3 #include .sp int pmReconnectContext(int \fIhandle\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION As a consequence of network, host or Performance Metrics Collector Daemon (PMCD) failures, an applications connection to a PMCD may be established and then subsequently lost. .PP The routine .B pmReconnectContext allows an application to request that the context identified by .I handle should be re-established, provided the associated PMCD is accessible. .PP To avoid flooding the system with reconnect requests, .B pmReconnectContext will only attempt a reconnection after a suitable delay from the previous unsuccessful attempt to reconnect this context. This imposed restriction on the reconnect re-try time interval uses an exponential back-off so that the initial delay is 5 seconds after the first unsuccessful attempt, then 10 seconds, then 20 seconds, then 40 seconds and then 80 seconds thereafter. .PP The environment variable .B PMCD_RECONNECT_TIMEOUT may be used to redefine the back-off intervals, see .BR PMAPI (3). .PP If the reconnection succeeds, .B pmReconnectContext returns .IR handle . .PP If .I handle identifies a context associated with an archive source of metrics, .B pmReconnectContext does nothing and returns .IR handle . .PP Calling .B pmReconnectContext with a handle identifying a currently connected context will cause the connection to be broken before any reconnection is attempted. .PP Note that even in the case of a successful reconnection, .B pmReconnectContext does not change the current Performance Metrics Application Programming Interface (PMAPI) context. .PP When attempting to connect to a remote .BR pmcd (1) on a machine that is booting, .B pmReconnectContext could potentially block for a long time until the remote machine finishes its initialization. .B pmReconnectContext will abort and return an error if the connection has not been established after some specified interval has elapsed. The default interval is 5 seconds. This may be modified by setting .B PMCD_CONNECT_TIMEOUT in the environment to a real number of seconds for the desired timeout. This is most useful in cases where the remote host is at the end of a slow network, requiring longer latencies to establish the connection correctly. .SH ENVIRONMENT .TP .B PMCD_CONNECT_TIMEOUT Timeout period (in seconds) for .BR pmcd (1) connection attempts. .TP .B PMCD_RECONNECT_TIMEOUT Redefines the back-off intervals - refer to .BR PMAPI (3). .SH SEE ALSO .BR pmcd (1), .BR PMAPI (3), .BR pmNewContext (3) and .BR pmUseContext (3). .SH DIAGNOSTICS .P .B PM_ERR_NOCONTEXT .IP .I handle does not identify a valid PMAPI context .P .B \-ETIMEDOUT .IP The re-try time has not elapsed, or the reconnection is attempted and fails. .SH CAVEAT .P Applications that use .BR gethostbyname (3) should exercise caution because the static fields in .I "struct hostent" may not be preserved across some .BR PMAPI (3) calls. In particular, .BR pmNewContext (3) and .BR pmReconnectContext (3) both may call .BR gethostbyname (3) internally. pcp-3.8.12ubuntu1/man/man3/pmfreeeventresult.30000664000000000000000000000270312272262501016060 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMFREEEVENTRESULT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmFreeEventResult\f1 \- release storage allocated for unpacked event records .SH "C SYNOPSIS" .ft 3 #include .sp void pmFreeEventResult(pmResult **\fIrset\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. When processing event records, if .BR pmUnpackEventRecords (3) is used to unpack event records from a metric within a .I pmResult structure with a value of type .B PM_TYPE_EVENT then the structure returned from .BR pmUnpackEventRecords (3) is a NULL pointer terminated array of pointers to .I pmResult structures, one for each event record. .PP .B pmFreeEventResult is a convenience method that frees all of the .I pmResult structures and the array of pointers (\c .IR rset ). .SH SEE ALSO .BR PMAPI (3) and .BR pmUnpackEventRecords (3). pcp-3.8.12ubuntu1/man/man3/pmisettimezone.30000664000000000000000000000300712272262501015353 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMISETTIMEZONE 3 "" "Performance Co-Pilot" .SH NAME \f3pmiSetTimezone\f1 \- set the source timezone for a LOGIMPORT archive .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmiSetTimezone(const char *\fIvalue\fP); .sp cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp pmiSetTimezone($\fIvalue\fP); .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiSetTimezone sets the source timezone in the current context to be .IR value . .PP In the absence of a call to .B pmiSetTimezone the source timezone defaults to the timezone of the localhost. .SH DIAGNOSTICS .B pmiSetTimezone returns zero on success else a negative value that can be turned into an error message by calling .BR pmiErrStr (3). .SH SEE ALSO .BR LOGIMPORT (3), .BR pmiErrStr (3), .BR pmiSetHostname (3) and .BR pmiStart (3). pcp-3.8.12ubuntu1/man/man3/pmnameall.30000664000000000000000000000475712272262501014262 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNAMEALL 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmNameAll\f1 \- translate a PMID to a set of performance metric names .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmNameAll(pmID \fIpmid\fP, char ***\fInameset\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Given a Performance Metric ID (PMID) via .IR pmid , .B pmNameAll will determine all the corresponding metric names, if any, in the Performance Metrics Name Space (PMNS), and return these via .IR nameset . .PP The resulting list of pointers .I nameset .B and the values (the relative names) that the pointers reference will have been allocated by .B pmNameAll with a single call to .BR malloc (3C), and it is the responsibility of the .B pmNameAll caller to .CW free(nameset) to release the space when it is no longer required. .PP In the absence of errors, .B pmNameAll returns the number of names in .IR nameset . .PP For many examples of a PMNS, there will be a 1:1 mapping between a name and a PMID, and under these circumstances, .BR pmNameID (3) provides a slightly simpler interface in the absence of duplicate names for a particular PMID. .SH SEE ALSO .BR PMAPI (3), .BR pmGetChildren (3), .BR pmGetChildrenStatus (3), .BR pmGetConfig (3), .BR pmLoadASCIINameSpace (3), .BR pmLoadNameSpace (3), .BR pmLookupName (3), .BR pmNameID (3), .BR pmNewContext (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOPMNS\f1 Failed to access a PMNS for operation. Note that if the application hasn't a priori called .BR pmLoadNameSpace (3) and wants to use the distributed PMNS, then a call to .B pmNameAll must be made after the creation of a context (see .BR pmNewContext (3)). .IP \f3PM_ERR_PMID\f1 .I pmid does not correspond to a defined PMID in the PMNS. .IP \f3PM_ERR_*\f1 Other diagnostics are for protocol failures when accessing the distributed PMNS. pcp-3.8.12ubuntu1/man/man3/pmunitsstr.30000664000000000000000000000472112272262501014533 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMUNITSSTR 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmUnitsStr\f1, \f3pmUnitsStr_r \- convert a performance metric's units into a string .SH "C SYNOPSIS" .ft 3 #include .sp const char *pmUnitsStr(const pmUnits *\fIpu\fP); .br char *pmUnitsStr_r(const pmUnits *\fIpu\fP, char *\fIbuf\fP, int \fIbuflen\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. The encoding of a performance metric's dimensionality and scale uses a .CW pmUnits structure; see .BR pmLookupDesc (3). .PP As an aid to labeling graphs and tables, or for error messages, .B pmUnitsStr will take a dimension and scale specification as per .IR pu , and return the corresponding text string. The .B pmUnitsStr_r function does the same, but stores the result in a user-supplied buffer .I buf of length .IR buflen , which should have room for at least 60 bytes. .PP For example .CW "{1, -2, 0, PM_SPACE_MBYTE, PM_TIME_SEC, 0}" , as the value of .I *pu gives the result string .CW "Mbyte / sec^2" . .PP The string value result from .B pmUnitsStr is held in a single static buffer, so the returned value is only valid until the next call to .BR pmUnitsStr . .PP If the ``count'' dimension is non-zero, and the ``count'' scale is not zero, then the text string will include a decimal scaling factor, eg. .CW "count x 10^6" . .PP As a special case, if all components of the dimension are zero, then the ``count'' scale is used to produce the text. If this scale is zero the result is an empty string, otherwise the result is of the form .CW "x1 0^2" . .SH NOTES .B pmUnitsStr returns a pointer to a static buffer and hence is not thread-safe. Multi-threaded applications should use .B pmUnitsStr_r instead. .SH SEE ALSO .BR PMAPI (3), .BR pmAtomStr (3), .BR pmConvScale (3), .BR pmExtractValue (3), .BR pmLookupDesc (3), .BR pmPrintValue (3) and .BR pmTypeStr (3). pcp-3.8.12ubuntu1/man/man3/pmsortinstances.30000664000000000000000000000243512272262501015537 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMSORTINSTANCES 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmSortInstances\f1 \- sort performance metric values on instance identifier .SH "C SYNOPSIS" .ft 3 #include .sp void pmSortInstances(pmResult *\fIresult\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. .PP The routine .B pmSortInstances may be used to guarantee that for each performance metric in the .I result from .BR pmFetch (3), the instances are in ascending instance identifier sequence. .PP This is most useful when trying to compute rates from two consecutive .BR pmFetch (3) results. .SH SEE ALSO .BR PMAPI (3) and .BR pmFetch (3). .SH DIAGNOSTICS None. pcp-3.8.12ubuntu1/man/man3/pmnameid.30000664000000000000000000000447312272262501014101 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNAMEID 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmNameID\f1 \- translate a PMID to a performance metric name .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmNameID(pmID \fIpmid\fP, char **\fIname\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION Given a Performance Metric ID (PMID) via .IR pmid , .B pmNameID will determine the corresponding metric name, if any, in the Performance Metrics Name Space (PMNS), and return this via .IR name . .PP If the PMNS contains multiple names associated with the requested PMID, one of these will be returned via .IR name , but there is no way to determine which of the duplicate names this will be. See .BR pmNameAll (3) if all of the corresponding names are required. .PP .I name is a null-byte terminated string, allocated by .B pmNameID using .BR malloc (3C) and it is the caller's responsibility to call .BR free (3C) to release the storage when the value is no longer required. .PP In the absence of errors, .B pmNameID returns zero. .SH SEE ALSO .BR PMAPI (3), .BR pmGetChildren (3), .BR pmGetChildrenStatus (3), .BR pmGetConfig (3), .BR pmLoadASCIINameSpace (3), .BR pmLoadNameSpace (3), .BR pmLookupName (3), .BR pmNameAll (3), .BR pmNewContext (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOPMNS\f1 Failed to access a PMNS for operation. Note that if the application hasn't a priori called .BR pmLoadNameSpace (3) and wants to use the distributed PMNS, then a call to .B pmNameId must be made after the creation of a context (see .BR pmNewContext (3)). .IP \f3PM_ERR_PMID\f1 .I pmid does not correspond to a defined PMID in the PMNS. .IP \f3PM_ERR_*\f1 Other diagnostics are for protocol failures when accessing the distributed PMNS. pcp-3.8.12ubuntu1/man/man3/pmloadderivedconfig.30000664000000000000000000000375712272262501016320 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2009 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOADDERIVEDCONFIG 3 "" "Performance Co-Pilot" .SH NAME \f3pmLoadDerivedConfig\f1 \- load derived metric definitions from a file .SH "C SYNOPSIS" .ft 3 #include .sp int pmLoadDerivedConfig(char *\fIfname\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .PP Each line of the file .I fname is either a comment line (with a ``#'' in the first position of the line) or the declaration of a derived performance metric, specified as: .IP * 2n the name of the derived metric, using the same ``dot notation'' syntax that is used for PCP performance metrics, see .BR PCPIntro (1) and .BR pmns (5). .IP * 2n an equals sign (``='') .IP * 2n a valid expression for a derived metric, as described in .BR pmRegisterDerived (3). .PP White space is ignored in the lines. .PP For each line containing a derived metric definition, .BR pmRegisterDerived (3) is called to register the new derived metric. .PP The result from .B pmLoadDerivedConfig will be the number of derived metrics loaded from .I fname else a value less than zero in the case of an error. .SH EXAMPLE .nf # sample derived metric definitions bad_in_pkts = network.interface.in.errors + network.interface.in.drops # note the following would need to be on a single line ... disk.dev.read_pct = 100 * delta(disk.dev.read) / (delta(disk.dev.read) + delta(disk.dev.write)) .fi .SH SEE ALSO .BR PCPIntro (1), .BR PMAPI (3) and .BR pmRegisterDerived (3). pcp-3.8.12ubuntu1/man/man3/pmdadaemon.30000664000000000000000000000472512272262501014414 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDADAEMON 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaDaemon\f1 \- initialize the PMDA to run as a daemon .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n void pmdaDaemon(pmdaInterface *\fIdispatch\fP, int \fIinterface\fP, char\ *\fIname\fP, int\ \fIdomain\fP, char\ *\fIlogfile\fP, char\ *\fIhelptext\fP); .sp .in .hy .ad cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION .B pmdaDaemon initializes the .B pmdaInterface structure to use the .I interface extensions assuming the .BR PMDA (3) is to be run as a daemon. The .B pmdaInterface structure is initialized with: .TP 15 .I name The name of the agent. .TP .I domain The default domain number of the agent which uniquely identifies this PMDA from other running PMDAs. This may be subsequently changed by a command line option .B \-d (see .BR pmdaGetOpt (3)). .TP .I logfile The default path to the log file. This may be replaced by the .B \-l command line option if using .BR pmdaGetOpt . .TP .I helptext The default path to the help text (see .BR pmdaText (3). This may be replaced by the .B \-h command line option if using .BR pmdaGetOpt (3). If no help text is installed, or you are not using .BR pmdaText (3), then this should be set to NULL. .PP The callbacks are initialized to .BR pmdaProfile (3), .BR pmdaFetch (3), .BR pmdaDesc (3), .BR pmdaText (3), .BR pmdaInstance (3) and .BR pmdaStore (3). .SH DIAGNOSTICS .TP 15 .B Unable to allocate memory for pmdaExt structure In addition, the .I dispatch->status field is set to a value less than zero. .TP .BI "PMDA interface version " interface " not supported" The .I interface version is not supported by .BR pmdaDaemon . .SH CAVEAT The PMDA must be using .B PMDA_INTERFACE_2 or later. .SH SEE ALSO .BR PMAPI (3), .BR PMDA (3), .BR pmdaDSO (3), .BR pmdaGetOpt (3) and .BR pmdaText (3). pcp-3.8.12ubuntu1/man/man3/pmgetpmnslocation.30000664000000000000000000000405212272262501016043 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMGETPMNSLOCATION 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmGetPMNSLocation\f1 \- determine the location of the currently used PMNS .SH "C SYNOPSIS" .ft 3 #include .sp int pmGetPMNSLocation(void); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION If an application needs to know where the Performance Metrics Name Space (PMNS) is coming from then .B pmGetPMNSLocation will return whether it is from an archive, \f3PMNS_ARCHIVE\f1, or from a local PMNS file, \f3PMNS_LOCAL\f1, or from a remote pmcd, \f3PMNS_REMOTE\f1. .P This information may be useful in determining an appropriate error message depending on the PMNS' location. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR PMAPI (3), .BR pmGetConfig (3), .BR pmLoadASCIINameSpace (3), .BR pmLoadNameSpace (3), .BR pmTrimNameSpace (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOPMNS\f1 If is not possible to determine where the location of the PMNS is. This could be due to problems with the current context or being unable to load a local PMNS. pcp-3.8.12ubuntu1/man/man3/pmparsemetricspec.30000664000000000000000000000546012272262501016032 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMPARSEMETRICSPEC 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmParseMetricSpec\f1, \f3pmFreeMetricSpec\f1 \- uniform metric specification parser .SH "C SYNOPSIS" .ft 3 #include .sp .ad l .hy 0 .in +8n .ti -8n int pmParseMetricSpec(const char *\fIstring\fP, int \fIisarch\fP, char\ *\fIsource\fP, pmMetricSpec\ **\fIrsltp\fP, char\ **\fIerrmsg\fP); .br .ti -8n void pmFreeMetricSpec(pmMetricSpec *\fIrslt\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .B pmParseMetricSpec accepts a .B string specifying the name of a PCP performance metric, and optionally the source (either a hostname or a PCP archive log filename) and instances for that metric. The syntax is described in .BR PCPIntro (1). .PP If neither \fBhost\fR nor \fBarchive\fR component of the metric specification is provided, the \fBisarch\fR and \fBsource\fR arguments are used to fill in the returned .B pmMetricSpec structure. .PP The .B pmMetricSpec structure that is returned via .B rsltp represents the parsed .B string and has the following declaration: .PP .nf .ft CW typedef struct { int isarch; /* source type: 0 -> live host, 1 -> archive, 2 -> local context */ char *source; /* name of source host or archive */ char *metric; /* name of metric */ int ninst; /* number of instances, 0 -> all */ char *inst[1]; /* array of instance names */ } pmMetricSpec; .fi .PP .B pmParseMetricSpec returns 0 if the given .B string was successfully parsed. In this case all the storage allocated by .B pmParseMetricSpec can be released by a single call to .BR free (3C) using the address returned from .B pmMetricSpec via .BR rsltp . The convenience macro .B pmFreeMetricSpec is a thinly disguised wrapper for .BR free (3C). .PP .B pmParseMetricSpec returns .B PM_ERR_GENERIC and a dynamically allocated error message string in .BR errmsg , if the given .B string does not parse. Be sure to .BR free (3C) the error message string in this situation. .PP In the case of an error, .B rsltp is undefined. In the case of success, .B errmsg is undefined. If .B "rsltp->ninst" is 0, then .B "rsltp->inst[0]" is undefined. .SH SEE ALSO .BR PMAPI (3) and .BR pmLookupName (3). pcp-3.8.12ubuntu1/man/man3/pmfetcharchive.30000664000000000000000000000417212272262501015273 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMFETCHARCHIVE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmFetchArchive\f1 \- get performance metrics directly from an archive log .SH "C SYNOPSIS" .ft 3 #include .sp int pmFetchArchive(pmResult **\fIresult\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .B pmFetchArchive is a variant of .BR pmFetch (3) that may only be used when the current Performance Metrics Application Programming Interface (PMAPI) context is associated with an archive log. .PP The .I result is instantiated with all of the metrics (and instances) from the next archive record, consequently there is no notion of a list of desired metrics, and the instance profile of the PMAPI context is ignored. .PP It is expected that .B pmFetchArchive would be used to create utilities that scan archive logs, while the more common access to the archives would be via the .BR pmFetch (3) interface. .PP To skip records within the archive log, use .BR pmSetMode (3) to change the collection time within the current PMAPI context, then call .BR pmFetchArchive. .PP Note that the .I result returned by .B pmFetchArchive is dynamically allocated, and must be released using .BR pmFreeResult (3), not .BR free (3C). See .BR pmFetch (3) and .BR pmFreeResult (3) for further details. .PP .B pmFetchArchive returns zero on success. .SH SEE ALSO .BR PMAPI (3), .BR pmFetch (3), .BR pmFreeResult (3), .BR pmNewContext (3), .BR pmSetMode (3) and .BR pmTrimNameSpace (3). .SH DIAGNOSTICS .IP \f3PM_ERR_NOTARCHIVE\f1 the current PMAPI context is not associated with an archive log pcp-3.8.12ubuntu1/man/man3/pmiend.30000664000000000000000000000274712272262501013565 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIEND 3 "" "Performance Co-Pilot" .SH NAME \f3pmiEnd\f1 \- finish up a LOGIMPORT archive .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmiEnd(void); .sp cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp pmiEnd(); .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiEnd closes the current context, forcing the trailer records to be written to the PCP archive files, and then these files are closed. .PP In normal operations, an application would include a call to .B pmiEnd at the end of processing for each context created with a call to .BR pmiStart (3). .SH DIAGNOSTICS .B pmiEnd returns zero on success else a negative value that can be turned into an error message by calling .BR pmiErrStr (3). .SH SEE ALSO .BR LOGIMPORT (3) and .BR pmiStart (3). pcp-3.8.12ubuntu1/man/man3/pmeventflagsstr.30000664000000000000000000000337412272262501015532 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMEVENTFLAGSSTR 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmEventFlagsStr\f1, \f3pmEventFlagsStr_r\f1 \- convert an event record flags value into a string .SH "C SYNOPSIS" .ft 3 #include .sp const char *pmEventFlagsStr(int \fIflags\fP); .br char *pmEventFlagsStr_r(int \fIflags\fP, char *\fIbuf\fP, int \fIbuflen\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. For use in error and diagnostic messages, .B pmEventFlagsStr returns a `human readable' version of the value .IR flags , assuming this to be the .B er_flags field of a .BR pmEventRecord . The .B pmEventFlagsStr_r function does the same, but stores the result in a user-supplied buffer .I buf of length .IR buflen , which should have room for at least 64 bytes. .PP The string value result from .B pmEventFlagsStr is held in a single static buffer, so the returned value is only valid until the next call to .BR pmEventFlagsStr . .SH NOTES .B pmEventFlagsStr returns a pointer to a static buffer and hence is not thread-safe. Multi-threaded applications should use .B pmEventFlagsStr_r instead. .SH SEE ALSO .BR PMAPI (3) and .BR pmdaEventAddRecord (3). pcp-3.8.12ubuntu1/man/man3/pmnewzone.30000664000000000000000000000304612272262501014324 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNEWZONE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmNewZone\f1 \- establish a reporting timezone .SH "C SYNOPSIS" .ft 3 #include .sp int pmNewZone(const char *\fItz\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION The current reporting timezone affects the timezone used by .BR pmCtime (3) and .BR pmLocaltime (3). .PP The argument .I tz defines a timezone string, in the format described for the .B TZ environment variable, see .BR environ (5). .PP .B pmNewZone sets the current reporting timezone, and returns a value that may be used in a subsequent call to .BR pmUseZone (3) to restore this reporting timezone. .SH SEE ALSO .BR PMAPI (3), .BR pmCtime (3), .BR pmGetConfig (3), .BR pmLocaltime (3), .BR pmNewContextZone (3), .BR pmUseZone (3), .BR pmWhichZone (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR environ (5). .SH DIAGNOSTICS A return value less than zero indicates a fatal error from a system call, most likely .BR malloc (3C). pcp-3.8.12ubuntu1/man/man3/pmparsehostattrsspec.30000664000000000000000000001502412272262501016577 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMPARSEHOSTATTRSSPEC 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmParseHostAttrsSpec\f1, \f3__pmUnparseHostAttrsSpec\f1, \f3__pmFreeHostAttrsSpec\f1, \f3__pmFreeAttrsSpec\f1 \- host and attributes specification parser .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int __pmParseHostAttrsSpec(const char *\fIstring\fP, pmHostSpec **\fIhostsp\fP, int\ *\fIcount\fP, __pmHashCtl\ *\fIattrs\fP, char\ **\fIerrmsg\fP); .br .ti -8n int __pmUnparseHostAttrsSpec(pmHostSpec *\fIhostsp\fP, int\ *\fIcount\fP, __pmHashCtl\ *\fIattrs\fP, char\ *\fIstring\fP, size_t \fIsize\fP); .br .ti -8n void __pmFreeHostAttrsSpec(pmHostSpec *\fIhosts\fP, int \fIcount\fP, __pmHashCtl\ *\fIattrs\fP); .br .ti -8n void __pmFreeAttrsSpec(__pmHashCtl\ *\fIattrs\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .B __pmParseHostAttrsSpec accepts a .B string specifying the location of a PCP performance metric collector daemon, and any attributes that should be associated with the connection to that daemon. .PP The syntax allows the optional specification of a protocol (native PCP protocol, encrypted PCP protocol or unix domain socket protocol). .PP If the specified protocol is native PCP protocol, or encrypted PCP protocol, an initial .BR pmcd (1) hostname with optional port numbers and optional proxy host, and optional attributes which are to be associated with the connection may be specified. Some examples follow: .PP .in +0.5i .nf .ft CW pcp://nas1.servers.com:44321@firewalls.r.us?compress pcps://nas1.servers.com?user=otto&pass=blotto&compress .ft R .fi .in .PP If the specified protocol is a unix domain socket protocol, the path to the socket in the local file system may be specified along with optional attributes which are to be associated with the connection. For example: .PP .in +0.5i .nf .ft CW unix://$PCP_RUN_DIR/pmcd.socket:?compress local://my/local/pmcd.socket:?user=otto&pass=blotto&compress .ft R .fi .in .PP If the optional protocol component is not specified, then the default setting will be used - which is the native PCP binary protocol. However, this can still be overwritten via the environment as described in .BR PCPIntro (1). If the protocol prefix is specified, it must be one of either "pcp://" (clear), "pcps://" (secure, encrypted), "unix://" (authenticated local) or "local://" ("unix://" then "pcp://"). .PP The path specified for the "unix://" and "local://" protocols will always be interpreted as an absolute path name. For example, the following are all interpreted identically as .IR $PCP_RUN_DIR/pmcd.socket . .PP .in +0.5i .nf .ft CW unix://$PCP_RUN_DIR/pmcd.socket unix:/$PCP_RUN_DIR/pmcd.socket unix:$PCP_RUN_DIR/pmcd.socket .ft R .fi .in .PP Refer to .BR __pmParseHostSpec (3) for further details of the host and proxy host components. .PP If any optional connection attributes are to be specified, these are separated from the hostname component via the '?' character. Each attribute is separated by the '&' character, and each can be either a simple attribute flag (such as "compress") or a name=value pair (such as "username=fred"). .PP .B __pmParseHostAttrsSpec takes a null-terminated host-and-attributes specification .B string and returns an array of .B pmHostSpec structures, where the array has .B count entries, and an .B attrs hash table containing any attributes (including the optional protocol, if it was specified). .PP Full details of the .B pmHostSpec structures are provided in .BR __pmParseHostSpec (3). .PP The .B __pmHashCtl structure that is filled out on return via .BR attributes , represents each individual attribute in the specification .B string with any associated value. It should be considered an opaque structure and should be zeroed beforehand. .PP The returned hash table control structure can be iterated using one of the supplied iteration mechanisms \- .B __pmHashWalkCB (a callback-based mechanism) or .B __pmHashWalk (a simple procedural mechanism). These provide access to the individual hash nodes, as .B __pmHashNode entries, which provide access to decoded attributes and their (optional) values. .PP .nf .ft CW typedef struct __pmHashNode { __pmHashNode *next; /* next node in hash bucket (internal) */ unsigned int key; /* key identifying particular attribute */ void *data; /* attributes value (optional, string) */ } __pmHashNode; .fi .PP There are a set number of valid attributes, however these may be extended in future releases as new connection parameters become needed. These can be identified via the PCP_ATTR_* macros in the PCP header files. .PP .B __pmUnparseHostSpec performs the inverse operation, creating a .B string representation from .B hosts and .B attributes structures. The size of the supplied .B string buffer must be provided by the caller using the .B size parameter. .SH "RETURN VALUE" If the given .B string is successfully parsed .B __pmParseHostAttrsSpec returns zero. In this case the dynamic storage allocated by .B __pmParseHostAttrsSpec can be released by calling .B __pmFreeHostAttrsSpec using the addresses returned from .B __pmParseHostAttrsSpec .P Alternatively, the .B hosts and .B attributes memory can be freed separately, using .BR __pmFreeHostSpec (3) and .BR __pmFreeAttrsSpec . .P .B __pmParseHostAttrsSpec returns .B PM_ERR_GENERIC and a dynamically allocated error message string in .BR errmsg , if the given .B string does not parse, and the user-supplied .B errmsg pointer is non-null. Be sure to .BR free (3C) the error message string in this situation. .PP In the case of an error, both .B hosts and .B attributes are undefined. In the case of success, .B errmsg is undefined. .PP On success .B __pmUnparseHostAttrsSpec returns a positive value indicating the number of characters written into the supplied buffer. However, if the supplied buffer was too small, a negative status code of .B \-E2BIG will be returned. .SH SEE ALSO .BR pmcd (1), .BR pmproxy (1), .BR pmchart (1), .BR __pmParseHostSpec (3), .BR PMAPI (3) and .BR pmNewContext (3). pcp-3.8.12ubuntu1/man/man3/pmlookupname.30000664000000000000000000000476412272262501015021 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOOKUPNAME 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmLookupName\f1 \- translate performance metric names into PMIDs .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmLookupName(int \fInumpmid\fP, char **\fInamelist\fP, pmID *\fIpmidlist\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .PP Given a list in .I namelist containing .I numpmid full pathnames for performance metrics from a Performance Metrics Name Space (PMNS), .B pmLookupName returns the list of associated Performance Metric Identifiers (PMIDs) via .IR pmidlist . .PP The result from .B pmLookupName will be the number of names translated in the absence of errors, else an error code less than zero. When errors are encountered, the corresponding value in .I pmidlist will be PM_ID_NULL. .PP Note that the error protocol guarantees there is a 1:1 relationship between the elements of .I namelist and .IR pmidlist , hence both lists contain exactly .I numpmid elements. For this reason, the caller is expected to have pre-allocated a suitably sized array for .IR pmidlist . .SH SEE ALSO .BR PMAPI (3), .BR pmGetChildren (3), .BR pmGetChildrenStatus (3), .BR pmGetConfig (3), .BR pmLoadNameSpace (3), .BR pmNameID (3), .BR pmNewContext (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .IP \f3PM_ERR_TOOSMALL\f1 .I numpmid must be at least 1 .IP \f3PM_ERR_NOPMNS\f1 Failed to access a PMNS for operation. Note that if the application hasn't a priori called .BR pmLoadNameSpace (3) and wants to use the distributed PMNS, then a call to .B pmLookupName must be made after the creation of a context (see .BR pmNewContext (3)). .IP \f3PM_ERR_NAME\f1 One or more of the elements of .I namelist does not correspond to a valid metric name in the PMNS. .IP \f3PM_ERR_NONLEAF\f1 A name referred to a node in the PMNS but it was not a leaf node. .IP \f3PM_ERR_*\f1 Other diagnostics are for protocol failures when accessing the distributed PMNS. pcp-3.8.12ubuntu1/man/man3/pmiputvaluehandle.30000664000000000000000000000366612272262501016041 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIPUTVALUEHANDLE 3 "" "Performance Co-Pilot" .SH NAME \f3pmiPutValueHandle\f1 \- add a value for a metric-instance pair via a handle .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmiPutValueHandle(int \fIhandle\fP, const char *\fIvalue\fP); .sp cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp pmiPutValueHandle($\fIhandle\fP, $\fIvalue\fP); .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiPutValueHandle adds a single value to the current output record for a given metric and instance, using the .I handle defined by an earlier call to .BR pmiGetHandle (3). .PP The .I value should be in a format consistent with the metric's type as defined in the call to .BR pmiAddMetric (3). .PP No data will be written until .BR pmiWrite (3) is called, so multiple calls to .B pmiPutValueHandle or .BR pmiPutValue (3) are typically used to accumulate data values for several metric-instance pairs before calling .BR pmiWrite (3). .SH DIAGNOSTICS .B pmiPutValueHandle returns zero on success else a negative value that can be turned into an error message by calling .BR pmiErrStr (3). .SH SEE ALSO .BR LOGIMPORT (3), .BR pmiErrStr (3), .BR pmiGetHandle (3), .BR pmiPutResult (3), .BR pmiPutValue (3) and .BR pmiWrite (3). pcp-3.8.12ubuntu1/man/man3/pmlocalpmda.30000664000000000000000000000614012272262501014571 0ustar '\"macro stdmacro .TH PMLOCALPMDA 3 "" "Performance Co-Pilot" .SH NAME \f3__pmLocalPMDA\f1 \- change the table of DSO PMDAs for PM_CONTEXT_LOCAL contexts .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int __pmLocalPMDA(int \fIop\fP, int \fIdomain\fP, const char *\fIname\fP, const\ char\ *\fIinit\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION PCP contexts of type .B PM_CONTEXT_LOCAL are used by clients that wish to fetch metrics directly from one or more PMDAs on the local host without involving .BR pmcd (1). A PMDA that is to be used in this way must have been built as a Dynamic Shared Object (DSO). .P Historically the table of PMDAs available for use with .B PM_CONTEXT_LOCAL was hardcoded to the following: .IP * 2n The PMDA (or PMDAs) that export the operating system performance data and data about process activity. .PD 0 .IP * The .B mmv PMDA. .IP * The .B sample PMDA provided .B $PCP_LITE_SAMPLE or .B $PMDA_LOCAL_SAMPLE is set in the environment \- used mostly for QA and testing. .PD .PP The initial table of PMDAs available for use with .B PM_CONTEXT_LOCAL is now generated dynamically from all those PMDAs that have been installed as DSOs on the local host. The one exception is the ``pmcd'' PMDA which only operates correctly in the address space of a running .BR pmcd (1) process and so is not available to an application using a .B PM_CONTEXT_LOCAL context. .PP .B __pmLocalPMDA provides a number of services to amend the table of PMDAs available for use with .BR PM_CONTEXT_LOCAL . .P The .I op argument specifies the what should be done and takes one of the following values and actions: .IP PM_LOCAL_ADD 16n Append an entry to the table for the PMDA with a Performance Metrics Domain (PMD) of .IR domain , the path to the DSO PMDA is given by .I path and the PMDA's initialization routine is .IR init . .IP PM_LOCAL_DEL Removes all entries in the table where the .I domain matches, or the .I path matches. Setting the arguments .I domain to \-1 or .I path to .B NULL to force matching on the .I other argument. The .I init argument is ignored. .IP PM_LOCAL_CLEAR Remove all entries from the table. All the other arguments are ignored in this case. .P The .IR domain , .I name and .I init arguments have similar syntax and semantics to the associated fields in the .BR pmcd (1) configuration file. The one difference is the .I path argument which is used by .B __pmLocalPMDA to find a likely looking DSO by searching in this order: .B $PCP_PMDAS_DIR\c /\c .IR path , .IR path , .B $PCP_PMDAS_DIR\c /\c .I path\c \&.\c .I dso-suffix and finally .I path\c \&.\c .I dso-suffix (\c .I dso-suffix is the local platform specific default file name suffix for a DSO, e.g. .B so for Linux, .B dylib for Mac OS X, .B dll for Windows, etc.). .SH "RETURN VALUE" In most cases, .B __pmLocalPMDA returns 0 to indicate success. If .I op is invalid, then the return value is .B PM_ERR_CONV else if there is no matching table entry found for a .B PM_LOCAL_DEL operation, PM_ERR_INDOM is returned. .SH SEE ALSO .BR pmcd (1), .BR PMAPI (3), .BR pmNewContext (3) and .BR __pmSpecLocalPMDA (3). pcp-3.8.12ubuntu1/man/man3/pmaddprofile.30000664000000000000000000000543412272262501014753 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMADDPROFILE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmAddProfile\f1 \- add instance(s) to the current PMAPI instance profile .SH "C SYNOPSIS" .ft 3 #include .sp int pmAddProfile(pmInDom \fIindom\fP, int \fInuminst\fP, int *\fIinstlist\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. The set of instances for performance metrics returned from a .BR pmFetch (3) call may be filtered or restricted using an instance profile. There is one instance profile for each context the application creates at the Performance Metrics Application Programming Interface .RB ( PMAPI (3)), and each instance profile may include instances from one or more instance domains (see .BR pmLookupDesc (3)). .PP .B pmAddProfile may be used to add new instance specifications to the instance profile of the current PMAPI context. .PP In the simplest variant, the list of instances identified by the .I instlist argument for the .I indom instance domain are added to the instance profile. The list of instance identifiers contains .I numinst values. .PP The .I indom value would normally be extracted from a call to .BR pmLookupDesc (3) for a particular performance metric, and the instances in .I instlist would typically be determined by calls to .BR pmGetInDom (3) or .BR pmLookupInDom (3). .PP To select all instances in all instance domains, use .in 1.0i .nf .ft CW pmAddProfile(PM_INDOM_NULL, 0, (int *)0) .ft .fi .in This is the only case where .I indom may be equal to .BR PM_INDOM_NULL . If .I numinst is zero, or .I instlist is NULL, then all instances in .I indom are selected. .SH SEE ALSO .BR PMAPI (3), .BR pmDelProfile (3), .BR pmFetch (3), .BR pmGetInDom (3), .BR pmLookupDesc (3), .BR pmLookupInDom (3), .BR pmNewContext (3), .BR pmUseContext (3) and .BR pmWhichContext (3). .SH DIAGNOSTICS .IP \f3PM_ERR_PROFILESPEC\f1 .I indom was .B PM_INDOM_NULL and .I instlist was not empty .SH CAVEAT It is possible to add non-existent instance domains and non-existent instances to an instance profile. None of the routines that use the instance profile will ever issue an error if you do this. The cost of checking, when checking is possible, outweighs any benefits. pcp-3.8.12ubuntu1/man/man3/pmnameindom.30000664000000000000000000000377212272262501014614 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNAMEINDOM 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmNameInDom\f1 \- translate an instance identifier into an instance name .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmNameInDom(pmInDom \fIindom\fP, int \fIinst\fP, char **\fIname\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. For the instance domain .IR indom , in the current Performance Metrics Application Programming Interface (PMAPI) context, locate the instance with the internal instance identifier given by .IR inst , and return the full external instance identification via .IR name . .PP The value for the instance domain .I indom is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP The space for the value of .I name will have been allocated in .B pmNameInDom with .BR malloc (3C), and it is the responsibility of the caller to .BR free (3C) the space when it is no longer required. .PP .B pmNameInDom returns zero on success. .SH SEE ALSO .BR PMAPI (3), .BR pmGetConfig (3), .BR pmGetInDom (3), .BR pmLookupInDom (3), .BR pmNameInDomArchive (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .IP \f3PM_ERR_INDOM\f1 .I indom is not a valid instance domain identifier .IP \f3PM_ERR_INST\f1 The instance identifier .I inst is not known for the instance domain .I indom in the current PMAPI context pcp-3.8.12ubuntu1/man/man3/pmgetconfig.30000664000000000000000000000652612272262501014612 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMGETCONFIG 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmGetConfig\f1 \- return Performance Co-Pilot configuration variable .SH "C SYNOPSIS" .ft 3 #include .br char *pmGetConfig(const char *\fIvariable\fP); .sp #include .br char *__pmGetAPIConfig(const char *\fIfeature\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION The .B pmGetConfig function searches for .I variable first in the environment and then, if not found, in the Performance Co-Pilot (PCP) configuration file and returns the string result. If .I variable is not already in the environment, it is added with a call to .BR putenv (3) before returning. .PP The default location of the PCP configuration file is .B /etc/pcp.conf but this may be changed by setting .B PCP_CONF in the environment to a new location, as described in .BR pcp.conf (5). .PP The internal .B __pmGetAPIConfig function reports on features of the PCP library. It can be used to query support for multi-threading, security extensions, and other features. .PP The .BR pmconfig (1) utility provides command line access to both of these interfaces, and also provides a mechanism for listing all available .B variables and .B features that are valid arguments to these routines. .SH "RETURN VALUE" If .I variable is not found in either the environment nor the PCP configuration file then the return value is an empty string. If the PCP configuration file is not found then a fatal error message is printed and the process will .BR exit (2) \- although this sounds drastic, it is the only course of action available because the PCP configuration/installation is fatally flawed. .PP If the .B pmGetConfig function returns a non-empty string, the returned value points into the environment and so changing it is a bad idea. This function returns the same type as the .BR getenv (3) function (which should probably be a .IR "const char *" ). .PP The .B __pmGetAPIConfig routine on the other hand returns NULL on failure to lookup the requested .IR feature . It does not modify the environment, and returns a pointer to a static read-only string which also should not be modified or freed by the caller. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR PCPIntro (1), .BR pmconfig (1), .BR exit (2), .BR PMAPI (3), .BR getenv (3C), .BR putenv (3C), .BR pcp.conf (5), .BR pcp.env (5) and .BR environ (5). pcp-3.8.12ubuntu1/man/man3/pmtypestr.30000664000000000000000000000410312272262501014344 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMTYPESTR 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmTypeStr\f1, \f3pmTypeStr_r\f1 \- convert a performance metric type into a string .SH "C SYNOPSIS" .ft 3 #include .sp const char *pmTypeStr(int \fItype\fP); .br char *pmTypeStr_r(int \fItype\fP, char *\fIbuf\fP, int \fIbuflen\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Given a performance metric .IR type , .B pmTypeStr produces a terse ASCII equivalent, appropriate for use in error and diagnostic messages. The .B pmTypeStr_r function does the same, but stores the result in a user-supplied buffer .I buf of length .IR buflen , which should have room for at least 20 bytes. .PP The value for .I type is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP Examples are .B 32 (for .I type equals .BR PM_TYPE_32 ), .B U64 (for .I type equals .BR PM_TYPE_U64 ), .B AGGREGATE (for .I type equals .BR PM_TYPE_AGGREGATE ), etc. .PP The string value result for .B pmTypeStr is held in a single static buffer, so the returned value is only valid until the next call to .BR pmTypeStr . .SH NOTES .B pmTypeStr returns a pointer to a static buffer and hence is not thread-safe. Multi-threaded applications should use .B pmTypeStr_r instead. .SH SEE ALSO .BR PMAPI (3), .BR pmAtomStr (3), .BR pmConvScale (3), .BR pmExtractValue (3), .BR pmLookupDesc (3), .BR pmPrintValue (3) and .BR pmUnitsStr (3). pcp-3.8.12ubuntu1/man/man3/pmparsetimewindow.30000664000000000000000000001056412272262501016063 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMPARSETIMEWINDOW 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmParseTimeWindow\f1 \- parse time window command line arguments .SH "C SYNOPSIS" .ft 3 #include .sp .ad l .hy 0 .in +8n .ti -8n int pmParseTimeWindow(const char *\fIswStart\fP, const\ char\ *\fIswEnd\fP, const\ char\ *\fIswAlign\fP, const\ char\ *\fIswOffset\fP, const\ struct\ timeval\ *\fIlogStart\fP, const\ struct\ timeval\ *\fIlogEnd\fP, struct\ timeval\ *\fIrsltStart\fP, struct\ timeval\ *\fIrsltEnd\fP, struct\ timeval\ *\fIrsltOffset\fP, char\ **\fIerrMsg\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .B pmParseTimeWindow is designed to encapsulate the interpretation of the .BR \-S , .BR \-T , .B \-A and .B \-O command line options used by Performance Co-Pilot (PCP) applications to define a time window of interest. The time window is defined by a start time and an end time that constrains the time interval during which the PCP application will retrieve and display performance metrics. In the absence of the .B \-O and .B \-A options to specify an initial sample time origin and time alignment (see below), the PCP application will retrieve the first sample at the start of the time window. .P The syntax and meaning of the various argument formats for these options is described in .BR PCPIntro (1). .SH USAGE .B pmParseTimeWindow expects to be called with the argument of the .B \-S option as .BR swStart , the argument of the .B \-T option as .BR swEnd , the argument of the .B \-A option as .BR swAlign , and the argument of the .B \-O option as .BR swOffset . Any or all of these parameters may be NULL to indicate that the corresponding command line option was not present. .P If the application is using a PCP archive log as the source of performance metrics, you also need to supply the time of the first archive log entry as .BR logStart , and the time of the last archive log entry as .BR logEnd . See .BR pmGetArchiveLabel (3) and .BR pmGetArchiveEnd (3) for how to obtain values for these times. .P If the application is manipulating multiple concurrent archive logs, then the caller must resolve how the default time window is to be defined (the union of the time intervals in all archive logs is a likely interpretation). .P If the application is using a live feed of performance data, .B logStart should be the current time (but could be aligned on the next second for example), while .B logEnd should have its .I tv_sec component set to .BR INT_MAX . .P The .BR rsltStart , .B rsltEnd and .B rsltOffset structures must be allocated before calling .BR pmParseTimeWindow . .P You also need to set the current PCP reporting time zone to correctly reflect the .B \-z and .B \-Z command line parameters before calling .BR pmParseTimeWindow . See .BR pmUseZone (3) and friends for information on how this is done. .SH SEE ALSO .BR PMAPI (3), .BR pmGetArchiveEnd (3), .BR pmGetArchiveLabel (3), .BR pmNewContextZone (3), .BR pmNewZone (3), .BR pmParseInterval (3) and .BR pmUseZone (3). .SH DIAGNOSTICS If the conversion is successful, .B pmParseTimeWindow returns 1 and fills in .BR rsltStart , .B rsltEnd and .B rsltOffset with the start, end, and offset times for the time window defined by the input parameters. The .B errMsg parameter is not changed when .BR pmParseTimeWindow returns 1. .P If the conversion is successful, but the requested alignment could not be performed (e.g. the PCP archive log is too short) the alignment is ignored, .BR rsltStart , .B rsltEnd and .B rsltOffset are filled in and .BR pmParseTimeWindow returns 0. In this case, .B errMsg will point to a warning message in an internal static buffer. This buffer should not be freed. .P If the argument strings could not be parsed, .B pmParseTimeWindow returns \-1. In this case, .BR errMsg will point to an error message in a static internal buffer. pcp-3.8.12ubuntu1/man/man3/pmloadasciinamespace.30000664000000000000000000000612312272262501016443 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOADASCIINAMESPACE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmLoadASCIINameSpace\f1 \- establish a local PMNS for an application .SH "C SYNOPSIS" .ft 3 #include .sp int pmLoadASCIINameSpace(const char *\fIfilename\fP, int \fIdupok\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION If the application wants to force using a local Performance Metrics Name Space (PMNS) instead of a distributed PMNS then it must load the PMNS using .B pmLoadASCIINameSpace or .BR pmLoadNameSpace (3). If the application wants to use a distributed PMNS, then it should NOT make a call to load the PMNS explicitly. .PP .B pmLoadASCIINameSpace is a variant of .BR pmLoadNameSpace (3) in which the .I dupok argument may be used to control the handling of multiple names in the PMNS that may be associated with a single Performance Metric Identifier (PMID). A value of 0 disallows duplicates, any other value allows duplicates. .PP The .I filename argument designates the PMNS of interest. For applications not requiring a tailored PMNS, the special value .B PM_NS_DEFAULT may be used for .IR filename , to force the default local PMNS to be loaded. .PP The default local PMNS is found in the file .I $PCP_VAR_DIR/pmns/root unless the environment variable .B PMNS_DEFAULT is set, in which case the value is assumed to be the pathname to the file containing the default local PMNS. .PP .B pmLoadASCIINameSpace returns zero on success. .SH FILES .IP \f2$PCP_VAR_DIR/pmns/root\f1 2.5i the default local PMNS, when the environment variable .B PMNS_DEFAULT is unset .RE .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .IR pmGetConfig (3) function. .SH SEE ALSO .BR PMAPI (3), .BR pmGetConfig (3), .BR pmLoadNameSpace (3), .BR pmTrimNameSpace (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). .SH DIAGNOSTICS Syntax and other errors in the parsing of the PMNS are reported on .I stderr with a message of the form ``Error Parsing ASCII PMNS: ...''. .PP .B PM_ERR_DUPPMNS .IP It is an error to try to load more than one PMNS, or to call either .B pmLoadASCIINameSpace and/or .BR pmLoadNameSpace (3) more than once. .PP .B PM_ERR_PMNS .IP Syntax error in an ASCII format PMNS. pcp-3.8.12ubuntu1/man/man3/pmiaddinstance.30000664000000000000000000000477512272262501015277 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIADDINSTANCE 3 "" "Performance Co-Pilot" .SH NAME \f3pmiAddInstance\f1 \- add an element to an instance domain in a LOGIMPORT context .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmiAddInstance(pmInDom \fIindom\fP, const char *\fIinstance\fP, int \fIinst\fP); .sp cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp pmiAddInstance($\fIindom\fP, $\fIinstance\fP, $\fIinst\fP); .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiAddInstance adds a new element to the instance domain identified by .IR indom . .PP .I indom would normally be constructed using the .B pmInDom_build macro, e.g. pmInDom_build(PMI_DOMAIN,0) for the first instance domain in the Performance Metrics Domain PMI_DOMAIN (which is the default for all meta data created by the LOGIMPORT library). .PP The new instance must have both an external name (\c .IR instance ) and an internal instance identifier (\c .IR inst ) that is unique across all instances in the .I indom instance domain. There is a special ``uniqueness rule'' for .I instance that is imposed by .BR pmLookupInDom (3), namely that the external instance name must be unique in the leading non-space characters, e.g. the instance names ``foo'' and ``foo bar'' are considered the same by this rule and not allowed in the same instance domain, but ``foo'' and ``foobar'' would be allowed. .PP Once defined, the external instance name can be used in calls to .BR pmiGetHandle (3) and/or .BR pmiPutValue (3) with the name of a metric defined over the same instance domain. .SH DIAGNOSTICS .B pmiAddInstance returns zero on success else a negative value that can be turned into an error message by calling .BR pmiErrStr (3). .SH SEE ALSO .BR LOGIMPORT (3), .BR pmiAddMetric (3), .BR pmiErrStr (3), .BR pmiGetHandle (3), .BR pmiPutValue (3) and .BR pmLookupInDom (3). pcp-3.8.12ubuntu1/man/man3/pmgetindomarchive.30000664000000000000000000000616712272262501016016 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMGETINDOMARCHIVE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmGetInDomArchive\f1 \- get instance identifiers for a performance metrics instance domain .SH "C SYNOPSIS" .ft 3 #include .sp int pmGetInDomArchive(pmInDom \fIindom\fP, int **\fIinstlist\fP, char ***\fInamelist\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Provided the current Performance Metrics Application Programming Interface (PMAPI) context is associated with an archive log, .B pmGetInDomArchive will scan the union of all the instance domain metadata for the instance domain .IR indom , and return via .I instlist the internal instance identifiers for all instances, and via .I namelist the full external identifiers for all instances. .PP This routine is a specialized version of the more general PMAPI routine .BR pmGetInDom . .PP The number of instances found is returned as the function value (else less than zero to indicate an error). .PP The value for the instance domain .I indom is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP The resulting lists of instance identifiers (\c .I instlist and .IR namelist ), and the names that the elements of .I namelist point to, will have been allocated by .B pmGetInDomArchive with two calls to .BR malloc (3C), and it is the responsibility of the caller to .CW free(instlist) and .CW free(namelist) to release the space when it is no longer required. .PP When the result of .B pmGetInDomArchive is less than one, both .I instlist and .I namelist are undefined (no space will have been allocated, and so calling .BR free (3C) is a singularly bad idea). .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR PMAPI (3), .BR pmGetConfig (3), .BR pmGetInDom (3), .BR pmLookupDesc (3), .BR pmLookupInDomArchive (3), .BR pmNameInDomArchive (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOTARCHIVE\f1 the current PMAPI context is not associated with an archive log .IP \f3PM_ERR_INDOM_LOG\f1 .I indom is not a defined instance domain identifier for the archive log pcp-3.8.12ubuntu1/man/man3/pmnewcontext.30000664000000000000000000001606212272262501015037 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNEWCONTEXT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmNewContext\f1 \- establish a new PMAPI context .SH "C SYNOPSIS" .ft 3 #include .sp int pmNewContext(int \fItype\fP, const char *\fIname\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION An application using the Performance Metrics Application Programming Interface (PMAPI) may manipulate several concurrent contexts, each associated with a source of performance metrics, e.g. \c .BR pmcd (1) on some host, or an archive log of performance metrics as created by .BR pmlogger (1), or a standalone connection on the local host that does not involve .BR pmcd (1). .PP .BR pmNewContext may be used to establish a new context. The source of the metrics is identified by .IR name , and may be either a host name (\c .I type is .BR PM_CONTEXT_HOST ), or the base name common to all of the physical files of an archive log (\c .I type is .BR PM_CONTEXT_ARCHIVE ). .PP For a .I type of .BR PM_CONTEXT_HOST , in addition to identifying a host the .I name may also be used to encode additional optional information in the form of a .BR pmcd (1) port number, a .BR pmproxy (1) hostname and a proxy port number. For example the .I name \&"app23:14321,4321@firewall.example.com:11111" specifies a connection on port .I 14321 (or port .I 4321 if .I 14321 is unavailable) to .BR pmcd (1) on the host .I app23 via port .I 11111 to .BR pmproxy (1) on the host .IR firewall.example.com . .PP For a .I type of .BR PM_CONTEXT_ARCHIVE , .I name may also be the name of any of the physical files of an archive, e.g. .IB myarchive .meta (the metadata file) or .IB myarchive .index (the temporal index) or .IB myarchive .0 (the first data volume of the archive) or .IB myarchive .0.bz2 or .IB myarchive .0.bz (the first data volume compressed with .BR bzip2 (1)) or .IB myarchive .0.gz or .IB myarchive .0.Z or .IB myarchive .0.z (the first data volume compressed with .BR gzip (1)), .IB myarchive .1 or .IB myarchive .3.bz2 or .IB myarchive .42.gz etc. .PP In the case where .I type is .BR PM_CONTEXT_LOCAL , .I name is ignored, and the context uses a standalone connection to the PMDA methods used by .BR pmcd (1). When this type of context is used, the range of accessible performance metrics is constrained to those from the operating system, and optionally the ``proc'', ``sample'' and ``ib'' PMDAs. .PP In the case where \f2type\fP is \f3PM_CONTEXT_HOST\fP, additional flags can be added to the \f2type\fP to indicate if the connection to \f3pmcd\fP(1) should be encrypted (\f3PM_CTXFLAG_SECURE\fP), deferred (\f3PM_CTXFLAG_SHALLOW\fP) and if the file descriptor used to communicate with \f3pmcd\fP(1), should not be shared across contexts (\f3PM_CTXFLAG_EXCLUSIVE\fP). These final two context flags are now deprecated and ignored. .PP The initial instance profile is set up to select all instances in all instance domains. In the case of an archive, the initial collection time is also set to zero, so that an initial .BR pmFetch (3) will result in the earliest set of metrics being returned from the archive. .PP Once established, the association between a context and a source of metrics is fixed for the life of the context, however routines are provided to independently manipulate both the instance profile (see .BR pmAddProfile (3) and .BR pmDelProfile (3)) and the collection time for archives (see .BR pmSetMode (3)). .PP .B pmNewContext returns a handle that may be used with subsequent calls to .BR pmUseContext (3). .PP The new context remains the current PMAPI context for all subsequent calls across the PMAPI, until another call to .BR pmNewContext (3) is made, or the context is explicitly changed with a call to .BR pmDupContext (3) or .BR pmUseContext (3), or destroyed using .BR pmDestroyContext (3). .PP When attempting to connect to a remote .BR pmcd (1) on a machine that is booting, .B pmNewContext could potentially block for a long time until the remote machine finishes its initialization. .B pmNewContext will abort and return an error if the connection has not been established after some specified interval has elapsed. The default interval is 5 seconds. This may be modified by setting .B PMCD_CONNECT_TIMEOUT in the environment to a real number of seconds for the desired timeout. This is most useful in cases where the remote host is at the end of a slow network, requiring longer latencies to establish the connection correctly. .SH ENVIRONMENT .TP .B PMCD_CONNECT_TIMEOUT Timeout period (in seconds) for .BR pmcd (1) connection attempts. .TP .B PMCD_PORT TCP/IP port(s) for connecting to .BR pmcd (1), historically was 4321 and more recently the officially registered port 44321; in the current release, .B pmcd listens on both these ports as a transitional arrangement. If used, should be set to a comma-separated list of numerical port numbers. .TP .B PMDA_PATH When searching for PMDAs to be loaded when .I type is .BR PM_CONTEXT_LOCAL , the .B PMDA_PATH environment variable may be used to define a search path of directories to be used to locate the PMDA executables. The default search path is .BR $PCP_SHARE_DIR/lib:/usr/pcp/lib . .SH CAVEATS When using a .I type of .BR PM_CONTEXT_LOCAL , the operating system PMDA may export data structures directly from the kernel, which means that the .B pmNewContext caller should be an executable program compiled for the same object code format as the booted kernel. .P In addition, applications using a .B PM_CONTEXT_LOCAL context must be single-threaded because the various DSO PMDAs may not be thread-safe. This restriction is enforced at the .BR PMAPI (3), where routines may return the error code .B PM_ERR_THREAD if the library detects calls from more than one thread. .P Applications that use .BR gethostbyname (3N) should exercise caution because the static fields in .I "struct hostent" may not be preserved across some .BR PMAPI (3) calls. In particular, .BR pmNewContext (3) and .BR pmReconnectContext (3) both may call .BR gethostbyname (3N) internally. .SH SEE ALSO .BR pmcd (1), .BR pmproxy (1), .BR pmAddProfile (3), .BR PMAPI (3), .BR pmDelProfile (3), .BR pmDestroyContext (3), .BR pmDupContext (3), .BR pmGetConfig (3), .BR pmReconnectContext (3), .BR pmSetMode (3), .BR pmUseContext (3), .BR pmWhichContext (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .P .B PM_ERR_PERMISSION .IP No permission to perform requested operation .P .B PM_ERR_CONNLIMIT .IP PMCD connection limit for this host exceeded .P .B PM_ERR_NOCONTEXT .IP Requested context type was not .BR PM_CONTEXT_LOCAL , .B PM_CONTEXT_HOST or .BR PM_CONTEXT_ARCHIVE . pcp-3.8.12ubuntu1/man/man3/pmparsetime.30000664000000000000000000000515712272262501014635 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMPARSETIME 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmParseTime\f1 \- parse time point specification .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int __pmParseTime(const char *\fIstring\fP, struct timeval *\fIlogStart\fP, struct\ timeval\ *\fIlogEnd\fP, struct\ timeval\ *\fIrslt\fP, char\ **\fIerrMsg\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .B __pmParseTime is designed to encapsulate the interpretation of a time point specification in command line switches for use by the PCP client tools. .P This function expects to be called with the time point specification as .BR string . If the tool is running against PCP archive(s), you also need to supply the start time of the first (only) archive as .BR logStart , and the end of the last (only) archive as .BR logEnd . See .BR pmGetArchiveLabel (3) and .BR pmGetArchiveEnd (3) for how to obtain values for these parameters. If the tool is running against a live feed of performance data, .B logStart should be the current time (but could be aligned on the next second for example), while .B logEnd should have its tv_sec component set to INT_MAX. .P The .B rslt structure must be allocated before calling .BR __pmParseTime . .P You also need to set the current PCP reporting time zone to correctly reflect the \-z and \-Z command line parameters before calling .BR __pmParseTime . See .BR pmUseZone (3) and friends for information on how this is done. .P If the conversion is successful, .B __pmParseTime returns 0, and fills in .B rslt with the time value defined by the input parameters. If the argument strings could not be parsed, it returns \-1 and a dynamically allocated error message string in .BR errMsg . Be sure to .BR free (3C) this error message string. .SH SEE ALSO .BR PMAPI (3), .BR pmGetArchiveEnd (3), .BR pmGetArchiveLabel (3), .BR pmNewContextZone (3), .BR pmNewZone (3), .BR pmParseInterval (3), .BR pmParseTimeWindow (3), .BR pmUseZone (3), .BR __pmConvertTime (3) and .BR __pmParseCtime (3). pcp-3.8.12ubuntu1/man/man3/pmfetch.30000664000000000000000000002624512272262501013736 0ustar '\"! tbl | mmdoc '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMFETCH 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmFetch\f1 \- get performance metric values .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmFetch(int \fInumpmid\fP, pmID *\fIpmidlist\fP, pmResult **\fIresult\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\fR\\$2 .el \fI\\$1\fR\\$2 .. .\" some useful acronyms ... always cite the full text at the first use .\" and use uppercase acronym thereafter .\" Performance Metrics Application Programming Interface (PMAPI) .\" Performance Metrics Name Space (PMNS) .\" Performance Metrics Collector Daemon (PMCD) .\" Performance Metric ID (PMID) Given a list of Performance Metric IDs (PMID)s, e.g. as constructed by .BR pmLookupName (3), via .I pmidlist and .IR numpmid , fetch the values for these performance metrics. .PP The call to .B pmFetch is executed in the context of a source of metrics, instance profile and collection time, previously established by calls to the appropriate context and profile functions, namely some of .BR pmNewContext (3), .BR pmDupContext (3), .BR pmUseContext (3), .BR pmAddProfile (3), .BR pmDelProfile (3) and .BR pmSetMode (3). .PP The principal result from .B pmFetch is returned in the argument .I result as a tree, using the following component data structures; .PP .ft CW .nf .in +0.5i typedef struct { unsigned int vtype : 8; /* value type (same as pmDesc.type) */ unsigned int vlen : 24; /* bytes for vtype/vlen + vbuf */ char vbuf[1]; /* one or more values */ } pmValueBlock; typedef struct { int inst; /* instance identifier */ union { pmValueBlock *pval; /* pointer to value-block */ int lval; /* integer value insitu */ } value; } pmValue; typedef struct { pmID pmid; /* metric identifier */ int numval; /* number of values or error code */ int valfmt; /* value style, insitu or ptr */ pmValue vlist[1]; /* set of instances/values */ } pmValueSet; /* Result returned by pmFetch() */ typedef struct { struct timeval timestamp; /* time stamped by collector */ int numpmid; /* number of PMIDs */ pmValueSet *vset[1]; /* set of value sets */ } pmResult; .in .fi .ft 1 .PP To accommodate metrics with multiple value instances, the .CW numval field indicates how many values are returned for each requested PMID. The field .CW valfmt in the .CW pmValueSet structure indicates if the values for this metric are stored .I insitu in the .CW lval field, i.e. a 32-bit integer quantity (either int, unsigned int, long or unsigned long) or if the values are held in associated .CW pmValueBlock structures. The .CW pmValueBlock structure is always used for floating point values (float or double) and also accommodates arbitrary sized binary data such as `string-valued' metrics and metrics with aggregated or complex data types. The maximum length of a .CW pmValueBlock buffer is .B PM_VAL_VLEN_MAX bytes. If the .CW pmValueBlock format is used, the .CW vtype field indicates the data type of the value. This field has the same interpretation as the .CW type field in the .B pmDesc structure, see .BR pmLookupDesc (3). .PP Note that the insitu value may be a signed or unsigned 32 bit integer, signed or unsigned 32 bit long value (on 32 bit platforms), In the special cases described below, it may also be a 32 bit floating point value. If the application needs to know the type of an insitu value, which is almost always the case, it is necessary to fetch the descriptor for the metric and interpret the .B type field, as described in detail in .BR pmLookupDesc (3). When the .CW pmResult is received from a PCP1.x .BR pmcd , insitu values may also be 32 bit floating point values (of type .BR PM_TYPE_FLOAT ). In all cases, it is good practice to use .BR pmLookupDesc (3) to fetch the descriptor for the metric and interpret the .B type field therein. Note also that the .BR PMAPI (3) will automatically translate from the PCP2.0 format to the PCP1.x format when a PCP1.x client requests 32 bit floating point values from a PCP2.0 .BR pmcd , but the reverse translation does not occur (because the PCP2.0 .B pmcd cannot automatically distinguish between arbitrary 32 bit floating point values and 32 bit integers). .PP If one value (i.e. associated with a particular instance) for a requested metric is `unavailable' (at the requested time), then there is no associated .CW pmValue structure in the .IR result . If there are no available values for a metric, then .CW numval will be zero and the associated .CW pmValue[] instance will be empty (\c .CW valfmt is undefined in these circumstances, however .CW pmid will be correctly set to the PMID of the metric with no values). .PP As an extension of this protocol, if the Performance Metrics Collection System (PMCS) is able to provide a reason why no values are available for a particular metric, this is encoded as a standard error code in the corresponding .CW numval . Since the error codes are all negative, values for a requested metric are `unavailable' if .CW numval is less than, or equal to, zero. A performance metric's value may be `unavailable' for any of the following reasons; .IP "+" 3n The metric is not supported in this version of the software for the associated Performance Metric Domain .IP "+" Collection is not currently activated in the software for the associated Performance Metric Domain .IP "+" The associated PMID is not known .IP "+" The current system configuration does not include the associated hardware component and/or the associated software module, e.g. a disk is not installed, or off-line, or Oracle is not installed .IP "+" The metric is one for which an instance profile is required, and none was provided (there are a small number of metrics in this category, typically ones with very large, and/or very dynamic instance domains, and/or expensive metric instantiation methods). .PP In general, we may not be able to differentiate between the various cases, and if differentiation is not possible, .CW numval will simply be zero. .PP The argument definition and the result specifications have been constructed to ensure that for each PMID in the requested .I pmidlist there is exactly one .CW pmValueSet in the .IR result , and further the PMIDs appear in exactly the same sequence in both .I pmidlist and .IR result . This makes the number and order of entries in .I result completely deterministic, and greatly simplifies the application programming logic after the call to .BR pmFetch . .PP The .I result structure returned by .B pmFetch is dynamically allocated using a combination of .BR malloc (3C) calls and specialized allocation strategies, and should be released when no longer required by calling .BR pmFreeResult (3) \- under no circumstances should .BR free (3C) be called directly to release this space. .PP As common error conditions are encoded in the .I result data structure, we'd expect only cataclysmic events to cause an error value to be returned. One example would be if the metrics source context was a remote host, and that host or the PMCS on that host became unreachable. Otherwise the value returned by the .B pmFetch function will be non-negative. .PP If the current context involves fetching metrics from a Performance Metrics Collector Daemon (PMCD), then the return value may be used to encode out-of-band changes in the state of the PMCD and the associated Performance Metrics Daemon Agents (PMDAs), as a bit-wise ``or'' of the following values: .sp 0.5v .IP \fBPMCD_RESTART_AGENT\fR 20n An attempt has been made to restart at least one failed PMDA. .IP \fBPMCD_ADD_AGENT\fR At least one PMDA has been started. .IP \fBPMCD_DROP_AGENT\fR PMCD has noticed the termination of at least one PMDA. .PP The default is to return zero to indicate no change in state, however the .CW pmResult returned by .B pmFetch has the same interpretation independent of the return value being zero or greater than zero. .SH SEE ALSO .BR pmcd (1), .BR pmAddProfile (3), .BR PMAPI (3), .BR pmDelProfile (3), .BR pmDupContext (3), .BR pmExtractValue (3), .BR pmFetchArchive (3), .BR pmFreeResult (3), .BR pmGetInDom (3), .BR pmLookupDesc (3), .BR pmLookupName (3), .BR pmNewContext (3), .BR pmSetMode (3), .BR pmUseContext (3) and .BR pmWhichContext (3). .PP Note that .B pmFetch is the most primitive method of fetching metric values from the PMCS. More user friendly interfaces to the PMCS are available or currently under development \- these higher level fetch methods insulate the user from the intricacies of context creation, setting up instance profiles, .CW pmResult traversal, and splitting fetches into batches to minimize PDU traffic or according to other optimization criteria. .SH DIAGNOSTICS As mentioned above, .B pmFetch returns error codes .I insitu in the argument .IR result . If no result is returned, e.g. due to IPC failure using the current PMAPI context, or end of file on an archive log, then .B pmFetch will return a negative error code which may be examined using .BR pmErrStr (3). .IP \f3PM_ERR_EOL\f1 When fetching records from an archive log, .B pmFetch returns this error code to indicate the end of the log has been passed (or the start of the log has been passed, if the direction of traversal is backwards in time). If the ``mode'' for the current PMAPI context (see .BR pmSetMode (3)) is .B PM_MODE_INTERP then the time origin is advanced, even when this error code is returned. In this way applications that position the time outside the range defined by the records in the archive, and then commence to .B pmFetch will eventually see valid results once the time origin moves inside the temporal span of the archive. .SH ENVIRONMENT Many of the performance metrics exported from PCP agents have the semantics of .I counter meaning they are expected to be monotonically increasing. Under some circumstances, one value of these metrics may be smaller than the previously fetched value. This can happen when a counter of finite precision overflows, or when the PCP agent has been reset or restarted, or when the PCP agent is exporting values from some underlying instrumentation that is subject to some asynchronous discontinuity. .sp 0.5v The environment variable .B PCP_COUNTER_WRAP may be set to indicate that all such cases of a decreasing ``counter'' should be treated as a counter overflow, and hence the values are assumed to have wrapped once in the interval between consecutive samples. This ``wrapping'' behavior was the default in earlier PCP versions, but by default has been disabled in PCP version 1.3 and later. pcp-3.8.12ubuntu1/man/man3/pmdaname.30000664000000000000000000000447312272262501014071 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" Copyright (c) 2009 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDANAME 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaName\f1 \- translate a PMID to a set of dynamic performance metric names .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmdaName(pmID \fIpmid\fP, char ***\fInameset\fP, pmdaExt *\fIpmda\fP); .sp cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION As part of the Performance Metrics Domain Agent (PMDA) API (see .BR PMDA (3)), .BR pmdaName is the generic callback for translating a .I pmid into one or more dynamic metric names (\c .IR nameset ). .PP Because implementing dynamic performance metrics requires specific PMDA support, and the facility is an optional component of a PMDA (most PMDAs do .B not support dynamic performance metrics), .B pmdaName is a skeleton implementation that returns .BR PM_ERR_NAME . .PP A PMDA that supports dynamic performance metrics will provide a private callback that replaces .B pmdaName (by assignment to .I version.four.name of the .I pmdaInterface structure) and implements the translation from a .I pmid to a set of dynamic performance metric names returned via .IR nameset . The behaviour, return values and memory allocation rules for .I nameset are the same as for .BR pmNameAll (3). .SH DIAGNOSTICS .B pmdaName returns .B PM_ERR_PMID if the name is not recognized or cannot be translated, otherwise the number of metric names found (most commonly 1). .SH CAVEAT The PMDA must be using .B PMDA_PROTOCOL_4 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH SEE ALSO .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaDSO (3), .BR pmdaMain (3), .BR pmNameAll (3) and .BR pmNameID (3). pcp-3.8.12ubuntu1/man/man3/pmerrstr.30000664000000000000000000000360412272262501014160 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMERRSTR 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmErrStr\f1, \f3pmErrStr_r\f1 \- convert a PMAPI error code into a string .SH "C SYNOPSIS" .ft 3 #include .sp const char *pmErrStr(int \fIcode\fP); .br char *pmErrStr_r(int \fIcode\fP, char *\fIbuf\fP, int \fIbuflen\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION Translate an error code into a text string, suitable for generating a diagnostic message. The .B pmErrStr_r function does the same, but stores the result in a user-supplied buffer .I buf of length .IR buflen , which should have room for at least .B PM_MAXERRMSGLEN bytes. .PP By convention, all error codes are negative. The small values are assumed to be negated versions of the Unix error codes as defined in .B and the strings returned are as per .BR strerror (3C). The larger, negative error codes are Performance Metrics Application Programming Interface (PMAPI) error conditions and .BR pmErrStr (3) returns an appropriate PMAPI error string, as determined by .IR code . .SH NOTES .B pmErrStr returns a pointer to a static buffer, so the returned value is only valid until the next call to .B pmErrStr and hence is not thread-safe. Multi-threaded applications should use .B pmErrStr_r instead. .SH SEE ALSO .BR pmerr (1), .BR PMAPI (3) and .BR perror (3C). pcp-3.8.12ubuntu1/man/man3/mmv_lookup_value_desc.30000664000000000000000000000410212272262501016656 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2009 Max Matveev .\" Copyright (c) 2009 Aconex. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH MMV_LOOKUP_VALUE_DESC 3 "" "Performance Co-Pilot" .SH NAME \f3mmv_lookup_value_desc\f1 - find a value in the Memory Mapped Value file .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n pmAtomValue *mmv_lookup_value_desc(void *\fIaddr\fP, const char *\fImetric\fP, const\ char\ *\fIinst\fP); .sp .in .hy .ad cc ... \-lpcp_mmv \-lpcp .ft 1 .SH DESCRIPTION .P \f3mmv_lookup_value_desc\f1 searches for the value of the instance identified by the external instance name \f2inst\f1 of the metric \f2metric\f1 in the \f3MMV\f1(5) file. \f2addr\f1 is the address returned from \f3mmv_stats_init\f1(). .P The pointer returned points to a pmAtomValue union, which is defined as follows: .P .nf typedef union { __int32_t l; /* 32-bit signed */ __uint32_t ul; /* 32-bit unsigned */ __int64_t ll; /* 64-bit signed */ __uint64_t ull; /* 64-bit unsigned */ float f; /* 32-bit floating point */ double d; /* 64-bit floating point */ char *cp; /* char ptr */ pmValueBlock *vbp; /* pmValueBlock ptr */ } pmAtomValue; .fi .P MMV string values should be set using either of the \f3mmv_set_string\f1 or \f3mmv_set_strlen\f1 routines. .SH RETURNS The function returns the address inside of the memory mapped region on success or NULL on failure. .SH SEE ALSO .BR mmv_stats_init (3), .BR mmv_inc_value (3) and .BR mmv (5). pcp-3.8.12ubuntu1/man/man3/pmwhichcontext.30000664000000000000000000000273712272262501015354 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMWHICHCONTEXT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmWhichContext\f1 \- identify the current PMAPI context .SH "C SYNOPSIS" .ft 3 #include .sp int pmWhichContext(void); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION An application using the Performance Metrics Application Programming Interface (PMAPI) may manipulate several concurrent contexts, each associated with a source of performance metrics, e.g. \c .BR pmcd (1) on some host, or an archive log of performance metrics as created by .BR pmlogger (1). .PP .B pmWhichContext returns a handle for the current PMAPI context, that may be used in the associated PMAPI routines that require a handle to identify a PMAPI context. .SH SEE ALSO .BR PMAPI (3), .BR pmDestroyContext (3), .BR pmDupContext (3), .BR pmNewContext (3) and .BR pmUseContext (3). .SH DIAGNOSTICS .IP \f3PM_ERR_NOCONTEXT\f1 no current context pcp-3.8.12ubuntu1/man/man3/pmparseinterval.30000664000000000000000000000405512272262501015517 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMPARSEINTERVAL 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmParseInterval\f1 \- convert interval string to \fBtimeval\fR structure .SH "C SYNOPSIS" .ft 3 #include .sp .ad l .hy 0 .in +8n .ti -8n int pmParseInterval(const char *\fIstring\fP, struct timeval *\fIrslt\fP, char\ **\fIerrmsg\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. .SH DESCRIPTION .B pmParseInterval parses the argument .I string specifying an interval of time and fills in the .B tv_sec and .B tv_usec components of the .I rslt structure to represent that interval. .PP The input .I string is most commonly the argument following a .BR \-t command line option to a PCP application, and the syntax is fully described in .BR PCPIntro (1). .PP .B pmParseInterval returns 0 and .I errmsg is undefined if the parsing is successful. .PP If the given .I string does not conform to the required syntax .B pmParseInterval returns \-1 and a dynamically allocated error message string in .IR errmsg . The error message is terminated with a newline and includes the text of the input .I string along with an indicator of the position at which the error was detected, e.g. .br .in +1i .CW "\&4minutes 30mumble" .br .CW "\& ^ -- unexpected value" .in -1i .PP In the case of an error, the caller is responsible for calling .BR free (3C) to release the space allocated for .IR errmsg . .SH SEE ALSO .BR PMAPI (3) and .BR pmParseTimeWindow (3). pcp-3.8.12ubuntu1/man/man3/pmdaeventclient.30000664000000000000000000000523412272262501015465 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" Copyright (c) 2011 Nathan Scott. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAEVENTCLIENT 3 "PCP" "Performance Co-Pilot" .SH NAME .ad l \f3pmdaEventNewClient\f1, \f3pmdaEventEndClient\f1, \f3pmdaEventClients\f1 \- client context tracking interfaces for event queues .br .ad .SH "C SYNOPSIS" .ft 3 .nf #include #include #include .fi .sp .ad l .hy 0 .in +8n .ti -8n int pmdaEventNewClient(int \fIcontext\fP); .br .ti -8n int pmdaEventEndClient(int \fIcontext\fP); .br .ti -8n int pmdaEventClients(pmAtomValue *\fIavp\fP); .sp .in .hy .ad cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. A Performance Metrics Domain Agent (PMDA) that exports event records needs to track which clients are connected to it, in order that it can track which events have been sent to which clients so far. Only once an event has been sent to all monitoring tools that registered an interest can the event be discarded and any memory reclaimed. .PP The .BR PMDA (3) library provides callback routines for PMDA developers to provide custom handling of client connections and disconnections. If the PMDA is making use of the event queueing mechanism provided by .BR pmdaEventNewQueue (3) and friends, client connections and disconnections must be tracked via calls to .B pmdaEventNewClient and .B pmdaEventEndClient respectively. This allows the library to keep track of when events can be discarded from a queue, for example, for the .I context specified. This parameter is passed into the e_endCallBack function directly, and for other callback functions is available via the e_context field of the pmdaExt structure. Additionally, it can be queried at any time using .BR pmdaGetContext (3). .PP Sometimes it is useful for the PMDA to export a metric indicating the current count of attached clients \- this is available using the .B pmdaEventClients routine, which will fill in the .I avp pmAtomValue structure on behalf of a PMDA fetch callback routine. .SH SEE ALSO .BR pmdaEventNewArray (3), .BR pmdaEventNewQueue (3), .BR PMAPI (3), .BR PMDA (3) and .BR pmEventFlagsStr (3). pcp-3.8.12ubuntu1/man/man3/pmextractvalue.30000664000000000000000000001446312272262501015353 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMEXTRACTVALUE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmExtractValue\f1 \- extract a performance metric value from a pmResult structure .SH "C SYNOPSIS" .ft 3 #include .sp .ad l .hy 0 .in +8n .ti -8n int pmExtractValue(int \fIvalfmt\fP, const pmValue *\fIival\fP, int\ \fIitype\fP, pmAtomValue\ *\fIoval\fP, int\ \fIotype\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. The .CW pmValue structure is embedded within the .CW pmResult structure that is used to return one or more performance metrics; see .BR pmFetch (3). .PP All performance metric values may be encoded in a .CW pmAtomValue union, defined as follows; .PP .ft CW .nf .in +0.5i typedef union { __int32_t l; /* 32-bit signed */ __uint32_t ul; /* 32-bit unsigned */ __int64_t ll; /* 64-bit signed */ __uint64_t ull; /* 64-bit unsigned */ float f; /* 32-bit floating point */ double d; /* 64-bit floating point */ char *cp; /* char ptr */ pmValueBlock *vbp; /* pmValueBlock ptr */ } pmAtomValue; .in .fi .ft 1 .PP The routine .B pmExtractValue provides a convenient mechanism for extracting values from the .CW pmValue part of a .CW pmResult structure, optionally converting the data type, and making the result available to the application programmer. .PP .I itype defines the data type of the input value held in .I ival according to the storage format defined by .I valfmt (see .BR pmFetch (3)). .I otype defines the data type of the result to be placed in .IR oval . .PP The value for .I itype is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP The .I otype value should be one of the defined .BR PM_TYPE_ ... values, that have a 1:1 correspondence with the fields in the .CW pmAtomValue union. .PP Normally the .I valfmt parameter would be plucked from the same .CW pmResult structure that provides the .I ival parameter, and if .I valfmt specifies .BR PM_VAL_INSITU , then the following types are not allowed, as these cannot be encoded in 32-bits; .BR __int64_t , .BR __uint64_t , .BR double , .B char * and .B void * (the corresponding .I itype values are .BR PM_TYPE_64 , .BR PM_TYPE_U64 , .BR PM_TYPE_DOUBLE , .BR PM_TYPE_STRING , .B PM_TYPE_AGGREGATE and .B PM_TYPE_EVENT respectively). If .I valfmt specifies .BR PM_VAL_PTR , then the value will be extracted from the associated .CW pmValueBlock structure, and the .BR __int32_t , .B __uint32_t and .B float options (\c .I itype being .BR PM_TYPE_32 , .B PM_TYPE_U32 and .B PM_TYPE_FLOAT respectively) are not allowed, as .B PM_VAL_INSITU is the appropriate encoding for these. .PP The following table defines the various possibilities for the type conversion -- the input type (\c .IR itype ) is shown vertically, and the output type (\c .IR otype ) is shown horizontally. Y means the conversion is always acceptable, N means the conversion can never be performed (the function returns .BR PM_ERR_CONV ), P means the conversion may lose accuracy (but no error status is returned), T means the result may be subject to high-order truncation (in which case the function returns .BR PM_ERR_TRUNC ) and S means the conversion may be impossible due to the sign of the input value (in which case the function returns .BR PM_ERR_SIGN ). If an error occurs, the value represented by .I oval will be zero (or .BR NULL ). .PP Note that although some of the conversions involving the types .B PM_TYPE_STRING and .B PM_TYPE_AGGREGATE are indeed possible, but are marked N \- the rationale is that .B pmExtractValue should not be attempting to duplicate functionality already available in the C library via .BR sscanf (3) and .BR sprintf (3). .PP No conversion involving the type .B PM_TYPE_EVENT is supported. .PP .ft CW .nf | 32 | U32 | 64 | U64 | FLOAT | DBLE | STRNG | AGGR | EVENT ======|=====|=======|=====|=======|=======|======|=======|======|======= 32 | Y | S | Y | S | P | P | N | N | N U32 | T | Y | Y | Y | P | P | N | N | N 64 | T | T,S | Y | S | P | P | N | N | N U64 | T | T | T | Y | P | P | N | N | N FLOAT | P,T | P,T,S | P,T | P,T,S | Y | Y | N | N | N DBLE | P,T | P,T,S | P,T | P,T,S | P | Y | N | N | N STRNG | N | N | N | N | N | N | Y | N | N AGGR | N | N | N | N | N | N | N | Y | N EVENT | N | N | N | N | N | N | N | N | N .fi .ft 1 .PP In the cases where multiple conversion errors could occur, the first encountered error will be notified, and the order of checking is not defined. .PP If the output conversion is to one of the pointer types, i.e. \c .I otype is .B PM_TYPE_STRING or .BR PM_TYPE_AGGREGATE , then the value buffer will have been allocated by .BR pmExtractValue (3) using .BR malloc (3C), and it is the caller's responsibility to free the space when it is no longer required. .PP Although this function appears rather complex, it has been constructed to assist the development of performance tools that wish to convert values, whose type is only known via the .CW type field in a .CW pmDesc structure, into a canonical type for local processing. .SH SEE ALSO .BR PMAPI (3), .BR pmAtomStr (3), .BR pmConvScale (3), .BR pmFetch (3), .BR pmLookupDesc (3), .BR pmPrintValue (3), .BR pmTypeStr (3), .BR pmUnitsStr (3) and .BR pmUnpackEventRecords (3). .SH DIAGNOSTICS .P .B PM_ERR_CONV .IP Impossible conversion, marked by N in above table .P .B PM_ERR_TRUNC .IP High-order truncation occurred .P .B PM_ERR_SIGN .IP Conversion of negative value to unsigned type attempted pcp-3.8.12ubuntu1/man/man3/pmcontrollog.30000664000000000000000000001600712272262501015022 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMCONTROLLOG 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmControlLog\f1 \- enable, disable or enquire about logging of performance metrics .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int __pmControlLog(int \fIfd\fP, const pmResult *\fIrequest\fP, int\ \fIcontrol\fP, int\ \fIstate\fP, int\ \fIdelta\fP, pmResult\ **\fIstatus\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\fR\\$2 .el \fI\\$1\fR\\$2 .. .B __pmControlLog may be used to enable or disable the archive logging for particular performance metrics, as identified by the .I request parameter; see .BR pmFetch (3) for an explanation of the .CW pmResult structure. .PP The application must have previously issued a call to .BR __pmConnectLogger (3) to establish a control-port connection to the .BR pmlogger (1) instance to whom the control request is to be directed, and .I fd (the result from .BR __pmConnectLogger (3)) identifies this connection. .PP Within .IR request , only the details of the performance metrics and their associated instances will be used, i.e. the values of the metrics, if any, will be ignored. .I request would typically be constructed as the result of an earlier call to .BR pmFetch (3). For metrics with a singular value (having an instance domain of .BR PM_INDOM_NULL ) the corresponding .CW pmValueSet should have the value one in the .CW numval field and .B PM_IN_NULL as the .CW inst field of the single .CW pmValue supplied. If multiple explicit instances are to be logged, the .CW numval field of the .CW pmValueSet should contain the number of instances supplied and the .CW inst fields of the .CW pmValue structures should contain specific instance identifiers (which may not have the reserved value .BR PM_IN_NULL ). .PP If the .CW numval field within any of the .CW pmValueSet structures in .I request has a value of zero, it indicates that all available instances of the metric should be used. Enumeration of the instance domain is deferred until the logger fetches the metric prior to writing it to the log, rather than being performed when the .B __pmControlLog request is received. This is useful for metrics with instance domains that change over time. It is an error to specify .CW numval equal to zero if the corresponding metric has a singular value (no instance domain). .PP There are several sorts of logging control available, namely mandatory or advisory, as defined by the .I control argument, and on, off or maybe as defined by the .I state argument. These different types of control may be used to ensure that some performance metrics can be guaranteed to always be in the log, while others may be dynamically enabled or disabled as determined by the level and type of system activity. .PP The actual action to be performed is defined by the combination of .I control and .I state as follows. If .I control is .B PM_LOG_MANDATORY and .I state is .BR PM_LOG_ON , then logging is enabled. If .I control is .B PM_LOG_MANDATORY and .I state is .BR PM_LOG_OFF , then logging is disabled. If .I control is .B PM_LOG_MANDATORY and .I state is .BR PM_LOG_MAYBE , then subsequent advisory controls will be honored. If the logging state prior to the request was mandatory (on or off), the state is changed to advisory off. If the logging state was already advisory (either on or off), it remains unchanged. If .I control is .B PM_LOG_ADVISORY and the last mandatory control for the metric was .BR PM_LOG_MAYBE , then logging is enabled or disabled as specified by the .I state argument, i.e. .B PM_LOG_ON or .BR PM_LOG_OFF . When the arguments .I state and .I control specify a request to change the logging behavior, the argument .I delta defines the logging interval in milliseconds to be applied to all metrics and instances identified in .IR request . .PP The result argument .I status returns the current logging state for each of the nominated performance metrics. There is a 1:1 correspondence between the elements of .I request and .IR status. For metrics in .I request that have .CW pmValueSet s with .CW numval equal to zero, the corresponding .CW pmValueSet in .IR result will contain a value for each available instance at the time of the call. Each metric value in .I status will have the current logging state encoded in it. The detailed outcome of the operation for each metric can be determined by comparing these values to that requested via .IR control , .I state and .IR delta . .PP Macros defined in .B may be used to extract the state and logging interval from the returned metric values. .B PMLC_GET_ON returns true if logging is on, or false if it is off; .B PMLC_GET_MAND returns true if logging is mandatory, or false if it is advisory; .B PMLC_GET_INLOG returns true if the metric has been logged at least once, or false otherwise; .B PMLC_GET_AVAIL returns true if the metric was available from its source the last time it was supposed to be logged, or false if it was unavailable; and .B PMLC_GET_DELTA returns the current logging interval for the metric (in milliseconds). .B PMLC_MAX_DELTA defines the greatest .I delta that can be returned in an encoded metric value. .PP As a special case, when .I control is .BR PM_LOG_ENQUIRE , .I state and .I delta are ignored, and .I status returns the current logging state of the nominated performance metrics (this variant makes no changes to the logging state). .PP If the value of the logging interval is 0, either for .I delta in a request to change state to .BR PM_LOG_ON , or encoded in the value returned from .BR PM_LOG_ENQUIRE , then this corresponds to the special ``once only'' logging of metrics that appear once in the archive log, and are never logged again. .PP .B __pmControlLog returns zero on success. .SH NOTE This routine is not thread-safe as there is no serialization on the use of the communication channel between the sending of the request and receiving the reply. It is assumed that the caller is single-threaded, which is true for the only current user of this routine, namely .BR pmlc (1). .SH SEE ALSO .BR pmlc (1), .BR pmlogger (1), .BR PMAPI (3), .BR pmFetch (3) and .BR __pmConnectLogger (3). .SH DIAGNOSTICS .IP \f3PM_ERR_TOOSMALL\f1 The number of metrics in .I request is less than one. .IP \f3PM_ERR_VALUE\f1 One or more of the .CW pmValueSet s in .I request had .CW numval (the number of instances) less than one. .IP \f3EINVAL\f1 An invalid combination of .I control and .I state was specified, or .I delta was negative. pcp-3.8.12ubuntu1/man/man3/pmatomstr.30000664000000000000000000000573312272262501014335 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMATOMSTR 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmAtomStr\f1, \f3pmAtomStr_r\f1 \- convert a performance metric value into a string .SH "C SYNOPSIS" .ft 3 #include .sp const char *pmAtomStr(const pmAtomValue *\fIavp\fP, int \fItype\fP); .br char *pmAtomStr_r(const pmAtomValue *\fIavp\fP, int \fItype\fP, char *\fIbuf\fP, int \fIbuflen\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. All performance metric values may be encoded in a .CW pmAtomValue union, defined as follows; .PP .ft CW .nf .in +0.5i typedef union { __int32_t l; /* 32-bit signed */ __uint32_t ul; /* 32-bit unsigned */ __int64_t ll; /* 64-bit signed */ __uint64_t ull; /* 64-bit unsigned */ float f; /* 32-bit floating point */ double d; /* 64-bit floating point */ char *cp; /* char ptr */ pmValueBlock *vbp; /* pmValueBlock ptr */ } pmAtomValue; .in .fi .ft 1 .PP Given the performance metric value pointed to by .IR avp , and a performance metric type defined by .IR type , .B pmAtomStr will generate the corresponding metric value as a string, suitable for diagnostic or report output. The .B pmAtomStr_r function does the same, but stores the result in a user-supplied buffer .I buf of length .IR buflen , which should have room for at least 80 bytes. .PP The value for .I type is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP If the .I type is .B PM_TYPE_STRING values longer than 38 characters will be truncated after 34 characters, and truncation shown with ellipsis ``...'' at the end of the value. .PP If the .I type is .B PM_TYPE_AGGREGATE then up to the first three 32-bit words are displayed as hexadecimal values. .PP If the .I type is .B PM_TYPE_EVENT then a summary of the number of event records found in the value is generated. .PP The return value from .B pmAtomStr is held in a single static buffer, so the returned value is only valid until the next call to .BR pmAtomStr . .SH NOTES .B pmAtomStr returns a pointer to a static buffer and hence is not thread-safe. Multi-threaded applications should use .B pmAtomStr_r instead. .SH SEE ALSO .BR PMAPI (3), .BR pmConvScale (3), .BR pmExtractValue (3), .BR pmLookupDesc (3), .BR pmPrintValue (3), .BR pmTypeStr (3) and .BR pmUnitsStr (3). pcp-3.8.12ubuntu1/man/man3/pmdagetopt.30000664000000000000000000001032512272262501014444 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAGETOPT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaGetOpt\f1 \- get options from argument vector, trapping generic PMDA options .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int pmdaGetOpt(int \fIargc\fP, char *const *\fIargv\fP, const\ char\ *\fIoptstring\fP, pmdaInterface\ *\fIdispatch\fP, int\ *\fIerr\fP); .sp .in .hy .ad cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION This function is a wrapper for .BR getopt (3). The behavior of the function is identical except that certain options are assumed to have a predefined behavior which initializes several fields in the .B pmdaInterface structure. .PP The options that .B pmdaGetOpt will trap are: .TP 15 .BI \-D trace Set the .BR PMAPI (3) debug control variable .RB ( pmDebug ) to .IR trace . Used for controlling levels of trace output while debugging. .TP .BI \-d domain Set the .I domain number of this agent. .TP .BI \-h helpfile Obtain the help text (see .BR pmdaText (3)) for the metrics from this file rather than from the path specified with .BR pmdaDSO (3) or .BR pmdaDaemon (3). .TP .BI \-i port Expect PMCD to connect on inet .I port (number or name). .TP .BI \-6 port Expect PMCD to connect on ipv6 .I port (number or name). .TP .BI \-l logfile Redirect diagnostics and trace output to .IR logfile . .TP .B \-p Expect PMCD to supply stdin/stdout pipe. .TP .BI \-u socket Expect PMCD to connect on unix domain .IR socket . .PP Only one of .BR \-i , .BR \-6 , .BR \-p and .B \-u may be specified. If none of these three options is given, a pipe .RB ( \-p ) is assumed. When these options are encountered by .BR pmdaGetOpt , the option is processed and the next option is examined. Therefore, .B pmdaGetOpt will only return when an option other than those listed above is found, or the end of the list is reached. The returned value will be the argument or EOF, respectively. .PP A PMDA can control which of these options the program will accept with the .I optstring argument. To accept all the options, the PMDA should call .B pmdaGetOpt with the option string "D:d:h:i:l:pu:". Any PMDA specific options should be added to this string in the style of .BR getopt (3), and returned by .B pmdaGetOpt if encountered. However, the PMDA cannot reuse any of the options specified above. .PP .B pmdaGetOpt takes a pointer to an int, .IR err , which is used as an error count. This variable should be initialized to zero before .B pmdaGetOpt is first called, and tested when .B pmdaGetOpt returns EOF. .PP .B pmdaGetOpt does not modify .I argc or .IR argv . .SH EXAMPLE A PMDA which takes the additional argument .B \-n and does not use .B pmDebug might call .B pmdaGetOpt like this: .PP .nf .ft CW .in +0.5i pmdaInterface dispatch; int err = 0; int c = 0; while ((c = pmdaGetOpt(argv, argc, "d:h:i:l:pu:6:n:", dispatch &err)) != EOF) { /* process argument 'n', may use optarg etc. */ } if (err) usage(argv[0]); .in .fi .PP The global variables used by .B getopt (3) may be used by the caller of .B pmdaGetOpt within the argument parsing loop. .SH DIAGNOSTICS .B pmdaGetOpt will display the same error messages as .BR getopt . .SH CAVEAT The options .BR \-D , .BR \-d , .BR \-i , .BR \-l , .BR \-p and .B \-u cannot be reused for other purposes by the PMDA. .PP The PMDA must be using .B PMDA_INTERFACE_2 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH SEE ALSO .BR pmdbg (1), .BR getopt (3), .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaDSO (3) and .BR pmdaText (3). pcp-3.8.12ubuntu1/man/man3/pmiputresult.30000664000000000000000000000421512272262501015056 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIPUTRESULT 3 "" "Performance Co-Pilot" .SH NAME \f3pmiPutResult\f1 \- add a data record to a LOGIMPORT archive .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmiPutResult(const pmResult *\fIresult\fP); .sp cc ... \-lpcp_import \-lpcp .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiPutResult provides an interface for developers familiar with the internal PCP data structures to create output archives directly. .PP By building the .B pmResult data structure directly, then calling .B pmiPutResult the developer avoids calls to .BR pmiPutValue (3) and/or .BR pmiPutValueHandle (3) followed by a call to .BR pmiWrite (3) for each record written to the archive. .PP Any metrics and instances appearing in the .I result must have been defined by prior calls to .BR pmiAddMetric (3) and .BR pmiAddInstance (3). .PP .B pmiPutResult will arrange for any new metadata (metrics and/or instance domain changes) covered by .I result to be also written to the PCP archive. .PP Because of the complexity of the .B pmResult data structure, this routine is not available in the Perl interface to the LOGIMPORT services. .SH DIAGNOSTICS .B pmiPutResult returns zero on success else a negative value that can be turned into an error message by calling .BR pmiErrStr (3). .SH SEE ALSO .BR LOGIMPORT (3), .BR PMAPI (3), .BR pmiAddInstance (3), .BR pmiAddMetric (3), .BR pmiErrStr (3), .BR pmiPutValue (3), .BR pmiPutValueHandle (3), .BR pmiSetTimezone (3) and .BR pmiWrite (3). pcp-3.8.12ubuntu1/man/man3/pmderivederrstr.30000664000000000000000000000215212272262501015520 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2009 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDERIVEDERRSTR 3 "" "Performance Co-Pilot" .SH NAME \f3pmDerivedErrStr\f1 \- return error message from failure to parse derived metric definition .SH "C SYNOPSIS" .ft 3 #include .sp char *pmDerivedErrStr(void); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .PP When .BR pmRegisterDerived (3) is called to add a new derived metric definition and an error occurs, .B pmDerivedErrStr may be called to return the associated error message. .SH SEE ALSO .BR PCPIntro (1), .BR PMAPI (3) and .BR pmRegisterDerived (3). pcp-3.8.12ubuntu1/man/man3/pmdaattribute.30000664000000000000000000000631712272262501015153 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAATTRIBUTE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaAttribute\f1 \- informs a PMDA about client connection attributes .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmdaAttribute(int \fIcontext\fP, int \fIkey\fP, char *\fIvalue\fP, int \fIlength\fP, pmdaExt *\fIpmda\fP); .sp cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION As part of the Performance Metrics Domain Agent (PMDA) API (see .BR PMDA (3)), .B pmdaAttribute is the generic callback for responding to client connection attributes. These attributes include client credential information, such as user ID and group ID. .PP A PMDA that supports connection attributes will provide a private .B pmdaAttribute callback by assignment to .I version.six.attribute of the .I pmdaInterface structure, and implement custom logic for any of the attribute .IR key \-\c .I value pairs of interest to it. .PP All attributes are associated with a specific client context, and these can be uniquely identified using the .I ctx first argument. The PMDA should track client connections, and disconnections using the .BR pmdaSetEndContextCallBack (3) interface, as a result. The .BR pmdaGetContext (3) interface may be particularly helpful also. .PP All attributes are passed as .IR key \-\c .I value pairs and the .I value is always passed as a null-terminated string of given .IR length . This includes numeric attributes like the user ID. .PP The most commonly used attributes would be PCP_ATTR_USERID and PCP_ATTR_GROUPID but others may also be optionally passed (such as PCP_ATTR_USERNAME) if they are available. Some attributes will be consumed by .B pmcd and never through passed to PMDAs, such as PCP_ATTR_PASSWORD. A complete list of all possible attributes can be found in the headers listed above, all are prefixed by PCP_ATTR. .SH DIAGNOSTICS .B pmdaAttribute should return either zero on success, or a negative return code to indicate an error in handling the attribute. This return code cannot be used to indicate a client should be disallowed access \- such functionality must be performed by the agent in response to callbacks for the client in question (using PM_ERR_PERMISSION for those specific callbacks, for that specific client. In other words, errors will be be passed to PMCD but there is no guarantee made that the error will be return to the client and result in termination of the client, for example. .SH CAVEAT The PMDA must be using .B PMDA_PROTOCOL_6 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH SEE ALSO .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaDSO (3), .BR pmdaMain (3) and .BR pmdaGetContext (3). pcp-3.8.12ubuntu1/man/man3/pmlookupdesc.30000664000000000000000000001650512272262501015013 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .\" add in the -me strings for super and subscripts .ie n \{\ . ds [ \u\x'-0.25v' . ds ] \d . ds { \d\x'0.25v' . ds } \u .\} .el \{\ . ds [ \v'-0.4m'\x'-0.2m'\s-3 . ds ] \s0\v'0.4m' . ds { \v'0.4m'\x'0.2m'\s-3 . ds } \s0\v'-0.4m' .\} .TH PMLOOKUPDESC 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmLookupDesc\f1 \- obtain a description for a performance metric .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmLookupDesc(pmID \fIpmid\fP, pmDesc *\fIdesc\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Given a Performance Metrics Identifier (PMID) as .IR pmid , fill in the given .CW pmDesc structure, pointed to by the parameter .IR desc , from the current Performance Metrics Application Programming Interface (PMAPI) context. .PP The .CW pmDesc structure provides all of the information required to describe and manipulate a performance metric via the PMAPI, and has the following declaration. .PP .ft CW .nf .in +0.5i /* Performance Metric Descriptor */ typedef struct { pmID pmid; /* unique identifier */ int type; /* base data type (see below) */ pmInDom indom; /* instance domain */ int sem; /* semantics of value (see below) * pmUnits units; /* dimension and units (see below) */ } pmDesc; /* pmDesc.type -- data type of metric values */ #define PM_TYPE_NOSUPPORT \-1 /* not impl. in this version */ #define PM_TYPE_32 0 /* 32-bit signed integer */ #define PM_TYPE_U32 1 /* 32-bit unsigned integer */ #define PM_TYPE_64 2 /* 64-bit signed integer */ #define PM_TYPE_U64 3 /* 64-bit unsigned integer */ #define PM_TYPE_FLOAT 4 /* 32-bit floating point */ #define PM_TYPE_DOUBLE 5 /* 64-bit floating point */ #define PM_TYPE_STRING 6 /* array of char */ #define PM_TYPE_AGGREGATE 7 /* arbitrary binary data */ #define PM_TYPE_AGGREGATE_STATIC 8 /* static pointer to aggregate */ #define PM_TYPE_EVENT 9 /* packed pmEventArray */ #define PM_TYPE_UNKNOWN 255 /* used in pmValueBlock, not pmDesc */ /* pmDesc.sem -- semantics/interpretation of metric values */ #define PM_SEM_COUNTER 1 /* cumulative ctr (monotonic incr) */ #define PM_SEM_INSTANT 3 /* instant. value continuous domain */ #define PM_SEM_DISCRETE 4 /* instant. value discrete domain */ .in .fi .ft 1 .PP The .CW type field in the .CW pmDesc describes various encodings (or formats) for a metric's value. .PP If a value is counted in the underlying base instrumentation with less than 32 bits of integer precision, it is the responsibility of the Performance Metrics Domain Agent (PMDA) to promote the value to a 32-bit integer before it is exported into the Performance Metrics Collection Subsystem (PMCS); i.e. applications above the PMAPI never have to deal with 8-bit and 16-bit counters. .PP If the value of a performance metric is of type .BR PM_TYPE_AGGREGATE , .BR PM_TYPE_AGGREGATE_STATIC, .B PM_TYPE_EVENT or .BR PM_TYPE_STRING , the interpretation of the value is unknown to the PMCS. In these cases, the application using the value, and the PMDA providing the value must have some common understanding about how the value is structured and interpreted. .PP Each value for a performance metric is assumed to be drawn from a set of values that can be described in terms of their dimensionality and scale by a compact encoding as follows. The dimensionality is defined by a power, or index, in each of 3 orthogonal dimensions, namely Space, Time and Count (or Events, which are dimensionless). For example I/O throughput might be represented as .ti 1i .CW "\0\0\0\0\0\0\0\0\0\0-1" .ti 1i .CW "Space.Time" .br while the running total of system calls is .CW "Count" , memory allocation is .CW Space and average service time is .ti 1i .CW "\0\0\0\0\0\0\0\0\0\0-1" .ti 1i .CW "Time.Count" .br In each dimension there are a number of common scale values that may be used to better encode ranges that might otherwise exhaust the precision of a 32-bit value. This information is encoded in the .CW pmUnits structure which is embedded in the .CW pmDesc structure. .PP .ft CW .nf .in +0.5i /* * Encoding for the units (dimensions Time and Space) and scale * for Performance Metric Values * * For example, a pmUnits struct of * { 1, \-1, 0, PM_SPACE_MBYTE, PM_TIME_SEC, 0 } * represents Mbytes/sec, while * { 0, 1, \-1, 0, PM_TIME_HOUR, 6 } * represents hours/million-events */ typedef struct { int dimSpace:4; /* space dimension */ int dimTime:4; /* time dimension */ int dimCount:4; /* event dimension */ int scaleSpace:4; /* one of PM_SPACE_* below */ int scaleTime:4; /* one of PM_TIME_* below */ int scaleCount:4; /* one of PM_COUNT_* below */ } pmUnits; /* dimensional units and scale of value */ /* pmUnits.scaleSpace */ #define PM_SPACE_BYTE 0 /* bytes */ #define PM_SPACE_KBYTE 1 /* Kilobytes (1024) */ #define PM_SPACE_MBYTE 2 /* Megabytes (1024^2) */ #define PM_SPACE_GBYTE 3 /* Gigabytes (1024^3) */ #define PM_SPACE_TBYTE 4 /* Terabytes (1024^4) */ /* pmUnits.scaleTime */ #define PM_TIME_NSEC 0 /* nanoseconds */ #define PM_TIME_USEC 1 /* microseconds */ #define PM_TIME_MSEC 2 /* milliseconds */ #define PM_TIME_SEC 3 /* seconds */ #define PM_TIME_MIN 4 /* minutes */ #define PM_TIME_HOUR 5 /* hours */ /* * pmUnits.scaleCount (e.g. count events, syscalls, interrupts, * etc.) these are simply powers of 10, and not enumerated here, * e.g. 6 for 10^6, or \-3 for 10^\-3 */ #define PM_COUNT_ONE 0 /* 1 */ .in .fi .ft 1 .PP Special routines (e.g. \c .BR pmExtractValue (3), .BR pmConvScale (3)) are provided to manipulate values in conjunction with the .CW pmUnits structure that defines the dimension and scale of the values for a particular performance metric. .PP Below the PMAPI, the information required to complete the .CW pmDesc structure, is fetched from the PMDAs, and in this way the format and scale of performance metrics may change dynamically, as the PMDAs and their underlying instrumentation evolve with time. In particular, when some metrics suddenly become 64-bits long, or change their units from Mbytes to Gbytes, well-written applications using the services provided by the PMAPI will continue to function correctly. .SH SEE ALSO .BR PMAPI (3), .BR pmAtomStr (3), .BR pmConvScale (3), .BR pmExtractValue (3), .BR pmGetConfig (3), .BR pmTypesStr (3), .BR pmUnitsStr (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .IP \f3PM_ERR_PMID\f1 The requested PMID is not known to the PMCS .IP \f3PM_ERR_NOAGENT\f1 The PMDA responsible for providing the metric is currently not available pcp-3.8.12ubuntu1/man/man3/pmprintvalue.30000664000000000000000000000407412272262501015032 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMPRINTVALUE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmPrintValue\f1 \- print a performance metric value .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n void pmPrintValue(FILE *\fIf\fP, int \fIvalfmt\fP, int \fItype\fP, const\ pmValue\ *\fIval\fP, int\ \fIminwidth\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. The value of a single performance metric (as identified by .IR val ) is printed on the standard I/O stream identified by .IR f . .PP The value of the performance metric is interpreted according to the format of .I val as defined by .I valfmt (from a .CW pmValueSet within a .CW pmResult structure; see .BR pmFetch (3)) and the generic description of the metrics type passed in via .IR type . .PP The value for .I type is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP The output will be optionally padded to be at least .I minwidth characters wide. .PP .B pmPrintValue is most useful for displaying values of performance metrics from .BR pmFetch (3) (which returns a set of .I valfmt and .I val pairs for each requested metric), based upon the metrics type as returned from .BR pmLookupDesc (3). .SH SEE ALSO .BR PMAPI (3), .BR pmAtomStr (3), .BR pmConvScale (3), .BR pmExtractValue (3), .BR pmFetch (3), .BR pmLookupDesc (3), .BR pmTypeStr (3) and .BR pmUnitsStr (3). pcp-3.8.12ubuntu1/man/man3/pmnameindomarchive.30000664000000000000000000000455312272262501016154 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNAMEINDOMARCHIVE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmNameInDomArchive\f1 \- translate an instance identifier into an instance name .SH "C SYNOPSIS" .ft 3 #include .sp int pmNameInDomArchive(pmInDom \fIindom\fP, int \fIinst\fP, char **\fIname\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Provided that the current Performance Metrics Application Programming Interface (PMAPI) context is associated with an archive log, .B pmNameInDomArchive will scan the union of all the instance domain metadata for the instance domain .IR indom , locate the first instance with the internal instance identifier given by .IR inst , and return the full external instance identification via .IR name . .PP This routine is a specialized version of the more general PMAPI routine .BR pmNameInDom . .PP The value for the instance domain .I indom is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP The space for the value of .I name will have been allocated in .B pmNameInDomArchive with .BR malloc (3C), and it is the responsibility of the caller to .BR free (3C) the space when it is no longer required. .PP .B pmNameInDomArchive returns zero on success. .SH SEE ALSO .BR PMAPI (3), .BR pmGetConfig (3), .BR pmGetInDomArchive (3), .BR pmLookupInDomArchive (3), .BR pmNameInDom (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOTARCHIVE\f1 the current PMAPI context is not associated with an archive log .IP \f3PM_ERR_INDOM_LOG\f1 .I indom is not a defined instance domain identifier for the archive log .IP \f3PM_ERR_INST_LOG\f1 the instance identifier .I inst is not known for the instance domain .I indom in the archive log pcp-3.8.12ubuntu1/man/man3/pmgetarchivelabel.30000664000000000000000000000616012272262501015760 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMGETARCHIVELABEL 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmGetArchiveLabel\f1 \- fetch the label record from a performance metrics archive log .SH "C SYNOPSIS" .ft 3 #include .sp int pmGetArchiveLabel(pmLogLabel *\fIlp\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Within the framework of the Performance Co-Pilot (PCP), archive logs of performance metrics values may be accumulated and saved using the program .BR pmlogger (1). .PP The routine .B pmGetArchiveLabel may be used to fetch the label record from an archive log that has already been opened using .BR pmNewContext (3), or .BR pmDupContext (3), and thereby associated with the current Performance Metrics Application Programming Interface (PMAPI) context. .PP The result returned via the pointer .I lp is a structure that must be pre-allocated by the caller and has the following format (defined in .BR pmapi.h ). .PP .in +0.2i .ft CW .nf /* * Label Record at the start of every log file */ typedef struct { int ll_magic; /* PM_LOG_MAGIC | log format version no. */ pid_t ll_pid; /* PID of logger */ struct timeval ll_start;/* start of this log */ char ll_hostname[PM_LOG_MAXHOSTLEN]; /* name of collection host */ char ll_tz[40]; /* $TZ at collection host */ } pmLogLabel; .fi .ft 1 .in .PP For an application, the most useful information from the archive label is likely to be in the fields .CW ll_start , .CW ll_hostname or .CW ll_tz . .PP Note that the size of the .CW ll_hostname field is .CW PM_LOG_MAXHOSTLEN (64 bytes) which is less than .BR MAXHOSTNAMELEN (see .BR gethostbyname (3)) on some platforms. These semantics are necessary to retain backwards compatibility with the PCP archive file format. .PP .B pmGetArchiveLabel returns zero for success. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR pmlogger (1), .BR PMAPI (3), .BR pmDupContext (3), .BR pmGetConfig (3), .BR pmNewContext (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOCONTEXT\f1 the current PMAPI context is either invalid, or not associated with an archive log pcp-3.8.12ubuntu1/man/man3/pmafm.30000664000000000000000000002421212272262501013400 0ustar '\"macro stdmacro .\" .\" Copyright (c) 1998-2008 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMAFM 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmafm\f1, \f3pmRecordSetup\f1, \f3pmRecordAddHost\f1, \f3pmRecordControl\f1 \- record mode support for PMAPI clients .SH "C SYNOPSIS" .ft 3 #include .sp .ad l .hy 0 .in +8n .ti -8n FILE *pmRecordSetup(const char *\fIfolio\fP, const char *\fIcreator\fP, int\ \fIreplay\fP); .br .ti -8n int pmRecordAddHost(const char *\fIhost\fP, int \fIisdefault\fP, pmRecordHost\ **\fIrhp\fP); .br .ti -8n int pmRecordControl(pmRecordHost *\fIrhp\fP, int \fIrequest\fP, const\ char\ *\fIoptions\fP); .sp .in .hy .ad cc ... \-lpcp_gui .ft 1 .SH DESCRIPTION These routines may be used to create a Performance Co-Pilot (PCP) archive ``on the fly'' to support ``record mode'' services for PMAPI client applications. .PP Each record mode ``session'' involves one or more PCP archive logs each created using a dedicated .BR pmlogger (1) process, with an overall Archive Folio format as understood by .BR pmafm (1), to name and collect all of the archive logs associated with a single recording session. .PP The .I pmRecordHost structure is used to maintain state information between the creator of the recording session and the associated .BR pmlogger process(es). The structure is defined as: .sp 0.5v .ft CW .nf .in +0.25i typedef struct { FILE *f_config; /* caller writes pmlogger configuration here */ int fd_ipc; /* IPC channel to pmlogger */ char *logfile; /* full pathname for pmlogger error logfile */ pid_t pid; /* process id for pmlogger */ int status; /* exit status, \-1 if unknown */ } pmRecordHost; .in -0.25i .fi .ft R .PP The routines are used in combination to create a recording session as follows. .IP 1. 4n Call .B pmRecordSetup to establish a new recording session. A new Archive Folio will be created using the name .IR folio ; if the file or directory .I folio already exists, or the file .I folio cannot be created, this is an error. The application that is creating the session is identified by .I creator (most often this would be the same as the global PMAPI application name, .IR pmProgname ). If the application knows how to create its own configuration file to replay the recorded session, then .I replay should be non-zero. .RS .PP .B pmRecordSetup returns a .I stdio stream onto which the application should write the text of the required replay configuration file, if any. .RE .IP 2. For each .I host that is to be included in the recording session, call .BR pmRecordAddHost . A new .I pmRecordHost structure is returned via .IR rhp . It is assumed that .BR pmcd (1) is running on .I host as this is how .BR pmlogger (1) will retrieve the required performance metrics. .RS .PP If this .I host is the default host for this recording session, then .I isdefault should be non-zero. This will ensure that the corresponding archive appears first in the PCP archive folio, and hence the tools used to replay the archive folio will make the correct determination of the archive associated with the default host. At most one .I host per recording session may be nominated as the default host. .PP The calling application should write the desired .B pmlogger configuration onto the .I stdio stream returned via the .I f_config field in the .I pmRecordHost structure. .RE .IP 3. Optionally add arguments to the command line that will be used to launch .BR pmlogger (1) by calling .B pmRecordControl with a .I request of .BR PM_REC_SETARG . The argument is passed via .I options and one call to .B pmRecordControl is required for each distinct argument. .RS .PP An argument may be added for a particular .B pmlogger instance identified by .IR rhp , or if the .I rhp argument is NULL the argument is added for all .B pmlogger instances that will be launched in the current recording session. .PP Independent of any calls to .B pmRecordControl with a .I request of .BR PM_REC_SETARG , each .B pmlogger instance will automatically be launched with the following arguments: .BR \-c , .BR \-h , .BR \-l , .B \-x and the basename for the PCP archive log. .RE .IP 4. To commence the recording session, call .B pmRecordControl with a .I request of .BR PM_REC_ON , and .I rhp must be NULL. This will launch one .BR pmlogger (1) process for each host in the recording session, and initialize the .IR fd_ipc , .IR logfile , .I pid and .I status fields in the associated .I pmRecordHost structure(s). .IP 5. To terminate a .B pmlogger instance identified by .IR rhp , call .B pmRecordControl with a .I request of .BR PM_REC_OFF . If the .I rhp argument to .B pmRecordControl is NULL, the termination request is broadcast to all .B pmlogger processes in the current recording session. .RS .PP An informative dialog is generated directly by each .B pmlogger process and hence note the comments on the disposition of output from .B pmlogger below. .PP Alternatively, .B pmlogger can be started with options to limit the duration of logging, e.g. the .B \-T or .B \-s arguments, in which case there is no need to call .B pmRecordControl with a .I request of .B PM_REC_OFF and no dialog is generated. .RE .IP 6. To display the current status of the .B pmlogger instance identified by .IR rhp , call .B pmRecordControl with a .I request of .BR PM_REC_STATUS . If the .I rhp argument to .B pmRecordControl is NULL, the status request is broadcast to all .B pmlogger processes in the current recording session. .RS .PP The display is generated directly by each .B pmlogger process and hence note the comments on the disposition of output from .B pmlogger below. .RE .IP 7. To detach a .B pmlogger instance identified by .IR rhp and allow it to continue independent of the application that launched the recording session, call .B pmRecordControl with a .I request of .BR PM_REC_DETACH . If the .I rhp argument to .B pmRecordControl is NULL, the detach request is broadcast to all .B pmlogger processes in the current recording session. .RS .PP An informative dialog is generated directly by each .B pmlogger process and hence note the comments on the disposition of output from .B pmlogger below. .RE .PP The calling application should not close any of the returned .I stdio streams; this will be done by .B pmRecordControl when recording is commenced. .PP Once .B pmlogger has been started for a recording session, then .B pmlogger will assume responsibility for any dialog with the user in the event that the application that launched the recording session should exit, particularly without terminating the recording session. .PP By default, information and dialogs from .B pmlogger will be displayed using .BR pmquery (1) on the assumption that most applications wishing to launch a recording session are GUI-based. In the event that .B pmquery fails to display the information (for example, because the .B DISPLAY environment variable is not set), .B pmlogger will write on its own .I stderr stream (\c .B not the .I stderr stream of the launching process); the output will be assigned to the .I XXXXXX.host.\fBlog\fP file described in the FILES section below. For convenience, the full pathname to this file is provided via the .I logfile field in the .I pmRecordHost structure. .PP If the .I options argument to .B pmRecordControl is not NULL, this string may be used to pass additional arguments to .BR pmquery (1) in those cases where a dialog is to be displayed. One use of this capability would be to provide a .B \-geometry string to control the placement of the dialog. .PP Premature termination of a launched .B pmlogger process may be determined using the .I pmRecordHost structure, by calling .BR select (2) on the .I fd_ipc field or polling the .I status field that will contain the termination status from .BR waitpid (2) if known, else \-1. .SH SEE ALSO .BR pmafm (1), .BR pmlogger (1), .BR pmquery (1) and .BR PMAPI (3). .SH FILES These routines create a number of files in the .B "same directory" as the .I folio file named in the call to .BR pmRecordSetup . In all cases, the ``XXXXXX'' component is the result of calling .BR mktemp (3). .TP 10 .I XXXXXX If .I replay is non-zero, this is the creator's replay configuration file, else an empty control file, used to guarantee uniqueness. .PD 0 .TP .I folio The PCP Archive Folio, suitable for use with .BR pmafm (1). .TP .I XXXXXX.host.\fBconfig\fP The .BR pmlogger (1) configuration for each .I host \- if the same .I host is used in different calls to .B pmRecordAddHost within the same recording session then one of the letters ``a'' through ``z'' will be appended to the ``XXXXXX'' part of all associated file names to ensure uniqueness. .TP .I XXXXXX.host.\fBlog\fP .I stdout and .I stderr for the .BR pmlogger (1) instance for each .IR host . .TP .I XXXXXX.host.\fR{\fB0\fP,\fBmeta\fP,\fBindex\fP} The files comprising a single PCP archive for each .IR host . .SH DIAGNOSTICS .PD .PP .B pmRecordSetup may return .B NULL in the event of an error. Check .I errno for the real cause, but the value .B EINVAL typically means that the order of calls to these routines is not correct (there is obvious state associated with the current recording session that is maintained across calls to these routines). For example the following calls would produce this .B EINVAL error; calling .B pmRecordControl before calling .B pmRecordAddHost at least once, or calling .B pmRecordAddHost before calling .BR pmRecordSetup . .PP .B pmRecordControl and .B pmRecordAddHost both return 0 on success, else a value less than 0 suitable for decoding with .BR pmErrStr (3) on failure. The value .B \-EINVAL has the same interpretation as .I errno being set to .B EINVAL as described above. .PP .B pmRecordControl will return .B PM_ERR_IPC if the associated .B pmlogger process has already exited. pcp-3.8.12ubuntu1/man/man3/pmdainstance.30000664000000000000000000000605212272262501014750 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAINSTANCE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaInstance\f1 \- return instance descriptions for a PMDA .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int pmdaInstance(pmInDom \fIindom\fP, int \fIinst\fP, char *\fIname\fP, __pmInResult\ **\fIresult\fP, pmdaExt\ *\fIpmda\fP); .sp .in .hy .ad cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION .B pmdaInstance uses the standard .BR PMDA (3) data structures to return information concerning the instance domain .IR indom . .PP The .I result structure is constructed by .B pmdaInstance and will contain one or more instance names and/or identifiers as specified by the .I inst and .I name arguments. .PP If .I inst has the value .B PM_IN_NULL and .I name is a null string, .I result will contain all the instances names and identifiers in the instance domain. .PP If .I inst is .B PM_IN_NULL but .I name is the name of an instance in the instance domain .IR indom , then .I result will contain the instance identifier for instance .IR name . Note that if .I name contains no spaces, partial matching up to the first space in the instance name is performed, i.e. .RB `` 1 '' will match instance name .RB `` 1 .BR minute ''. If .I name contains an embedded space, then no partial matching is performed and .I name should match one of the instance names exactly. .PP If .I name is a null string but .I inst is an instance identifier in the instance domain .IR indom , then .I result will contain the name for instance .IR inst . The .I result structure is allocated with .BR malloc (3) and should be released by the caller with .BR free (3). .SH DIAGNOSTICS If any errors occur during the execution of .BR pmdaInstance , the .I result structure is deallocated. If the instance domain .I indom is not supported by the PMDA, .B pmdaInstance will return .BR PM_ERR_INDOM . .PP If the .I inst or .I name does not correspond to any instances in the .I indom domain, .B pmdaInstance will return .BR PM_ERR_INST . .SH CAVEAT The PMDA must be using .B PMDA_INTERFACE_2 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .PP Because of optional partial matching up to the first space in the instance name, the .B PMDA developer should ensure that if instance names are allowed to have spaces, the names are unique up to the first space. .SH SEE ALSO .BR malloc (3), .BR PMAPI (3), .BR PMDA (3) and .BR pmGetInDom (3). pcp-3.8.12ubuntu1/man/man3/pcpintro.30000664000000000000000000003763112272262501014147 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PCPINTRO 3 "PCP" "Performance Co-Pilot" .SH NAME \f3PCPIntro\f1 \- introduction to the Performance Co-Pilot (PCP) libraries .SH INTRODUCTION Performance Co-Pilot (PCP) is a toolkit designed for monitoring and managing system-level performance. .PP The PCP libraries support the APIs required to create new performance monitoring tools and new agents (or PMDAs) to export performance data. The .B libpcp library is used in both cases. The .B libpcp_pmda library is used only for PMDAs. .PP Individual library routines are documented in their own manual page entries. .PP Most routines return an integer value; greater than equal to zero for success and less than zero for an error. The error codes have symbolic names defined in .BR . Other negative values are used to encode errors that can be mapped to the traditional .I errno values defined in .BR , with the value negated. To translate all PCP error codes into useful messages use either .BR pmerr (1) or .BR pmErrStr (3); the latter may also be used to decode the .I \-errno cases. .SH "GENERAL ERRORS" These common errors may occur in various PCP interactions. .TP 4n .B PM_ERR_TIMEOUT .I "Timeout waiting for a response from PMCD" .br Many interactions between PCP applications involve synchronous message passing, and these are subject to timeout constraints. These errors are most frequently encountered when using network connections with slow data rates or long latencies. .RS .PP For client\-\c .B pmcd timeouts, refer to .BR PCPIntro (1) for environment variables that may be used to modify the timeout thresholds. For .BR pmcd -PMDA timeouts refer to the .B \-t and .B \-q options of .BR pmcd (1) and the PCP metric .B pmcd.control.timeout that can be dynamically changed with .BR pmstore (1). .RE .TP .B PM_ERR_APPVERSION .I "Metric not supported by this version of monitored application" .br Some performance metrics are unavailable from specific versions of the associated PMDA, or may be unavailable because the underlying instrumentation has changed or is not installed or is not enabled. This error is used in results from .BR pmFetch (3) to indicate these situations. .TP .B PM_ERR_IPC .I "IPC protocol failure" .br Generic protocol failure on a pipe or socket connecting two PCP applications, eg. client\-\c .BR pmcd , or client\-\c .BR pmtime , or PMDA\-\c .B pmcd or .BR pmlc \- pmlogger . .TP .B PM_ERR_TEXT .I "Oneline or help text is not available" .br Set by a PMDA, and passed back to a PCP client, to indicate that the PMDA is unable to supply the requested metric or instance domain help text. .TP .B PM_ERR_VALUE .I "Missing metric value(s)" .br This error is used for a number of conditions in which the value of a performance metric is inappropriate for the context in which it is being used, eg. .RS .IP (a) 4n Bad value for the metric .B pmcd.timezone when trying to set the timezone via .BR pmNewContextZone (3) for a remote or archive context. .IP (b) Attempting to interpolate values for a metric with non-numeric data type from a PCP archive. .IP (c) A bad .I result data structure passed to .BR pmStore (3). .RE .TP .B PM_ERR_NAME .I "Unknown metric name" .br Just what the message says. .TP .B PM_ERR_PMID .I "Unknown or illegal metric identifier" .br Just what the message says. .TP .B PM_ERR_INDOM .I "Unknown or illegal instance domain identifier" .br A request nominates an instance domain that is unknown or .BR PM_INDOM_NULL . May occur as a consequence of the instance domain identifier passed by a PCP client to .BR pmGetInDom (3), .BR pmLookupInDom (3), .BR pmNameInDom (3), .BR pmGetInDomArchive (3), .BR pmLookupInDomArchive (3), .BR pmNameInDomArchive (3) or a request passed from .BR pmcd (1) to a PMDA. .TP .B PM_ERR_EOF .I "IPC channel closed" .br End of file on a pipe or socket connecting two PCP applications, eg. client\-\c .BR pmcd , or client\-\c .B pmtime or PMDA\-\c .BR pmcd. .TP .B PM_ERR_NOCONTEXT .I "Attempt to use an illegal context" .br Typically caused by a PCP client that tries to make calls before calling .BR pmNewContext (3) or after calling .BR pmDestroyContext (3). .TP .B PM_ERR_PERMISSION .I "No permission to perform requested operation" .br PCP-specific access controls apply to .BR pmcd (1) and .BR pmlogger (1). Platform-specific permission errors are returned as .BR \-EPERM . .TP .B PM_ERR_CONV .I "Impossible value or scale conversion" .br Some value conversion requests are illegal, eg. bad debug flag symbolic name for .B \-D option, or asking .BR pmExtractValue (3) to translate non-numeric data types to numbers and .IR vice " " versa . .TP .B PM_ERR_TRUNC .I "Truncation in value conversion" .br Some conversion requests to .BR pmExtractValue (3) cannot be performed based on the metric types and values involved, in this case conversion would result in loss of precision. .TP .B PM_ERR_SIGN .I "Negative value in conversion to unsigned" .br Some conversion requests to .BR pmExtractValue (3) cannot be performed based on the metric types and values involved, in this case converting a negative value to an unsigned value. .TP .B PM_ERR_TYPE .I "Unknown or illegal metric type" .br The metric type is held in the metric descriptor and sometimes encoded in the metric values returned from a call to .BR pmFetch (3). Legal values for the metric type are defined by the .B PM_TYPE_* macros in .BR . .TP .B PM_ERR_UNIT .I "Illegal pmUnits specification" .br Some conversion requests to .BR pmConvScale (3) cannot be performed due to illegal or incompatible specifications of the source and destination units. .TP .B PM_ERR_PROFILE .I "Explicit instance identifier(s) required" .br Some PMDAs, especially the .B proc PMDA, will not return ``all instances'' for a .BR pmFetch (3) request due to the cost. The client must explicitly built an instance profile using .BR pmAddProfile (3) and/or .BR pmDelProfile (3) before calling .BR pmFetch (3). See also the .B \-F option to .BR pminfo (1). .TP .B PM_ERR_INST .I "Unknown or illegal instance identifier" .br A request to a PMDA nominates an instance that is unknown. May occur as a consequence of the profile established prior to a .BR pmFetch (3) call, or an explicit instance name or identifier to .BR pmLookupInDom (3) or .BR pmNameInDom (3). .TP .B PM_ERR_MODE .I "Illegal mode specification" .br Illegal .I mode argument to .BR pmSetMode (3). .TP .B PM_ERR_PROFILESPEC .I "NULL pmInDom with non-NULL instlist" .br Bad arguments passed from a PCP client to .BR pmAddProfile (3). .TP .B PM_ERR_TOOSMALL .I "Insufficient elements in list" .br Parameter passing error by caller specifying a list with less than one element to .BR pmFetch (3), .BR pmLookupName (3) or .BR pmStore (3). .TP .B PM_ERR_THREAD .I "Operation not supported for multi-threaded applications" .br As documented in .BR PMAPI (3) and elsewhere, some .B libpcp routines are intended solely for use from single-threaded applications. .TP .B PM_ERR_TOOBIG .I "Result size exceeded" .br Indicates a fatal error in the message (or PDU) passing protocol between two PCP applications. This is an internal error, and other than an exotic networking failure, should not occur. .TP .B PM_ERR_RESET .I "PMCD reset or configuration change" .br Not used. .RS .PP Refer to .BR pmFetch (3) for an alternative mechanism that may be used to notify a PCP client when .BR pmcd (1) has experienced one or more configuration changes since the last request from the client. Usually these changes involve a change to the namespace exported via .B pmcd and/or changes to the PMDAs under .BR pmcd 's control. .RE .TP .B PM_ERR_FAULT .I "QA fault injected" .br Used only for PCP Quality Assurance (QA) testing. .TP .B PM_ERR_NYI .I "Functionality not yet implemented" .br Self explanatory and rarely used. .TP .B PM_ERR_GENERIC .I "Generic error, already reported above" .br Rarely used, this error may be returned when the error condition is a consequent of some earlier returned error and a more precise characterization is not possible. .SH "CLIENT-PMCD ERRORS" These errors may occur in the interactions between a PCP client and .BR pmcd (1) providing real-time performance data. .TP .B PM_ERR_NOAGENT .I "No PMCD agent for domain of request" .br A request sent to .BR pmcd (1) requires information from an agent or PMDA that does not exist. Usually this means the namespace being used by the client application contains metric names from a previously installed PMDA. .TP .B PM_ERR_CONNLIMIT .I "PMCD connection limit for this host exceeded" .br The client connection limit for .BR pmcd (1) is controlled by the optional .B access controls in .IR $PCP_PMCDCONF_PATH . By default there is no limit imposed by the PCP code, and this error would not be seen. .TP .B PM_ERR_AGAIN .I "Try again. Information not currently available" .br Used to notify a PCP client that the PMDA responsible for delivering the information is temporarily unavailable. See also .BR PM_ERR_PMDANOTREADY . .TP .B PM_ERR_NOPROFILE .I "Missing profile - protocol botch" .br Internal error in the communication between a client application and .BR pmcd (1) \- should not occur. .SH "CLIENT-ARCHIVE ERRORS" These errors may occur in the interactions between a PCP client and the library routines that provide historical performance data from PCP archives created by .BR pmlogger (1). .TP .B PM_ERR_LOGFILE .I "Missing archive file" .br Each PCP archive consists of multiple physical files as described in .BR pmlogger (1). This error occurs when one of the physical files is missing or cannot be opened for reading. .TP .B PM_ERR_EOL .I "End of PCP archive log" .br An attempt is made to read past the end file of the last volume of a PCP archive, or past the end of the time window (as specified with a .B \-T option) for a PCP archive. .TP .B PM_ERR_NOTHOST .I "Operation requires context with host source of metrics" .br Operations involving help text (ie. \c .BR pmLookupText (3) and .BR pmLookupInDomText (3)) or calls to .BR pmStore (3) require a host context and are not supported for PCP archives. .TP .B PM_ERR_LOGREC .I "Corrupted record in a PCP archive log" .br PCP archives can become corrupted for a variety of reasons, but the most common is premature termination of .BR pmlogger (1) without flushing its output buffers. .TP .B PM_ERR_LABEL .I "Illegal label record at start of a PCP archive log file" .br Each physical file in a PCP archive should begin with a common label record. This is a special case of .B PM_ERR_LOGREC errors. .TP .B PM_ERR_NODATA .I "Empty archive log file" .br An empty physical file can never be part of a valid PCP archive (at least the label record should be present). This is a special case of .B PM_ERR_LOGREC errors. .TP .B PM_ERR_NOTARCHIVE .I "Operation requires context with archive source of metrics" .br A call to one of the archive variant routines, i.e. \c .BR pmFetchArchive (3), .BR pmGetInDomArchive (3), .BR pmLookupInDomArchive (3) or .BR pmNameInDomArchive (3), when the current context is not associated with a PCP archive. .TP .B PM_ERR_PMID_LOG .I "Metric not defined in the PCP archive log" .br A PCP client has requested information about a metric, and there is no corresponding information in the PCP archive. This should not happen for well-behaved PCP clients. .TP .B PM_ERR_INDOM_LOG .I "Instance domain identifier not defined in the PCP archive log" .br A PCP client has requested information about an instance domain for one or more performance metrics, and there is no corresponding information in the PCP archive. If the client is using metric descriptors from the archive to identify the instance domain, this is less likely to happen. .RS .PP Because instance domains may vary over time, clients may need to use the variant routines .BR pmGetInDomArchive (3) or .BR pmLookupInDomArchive (3) or .BR pmNameInDomArchive (3) to manipulate the union of the instances in an instance domain over the life of an archive. .RE .TP .B PM_ERR_INST_LOG .I "Instance identifier not defined in the PCP archive log" .br A PCP client has requested information about a specific instance of a performance metric, and there is no corresponding information in the PCP archive. If the client is using instance names from the instance domain in the archive (rather than hard-coded instance names) and instance identifiers from the results returned by .BR pmFetch (3) or .BR pmFetchArchive (3) this is less likely to happen. .RS .PP Because instance domains may vary over time, clients may need to use the variant routines .BR pmLookupInDomArchive (3) or .BR pmNameInDomArchive (3) to manipulate the union of the instances in an instance domain over the life of an archive. .RE .SH "TIME CONTROL ERRORS" These errors may occur in the interactions between a GUI PCP client and the time control services provided by .BR pmtime (1). .TP .B PM_ERR_ISCONN .I "Already Connected" .br A PCP client application called .BR pmTimeConnect (3) when already connected to a .BR pmtime (1) instance. .TP .B PM_ERR_NOTCONN .I "Not Connected" .br A PCP client application called one of the time control routines .BR pmTime* (3) when not currently connected to any .BR pmtime (1) instance. .TP .B PM_ERR_NEEDPORT .I "A non-null port name is required" .br If a shared .BR pmtime (1) instance is being created the .I port argument to .BR pmTimeConnect (3) must not be invalid. .SH "NAMESPACE ERRORS" These errors may occur in the processing of PCP namespace operations. A PCP namespace, see .BR pmns (5), provides the external names and the internal identifiers for the available performance metrics. .TP .B PM_ERR_NONLEAF .I "Metric name is not a leaf in PMNS" .br The metric name passed to .BR pmLookupName (3) names a non-terminal path in the namespace, i.e. a group of metrics rather than a single metric. .TP .B PM_ERR_DUPPMNS .I "Attempt to reload the PMNS" .br When using an explicit local namespace, it is illegal to call either of .BR pmLoadNameSpace (3) or .BR pmLoadASCIINameSpace (3) more than once. .TP .B PM_ERR_PMNS .I "Problems parsing PMNS definitions" .br Only occurs when an ASCII namespace is explicitly loaded. .TP .B PM_ERR_NOPMNS .I "PMNS not accessible" .br Only occurs when an ASCII namespace is explicitly loaded. .SH "PMCD-PMDA ERRORS" These error codes are used in the interactions between .BR pmcd (1) and the PMDAs that provide the performance data. .TP .B PM_ERR_PMDANOTREADY .I "PMDA is not yet ready to respond to requests" .br Some PMDAs have long initialization or reset times, and will respond to .BR pmcd (1) with this error if they are busy at the moment. This error translates to .B PM_ERR_AGAIN for the PCP client who made the request to .BR pmcd which caused the initial request to the PMDA. At some later time the PMDA will inform .B pmcd (see .BR PM_ERR_PMDAREADY ) that it is now ready to process requests, and client requests will begin to succeed. .TP .B PM_ERR_PMDAREADY .I "PMDA is now responsive to requests" .br Used by PMDAs to asynchronously inform .BR pmcd (1) that they are now willing to resume processing requests. See also .BR PM_ERR_PMDANOTREADY . .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR pmerr (1), .BR PMAPI (3), .BR pmErrStr (3), .BR pmGetConfig (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man3/pmnewcontextzone.30000664000000000000000000000376512272262501015741 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNEWCONTEXTZONE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmNewContextZone\f1 \- establish a reporting timezone based on a PMAPI context .SH "C SYNOPSIS" .ft 3 #include .sp int pmNewContextZone(void); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. The current reporting timezone affects the timezone used by .BR pmCtime (3) and .BR pmLocaltime (3). .PP If the current PMAPI context is an archive, .B pmNewContextZone uses the timezone from the archive label record to set the current reporting timezone. .PP If the current PMAPI context corresponds to a host source of metrics, .B pmNewContextZone executes a .BR pmFetch (3) to retrieve the value for the metric .CW pmcd.timezone and uses that to set the current reporting timezone. .PP In both cases, .B pmNewContextZone returns a value to identify the current reporting timezone that may be used in a subsequent call to .BR pmUseZone (3) to restore this reporting timezone. .SH SEE ALSO .BR PMAPI (3), .BR pmCtime (3), .BR pmFetch (3), .BR pmGetConfig (3), .BR pmLocaltime (3), .BR pmNewContext (3), .BR pmNewZone (3), .BR pmUseZone (3), .BR pmWhichZone (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR environ (5). .SH DIAGNOSTICS .TP .B PM_ERR_NOCONTEXT the current PMAPI context is not valid .TP other a return value less than zero indicates a fatal error from a system call, most likely .BR malloc (3C) pcp-3.8.12ubuntu1/man/man3/pmdelprofile.30000664000000000000000000000560712272262501014771 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDELPROFILE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmDelProfile\f1 \- delete instance(s) from the current PMAPI instance profile .SH "C SYNOPSIS" .ft 3 #include .sp int pmDelProfile(pmInDom \fIindom\fP, int \fInuminst\fP, int *\fIinstlist\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. The set of instances for performance metrics returned from a .BR pmFetch (3) call may be filtered or restricted using an instance profile. There is one instance profile for each context the application creates at the Performance Metrics Application Programming Interface (PMAPI), and each instance profile may include instances from one or more instance domains (see .BR pmLookupDesc (3)). .PP .B pmDelProfile may be used to delete instance specifications from the instance profile of the current PMAPI context. .PP In the simplest variant, the list of instances identified by the .I instlist argument for the .I indom instance domain are removed from the instance profile. The list of instance identifiers contains .I numinst values. .PP The .I indom value would normally be extracted from a call to .BR pmLookupDesc (3) for a particular performance metric, and the instances in .I instlist would typically be determined by calls to .BR pmGetInDom (3) or .BR pmLookupInDom (3). .PP If .I indom equals .B PM_INDOM_NULL or .I numinst is zero, then all instance domains are selected for deletion. If .I instlist is .CW "NULL" , then all instances in the selected domain(s) are removed from the profile. .PP To disable all available instances in all domains, use .CW "pmDelProfile(PM_INDOM_NULL, 0, NULL)" . This is the only situation in which .I indom may be .BR PM_INDOM_NULL . .SH SEE ALSO .BR pmAddProfile (3), .BR PMAPI (3), .BR pmFetch (3), .BR pmGetInDom (3), .BR pmLookupDesc (3), .BR pmLookupInDom (3), .BR pmNewContext (3), .BR pmUseContext (3) and .BR pmWhichContext (3). .SH DIAGNOSTICS .IP \f3PM_ERR_PROFILESPEC\f1 .I indom was .B PM_INDOM_NULL and .I instlist was not empty .SH CAVEAT It is possible to delete non-existent instance domains and non-existent instances from an instance profile. None of the routines that use the instance profile will ever issue an error if you do this. The cost of checking, when checking is possible, outweighs any benefits. pcp-3.8.12ubuntu1/man/man3/pmierrstr.30000664000000000000000000000367412272262501014340 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIERRSTR 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmiErrStr\f1 \- convert a LOGIMPORT error code into a string .SH "C SYNOPSIS" .ft 3 #include .br #include .sp const char *pmiErrStr(int \fIcode\fP); .br char *pmiErrStr_r(int \fIcode\fP, char \fIbuf\fP, int \fIbuflen\fP); .sp cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp pmiErrStr($\fIcode\fP); .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiErrStr translates error codes returned from the other routines in the Log Import library into printable error messages. .PP .I code would normally have a negative value. As a special case, if .I code is \-1 then the error code returned from the last routine called in the LOGIMPORT library for this context will be used. .PP The .B pmiErrStr_r function does the same, but stores the result in a user-supplied buffer .I buf of length .IR buflen , which should have room for at least .B PMI_MAXERRMSGLEN bytes. .PP The set of possible error codes and messages is all those defined by .BR pmErrStr (3) and .BR PCPIntro (3), plus the additonal ones defined in .B with error code names of the form .BR PMI_ERR_.... .SH DIAGNOSTICS None. .SH SEE ALSO .BR LOGIMPORT (3), .BR PCPIntro (3) and .BR pmErrStr (3). pcp-3.8.12ubuntu1/man/man3/pmconvscale.30000664000000000000000000000614012272262501014612 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMCONVSCALE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmConvScale\f1 \- rescale a performance metric value .SH "C SYNOPSIS" .ft 3 #include .sp .ad l .hy 0 .in +8n .ti -8n int pmConvScale(int \fItype\fP, const pmAtomValue *\fIival\fP, const\ pmUnits\ *\fIiunit\fP, pmAtomValue\ *\fIoval\fP, const\ pmUnits\ *\fIounit\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. All performance metric values may be encoded in a .CW pmAtomValue union, defined as follows; .PP .ft CW .nf .in +0.5i typedef union { __int32_t l; /* 32-bit signed */ __uint32_t ul; /* 32-bit unsigned */ __int64_t ll; /* 64-bit signed */ __uint64_t ull; /* 64-bit unsigned */ float f; /* 32-bit floating point */ double d; /* 64-bit floating point */ char *cp; /* char ptr */ pmValueBlock *vbp; /* pmValueBlock ptr */ } pmAtomValue; .in .fi .ft 1 .PP The encoding of a performance metric's dimensionality and scale uses a .CW pmUnits structure; see .BR pmLookupDesc (3). .PP Given a performance metric value pointed to by .I ival multiply it by a scale factor and return the value in .IR oval . The scaling takes place from the units defined by .I iunit into the units defined by .IR ounit . Both input and output units must have the same dimensionality. .PP The performance metric type for both input and output values is determined by .IR type , the value for which is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP .B pmConvScale is most useful when values returned via .BR pmFetch (3), (and possibly extracted using .BR pmExtractValue (3)) need to be normalized into some canonical scale and units for the purposes of computation. .PP As a special case, if all components of the dimension are zero, then this is treated as synonymous with a ``count'' dimension of one, and so the ``count'' scale components determine the relative scaling. This accommodates the case where performance metrics are dimensionless, without special case handling on the part of the caller. .SH SEE ALSO .BR PMAPI (3), .BR pmAtomStr (3), .BR pmExtractValue (3), .BR pmFetch (3), .BR pmLookupDesc (3), .BR pmPrintValue (3), .BR pmTypeStr (3) and .BR pmUnitsStr (3). .SH DIAGNOSTICS .P .B PM_ERR_CONV .IP .I iunit and .I ounit have different dimensionality, or have inappropriate .I type .P .B PM_ERR_UNIT .IP Inappropriate .I iunit or .I ounit parameter pcp-3.8.12ubuntu1/man/man3/pmtrimnamespace.30000664000000000000000000000514212272262501015466 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMTRIMNAMESPACE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmTrimNameSpace\f1 \- prune a performance metrics name space .SH "C SYNOPSIS" .ft 3 #include .sp int pmTrimNameSpace(void); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION If the current Performance Metrics Application Programming Interface (PMAPI) context corresponds to a version 1 archive log of Performance Co-Pilot (PCP) performance metrics (as collected by .BR pmlogger (1) .BR -V1 ), then the currently loaded Performance Metrics Name Space (PMNS), is trimmed to exclude metrics for which no description can be found in the archive. The PMNS is further trimmed to remove empty subtrees that do not contain any performance metric. .PP Since PCP archives usually contain some subset of all metrics named in the default PMNS, .B pmTrimNameSpace effectively trims the application's PMNS to contain only the names of the metrics in the archive. .PP Since PCP 2.0, .B pmTrimNameSpace is only needed for dealing with version 1 archives. Version 2 archives actually store the "trimmed" PMNS. .PP Prior to any trimming, the PMNS is restored to the state as of the completion of the last .BR pmLoadASCIINameSpace (3) or .BR pmLoadNameSpace (3), so the effects of consecutive calls to .B pmTrimNameSpace with archive contexts are .B not additive. .PP If the current PMAPI context corresponds to a host and a .BR pmLoadASCIINameSpace (3) or .BR pmLoadNameSpace (3) call was made, then the PMNS reverts to all names loaded into the PMNS at the completion of the last .BR pmLoadASCIINameSpace (3) or .BR pmLoadNameSpace (3), i.e. any trimming is undone. .PP On success, .B pmTrimNameSpace returns zero. .SH SEE ALSO .BR pmlogger (1), .BR PMAPI (3), .BR pmLoadASCIINameSpace (3), .BR pmLoadNameSpace (3), .BR pmNewContext (3) and .BR pmns (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOPMNS\f1 you must have loaded a PMNS using .BR pmLoadASCIINameSpace (3) or .BR pmLoadNameSpace (3) before calling .B pmTrimNameSpace .IP \f3PM_ERR_NOCONTEXT\f1 the current PMAPI context is invalid pcp-3.8.12ubuntu1/man/man3/pmdaeventqueue.30000664000000000000000000001300012272262501015321 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2011-2012 Nathan Scott. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAEVENTQUEUE 3 "PCP" "Performance Co-Pilot" .SH NAME .ad l \f3pmdaEventNewQueue\f1, \f3pmdaEventNewActiveQueue\f1, \f3pmdaEventQueueHandle\f1, \f3pmdaEventQueueAppend\f1, \f3pmdaEventQueueRecords\f1, \f3pmdaEventQueueClients\f1, \f3pmdaEventQueueCounter\f1, \f3pmdaEventQueueBytes\f1, \f3pmdaEventQueueMemory\f1 \- utilities for PMDAs managing event queues .br .ad .SH "C SYNOPSIS" .ft 3 .nf #include #include #include .fi .sp .ad l .hy 0 .in +8n .ti -8n int pmdaEventNewQueue(const char *\fIname\fP, size_t \fImaxmem\fP); .br .ti -8n int pmdaEventNewActiveQueue(const char *\fIname\fP, size_t \fImaxmem\fP, int \fInclients\fP); .br .ti -8n int pmdaEventQueueHandle(const char *\fIname\fP); .br .ti -8n int pmdaEventQueueAppend(int \fIhandle\fP, void *\fIbuffer\fP, size_t \fIbytes\fP, struct timeval *\fItv\fP); .br .sp .in .hy .ad .in +8n .ti -8n typedef int (*pmdaEventDecodeCallBack)(int, void *, int, struct timeval *, void *); .br .ti -8n int pmdaEventQueueRecords(int \fIhandle\fP, pmAtomValue *\fIavp\fP, int \fIcontext\fP, pmdaEventDecodeCallBack \fIdecoder\fP, void *\fIdata\fP); .br .ti -8n int pmdaEventQueueClients(int \fIhandle\fP, pmAtomValue *\fIavp\fP); .br .ti -8n int pmdaEventQueueCounter(int \fIhandle\fP, pmAtomValue *\fIavp\fP); .br .ti -8n int pmdaEventQueueBytes(int \fIhandle\fP, pmAtomValue *\fIavp\fP); .br .ti -8n int pmdaEventQueueMemory(int \fIhandle\fP, pmAtomValue *\fIavp\fP); .sp .in .hy .ad cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. A Performance Metrics Domain Agent (PMDA) that exports event records must effectively act an event multiplexer. Events consumed by the PMDA may have to be forwarded on to any number of monitoring tools (or "client contexts"). These tools may be requesting events at different sampling intervals, and are very unlikely to request an event at the exact moment it arrives at the PMDA, making some form of event buffering and queueing scheme a necessity. Events must be held by the PMDA until either all registered clients have been sent them, or until a memory limit has been reached by the PMDA at which point it must discard older events as new ones arrive. .PP The routines described here are designed to assist the PMDA developer in managing both client contexts and queues of events at a high level. These fit logically above lower level primitives, such as those described in .BR pmdaEventNewArray (3), and shield the average PMDA from the details of directly building event record arrays for individual client contexts. .PP The PMDA registers a new queue of events using either .B pmdaEventNewQueue or .BR pmdaEventNewActiveQueue . These are passed an identifying .I name (for diagnostic purposes, and for subsequent lookup by .BR pmdaEventQueueLookup ) and .IR maxmem , an upper bound on the memory (in bytes) that can be consumed by events in this queue, before beginning to discard them (resulting in "missed" events for any client that has not kept up). If a queue is dynamically allocated (such that the PMDA may already have clients connected) the .B pmdaEventNewActiveQueue interface should be used, with the additional .I numclients parameter indicating the count of active client connections. The return is a negative error code on failure, suitable for decoding by the .BR pmErrStr (3) routine. Any non-negative value indicates success, and provides a .I handle suitable for passing into the other API routines. .PP For each new event received by the PMDA, the .B pmdaEventQueueAppend routine should be called, placing that event into the queue identified by .IR handle . The event itself must be contained in the passed in .IR buffer , having .I bytes length. The timestamp associated with the event (time at which the event occurred) is passed in via the final .I tv parameter. .PP In the PMDAs specific implementation of its fetch callback, when values for an event metric have been requested, the .BR pmdaEventQueueRecords routine should be used. It is passed the queue .I handle and the .I avp pmAtomValue structure to fill with event records, for the client making that fetch request (identified by the .I context parameter). Finally, the PMDA must also pass in an event decoding routine, which is responsible for decoding the fields of a single event into the individual event parameters of that event. The .I data parameter is an opaque cookie that can be used to pass situation-specific information into each .I decoder invocation. .PP Under some situations it is useful for the PMDA to export state about the queues under its control. The accessor routines \- .BR pmdaEventQueueClients , .BR pmdaEventQueueCounter , .BR pmdaEventQueueBytes and .BR pmdaEventQueueMemory provide a mechanism for querying a queue by its .I handle and filling in a .B pmAtomValue structure that the .B pmdaFetchCallBack method should return. .SH SEE ALSO .BR PMAPI (3), .BR PMDA (3), .BR pmdaEventNewClient (3) and .BR pmdaEventNewArray (3). pcp-3.8.12ubuntu1/man/man3/pmdapmid.30000664000000000000000000000415012272262501014072 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" Copyright (c) 2009 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAPMID 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaPMID\f1 \- translate a dynamic performance metric name into a PMID .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmdaPMID(char *\fIname\fP, pmID *\fIpmid\fP, pmdaExt *\fIpmda\fP); .sp cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION As part of the Performance Metrics Domain Agent (PMDA) API (see .BR PMDA (3)), .BR pmdaPMID is the generic callback for translating a dynamic metric .I name into a PMID (\c .IR pmid ). .PP Because implementing dynamic performance metrics requires specific PMDA support, and the facility is an optional component of a PMDA (most PMDAs do .B not support dynamic performance metrics), .B pmdaPMID is a skeleton implementation that returns .BR PM_ERR_NAME . .PP A PMDA that supports dynamic performance metrics will provide a private callback that replaces .B pmdaPMID (by assignment to .I version.four.pmid of the .I pmdaInterface structure) and implements the translation from a dynamic performance metric .I name into the associated .IR pmid . .SH DIAGNOSTICS .B pmdaPMID returns .B PM_ERR_NAME if the name is not recognized or cannot be translated, else returns 0. .SH CAVEAT The PMDA must be using .B PMDA_PROTOCOL_4 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH SEE ALSO .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaDSO (3), .BR pmdaMain (3) and .BR pmLookupName (3). pcp-3.8.12ubuntu1/man/man3/pmnumberstr.30000664000000000000000000000500212272262501014652 0ustar '\"! tbl | mmdoc '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMNUMBERSTR 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmNumberStr\f1, \f3pmNumberStr_r\f1 \- fixed width output format for numbers .SH "C SYNOPSIS" .ft 3 #include .sp const char *pmNumberStr(double \fIvalue\fP); .br char *pmNumberStr_r(double \fIvalue\fP, char *\fIbuf\fP, int \fIbuflen\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .B pmNumberStr returns the address of a 8-byte buffer that holds a null-byte terminated representation of .I value suitable for output with fixed width fields. The .B pmNumberStr_r function does the same, but stores the result in a user-supplied buffer .I buf of length .IR buflen , which should have room for at least 8 bytes. .PP The value is scaled using multipliers in powers of ``one thousand'' (the decimal ``kilo'') and has a bias that provides greater precision for positive numbers as opposed to negative numbers. .PP The format depends on the sign and magnitude of .I value as follows (\c \f(COd\f1 represents a decimal digit): .TS box,center; c | c lf(CW) | lf(CO). \f2value\f1 range format _ > 999995000000000 \f(CBinf?\fP 999995000000000 \- 999995000000 ddd.dd\f(CBT\fP 999995000000 \- 999995000 ddd.dd\f(CBG\fP 999995000 \- 999995 ddd.dd\f(CBM\fP 999995 \- 999.995 ddd.dd\f(CBK\fP 999.995 \- 0.005 ddd.dd 0.005 \- \-0.005 \f(CB 0.00\fP \-0.005 \- \-99.95 \-dd.dd \-99.995 \- \-99995 \-dd.dd\f(CBK\fP \-99995 \- \-99995000 \-dd.dd\f(CBM\fP \-99995000 \- \-99995000000 \-dd.dd\f(CBG\fP \-99995000000 \- \-99995000000000 \-dd.dd\f(CBT\fP < \-99995000000000 \f(CB\-inf?\fP .TE .PP At the boundary points of the ranges, the chosen format will retain the maximum number of significant digits. .SH NOTES .B pmNumberStr returns a pointer to a static buffer and hence is not thread-safe. Multi-threaded applications should use .B pmNumberStr_r instead. .SH SEE ALSO .BR printf (3) pcp-3.8.12ubuntu1/man/man3/GNUmakefile0000664000000000000000000000165712272262521014300 0ustar # # Copyright (c) 2013-2014 Red Hat. # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs MAN_SECTION = 3 MAN_PAGES = $(shell echo *.3) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) LSRCFILES = $(MAN_PAGES) default :: $(MAN_PAGES) default_pcp : $(MAN_PAGES) include $(BUILDRULES) install :: install_pcp install_pcp : default $(INSTALL_MAN) pcp-3.8.12ubuntu1/man/man3/pmusezone.30000664000000000000000000000255412272262501014332 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMUSEZONE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmUseZone\f1 \- re-establish a reporting timezone .SH "C SYNOPSIS" .ft 3 #include .sp int pmUseZone(const int \fItz_handle\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION The current reporting timezone effects the timezone used by .BR pmCtime (3) and .BR pmLocaltime (3). .PP The argument .I tz_handle identifies a reporting timezone as previously established by a call to .BR pmNewZone (3) or .BR pmNewContextZone (3), and this becomes the current reporting timezone. .SH SEE ALSO .BR PMAPI (3), .BR pmCtime (3), .BR pmLocaltime (3), .BR pmNewContextZone (3), .BR pmNewZone (3) and .BR pmWhichZone (3). .SH DIAGNOSTICS A return value less than zero indicates the value of .I tz_handle is not legal. pcp-3.8.12ubuntu1/man/man3/pmmktime.30000664000000000000000000000336312272262501014127 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMMKTIME 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmMktime\f1 \- convert a \fBtm\fR structure to a calendar time .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp time_t *__pmMktime(struct tm *\fItimeptr\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .B __pmMktime is very similar to .BR mktime (3), except the timezone used is the current ``reporting timezone'' (rather than the default .B TZ environment variable scheme). .PP Like .BR mktime (3) the time to be converted is passed via .IR timeptr , and the function result contains the calendar time (the number of seconds since 00:00:00 UTC, January 1, 1970). .PP The default current reporting timezone is as defined by the .B TZ environment variable, so .B __pmMktime and .BR mktime (3) will initially produce similar conversions. .PP Use .BR pmNewZone (3), .BR pmNewContextZone (3) or .BR pmUseZone (3) to establish a new current reporting timezone that will effect .B __pmMktime but not .BR mktime (3). .SH SEE ALSO .BR mktime (3), .BR PMAPI (3), .BR pmCtime (3), .BR pmLocaltime (3), .BR pmNewContextZone (3), .BR pmNewZone (3) and .BR pmUseZone (3). pcp-3.8.12ubuntu1/man/man3/pmstore.30000664000000000000000000000553712272262501014002 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMSTORE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmStore\f1 \- modify values of performance metrics .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmStore(const pmResult *\fIresult\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. In some special cases it may be helpful to modify the current values of performance metrics, e.g. to reset a counter to zero, or to modify a ``metric'' which is a control variable for some agent collecting performance metrics. .PP The routine .B pmStore is a lightweight inverse of .BR pmFetch (3). .PP The caller must build the .CW pmResult data structure (of course, this could have been returned from an earlier .BR pmFetch (3) call) and then call .BR pmStore . .PP It is an error to pass a request to .B pmStore in which the .CW numval field within any of the .B pmValueSet structure has a value less than one. .PP The current Performance Metrics Application Programming Interface (PMAPI) context must be one with a host as the source of metrics, and the current value of the nominated metrics will be changed, i.e. .B pmStore cannot be used to make retrospective changes to information in either the archive logs, or in the recent past for real-time sources of metrics. .PP The return code from .B pmStore is zero for success. .SH SEE ALSO .BR PMAPI (3), .BR pmFetch (3) and .BR pmSetMode (3). .SH DIAGNOSTICS .IP \f3PM_ERR_GENERIC\f1 At least one of the modifications was rejected. No other status is available from below the PMAPI (this is the lightweight part of the functionality!). In cases where the outcome of .B pmStore for individual metrics is important, the caller should make one call to .B pmStore for each metric. On the other hand, a bulk modification can be performed in a single .B pmStore call for situations in which the outcome is not critical. .IP \f3PM_ERR_NOTHOST\f1 The current PMAPI context is an archive rather than a host, or it is a host that is not set to the current time, i.e. has been ``rewound'' to the recent past using .BR pmSetMode (3). .IP \f3PM_ERR_TOOSMALL\f1 The number of metrics specified in .I result is less than one. .IP \f3PM_ERR_VALUE\f1 One or more of the .CW pmValueSet s in .I result has a .CW numval field with a value less than one. pcp-3.8.12ubuntu1/man/man3/pmopenlog.30000664000000000000000000000353612272262501014306 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMOPENLOG 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmOpenLog\f1 \- create a log file for diagnostics and debug output .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n FILE *__pmOpenLog(const char *\fIprogname\fP, const char *\fIlogname\fP, FILE\ *\fIoldstream\fP, int\ *\fIstatus\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .B __pmOpenLog reassigns the standard I/O stream .I oldstream to be associated with the file .IR logname . If it already exists, .I logname will be removed and recreated if possible (to ensure correct ownership and permissions from the caller to .BR __pmOpenLog ). .PP On return, the function value is the new standard I/O stream. In the event of an error, this will be .I oldstream unchanged and .I status will be 0. .PP For success, .I status is 1, a standard preamble is written to .I logname .ti +0.5i .ft B Log for \fIprogname\fB on \fIhostname\fB started \fIdate and time\fB .ft R .br and an .BR atexit (3) handler is installed to write the postscript message to .I logname .ti +0.5i .ft B Log finished \fIdate and time\fB .ft R .br when the processes exits. .PP .I progname is only used to annotate messages. .SH SEE ALSO .BR atexit (3) and .BR freopen (3). pcp-3.8.12ubuntu1/man/man3/pmdainit.30000664000000000000000000002074112272262501014110 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAINIT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaInit\f1, \f3pmdaRehash\f1, \f3pmdaSetFlags\f1 \- initialize a PMDA .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n void pmdaInit(pmdaInterface *\fIdispatch\fP, pmdaIndom *\fIindoms\fP, int\ \fInindoms\fP, pmdaMetric\ *\fImetrics\fP, int\ \fInmetrics\fP); .br .ti -8n void pmdaRehash(pmdaExt *\fIpmda\fP, pmdaMetric\ *\fImetrics\fP, int\ \fInmetrics\fP); .br .ti -8n void pmdaSetFlags(pmdaInterface *\fIdispatch\fP, int \fIflags\fP); .sp .in .hy .ad cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION .B pmdaInit initializes a PMDA so that it is ready to receive PDUs from .BR pmcd (1). The function expects as arguments the instance domain table .RI ( indoms ) and the metric description table .RI ( metrics ) that are initialized by the PMDA. The arguments .I nindoms and .I nmetrics should be set to the number of instances and metrics in the tables, respectively. .PP Much of the .B pmdaInterface structure can be automatically initialized with .BR pmdaDaemon (3), .BR pmdaGetOpt (3) and .BR pmdaDSO (3). .B pmdaInit completes the PMDA initialization phase with three operations. The first operation adds the domain and instance numbers to the instance and metric tables. Singular metrics (metrics without an instance domain) should have the instance domain .B PM_INDOM_NULL set in the .I indom field of the .B pmDesc structure (see .BR pmLookupDesc (3)). Metrics with an instance domain should set this field to be the serial number of the instance domain in the .I indoms table. .PP The instance domain table may be made empty by setting .I indoms to NULL and .I nindoms to 0. This allows the caller to provide custom Fetch and Instance callback functions. The metric table may be made empty by setting .I metrics to NULL and .I nmetrics to 0. This allows the caller to provide custom Fetch and Descriptor callback functions. .SH EXAMPLE For example, a PMDA has three metrics: A, B and C, and two instance domains X and Y, with two instances in each instance domain. The instance domain and metrics description tables could be defined as: .PP .nf .ft CW .in +0.5i static pmdaInstid _X[] = { { 0, "X1" }, { 1, "X2" } }; static pmdaInstid _Y[] = { { 0, "Y1" }, { 1, "Y2" } }; static pmdaIndom indomtab[] = { #define X_INDOM 0 { X_INDOM, 2, _X }, #define Y_INDOM 3 { Y_INDOM, 2, _Y } }; static pmdaMetric metrictab[] = { /* A */ { (void *)0, { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { 0,0,0,0,0,0} }, }, /* B */ { (void *)0, { PMDA_PMID(0,1), PM_TYPE_U32, X_INDOM, PM_SEM_INSTANT, { 0,0,0,0,0,0} }, }, /* C */ { (void *)0, { PMDA_PMID(0,2), PM_TYPE_DOUBLE, Y_INDOM, PM_SEM_INSTANT, { 0,1,0,0,PM_TIME_SEC,0} }, } }; .in .fi .PP The metric description table defines metric A with no instance domain, metric B with instance domain X and metric C with instance domain Y. Metric C has units of seconds, while the other metrics have no units (simple counters). .B pmdaInit will take these structures and assign the .BR PMDA (3) domain number to the .I it_indom field of each instance domain. This identifier also replaces the .I indom field of all metrics which have that instance domain, so that they are correctly associated. .PP The second stage opens the help text file, if one was specified with the .B \-h command line option (see .BR pmdaGetOpt (3)) or as a .I helptext argument to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .PP The final stage involves preparing the metric table lookup strategy. .SH "METRIC LOOKUP" When fetch and descriptor requests are made of the PMDA, each requested PMID must be mapped to a metric table entry. There are currently three strategies for performing this mapping \- direct, linear and hashed. Each has its own set of tradeoffs and an appropriate strategy should be selected for each PMDA. .PP If all of the metric PMID item numbers correspond to the position in the .I metrics table, then direct mapping is used. This is the most efficient of the lookup functions as it involves a direct array index (no additional memory is required nor any additional processing overhead). If the PMID numbering requirement is met by the PMDA, it is ideal. This strategy can be explicitly requested by calling .BR pmdaSetFlags \c (\f2pmda\f1, \f2PMDA_FLAG_EXT_DIRECT\f1) before calling .BR pmdaInit . In this case, if the direct mapping is not possible (e.g. due to an oversight on the part of the PMDA developer), a warning is logged and the linear strategy is used instead. .PP The second strategy (linear search) is the default, when a direct mapping cannot be established. This provides greater flexibility in the PMID numbering scheme, as the PMDA item numbers do not have to be unique (hence, the PMID cluster numbers can be used more freely, which is often extremely convenient for the PMDA developer). However, lookup involves a linear walk from the start of the metric table until a matching PMID is found, for each requested PMID in a request. .PP The third strategy (hash lookup) can be requested by calling .BR pmdaSetFlags \c (\f2pmda\f1, \f2PMDA_FLAG_EXT_HASHED\f1) before calling .BR pmdaInit . This strategy is most useful for PMDAs with large numbers of metrics (many hundreds, or thousands). Such PMDAs will almost always use the cluster numbering scheme, so the direct lookup scheme becomes inappropriate. They may also be prepared to sacrifice a small amount of additional memory for a hash table, mapping PMID to metric table offsets, to speed up lookups in their vast metric tables. .PP This final strategy can also be used by PMDAs serving up dynamically numbered metrics. For this case, the .B pmdaRehash function should be used to replace the metric table when new metrics become available, or existing metrics are removed. The PMID hash mapping will be recomputed at the same time that the new metric table is installed. .SH DIAGNOSTICS .B pmdaInit will set .I dispatch->status to a value less than zero if there is an error that would prevent the .BR PMDA (3) from successfully running. .BR pmcd (1) will terminate the connection to the .BR PMDA (3) if this occurs. .PP .B pmdaInit may issue any of these messages: .TP 15 .BI "PMDA interface version " interface " not supported" The .I interface version is not supported by .BR pmdaInit . .TP .B "Using pmdaFetch() but fetch call back not set" The fetch callback, .BR pmdaFetch (3), requires an additional callback to be provided using .BR pmdaSetFetchCallBack (3). .TP .BI "Illegal instance domain " inst " for metric " pmid The instance domain .I inst that was specified for metric .I pmid is not within the range of the instance domain table. .TP .B No help text path specified The help text callback, .BR pmdaText (3), requires a help text file for the metrics to have been opened, however no path to the help text was specified as a command line option, or as an argument to .BR pmdaDSO (3) or .BR pmdaDaemon (3). This message is only a warning. .TP .BI "Direct mapping for metrics disabled @ " num The unit numbers of the metrics did not correspond to the index in the metric description table. The direct mapping failed for metric number .I num in the .I metrics table. This is less efficient but is not fatal and the message is only a warning. .TP .BI "Hashed mapping for metrics disabled @ " num A memory allocation failure occurred while building the hash table to index the metric description table. This is a non-fatal warning message - a fallback to linear searching will be automatically performed should this situation arise. .SH CAVEAT The PMDA must be using .B PMDA_INTERFACE_2 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH SEE ALSO .BR newhelp (1), .BR pmcd (1), .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaDSO (3), .BR pmdaFetch (3), .BR pmdaGetOpt (3), .BR pmdaText (3) and .BR pmLookupDesc (3). pcp-3.8.12ubuntu1/man/man3/pmusecontext.30000664000000000000000000000347012272262501015041 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMUSECONTEXT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmUseContext\f1 \- change current PMAPI context .SH "C SYNOPSIS" .ft 3 #include .sp int pmUseContext(int \fIhandle\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION An application using the Performance Metrics Application Programming Interface (PMAPI) may manipulate several concurrent contexts, each associated with a source of performance metrics, e.g. \c .BR pmcd (1) on some host, or an archive log of performance metrics as created by .BR pmlogger (1). .PP Calling .B pmUseContext causes the current PMAPI context to be set to the context identified by .IR handle . The value of .I handle must be one returned from an earlier call to .BR pmNewContext (3) or .BR pmDupContext (3). .PP Below the PMAPI, all contexts used by an application are saved in their most recently modified state, so .B pmUseContext restores the context to the state it was in the last time the context was used, not the state of the context when it was established. .SH SEE ALSO .BR PMAPI (3), .BR pmDestroyContext (3), .BR pmDupContext (3), .BR pmNewContext (3) and .BR pmWhichContext (3). .SH DIAGNOSTICS .B PM_ERR_NOCONTEXT .IP .I handle does not identify a valid PMAPI context pcp-3.8.12ubuntu1/man/man3/pmdachildren.30000664000000000000000000000605512272262501014737 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" Copyright (c) 2009 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDACHILDREN 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaChildren\f1 \- translate a PMID to a set of dynamic performance metric names .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int pmdaChildren(char *\fIname\fP, int \fItraverse\fP, char\ ***\fIoffspring\fP, int\ **\fIstatus\fP, pmdaExt\ *\fIpmda\fP); .sp .in .hy .ad cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION As part of the Performance Metrics Domain Agent (PMDA) API (see .BR PMDA (3)), .BR pmdaChildren is the generic callback for returning dynamic metric names (and their status) that are descendants of .IR name . .PP Because implementing dynamic performance metrics requires specific PMDA support, and the facility is an optional component of a PMDA (most PMDAs do .B not support dynamic performance metrics), .B pmdaChildren is a skeleton implementation that returns .BR PM_ERR_NAME . .PP A PMDA that supports dynamic performance metrics will provide a private callback that replaces .B pmdaChildren (by assignment to .I version.four.children of the .I pmdaInterface structure) and takes the initial metric .I name and returns names via .IR offspring [] and the leaf or non-leaf status of each via .IR status []. .PP If .I traverse is 0, then the behaviour is akin to .BR pmGetChildren (3) and .IR offspring [] contains the relative name component for the immediate descendants of .IR name. .PP If .I traverse is 1, then the behaviour is akin to .BR pmTraversePMNS (3) and .IR offspring [] contains the absolute names of all dynamic metrics that are decedents of .IR name . .PP The resulting list of pointers .I offspring .B and the values (the names) that the pointers reference will have been allocated by .B pmdaChildren with a single call to .BR malloc (3C), and the caller of .B pmdaChildren will call .BR free (\c .IR offspring ) to release the space when it is no longer required. The same holds true for the .I status array. .SH DIAGNOSTICS .B pmdaChildren returns .B PM_ERR_NAME if the name is not recognized or cannot be translated, otherwise the number of descendent metric names found. .SH CAVEAT The PMDA must be using .B PMDA_PROTOCOL_4 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH SEE ALSO .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaDSO (3), .BR pmdaMain (3), .BR pmGetChildren (3) and .BR pmTraversePMNS (3). pcp-3.8.12ubuntu1/man/man3/pmgetchildrenstatus.30000664000000000000000000000723712272262501016401 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMGETCHILDRENSTATUS 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmGetChildrenStatus\f1 \- return the descendent nodes of a PMNS node and their respective status .SH "C SYNOPSIS" .ft 3 #include .sp .ad l .hy 0 .in +8n .ti -8n int pmGetChildrenStatus(const char *\fIname\fP, char ***\fIoffspring\fP, int\ **\fIstatus\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Given a fully qualified pathname to a node in the current Performance Metrics Name Space (PMNS), as identified by .IR name , .B pmGetChildrenStatus returns via .I offspring a list of the relative names of all of the immediate descendent nodes of .I name in the current PMNS. .PP As a special case, if .I name is an empty string (i.e.\f3""\f1), the immediate descendants of the root node in the PMNS will be returned. .PP If .IR status is not NULL, then .B pmGetChildrenStatus will also return the status of each child via .IR status. The status will refer to either a leaf node (with value .B PMNS_LEAF_STATUS ) or a non-leaf node (with value .B PMNS_NONLEAF_STATUS ). .PP Normally, .B pmGetChildrenStatus will return the number of descendent names discovered, else a value less than zero for an error. The value zero indicates that .I name is a valid metric name, i.e. is associated with a leaf node in the PMNS. .PP The resulting list of pointers .I offspring .B and the values (the relative names) that the pointers reference will have been allocated by .B pmGetChildrenStatus with a single call to .BR malloc (3C), and it is the responsibility of the .B pmGetChildrenStatus caller to .BR free (\c .IR offspring ) to release the space when it is no longer required. The same holds true for the .I status array. .PP When an error occurs, or .I name is a leaf node (i.e. the result of .B pmGetChildrenStatus is less than one), both .I offspring and .I status are undefined (no space will have been allocated, and so calling .BR free (3C) is a singularly bad idea). .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR PMAPI (3), .BR pmGetChildren (3), .BR pmGetConfig (3), .BR pmLoadASCIINameSpace (3), .BR pmLoadNameSpace (3), .BR pmLookupName (3), .BR pmNameID (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOPMNS\f1 Failed to access a PMNS for operation. Note that if the application hasn't a priori called pmLoadNameSpace(3) and wants to use the distributed PMNS, then a call to .B pmGetChildrenStatus must be made inside a current context. .IP \f3PM_ERR_NAME\f1 The pathname .I name is not valid in the current PMNS .IP \f3PM_ERR_*\f1 Other diagnostics are for protocol failures when accessing the distributed PMNS. pcp-3.8.12ubuntu1/man/man3/pmiunits.30000664000000000000000000000423112272262501014147 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2012 Red Hat. .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIUNITS 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmiUnits\f1, \f3pmiID\f1, \f3pmiInDom\f1 \- construct core metric data structures .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n pmID pmiID(int \fIdomain\fP, int \fIcluster\fP, int \fIitem\fP); .ti -8n pmInDom pmiInDom(int \fIdomain\fP, int \fIserial\fP); .ti -8n pmUnits pmiUnits(int \fIdimSpace\fP, int \fIdimTime\fP, int \fIdimCount\fP, int\ \fIscaleSpace\fP, int\ \fIscaleTime\fP, int\ \fIscaleCount\fP); .sp .in .hy .ad cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp .ad l .hy 0 .in +8n .ti -8n $pmid = pmiID($\fIdomain\fP, $\fIcluster\fP, $\fIitem\fP); .ti -8n $indom = pmiInDom($\fIdomain\fP, $\fIserial\fP); .ti -8n $units = pmiUnits($\fIdimSpace\fP, $\fIdimTime\fP, $\fIdimCount\fP, $\fIscaleSpace\fP, $\fIscaleTime\fP, $\fIscaleCount\fP); .sp .in .hy .ad .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), these routines provide convenience methods (especially for script use) for constructing .BR pmID , .B pmInDom and .B pmUnits structures respectively, to be used in subsequent calls to .BR pmiAddMetric (3) and .BR pmiAddInstance (3). .PP Refer to .BR pmLookupDesc (3) for a complete description of the values and semantics of the components of a .B pmUnits structure, and hence the valid argument values for .BR pmiUnits . .SH DIAGNOSTICS None. .SH SEE ALSO .BR LOGIMPORT (3), .BR pmiAddMetric (3), .BR pmiAddInstance (3) and .BR pmLookupDesc (3). pcp-3.8.12ubuntu1/man/man3/pmistart.30000664000000000000000000000746012272262501014151 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMISTART 3 "" "Performance Co-Pilot" .SH NAME \f3pmiStart\f1 \- establish a new LOGIMPORT context .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmiStart(const char *\fIarchive\fP, int \fIinherit\fP); .sp cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp pmiStart($\fIarchive\fP, $\fIinherit\fP); .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiStart creates a new context. Each context maintains the following state and metadata: .IP \(bu 3n The base name (\c .IR archive ) for the physical files that constitute the output PCP archive. .IP \(bu 3n The source hostname for the data that will be written to the PCP archive. Defaults to the hostname of the localhost, but can be set using .BR pmiSetHostname (3). .IP \(bu 3n The source timezone for the PCP archive. Defaults to the timezone of the localhost, but can be set using .BR pmiSetTimezone (3). .IP \(bu 3n Metrics and instance domains, as defined by .BR pmiAddMetric (3). .IP \(bu 3n Instances for each instance domain, as defined by .BR pmiAddInstance (3). .IP \(bu 3n Handles as defined by .BR pmiGetHandle (3). Each handle is a metric-instance pair, and each metric-instance pair may have an associated value in each record written to the output PCP archive. .IP \(bu 3n An optional set of data values for one or more metric-instance pairs (ready for the next record to be written to the output PCP archive) as defined by calls to .BR pmPutValue (3) or .BR pmPutValuehandle (3). .PP If .I inherit is true, then the new context will inherit any and all metadata (metrics, instance domains, instances and handles) from the current context, otherwise the new context is created with no metadata. The basename for the output PCP archive, the source hostname, the source timezone and any data values from the current context are .B not inherited. If this is the first call to .B pmiStart the metadata will be empty independent of the value of .IR inherit . .PP Since no physical files for the output PCP archive will be created until the first call to .BR pmiWrite (3) or .BR pmiPutRecord(3), .I archive could be NULL to create a convenience context that is populated with metadata to be inherited by subsequent contexts. .PP The return value is a context identifier that could be used in a subsequent call to .BR pmUseContext (3) and the new context becomes the current context which persists for all subsequent calls up to either another .B pmiStart call or a call to .BR pmiUseContext (3) or a call to .BR pmiEnd (3). .SH DIAGNOSTICS It is an error if the physical files \fIarchive\fR.\fB0\fR and/or \fIarchive\fR.\fBindex\fR and/or \fIarchive\fR.\fBmeta\fR already exist, but this is not discovered until the first attempt is made to output some data by calling .BR pmiWrite (3) or .BR pmiPutRecord(3), so .B pmiStart always returns a positive context identifier. .SH SEE ALSO .BR LOGIMPORT (3), .BR pmiAddInstance (3), .BR pmiAddMetric (3), .BR pmiEnd (3), .BR pmiErrStr (3), .BR pmiGetHandle (3), .BR pmiPutResult (3), .BR pmiPutValue (3), .BR pmiPutValueHandle (3), .BR pmiSetHostname (3), .BR pmiSetTimezone (3), .BR pmiUseContext (3) and .BR pmiWrite (3). pcp-3.8.12ubuntu1/man/man3/pmprintf.30000664000000000000000000000537512272262501014150 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMPRINTF 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmprintf\f1, \f3pmflush\f1 \- print formatted output in a window or to standard error .SH "C SYNOPSIS" .ft 3 #include .sp int pmprintf(const char *\fIfmt\fP, ... /*\fIargs\fP*/); .br int pmflush(void); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION The combination of .B pmprintf and .B pmflush produces output in either an .BR xconfirm (1) window, on the standard error stream, or to a file in a manner similar to .BR fprintf (3). The \f2fmt\f1 argument is used to control the conversion, formatting, and printing of the variable length \f2args\f1 list. The output technique is controlled via an environment variable. .PP .B pmprintf appends the formatted message string to an internal buffer shared by the two routines, without actually producing any output. .PP .B pmflush causes the internal buffer to be either displayed in a window, printed on standard error, or flushed to a file and the internal buffer to be cleared. .PP .SH ENVIRONMENT The environment variable .BR PCP_STDERR controls the output technique used by \f3pmflush\f1: .RS +4n .PP If .B PCP_STDERR is unset, the text is written onto the .I stderr stream of the caller. .PP If .B PCP_STDERR is set to the literal reserved word .B DISPLAY then the text will be displayed as a GUI dialog using .BR xconfirm (1). .PP If .B PCP_STDERR is set to any other value then \f3pmflush\f1 interprets the value as a file name and appends the text to that file. The file is created if it doesn't already exist, and in this case if the file creation fails, then .I stderr is used instead). .RE .SH FILES .B pmprintf uses the .BR mkstemp (3) function to create a temporary file. This temporary file is deleted when .B pmflush is called. .SH DIAGNOSTICS On successful completion, \f3pmprintf\f1 returns the number of characters transmitted, while .B pmflush returns a value of zero on successful completion. .PP For either routine, a negative value is returned if an error was encountered, and this can be passed to .BR pmErrStr (3) to obtain the associated error message. .PP .SH SEE ALSO .BR pmdbg (1), .BR fprintf (3), .BR mkstemp (3), .BR pmErrStr (3) and .BR PMAPI (3). pcp-3.8.12ubuntu1/man/man3/pmiaddmetric.30000664000000000000000000000710212272262501014741 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIADDMETRIC 3 "" "Performance Co-Pilot" .SH NAME \f3pmiAddMetric\f1 \- add a new metric definition to a LOGIMPORT context .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int pmiAddMetric(const char *\fIname\fP, pmID \fIpmid\fP, int\ \fItype\fP, pmInDom\ \fIindom\fP, int\ \fIsem\fP, pmUnits\ \fIunits\fP); .sp .in .hy .ad cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp pmiAddMetric($\fIname\fP, $\fIpmid\fP, $\fItype\fP, $\fIindom\fP, $\fIsem\fP, $\fIunits\fP); .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiAddMetric is used to define a new metric. The metric's .I name must follow the naming conventions described in .BR PCPIntro (1) and should be unique for each LOGIMPORT context. .PP The other arguments are in effect the fields of a .B pmDesc structure. Refer to .BR pmLookupDesc (3) for a complete description of the values and semantics of the components of this structure, and hence the valid argument values for .BR pmiAddMetrics . .PP The internal identifier for the metric may be given using the .I pmid argument and must be unique for each LOGIMPORT context. The value for .I pmid which would typically be constructed using the .B pmid_build macro, e.g. pmid_build(PMI_DOMAIN, 0, 3) for the fourth metric in first ``cluster'' of metrics in the Performance Metrics Domain PMI_DOMAIN (which is the default for all meta data created by the LOGIMPORT library). Alternatively, .I pmid may be .B PM_IN_NULL and .B pmiAddMetric will assign a unique .I pmid (although this means the .I pmid remains opaque and the application must use .BR pmiPutValue (3) or .BR pmiPutValueHandle (3) and cannot use .BR pmiPutResult (3) to add data values to the PCP archive). .PP .I type defines the data type of the metric and must be one of the .B PM_TYPE_... values defined in .BR . .PP The instance domain for the metric is defined by .I indom and may be .B PM_INDOM_NULL for a metric with a singular value, else the value for .I indom would normally be constructed using the .B pmInDom_build macro, e.g. pmInDom_build(LOGIMPORT,0) for the first instance domain in the Performance Metrics Domain LOGIMPORT (which is the default for all meta data created by the LOGIMPORT library). Multiple metrics can share the same instance domain if they have values for a similar (or more usually, identical) set of instances. .PP The semantics of the metric (counter, instantaneous value, etc.) is specified by the .I sem argument which would normally be the result of a call to the convenience constructor method .BR pmiUnits (3). .SH DIAGNOSTICS .B pmiAddMetric returns zero on success else a negative value that can be turned into an error message by calling .BR pmiErrStr (3). .SH SEE ALSO .BR PCPIntro (1), .BR LOGIMPORT (3), .BR pmiErrStr (3), .BR pmiPutResult (3), .BR pmiPutValue (3), .BR pmiPutValueHandle (3), .BR pmiUnits (3) and .BR pmLookupDesc (3). pcp-3.8.12ubuntu1/man/man3/pmtraversepmns.30000664000000000000000000000604312272262501015370 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMTRAVERSEPMNS 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmTraversePMNS\f1, \f3pmTraversePMNS_r\f1 \- traverse the performance metrics name space .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmTraversePMNS(const char *\fIname\fP, void (*\fIdometric\fP)(const char *)); int pmTraversePMNS_r(const char *\fIname\fP, void (*\fIdometric_r\fP)(const char *, void *), void *\fIclosure\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. .PP The routine .B pmTraversePMNS may be used to perform a depth-first traversal of the Performance Metrics Name Space (PMNS). .PP The traversal starts at the node identified by .I name \- if .I name is an empty string (i.e. \f3""\f1), the traversal starts at the root of the PMNS. Usually .I name would be the pathname of a non-leaf node in the PMNS. .PP For each leaf node (i.e. performance metric) found in the traversal, the user-supplied routine .I dometric is called with the full pathname of that metric in the PMNS as the single argument. This argument is null-byte terminated, and is constructed from a buffer that is managed internally to .BR pmTraversePMNS . Consequently the value is only valid during the call to .I dometric \- if the pathname needs to be retained, it should be copied using .BR strdup (3C) before returning from .IR dometric . .PP The .B pmTraversePMNS_r routine performs the same function, except the callback method .I func_r has an additional parameter that will be .I closure from the initial call to .BR pmTraversePMNS_r . The additional parameter to .B pmTraversePMNS_r and the callback method allows the caller to pass context through .B pmTraversePMNS_r and into the callback method .IR func_r , making the service more useful for multi-threaded applications where thread-private data can be accessed in the callback method via the .I closure argument. .PP On success .B pmTraversePMNS returns the number of children of .IR name , which may be zero. .SH SEE ALSO .BR PMAPI (3) and .BR pmGetChildren (3). .SH DIAGNOSTICS .IP \f3PM_ERR_NOPMNS\f1 Failed to access a PMNS for operation. Note that if the application hasn't a priori called pmLoadNameSpace(3) and wants to use the distributed PMNS, then a call to .B pmTraversePMNS must be made inside a current context. .IP \f3PM_ERR_NAME\f1 The initial pathname .I name is not valid in the current PMNS. .IP \f3PM_ERR_*\f1 Other diagnostics are for protocol failures when accessing the distributed PMNS. pcp-3.8.12ubuntu1/man/man3/pmdaprofile.30000664000000000000000000000304412272262501014602 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAPROFILE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaProfile\f1 \- update instance profile for PMDA in preparation for the next fetch from PMCD .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmdaProfile(__pmProfile *\fIprof\fP, pmdaExt *\fIpmda\fP); .sp cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION As part of the Performance Metrics Domain Agent (PMDA) API (see .BR PMDA (3)), .B pmdaProfile is the default callback which handles the receipt of a .B __pmProfile from .BR pmcd (1). A profile describes the instances that .B pmcd requires in the .B pmResult structure returned by the next fetch. .B pmdaProfile simply stores the new profile. .SH CAVEAT The PMDA must be using .B PMDA_PROTOCOL_2 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH SEE ALSO .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaDSO (3) and .BR pmdaFetch (3). pcp-3.8.12ubuntu1/man/man3/pmconverttime.30000664000000000000000000000365012272262501015177 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMCONVERTTIME 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmConvertTime\f1 \- convert \fBtm\fR structure to \fBtimeval\fR structure .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int __pmConvertTime(struct tm *\fItmin\fP, struct timeval *\fIorigin\fP, struct\ timeval\ *\fIrslt\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .B __pmConvertTime accepts a .B tm structure that has been filled in by .BR __pmParseCtime (3) and a reference time point .BR origin , and fills in the given .B rslt structure with the time the user meant when he specified a partial .B ctime or positive or negative time .BR interval . .PP Typically, the argument .B origin is the start time for a PCP archive log, unless the user specified a negative .B interval offset, in which case it is the end time of the log. .PP .B __pmConvertTime returns 0 if successful. It returns \-1 and writes an error message to .BR stderr , if an error is detected. .PP Use .BR pmNewZone (3), .BR pmNewContextZone (3) or .BR pmUseZone (3) to establish a new current timezone that will effect .BR __pmConvertTime . .SH SEE ALSO .BR PMAPI (3), .BR pmNewContextZone (3), .BR pmNewZone (3), .BR pmParseInterval (3), .BR pmParseTimeWindow (3), .BR pmUseZone (3), .BR __pmParseCtime (3) and .BR __pmParseTime (3). pcp-3.8.12ubuntu1/man/man3/pmaf.30000664000000000000000000001045112272262501013223 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMAF 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmAFregister\f1, \f3__pmAFunregister\f1, \f3__pmAFblock\f1, \f3__pmAFunblock\f1, \f3__pmAFisempty\f1 \- event queue services for periodic asynchronous callbacks .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int __pmAFregister(const struct timeval *\fIdelta\fP, void *\fIdata\fP, void\ (*\fIfunc\fP)(int,\ void *)); .br .in .hy .ad int __pmAFunregister(int \fIafid\fP); .br void __pmAFblock(void); .br void __pmAFunblock(void); .br int __pmAFisempty(void); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION The routines implement an event queue and callback framework that supports periodic evaluation of a series of events with varying frequencies for Performance Co-Pilot (PCP) applications. .P The .BR pmlogger (1) application, the .BR pmdatrace (1) PMDA and the .BR pmdahotproc (1) PMDA are the principal users of these services. .P An event is registered by calling .BR __pmAFregister , and on success the return value is an event number greater than zero. The event has associated event data identified by the opaque pointer .IR data . The event will occur with frequency .IR delta (the first instance will be .I delta after the current time when the event is registered), and each time the event occurs the function .I func will be called with the event number and the event data as arguments. .P Once the event occurs and the callback has been executed, the event will be rescheduled for .I delta into the future, except if all the fields of .I delta are zero, in which case the event will not be rescheduled (a ``one trip'' event). .P Internally, events are processed serially so there is no possibility of nested callbacks or re-entrant callbacks from the event management routines. .P Given an event number .IR afid , .B __pmAFunregister will permanently remove the corresponding entry from the event queue. .P To control the event queue processing, .B __pmAFblock and .B __pmAFunblock may be used to explicitly block and unblock the dispatch of events. This is most useful when the caller wishes to set up a number of events via .B __pmAFregister and complete the registration phase before the first event callback occurs. .P A call to .B __pmAFisempty returns 1 or 0 depending on whether the event queue is empty or not. .SH SEE ALSO .BR PMAPI (3) .SH DIAGNOSTICS .PP .B __pmAFregister and .B __pmAFunregister return values less than zero in the case of an error. These values are PCP error codes, and may be used to produce error messages via .BR pmErrStr (3). .P The routines support the standard PCP debug tracing, and the value .B DBG_TRACE_AF (or .B "\-D af" on the command line) will produce diagnostics on standard error that trace the enqueueing and execution of events. .SH CAVEATS These routines rely on .BR setitimer (2) and manipulate the handling of .B SIGALRM signals, and hence are probably ill-suited for applications that require direct and concurrent access to these services and resources. .P If the callback functions are slow, or delayed, it is possible that the event scheduling could fall behind and never catchup. When this begins to happen, events are silently skipped and rescheduled at the earliest possible time on the future according to the fixed schedule defined by the time of the call to .B __pmAFregister and the value of the .I delta argument to .BR __pmAFregister . .P In addition, the semantics of the interval timer(s) and the global state needed to support these services demand that applications calling these routines must do so from a single thread. This restriction is enforced at the .BR PMAPI (3), where routines may return the error code .B PM_ERR_THREAD if the library detects calls from more than one thread. pcp-3.8.12ubuntu1/man/man3/pmgetchildren.30000664000000000000000000000633412272262501015132 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMGETCHILDREN 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmGetChildren\f1 \- return the descendent nodes of a PMNS node .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmGetChildren(const char *\fIname\fP, char ***\fIoffspring\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Given a fully qualified pathname to a node in the current Performance Metrics Name Space (PMNS), as identified by .IR name , .B pmGetChildren returns via .I offspring a list of the relative names of all of the immediate descendent nodes of .I name in the current PMNS. .PP As a special case, if .I name is an empty string (i.e.\f3""\f1), the immediate descendants of the root node in the PMNS will be returned. .PP Normally, .B pmGetChildren will return the number of descendent names discovered, else a value less than zero for an error. The value zero indicates that .I name is a valid metric name, i.e. is associated with a leaf node in the PMNS. .PP The resulting list of pointers .I offspring .B and the values (the relative names) that the pointers reference will have been allocated by .B pmGetChildren with a single call to .BR malloc (3C), and it is the responsibility of the .B pmGetChildren caller to .BR free (\c .IR offspring ) to release the space when it is no longer required. .PP When an error occurs, or .I name is a leaf node (i.e. the result of .B pmGetChildren is less than one), .I offspring is undefined (no space will have been allocated, and so calling .BR free (3C) is a singularly bad idea). .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR PMAPI (3), .BR pmGetChildrenStatus (3), .BR pmGetConfig (3), .BR pmLoadASCIINameSpace (3), .BR pmLoadNameSpace (3), .BR pmLookupName (3), .BR pmNameID (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOPMNS\f1 Failed to access a PMNS for operation. Note that if the application hasn't a priori called pmLoadNameSpace(3) and wants to use the distributed PMNS, then a call to .B pmGetChildren must be made inside a current context. .IP \f3PM_ERR_NAME\f1 The pathname .I name is not valid in the current PMNS .IP \f3PM_ERR_*\f1 Other diagnostics are for protocol failures when accessing the distributed PMNS. pcp-3.8.12ubuntu1/man/man3/pmlocaltime.30000664000000000000000000000371312272262501014611 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOCALTIME 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmLocaltime\f1 \- convert the date and time for a reporting timezone .SH "C SYNOPSIS" .ft 3 #include .br #include .sp struct tm *pmLocaltime(const time_t *\fIclock\fP, struct tm *\fIresult\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .B pmLocaltime is very similar to .BR localtime (3), except the timezone used is the current ``reporting timezone'' (rather than the default .B TZ environment variable scheme), and the result is returned into a caller-declared buffer (rather than a private buffer). .PP Like .BR localtime (3) the time to be converted is passed via .IR clock , and the .I result contains the components broken out in the elements of the .I tm struct. .PP .B pmLocaltime returns .I result as the value of the function. .PP The default current reporting timezone is as defined by the .B TZ environment variable, so .B pmLocaltime and .BR localtime (3) will initially produce a similar encoding of the date and time. .PP Use .BR pmNewZone (3), .BR pmNewContextZone (3) or .BR pmUseZone (3) to establish a new current reporting timezone that will affect .B pmLocaltime but not .BR localtime (3). .SH SEE ALSO .BR localtime (3), .BR PMAPI (3), .BR pmCtime (3), .BR pmGetConfig (3), .BR pmNewContextZone (3), .BR pmNewZone (3), .BR pmUseZone (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man3/pmdaopenlog.30000664000000000000000000000376612272262501014620 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAOPENLOG 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaOpenLog\f1 \- redirect stderr to a logfile .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp void pmdaOpenLog(pmdaInterface * \fIdispatch\fP); .sp cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION .B pmdaOpenLog redirects .I stderr to the logfile specified in the .I dispatch structure, set by the previous call to .BR pmdaDaemon (3) or .BR pmdaGetOpt (3). The first line of the log file will detail the name of the calling process, the host the process is running on, and the current time. In addition, the log is appended with the exit time of the process by a routine registered with .BR atexit (3C). .SH CAVEAT The PMDA must be using .B PMDA_PROTOCOL_2 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .IR pmGetConfig (3) function. .SH SEE ALSO .BR pmcd (1), .BR atexit (2), .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3) and .BR pmdaGetOpt (3). pcp-3.8.12ubuntu1/man/man3/pmunpackeventrecords.30000664000000000000000000000727012272262501016547 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMUNPACKEVENTRECORDS 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmUnpackEventRecords\f1 \- unpack event records .SH "C SYNOPSIS" .ft 3 #include .sp int pmUnpackEventRecords(pmValueSet *\fIvsp\fP, int \fIidx\fP, pmResult ***\fIrap\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Event records are encoded as a packed array of records within a .I pmResult using a container metric with a value of type .BR PM_TYPE_EVENT . .PP .B pmUnpackEventRecords may be used to unpack event records from a metric value identified by .I vsp and .IR idx . If the metric has a singular value, .I idx should be 0, else the ordinal instance value identified by .I idx will be unpacked, i.e. vsp->vlist[idx]. The unpacked records are turned into .I pmResult structures, one per event record and one metric per event parameter, and .I rap is returned as a pointer to an array (NULL pointer terminated) of pointers to the .I pmResult structures. .PP Some control information from the packed event records is unpacked into additional ``anonymous'' metrics as follows: .TP 4n 1. If the event record has a non-zero flags value, then the corresponding .I pmResult will have the flags value encoded with the additional metric .B event.flags that is inserted ahead of all other event parameters. .TP 4n 2. If the event record flag is set to .BR PM_EVENT_FLAG_MISSED , then the corresponding .I pmResult will have one metric .B event.missed with a value that equals the number of event records ``missed'' because either the PMDA could not keep up, or the PMAPI client did not collect the event records fast enough. .PP .B pmUnpackEventRecords returns the number of .I pmResult structures as the return value, which is >= 0 for success. .PP .I rset and the associated .I pmResult structures may be freed using the convenience function .BR pmFreeEventResult (3). .SH "RETURN VALUE" The following errors are possible: .TP 10n PM_ERR_CONV The values associated with .I vsp are not encoded using the format PM_VAL_DPTR or PM_VAL_SPTR, or the flags at the head of the event record has an unexpected value. .TP 10n PM_ERR_INST The value associated with .I vsp is not singular as expected. .TP 10n PM_ERR_TYPE .I vsp is not a value of type .BR PM_TYPE_EVENT . .TP 10n PM_ERR_TOOSMALL The value identified by .I vbp is not legal because the value length is less than the minimum size, or the number of event records encoded in the (value header) .I pmEventArray structure is negative, or the number of missed event records in the .I pmEventArray array is negative. .TP 10n PM_ERR_TOOBIG Either .B vsp indicates more than one value is present (all the event records are expected to be packed in a single metric value), or when unpacking the event records, the processing continues past the end of the enclosing value. Indicates corruption of the packed event record. .TP 10n PM_ERR_TYPE Event parameters must have one of the arithmetic types, else .BR PM_TYPE_AGGREGATE , .B PM_TYPE_STRING or .BR PM_TYPE_AGGREGATE_STATIC . .TP 10n other values < 0 refer to .BR pmErrStr (3). .SH SEE ALSO .BR PMAPI (3) and .BR pmFreeEventResult (3). pcp-3.8.12ubuntu1/man/man3/pmiputvalue.30000664000000000000000000000445712272262501014664 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIPUTVALUE 3 "" "Performance Co-Pilot" .SH NAME \f3pmiPutValue\f1 \- add a value for a metric-instance pair .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int pmiPutValue(const char *\fIname\fP, const char *\fIinstance\fP, const\ char\ *\fIvalue\fP); .sp .in .hy .ad cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp pmiPutValue($\fIname\fP, $\fIinstance\fP, $\fIvalue\fP); .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiPutValue adds a single value to the current output record for a given metric and instance. .PP The metric's .I name should match one defined earlier in a call to .BR pmiAddMetric (3). .PP For singular metrics (those defined with an instance domain of .BR PM_INDOM_NULL ), the .I instance should be NULL or an empty string, otherwise .I instance should match the name of an instance defined earlier in a call to .BR pmiAddInstance (3) for the metric's instance domain. .PP The .I value should be in a format consistent with the metric's type as defined in the call to .BR pmiAddMetric (3). .PP No data will be written until .BR pmiWrite (3) is called, so multiple calls to .B pmiPutValue or .BR pmiPutValueHandle (3) are typically used to accumulate data values for several metric-instance pairs before calling .BR pmiWrite (3). .SH DIAGNOSTICS .B pmiPutValue returns zero on success else a negative value that can be turned into an error message by calling .BR pmiErrStr (3). .SH SEE ALSO .BR LOGIMPORT (3), .BR pmiAddInstance (3), .BR pmiAddMetric (3), .BR pmiErrStr (3), .BR pmiPutResult (3), .BR pmiPutValueHandle (3) and .BR pmiWrite (3). pcp-3.8.12ubuntu1/man/man3/pmwhichzone.30000664000000000000000000000277512272262501014645 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMWHICHZONE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmWhichZone\f1 \- return current reporting timezone .SH "C SYNOPSIS" .ft 3 #include .sp int pmWhichZone(char **\fItz\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION The current reporting timezone effects the timezone used by .BR pmCtime (3) and .BR pmLocaltime (3). .PP .B pmWhichZone returns the handle of the current timezone, as previously established by a call to .BR pmNewZone (3) or .BR pmNewContextZone (3). If the call is successful (i.e. there exists a current reporting timezone) then a non-negative integer is returned and .I tz is set to point to a static buffer containing the timezone string itself. .SH SEE ALSO .BR PMAPI (3), .BR pmCtime (3), .BR pmLocaltime (3), .BR pmNewContextZone (3), .BR pmNewZone (3) and .BR pmUseZone (3). .SH DIAGNOSTICS A return value less than zero indicates there is no current reporting timezone. pcp-3.8.12ubuntu1/man/man3/pmconnectlogger.30000664000000000000000000000526212272262501015472 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMCONNECTLOGGER 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmConnectLogger\f1 \- connect to a performance metrics logger control port .SH "C SYNOPSIS" .ft 3 #include .br #include .br .sp int __pmConnectLogger(const char *\fIhostname\fP, int \fIpid\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\fR\\$2 .el \fI\\$1\fR\\$2 .. Each instance of the Performance Co-Pilot (PCP) archive logger program .BR pmlogger (1) supports a control port on which .BR __pmControlLog (3) requests are received, and responses sent. Optionally, the .BR pmlogger (1) instance may be designated the ``primary'' logger. .PP .B __pmConnectLogger may be used to establish a control port connection to the .BR pmlogger (1) instance identified by process id .I pid on the host .IR hostname . .PP One special case is supported; for the reserved .I pid value of .B PM_LOG_CONTROL_PORT the requested connection is to the control port for the ``primary'' logger, whatever its process id might be. .PP On success, .B __pmConnectLogger returns a non-negative integer, that is a file descriptor that may be used in subsequent communication with the .BR pmlogger (1) instance, e.g. for .BR __pmControlLog (3). .PP As the control port to .BR pmlogger (1) is not mulitplexed, applications using .B __pmConnectLogger should use .BR close (2) to terminate the connection to .BR pmlogger (1) as soon as they have finished communicating. .PP If the application connects, and the .BR pmlogger (1) instance subsequently terminates, e.g. \c because the associated .BR pmcd (1) instance is terminated, the application will have to explicitly re-establish connection to a re-started .BR pmlogger (1) instance by calling .B __pmConnectLogger again. .SH SEE ALSO .BR pmcd (1), .BR pmlc (1), .BR pmlogger (1), .BR PMAPI (3) and .BR __pmControlLog (3). .SH DIAGNOSTICS .IP \f3PM_ERR_PERMISSION\f1 no permission to connect to the specified .BR pmlogger (1) instance .IP \f3\-ECONNREFUSED\f1 the designated .BR pmlogger (1) instance does not exist .IP \f3\-EEADDRINUSE\f1 the requested control port is already in use pcp-3.8.12ubuntu1/man/man3/pmisethostname.30000664000000000000000000000301012272262501015331 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMISETHOSTNAME 3 "" "Performance Co-Pilot" .SH NAME \f3pmiSetHostname\f1 \- set the source host name for a LOGIMPORT archive .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmiSetHostname(const char *\fIvalue\fP); .sp cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp pmiSetHostname($\fIvalue\fP); .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiSetHostname sets the source hostname in the current context to be .IR value . .PP In the absence of a call to .B pmiSetHostname the source hostname defaults to the hostname of the localhost. .SH DIAGNOSTICS .B pmiSetHostname returns zero on success else a negative value that can be turned into an error message by calling .BR pmiErrStr (3). .SH SEE ALSO .BR LOGIMPORT (3), .BR pmiErrStr (3), .BR pmiSetTimezone (3) and .BR pmiStart (3). pcp-3.8.12ubuntu1/man/man3/pmfreeresult.30000664000000000000000000000305412272262501015016 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMFREERESULT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmFreeResult\f1 \- release storage allocated for performance metrics values .SH "C SYNOPSIS" .ft 3 #include .sp void pmFreeResult(pmResult *\fIresult\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. The variable sized results returned by .BR pmFetch (3) are allocated below the Performance Metrics Application Programming Interface (PMAPI) using a combination of dynamic (i.e. \c .BR malloc (3)) and specialized allocation strategies. .PP Applications should call .B pmFreeResult to release the storage previously allocated for .I result by .BR pmFetch (3), when the application no longer requires access to the .CW pmResult structure. .PP Under .B no circumstances should an application use .CW "free(result)" to release storage previously allocated for a .CW pmResult by .BR pmFetch (3). .SH SEE ALSO .BR PMAPI (3) and .BR pmFetch (3). pcp-3.8.12ubuntu1/man/man3/pmunloadnamespace.30000664000000000000000000000261412272262501015776 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMUNLOADNAMESPACE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmUnloadNameSpace\f1 \- unload a local performance metrics name space for an application .SH "C SYNOPSIS" .ft 3 #include .sp void pmUnloadNameSpace(void); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION If one has previously loaded a local Name Space using .BR pmLoadNameSpace (3) or .BR pmLoadASCIINameSpace (3), then calling .BR pmUnloadNameSpace (3) will free up the memory associated with the Name Space and force all subsequent PMNS routine calls to use the distributed PMNS. If .BR pmUnloadNameSpace (3) is called before calling .BR pmLoadNameSpace (3) or .BR pmLoadASCIINameSpace (3), then it will effectively do nothing. .SH SEE ALSO .BR PMAPI (3), .BR pmLoadASCIINameSpace (3), .BR pmLoadNameSpace (3) and .BR pmns (5). pcp-3.8.12ubuntu1/man/man3/pmlookupipc.30000664000000000000000000000726512272262501014653 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOOKUPIPC 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmAddIPC\f1, \f3__pmLookupIPC\f1, \f3__pmFdLookupIPC\f1, \f3__pmOverrideLastFd\f1, \f3__pmPrintIPC\f1, \f3__pmResetIPC\f1 \- IPC version infrastructure support .SH "C SYNOPSIS" .ft 3 #include .br #include .sp int __pmAddIPC(int \fIfd\fP, __pmIPC \fIipc\fP); .br int __pmLookupIPC(__pmIPC **\fIipcp\fP); .br int __pmFdLookupIPC(int \fIfd\fP, __pmIPC **\fIipcp\fP); .br void __pmOverrideLastFd(int \fIfd\fP); .br void __pmPrintIPC(void); .br void __pmResetIPC(int \fIfd\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION IPC channels throughout the distributed PCP framework are affected by the PCP 2.0 (and later) PDU changes. These functions are the interface to the libpcp IPC connection management global data. This data consists of a hash table of __pmIPC structures (indexed by file descriptor) and a cached, most-recently-used file descriptor. .PP Newly created IPC channels must be registered with the hash table using \f3__pmAddIPC\f1, such that the PDU sending and decoding routines can determine whether they need to perform any PDU version translations or not, for backward compatibility with previous the PCP 1.x IPC protocol. .PP .B __pmLookupIPC and .B __pmFdLookupIPC both provide handles to the __pmIPC structure associated with the given file descriptor, as previously established by a call to .BR __pmAddIPC . The difference between the two is that one allows an explicit file descriptor lookup, and the other uses the cached, most-recently-used file descriptor. So .B __pmLookupIPC actually calls .B __pmFdLookupIPC using this cached file descriptor as the argument. The justification for having both is that in some places it is not possible to use .B __pmFdLookupIPC (which is preferred), since at that particular level of the PMAPI a file descriptor is not available (see the __pmDecodeError code for an example). .PP The .B __pmOverrideLastFd is an escape mechanism for use in those situations where the last PDU fetch did not go through the usual channels (ie. __pmGetPDU), so as to ensure that the cached file descriptor is the correct file descriptor for the PDU which is currently being processed. This will typically be used for archive PDU processing or where version information is not available for a given file descriptor (eg. immediately prior to a PDU version exchange). .PP .B __pmPrintIPC is a useful debugging routine for displaying a table mapping all currently registered file descriptors to their associated PDU version numbers. Unused entries in this table should display the value zero in the version column. .PP .B __pmResetIPC resets the version information associated with the given file descriptor to some known (invalid) number. Subsequent lookups on this file descriptor will return an UNKNOWN_VERSION embedded within the __pmIPC structure. .SH SEE ALSO .BR PMAPI (3) .SH DIAGNOSTICS A negative return value from \f3__pmLookupIPC\f1 indicates that the requested file descriptor is not registered in the hash table. This typically indicates closure of an IPC channel, so PM_ERR_IPC is returned if this is the case. pcp-3.8.12ubuntu1/man/man3/pmindomstr.30000664000000000000000000000544712272262501014505 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMINDOMSTR 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmInDomStr\f1, \f3pmInDomStr_r\f1 \- convert a performance metric instance domain identifier into a string .SH "C SYNOPSIS" .ft 3 #include .sp const char *pmInDomStr(pmInDom \fIindom\fP); .br char *pmInDomStr_r(pmInDom \fIindom\fP, char *\fIbuf\fP, int \fIbuflen\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. For use in error and diagnostic messages, .B pmInDomStr return a 'human readable' version of the specified instance domain identifier. The .B pmInDomStr_r function does the same, but stores the result in a user-supplied buffer .I buf of length .IR buflen , which should have room for at least 20 bytes. .PP The value for the instance domain .I indom is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP Internally, an instance domain identifier is encoded as follows; .PP .ft CW .nf .in +0.5i typedef struct { int pad:2; unsigned int domain:8; /* the administrative PMD */ unsigned int serial:22; /* unique within PMD */ } __pmInDom_int; .in .fi .ft 1 .PP .B pmInDomStr returns a string with each of the .CW domain and .CW serial subfields appearing as decimal numbers, separated by periods. .PP The string value returned by .B pmInDomStr is held in a single static buffer, so the returned value is only valid until the next call to .BR pmInDomStr . .SH NOTES .B pmInDomStr returns a pointer to a static buffer and hence is not thread-safe. Multi-threaded applications should use .B pmInDomStr_r instead. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR PMAPI (3), .BR pmGetConfig (3), .BR pmIDStr (3), .BR pmLookupDesc (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man3/pmsetmode.30000664000000000000000000001416712272262501014305 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMSETMODE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmSetMode\f1 \- set collection time parameters for the current PMAPI context .SH "C SYNOPSIS" .ft 3 #include .sp int pmSetMode(int \fImode\fP, const struct timeval *\fIwhen\fP, int \fIdelta\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. .B pmSetMode is used to define the collection time and/or mode for accessing performance metrics and meta-data in the current Performance Metrics Application Programming Interface (PMAPI) context. This mode affects the semantics of subsequent calls to the following PMAPI routines: .BR pmFetch (3), .BR pmFetchArchive (3), .BR pmLookupDesc (3), .BR pmGetInDom (3), .BR pmLookupInDom (3) and .BR pmNameInDom (3). .PP If .I mode is .B PM_MODE_LIVE then all information is returned from the active pool of performance metrics as of the time that the PMAPI call is made, and the other two parameters to .B pmSetMode are ignored. .B PM_MODE_LIVE is the default mode when a new PMAPI context of type .B PM_CONTEXT_HOST is created. .PP If the .I mode is not .BR PM_MODE_LIVE , then the .I when parameter defines a time origin, and all requests for meta-data (metric descriptions and instance identifiers from the instance domains) will be processed to reflect the state of the meta-data as of the time origin, i.e. we use the last state of this information at, or before, the time origin. .PP If the .I mode is .B PM_MODE_INTERP then, in the case of .BR pmFetch (3), the underlying code will use an interpolation scheme to compute the values of the metrics from the values recorded for times in the proximity of the time origin. A .I mode of .B PM_MODE_INTERP may only be used with an archive context. .PP If the .I mode is .B PM_MODE_FORW then, in the case of .BR pmFetch (3), the collection of recorded metric values will be scanned in a forwards direction in time, until values for at least one of the requested metrics is located after the time origin, and then all requested metrics stored in the log or archive at that time will be returned with the corresponding timestamp. A .I mode of .B PM_MODE_FORW may only be used with an archive context. .PP If the .I mode is .B PM_MODE_BACK then, the situation is the same as for .BR PM_MODE_FORW , except a .BR pmFetch (3) will be serviced by scanning the collection of recorded metrics in a backwards direction in time for metrics before the time origin. A .I mode of .B PM_MODE_BACK may only be used with an archive context. .PP If the .I mode is .B PM_MODE_FORW or .BR PM_MODE_BACK , and no qualifying metrics can be found in the requested direction of searching before the end or start of the archive log is found, then .BR pmFetch (3) returns the special error indicator, .BR PM_ERR_EOL . .PP For .IR mode s other than .BR PM_MODE_LIVE , after each successful .BR pmFetch (3), the time origin is reset to the timestamp returned via the .CW pmResult structure from .BR pmFetch (3). .PP The .B pmSetMode parameter .I delta defines an additional number of time units that should be used to adjust the time origin (forwards or backwards), after the new time origin from the .CW pmResult has been determined. This automatic adjustment of the time origin only occurs when the .I mode is .BR PM_MODE_INTERP , and the adjustment is applied, even if the .BR pmFetch (3) fails because the time origin is outside the range defined by the records in an archive log, i.e. returns .BR PM_ERR_EOL . The high-order bits of the .I mode parameter is also used to optionally set the units of time for the .I delta field. To specify the units of time use .B PM_XTB_SET macro with one of the values .BR PM_TIME_NSEC , .BR PM_TIME_MSEC , .BR PM_TIME_SEC , etc. as follows: .P .in +0.5i PM_MODE_INTERP | PM_XTB_SET(PM_TIME_XXXX) .P If no units are specified the default is to interpret .I delta as milliseconds. .PP Using these .I mode options, an application can implement replay, playback, fast forward, reverse, etc. for performance metric values held in the archive log by alternating calls to .B pmSetMode and .BR pmFetch (3). .PP As a special case, if .I when is .B NULL then the .I mode and .I delta arguments are used as described above, but the current time in the archive is not altered. .PP For example, the following code fragment may be used to dump just those values recorded in an archive in correct temporal sequence, for a selected set of performance metrics; this uses the default collection time mechanisms. .PP .ft CW .nf .in +0.5i pmNewContext(PM_CONTEXT_ARCHIVE, "myarchive"); while (pmFetch(npmid, pmidlist, &result) != PM_ERR_EOL) { /* * process real metric values as of result->timestamp */ \&. . . pmFreeResult(result); } .in .fi .ft 1 .PP Alternatively, to replay interpolated metrics from the log in reverse chronological order, at 10 second intervals (of recorded time), the following code fragment could be used. .PP .ft CW .nf .in +0.5i struct timeval mytime; mytime.tv_sec = 0x7fffffff; pmSetMode(PM_MODE_BACK, &mytime, 0); pmFetchArchive(&result); mytime = result->timestamp; pmFreeResult(result); pmSetMode(PM_MODE_INTERP | PM_XTB_SET(PM_TIME_SEC), &mytime, \-10); while (pmFetch(numpmid, pmidlist, &result) != PM_ERR_EOL) { /* * process interpolated metric values as of * result->timestamp */ \&. . . pmFreeResult(result); } .in .fi .ft 1 .SH "SEE ALSO" .BR PMAPI (3), .BR pmFetch (3), .BR pmFetchArchive (3), .BR pmGetInDom (3), .BR pmLookupDesc (3), .BR pmLookupInDom (3) and .BR pmNameInDom (3). .SH DIAGNOSTICS .IP \f3PM_ERR_MODE\f1 The .I mode parameter is invalid pcp-3.8.12ubuntu1/man/man3/pmparsehostspec.30000664000000000000000000001001312272262501015512 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" Copyright (c) 2007 Aconex, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .TH PMPARSEHOSTSPEC 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmParseHostSpec\f1, \f3__pmUnparseHostSpec\f1, \f3__pmFreeHostSpec\f1 \- uniform host specification parser .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int __pmParseHostSpec(const char *\fIstring\fP, pmHostSpec **\fIhostsp\fP, int\ *\fIcount\fP, char\ **\fIerrmsg\fP); .br .ti -8n int __pmUnparseHostSpec(pmHostSpec *\fIhosts\fP, int \fIcount\fP, char *\fIstring\fP, size_t \fIsize\fP); .br .ti -8n void __pmFreeHostSpec(pmHostSpec *\fIhosts\fP, int \fIcount\fP); .sp .in .hy .ad cc ... \-lpcp .ft 1 .SH DESCRIPTION .B __pmParseHostSpec accepts a .B string specifying the location of a PCP performance metric collector daemon. The syntax of the various formats of this .B string is described in .BR PCPIntro (1) where several examples are also presented. .PP The syntax allows the initial .BR pmcd (1) hostname to be optionally followed by a list of port numbers, which will be tried in order when connecting to .B pmcd on that host. The portlist is separated from the hostname using a colon, and each port in the list is comma-separated. .PP In addition, one or more optional .BR pmproxy (1) hosts can be specified (currently, only one proxy host is supported by the PCP protocols). These are separated from each other and from the .B pmcd component using the @ character. These may also be followed by an optional port list, using the same comma-separated syntax as before. .PP .B __pmParseHostSpec takes a null-terminated host specification .B string and returns an array of .B pmHostSpec structures, where the array has .B count entries. .PP These .B pmHostSpec structures that are returned via .B hostsp represent each individual host in the specification .B string and has the following declaration: .PP .nf .ft CW typedef struct { char *name; /* hostname (always valid) */ int *ports; /* array of host port numbers */ int nports; /* number of ports in host port array */ } pmHostSpec; .fi .PP .B __pmUnparseHostSpec performs the inverse operation, creating a .B string representation from a number of .B hosts structures. Where the .B count of structures indicated by .B hosts is greater than one, the proxy syntax is used to indicate a chain of proxied hosts. The size of the supplied .B string buffer must be provided by the caller using the .B size parameter. .SH "RETURN VALUE" If the given .B string is successfully parsed .B __pmParseHostSpec returns zero. In this case the dynamic storage allocated by .B __pmParseHostSpec can be released by calling .B __pmFreeHostSpec using the address returned from .B __pmParseHostSpec via .BR hosts . .P .B __pmParseHostSpec returns .B PM_ERR_GENERIC and a dynamically allocated error message string in .BR errmsg , if the given .B string does not parse, and the user-supplied .B errmsg pointer is non-null. Be sure to .BR free (3C) the error message string in this situation. .PP In the case of an error, .B hosts is undefined. In the case of success, .B errmsg is undefined. .PP On success .B __pmUnparseHostSpec returns a positive value indicating the number of characters written into the supplied buffer. However, if the supplied buffer was too small, a negative status code of .B \-E2BIG is returned. .SH SEE ALSO .BR pmcd (1), .BR pmproxy (1), .BR pmchart (1), .BR __pmParseHostAttrsSpec (3), .BR PMAPI (3) and .BR pmNewContext (3). pcp-3.8.12ubuntu1/man/man3/pmctime.30000664000000000000000000000370612272262501013743 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMCTIME 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmCtime\f1 \- format the date and time for a reporting timezone .SH "C SYNOPSIS" .ft 3 #include .br #include .sp char *pmCtime(const time_t *\fIclock\fP, char *\fIbuf\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .B pmCtime is very similar to .BR ctime (3), except the timezone used is the current ``reporting timezone'' (rather than the default .B TZ environment variable scheme), and the result is returned into a caller-declared buffer (rather than a private buffer). .PP Like .BR ctime (3) the time to be converted is passed via .IR clock , and the result in .I buf is fixed width fields in the format: .PP .in +1i Fri Sep 13 00:00:00 1986\en\e0 .PP The result buffer .I buf must be at least 26 bytes long, and no attempt is made to check this. .B pmCtime returns .I buf as the value of the function. .PP The default current reporting timezone is as defined by the .B TZ environment variable, so .B pmCtime and .BR ctime (3) will initially produce similar encoding of the date and time. .PP Use .BR pmNewZone (3), .BR pmNewContextZone (3) or .BR pmUseZone (3) to establish a new current reporting timezone that will effect .B pmCtime but not .BR ctime (3). .SH SEE ALSO .BR ctime (3), .BR PMAPI (3), .BR pmLocaltime (3), .BR pmNewContextZone (3), .BR pmNewZone (3) and .BR pmUseZone (3). pcp-3.8.12ubuntu1/man/man3/pmiusecontext.30000664000000000000000000000311712272262501015210 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIUSECONTEXT 3 "" "Performance Co-Pilot" .SH NAME \f3pmiUseContext\f1 \- change LOGIMPORT context .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmiUseContext(int \fIcontext\fP); .sp cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp pmiUseContext($\fIcontext\fP); .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiUseContext may be used by applications wishing to generate more than one PCP archive concurrently. .PP The .I context argument is a value returned from a previous call to .BR pmStart (3) and on successful return from .BR pmiUseContext , the current context will have been changed to the one identified by .IR context . .SH DIAGNOSTICS .B pmiUseContext returns zero on success else a negative value that can be turned into an error message by calling .BR pmiErrStr (3). .SH SEE ALSO .BR LOGIMPORT (3), .BR pmiErrStr (3) and .BR pmiStart (3). pcp-3.8.12ubuntu1/man/man3/pmdacache.30000664000000000000000000004612312272262501014212 0ustar '\"! tbl | mmdoc '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDACACHE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaCacheStore\f1, \f3pmdaCacheStoreKey\f1, \f3pmdaCacheLookup\f1, \f3pmdaCacheLookupName\f1, \f3pmdaCacheLookupKey\f1, \f3pmdaCacheOp\f1, \f3pmdaCachePurge\f1 \- manage a cache of instance domain information for a PMDA .SH "C SYNOPSIS" .ft 3 #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int pmdaCacheStore(pmInDom \fIindom\fP, int \fIflags\fP, const\ char\ *\fIname\fP, void\ *\fIprivate\fP); .br .ti -8n int pmdaCacheStoreKey(pmInDom \fIindom\fP, int \fIflags\fP, const\ char\ *\fIname\fP, int\ \fIkeylen\fP, const void\ *\fIkey\fP, void\ *\fIprivate\fP); .br .ti -8n int pmdaCacheLookup(pmInDom \fIindom\fP, int \fIinst\fP, char **\fIname\fP, void\ **\fIprivate\fP); .br .ti -8n int pmdaCacheLookupName(pmInDom \fIindom\fP, const char *\fIname\fP, int\ *\fIinst\fP, void\ **\fIprivate\fP); .br .ti -8n int pmdaCacheLookupKey(pmInDom \fIindom\fP, const char *\fIname\fP, int\ \fIkeylen\fP, const void\ *\fIkey\fP, char **\fIoname\fP, int\ *\fIinst\fP, void\ **\fIprivate\fP); .br .ti -8n int pmdaCacheOp(pmInDom \fIindom\fP, int \fIop\fP); .br .ti -8n int pmdaCachePurge(pmInDom \fIindom\fP, time_t \fIrecent\fP); .sp .in .hy .ad cc ... \-lpcp_pmda \-lpcp .ft 1 .de EX .in +2n .ie t .ft C .el .ft B .ie t .sp .5v .el .sp .ta \\w' 'u*8 .nf .. .de EE .fi .ie t .sp .5v .el .sp .ft R .in .. .SH DESCRIPTION The .B pmdaCache family of routines provide services to support the maintenance of complex instance domains for Performance Co-Pilot PMDAs. There is potentially one cache of information for each instance domain, and for each instance the cache maintains: .PD 0 .IP \- 2m external instance name (supplied by the PMDA) .IP \- 2m internal instance identifier (assigned by .B pmdaCacheStore or calculated from a ``hint'' by .BR pmdaCacheStoreKey ) .IP \- 2m state, where .B active instances are visible and part of the current instance domain, and .B inactive instances are hidden, but not forgotten; .B pmdaCacheStore or .B pmdaCacheStoreKey may be used to change the state of an instance .IP \- 2m an optional opaque pointer to data that is associated with the instance, but maintained by the PMDA .IP \- 2m an optional opaque key that is used as a ``hint'' to .B pmdaCacheStoreKey when guessing the initial internal instance identifier .IP \- 2m the last time the cache was saved and the instance had been marked as .B active at some point since the previous cache load or save operation .PD .PP The semantics of a PCP instance domain require a number of rules to be followed, namely: .PD 0 .IP 1. 3n Each internal instance identifier must be unique and in the range 0 to 2^31\0\-\01. This rule is enforced by the .B pmdaCache family of routines. .IP 2. 3n The external instance name must be unique. When the instance name contains a space, it is further constrained such that the name to the left of the first space (the short name) must also be unique. Refer to the INSTANCE NAME MATCHING section below. The PMDA must honor this rule, the .B pmdaCache family of routines will detect attempts to violate this rule. .IP 3. 3n Where an external instance name corresponds to some object or entity, there is an expectation that the association between the name and the object is fixed, e.g. ``/dev/hda'' is always the name of the same disk on a particular system. This rule is perhaps the responsibility of the PMDA, but is often a characteristic of the environment in which the PMDA runs. .IP 4. 3n It is preferable, although not mandatory, for the association between and external instance name and an internal instance identifier to be persistent. This rule is supported by the .B pmdaCache family of routines. .IP 5. 3n When opaque keys are used, the values of the keys must be unique across all instances within an instance domain. This rule is enforced by the .B pmdaCache family of routines. .PD .PP The visible interface to the cache is oriented towards the PMDA developer who is most concerned about the names of instances, while the details of how the rest of the PCP infrastructure expects the internal instance identifiers to be managed is not relevant. .PP Instances are updated in the cache for instance domain .I indom by calling .B pmdaCacheStore or .B pmdaCacheStoreKey with the external name of the instance passed via .I name. The opaque pointer .I private may be used to associate additional data with the entry in the cache; if no such data is required, .I private should be NULL. Any manipulation of the additional data (including allocation or freeing) is the responsibility of the PMDA caller, as the cache simply maintains the pointer to the data (passed via .IR private ). .PP For cases where the PMDA developer wishes to influence the allocation of internal instance identifiers, e.g. for instance domains with more than one natural dimension, or where there is a desire to allocate the same instance identifier each time the PMDA is started, even on different hosts, .B pmdaCacheStoreKey may be used. In this case, an initial ``hint'' for the instance identifier is provided as an opqaue key via the first .I keylen bytes in .I key (which could be any sort of data, including binary values) else if .I keylen is less than 1 or .I key is .B NULL then .I name is used as the ``hint''. The ``hint'' is hashed to produce an initial instance identifier in the range 0 to 2^31\0-\01. If this instance identifier is already allocated, then the value is rehashed. This procedure is repeated until an unallocated instance identifier is found, or .B pmdaCacheStoreKey gives up and returns .BR PM_ERR_GENERIC . For each instance domain, the ``hint'' must be unique across all instances, else .B pmdaCacheStoreKey returns .BR PM_ERR_INST . .PP The .I flags argument controls how the instance should be processed in the cache as follows: .TP PMDA_CACHE_ADD Insert the entry into the cache if it is not already there and mark it .BR active . If the entry is already in the cache mark it .BR active . .TP PMDA_CACHE_HIDE Mark the entry in the cache as .BR inactive , but remember the details of the association between the external instance name and the internal instance identifier. Entries that are .B inactive will be hidden from cache traversal via PMDA_CACHE_WALK_NEXT operations, but remain visible to .BR pmdaCacheLookup , .B pmdaCacheLookupName and .B pmdaCacheLookupKey requests. .TP PMDA_CACHE_CULL Remove the entry from the cache. .PP On success .B pmdaCacheStore or .B pmdaCacheStoreKey will return the internal instance identifier of the associated cache entry. Valid instance identifiers are guaranteed to be unique and non-negative. Failure will be indicated by a negative value (suitable for decoding with .BR pmErrStr (3)) and most likely PM_ERR_INST to indicate the requested instance is not in the cache, or \-EINVAL to indicate a potential violation of the short name uniqueness property (see the INSTANCE NAME MATCHING section below). .PP .B pmdaCacheLookup is used to search the entries in the cache based on the internal instance identifier .IR inst . .PP On success the return value will be PMDA_CACHE_ACTIVE or PMDA_CACHE_INACTIVE (depending on the .B active or .B inactive state of the cache entry), .I name (if not NULL) and .I private (if not NULL) will be set to the external instance name and the associate additional data area as provided when the instance was last activated via .B pmdaCacheStore or .BR pmdaCacheStoreKey . .PP .B pmdaCacheLookup failure is indicated by a negative return value suitable for decoding with .BR pmErrStr (3). .PP The .B pmdaCacheLookup interface is required by the PMDA's fetch callback that is registered via .BR pmdaSetFetchCallback (3). Here the internal instance identifier is passed to the fetch callback to identifier for which instance a value is required. Typical usage is shown in the code fragment below. .EX static int foo_callback(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { mydata *mdp; char *name; int sts; sts = pmdaCacheLookup(mdesc->m_desc.indom, inst, &name, (void **)&mdp); /* * expect sts == PMDA_CACHE_ACTIVE except for cataclysmic events * use mdp as required, name may be useful for diagnostics */ ... .EE .PP .B pmdaCacheLookupName is used to search the entries in the cache based on the external instance name .IR name . .PP On success the return value will be PMDA_CACHE_ACTIVE or PMDA_CACHE_INACTIVE (depending on the .B active or .B inactive state of the cache entry), .I inst (if not NULL) and .I private (if not NULL) will be set to the internal instance identifier and the associate additional data area as provided when the instance was last activated via .B pmdaCacheStore or .BR pmdaCacheStoreKey . .PP .B pmdaCacheLookupName failure is indicated by a negative return value suitable for decoding with .BR pmErrStr (3). .PP The .B pmdaCacheLookupName interface is useful for PMDAs wishing to update an instance domain based on the external instance names. .PP .B pmdaCacheLookupKey is used to search the entries in the cache based on an opaque key (or ``hint'') previously used in a call to .BR pmdaCacheStoreKey . The ``hint'' is provided via the first .I keylen bytes in .IR key . For symmetry with .BR pmdaCacheStoreKey , if .I keylen is less than 1 or .I key is .B NULL then .I name is used as the ``hint'' (although the results will be the same as calling .B pmdaCacheLookupName in this case). .PP On success the return value will be PMDA_CACHE_ACTIVE or PMDA_CACHE_INACTIVE (depending on the .B active or .B inactive state of the cache entry), .I oname (if not NULL), .I inst (if not NULL) and .I private (if not NULL) will be set to the external instance name, the internal instance identifier and the associate additional data area as provided when the instance was last activated via .B pmdaCacheStore or .BR pmdaCacheStoreKey . .PP .B pmdaCacheLookupKey failure is indicated by a negative return value suitable for decoding with .BR pmErrStr (3). .PP To avoid a persistent cache growing without bound, .B pmdaCachePurge can be used to cull all entries that have .I not been .B active in the last .I recent seconds. For performance reasons, the time accounting is imprecise and the entries are timestamped at the time of the next cache save operation .I after the entry has been added or marked .B active (refer to PMDA_CACHE_SAVE and PMDA_CACHE_SYNC below). On success .B pmdaCachePurge returns the number of culled entries, else in the case of an error the return value is negative (and suitable for decoding with .BR pmErrStr (3)). .PP .B pmdaCacheOp may be used to perform additional operations on the cache as follows: .TP PMDA_CACHE_LOAD The cache can optionally be maintained as a persistent external file, so that the mapping of instance names to instance identifiers is persistent across executions of a PMDA. This operation loads the cache from the external file, and then all new cache entries are marked .BR inactive , and the additional data pointer is set to NULL. Entries loaded from the external file are checked against the current cache contents and if the instance name and instance identifiers match then the state in the cache (\c .B active or .BR inactive ) is not changed. Should a mismatch be found (same instance name and different instance identifier, or same instance identifier and different instance name, or some but not all of the instance identifier, the instance name and the ``hint'' match) then the entry from the external file is ignored and a warning is issued on .IR stderr . Typically a PMDA would only perform this operation once per execution. .TP PMDA_CACHE_SAVE If any instance has been added to, or deleted from, the instance domain since the last PMDA_CACHE_LOAD, PMDA_CACHE_SAVE or PMDA_CACHE_SYNC operation, the .I entire cache is written to the external file as a bulk operation. This operation is provided for PMDAs that are .I not interested in using .B pmdaCachePurge and simply want the external file to reflect the set of known instances without accurate details of when they were last marked .BR active . .RS .PP Returns the number of instances saved to the external file, else 0 if the external file was already up to date. .RE .TP PMDA_CACHE_STRINGS Annotates this cache as being a special-purpose cache used for string de-duplication in PMDAs exporting large numbers of string valued metrics. This can be used to reduce the memory footprint of the PMDA (duplicate strings hash to the same bucket, and are stored in memory once only). Key comparisons are not terminated at the first space but rather the entire string is used for matching. These are specialised caches not useful for general purpose instance domain handling. .TP PMDA_CACHE_SYNC Within an instance domain, if any instance has been added to, or deleted from, or marked .B active since the last PMDA_CACHE_LOAD, PMDA_CACHE_SAVE or PMDA_CACHE_SYNC operation, the .I entire cache is written to the external file as a bulk operation. This operation is similar to PMDA_CACHE_SAVE, but will save the instance domain more frequently so the timestamps more accurately match the semantics expected by .BR pmdaCachePurge . .RS .PP Returns the number of instances saved to the external file, else 0 if the external file was already synchronized. .RE .TP PMDA_CACHE_CHECK Returns 1 if a cache exists for the specified instance domain, else 0. .TP PMDA_CACHE_REUSE When a new instance is added to the cache, the default strategy is to assign instance identifiers in a monotonic increasing manner. Once the maximum possible instance identifier value has been assigned, the strategy changes to one where starting from 0, the next available unused instance identifier will be used. Calling .B pmdaCacheOp with PMDA_CACHE_REUSE forces an irreversible change to a second (reuse) strategy where the next unallocated instance identifier will be used. This may be useful in cases where there is a desire to restrict the allocated instance identifiers to smaller values. The prevailing strategy will be saved and restored across PMDA_CACHE_SAVE and PMDA_CACHE_LOAD operations. If .B pmdaCacheStoreKey is ever used, the associated instance domain will be changed to PMDA_CACHE_REUSE mode. .TP PMDA_CACHE_REORG Reorganize the cache to allow faster retrieval of .B active entries, and the cost of slower retrieval for .B inactive entries, and reclaim any culled entries. The cache may be internally re-organized as entries are added, so this operation is not required for most PMDAs. .TP PMDA_CACHE_WALK_REWIND Prepares for a traversal of the cache in ascending instance identifier sequence. .TP PMDA_CACHE_WALK_NEXT Fetch the next .B active instance identifier from the cache. Requires a prior call using PMDA_CACHE_WALK_REWIND and will return \-1 when all instances have been processed. .RS .PP Only one cache walk can be active at any given time, nesting calls to PMDA_CACHE_WALK and PMDA_CACHE_REWIND will interfere with each other. .RE .TP PMDA_CACHE_ACTIVE Changes .B every .B inactive entry in the cache to be marked .BR active . .TP PMDA_CACHE_INACTIVE Changes .B every .B active entry in the cache to be marked .BR inactive . .TP PMDA_CACHE_CULL Remove .B every entry from the cache. .TP PMDA_CACHE_SIZE Return the number of entries in the cache (includes .BR active , .B inactive and any culled entries that have not yet been reclaimed). .TP PMDA_CACHE_SIZE_ACTIVE Return the number of .B active entries in the cache. .TP PMDA_CACHE_SIZE_INACTIVE Return the number of .B inactive entries in the cache. .TP PMDA_CACHE_DUMP Dump the current state of the cache on .IR stderr . .TP PMDA_CACHE_DUMP_ALL Like PMDA_CACHE_DUMP, but also dump the internal hashing structures used to support lookup by instance name, lookup by instance identifier and the collision statistics for ``hint'' hashing from .BR pmdaCacheStoreKey . .PP .B pmdaCacheOp returns a non-negative value on success, and failure is indicated by a negative return value (suitable for decoding with .BR pmErrStr (3)). .SH OTHER CONSIDERATIONS .PP When the .B pmdaCache routines are used for particular instance domain, .B pmdaInstance (3) and the instance domain enumeration behind .BR pmdaFetch (3) will attempt to extract instance domain information from the cache, thereby avoiding reference to the .B pmdaIndom data structures that have historically been used to define instance domains and service instance requests. A PMDA can adopt a hybrid approach and choose to implement some instance domains via the traditional .B pmdaIndom method, and others via the .B pmdaCache approach, however attempts to manage the .I same instance domain by both methods will result in the .B pmdaCache method silently prevailing. .PP If .B all instances in a PMDA are to be serviced from a .B pmdaCache then a .B pmdaIndom is not required, and the .B pmdaInit (3) call becomes .EX pmdaInit(dp, NULL, 0, metrictab, nmetrics); .EE However, the PMDA will need to explicitly initialize the .B indom field of the .B pmDesc in the .I metrictab entries, as this cannot be done by .BR pmdaInit (3) if .I indomtab is missing entries for the instance domains maintained in the cache. .PP Independent of how the instance domain is being maintained, to refresh an instance domain prior to a fetch or an instance domain operation, the standard methods of a ``wrapper'' to the .B pmdaInstance (3) and .B pmdaFetch (3) methods should be used. .PP Refer to the .B simple PMDA source code for an example use of the .B pmdaCache routines. .PP When using .BR pmdaCacheStoreKey , if there is a desire to ensure the given ``hint'' generates the same initial instance identifier across all platforms, then the caller should ensure the endian and word-size issues are considered, e.g. if the natural data structure used for the .I key is an array of 32-bit integers, then .BR htonl (3) should be used on each element of the array before calling .B pmdaCacheStoreKey or .BR pmdaCacheLookupKey . .SH INSTANCE NAME MATCHING .PP The following table summarizes the ``short name'' matching semantics for an instance domain (caches other than PMDA_CACHE_STRINGS style). .TS box, center; l | l | l l | l | ^ l | l | l. name in \fBpmdaCacheLookup\fR result cache name _ foodle foo no match (PM_ERR_INST) foo foodle no match (PM_ERR_INST) foo foo match foo bar foo match on short name (instance identifier) foo bar foo bar match on full name (instance identifier) foo foo bar bad match (\-EDOM) foo bar foo blah bad match (\-EDOM) .TE .SH FILES Cache persistence uses files with names constructed from the .I indom within the .B $PCP_VAR_DIR/config/pmda directory. .SH SEE ALSO .BR BYTEORDER (3), .BR PMAPI (3), .BR PMDA (3), .BR pmdaInit (3), .BR pmdaInstance (3), .BR pmdaFetch (3), .BR pmdaSetFetchCallback (3), .BR pmErrStr (3) and .BR pmGetInDom (3). pcp-3.8.12ubuntu1/man/man3/mmv_inc_value.30000664000000000000000000000252212272262501015124 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2009 Max Matveev .\" Copyright (c) 2009 Aconex. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH MMV_INC_VALUE 3 "" "Performance Co-Pilot" .SH NAME \f3mmv_inc_value\f1 - update a value in a Memory Mapped Value file .SH "C SYNOPSIS" .ft 3 #include .br #include .sp void mmv_inc_value(void *\fIaddr\fP, pmAtomValue *\fIval\fP, double \fIinc\fP); .sp cc ... \-lpcp_mmv \-lpcp .ft 1 .SH DESCRIPTION .P \f3mmv_inc_value\f1 provides a convenient way of updating a value returned by the \f3mmv_lookup_value_desc\f1. \f2addr\f1 is the address returned from \f3mmv_stats_init\f1(). .P The value of the \f2inc\f1 is internally cast to match the type of the metric and then added to the previous value of the metric. .SH SEE ALSO .BR mmv_stats_init (3), .BR mmv_lookup_value_desc (3) and .BR mmv (5). pcp-3.8.12ubuntu1/man/man3/pmdadso.30000664000000000000000000000463012272262501013731 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDADSO 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaDSO\f1 \- initialize the PMDA to run as a DSO .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int pmdaDSO(pmdaInterface *\fIdispatch\fP, int \fIinterface\fP, char\ *\fIname\fP, char\ *\fIhelptext\fP); .sp .in .hy .ad cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION .B pmdaDSO initializes the .B pmdaInterface structure to use the .I interface extensions, assuming the .BR PMDA (3) is to be run as a DSO. The .B pmdaInterface structure is initialized with: .TP 15 .I name The name of the agent. .TP .I helptext The default path to the help text (see .BR pmdaText (3). If no help text is installed, or you are not using .BR pmdaText (3), then this should be set to NULL. .PP The callbacks are initialized to .BR pmdaProfile (3), .BR pmdaFetch (3), .BR pmdaDesc (3), .BR pmdaText (3), .BR pmdaInstance (3) and .BR pmdaStore (3). .PP The .I interface structure also contains the .I domain of the .BR PMDA (3), which is defined in the .BR pmcd (1) configuration file. The .I domain is used to initialize the metric and instance descriptors (see .BR pmdaInit (3)). .SH DIAGNOSTICS .TP 15 .B Incompatible version of pmcd detected When .BR pmcd (1) creates the .B pmdaInterface structure, the .I dispatch.comm.version field is set to the highest protocol that .BR pmcd (1) understands. This message indicates that the .BR pmcd (1) process does not understand the protocol used by .BR pmdaDSO . .TP .B Unable to allocate memory for pmdaExt structure In addition, .I dispatch->status is set to a value less than zero. .SH CAVEAT The PMDA must be using .B PMDA_INTERFACE_2 or later. .SH SEE ALSO .BR pmcd (1), .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaInit (3) and .BR pmdaText (3). pcp-3.8.12ubuntu1/man/man3/pmgetarchiveend.30000664000000000000000000000577112272262501015456 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMGETARCHIVEEND 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmGetArchiveEnd\f1 \- locate logical end of file for an archive log .SH "C SYNOPSIS" .ft 3 #include .sp int pmGetArchiveEnd(struct timeval *\fItvp\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION Assuming the current PMAPI context is associated with an archive log, .B pmGetArchiveEnd will attempt to find the logical end of file (after the last complete record in the archive), and return the last recorded timestamp via .IR tvp . This timestamp may be passed to .BR pmSetMode (3) to reliably position the context at the last valid log record, e.g. in preparation for subsequent reading in reverse chronological order. .PP For archive logs that are not concurrently being written, the physical end of file and the logical end of file are co-incident. However if an archive log is being written by .BR pmlogger (1) at the same time an application is trying to read the archive, the logical end of file may be before the physical end of file due to write buffering that is not aligned with the logical record boundaries. .PP .B pmGetArchiveEnd returns an error less than zero if the context is neither valid, nor associated with an archive, or the archive is seriously corrupted. Otherwise, the return value is 0 if there has been no change of state since the last call, or 1 if the logical end of file has advanced since the last call. .PP In the absence of an error, the result returned via .I tvp is well-defined. .PP .BR pmGetArchiveEnd preserves the positioning state of the log file prior to this function call. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR PMAPI (3), .BR pmFetch (3), .BR pmFetchArchive (3), .BR pmGetArchiveLabel (3), .BR pmGetConfig (3), .BR pmSetMode (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOCONTEXT\f1 the current PMAPI context is either invalid, or not associated with an archive log .IP \f3PM_ERR_LOGREC\f1 the archive is sufficiently damaged, that not a single valid record can be found pcp-3.8.12ubuntu1/man/man3/pmda.30000664000000000000000000004110212272262501013216 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .\" add in the -me strings for super and subscripts .ie n \{\ . ds [ \u\x'-0.25v' . ds ] \d . ds { \d\x'0.25v' . ds } \u .\} .el \{\ . ds [ \v'-0.4m'\x'-0.2m'\s-3 . ds ] \s0\v'0.4m' . ds { \v'0.4m'\x'0.2m'\s-3 . ds } \s0\v'-0.4m' .\} .TH PMDA 3 "PCP" "Performance Co-Pilot" .SH NAME \f3PMDA\f1 \- introduction to the Performance Metrics Domain Agent support library .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. To assist in the development of Performance Metric Domain Agents .RB ( PMDA s) for the Performance Co-Pilot (PCP), a procedural interface is provided that extends the Performance Metrics Application Programming Interface ( .BR PMAPI (3)) library. These procedures are designed to enable a programmer to quickly build a .B PMDA which can then be tested and refined. However, this also implies that a .B PMDA has a particular structure which may not be suitable for all applications. .PP Once you are familiar with the PCP and .B PMDA frameworks, you can quickly implement a new .B PMDA with only a few data structures and functions. This is covered in far greater detail in the .IR "Performance Co-Pilot Programmer's Guide" . .PP A .B PMDA is responsible for a set of performance metrics, in the sense that it must respond to requests from .BR pmcd(1) for information about performance metrics, instance domains, and instantiated values. The .BR pmcd (1) process generates requests on behalf of performance tools that make requests using .BR PMAPI (3) routines. .PP This man page contains sections of the .B simple PMDA which is located at .IR $PCP_PMDAS_DIR/simple . .SH COMMUNICATING WITH PMCD Two approaches may be used for connecting a .B PMDA to a .BR pmcd (1) process. A Dynamic Shared Object (DSO) can be attached by .BR pmcd (1) using .BR dlopen (3) when the .BR pmcd (1) process is started. A procedural interface referenced through a shared data structure is used to handle requests from .BR pmcd (1) to the .BR PMDA . .PP The preferred approach is for a separate process (daemon) to communicate with .BR pmcd (1) using the Performance Data Units (PDU) Inter-Process Communication (IPC) protocol. .PP All .BR PMDA s are launched and controlled by the .BR pmcd (1) process on the local host. The requests from the clients are received by .BR pmcd (1) and forwarded to the appropriate .BR PMDA s. Responses, when required, are returned through .BR pmcd (1) to the clients. The requests (PDUs) that may be sent to a .B PMDA from .BR pmcd (1) are .BR PDU_FETCH , .BR PDU_PROFILE , .BR PDU_INSTANCE_REQ , .BR PDU_DESC_REQ , .BR PDU_TEXT_REQ and .BR PDU_RESULT . .SH DEFAULT CALLBACKS FOR HANDLING PDUs To allow a consistent framework, .BR pmdaMain (3) can be used by a daemon .B PMDA to handle the communication protocol using the same callbacks as a DSO .BR PMDA . The structure .B pmdaInterface is used to convey the common procedural interface and state information that is used by .BR pmcd (1) and a .BR PMDA . This state information includes tables describing the supported metrics and instance domains. .PP As most of the procedural interface is identical for all .BR PMDA s, they are provided as part of this support library .RB ( pmdaProfile (3), .BR pmdaFetch (3), .BR pmdaInstance (3), .BR pmdaDesc (3), .BR pmdaText (3) and .BR pmdaStore (3)). However, these routines require access to the .B pmdaInterface state information so it must be correctly initialized using .BR pmdaConnect (3), .BR pmdaDaemon (3), .BR pmdaOpenLog (3), .BR pmdaDSO (3), .BR pmdaGetOpt (3) and .BR pmdaInit (3). .SH INSTANCES AND INSTANCE DOMAINS Three structures are declared in .I /usr/include/pcp/pmda.h which provide a framework for declaring the metrics and instances supported by the .BR PMDA . .PP Every instance requires a unique integer identifier and a unique name, as defined by the structure .BR pmdaInstid : .PP .nf .ft CW .in +0.5i /* * Instance description: index and name */ typedef struct { int i_inst; /* internal instance identifier */ char *i_name; /* external instance identifier */ } pmdaInstid; .in .fi .PP An instance domain requires its own unique identification .RB ( pmInDom ), the number of instances the domain represents, and a pointer to an array of instance descriptions. This is defined in the structure .BR pmdaIndom : .PP .nf .ft CW .in +0.5i /* * Instance domain description: unique instance id, * number of instances in this domain, and the list of * instances (not null terminated). */ typedef struct { pmInDom it_indom; /* indom, filled in */ int it_numinst; /* number of instances */ pmdaInstid *it_set; /* instance identifiers */ } pmdaIndom; .in .fi .ft 1 .PP The .B simple PMDA has one instance domain for .IR simple . color with three instances .RI ( red , .I green and .IR blue ), and a second instance domain for .IR simple . now with instances which can be specified at run-time. These instance domains are defined as: .PP .nf .ft CW .in +0.5i static pmdaInstid _color[] = { { 0, "red" }, { 1, "green" }, { 2, "blue" } }; static pmdaInstid *_timenow = NULL; static pmdaIndom indomtab[] = { #define COLOR_INDOM 0 { COLOR_INDOM, 3, _color }, #define NOW_INDOM 1 { NOW_INDOM, 0, NULL }, }; .in .fi .PP The preprocessor macros .B COLOR_INDOM and .B NOW_INDOM are used in the metric description table to identify the instance domains of individual metrics. These correspond to the .I serial value in the instance domain .B pmInDom structure (the .I domain field is set by .BR pmdaInit (3) at run-time). The serial value must be unique for each instance domain within the .BR PMDA . .PP The indom table shown above which is usually passed to .BR pmdaInit (3) does not need to be created if one wants to write one's own Fetch and Instance functions. See .BR pmdaInit (3) for more details. .SH NAMESPACE Every .B PMDA has its own unique .B namespace using the format defined in .BR pmns (5). In summary, the namespace matches the names of the metrics to the unique identifier. The .B simple PMDA defines five metrics: .IR simple . numfetch , .IR simple . color , .IR simple . time . user, .IR simple . time . sys and .IR simple . now . The namespace for these metrics is defined in .I $PCP_PMDAS_DIR/simple/pmns and is installed as: .PP .nf .ft CW .in +0.5in simple { numfetch 253:0:0 color 253:0:1 time now 253:2:4 } simple.time { user 253:1:2 sys 253:1:3 } .in .fi .PP The domain number of .I 253 is obtained from .IR $PCP_VAR_DIR/pmns/stdpmid . New .BR PMDA s should specify a unique domain number in this file, and obtain the number during installation. This allows the domain number to change by modifying only the file .IR $PCP_VAR_DIR/pmns/stdpmid . .PP The .I simple.time and .I simple.now metrics are defined in separate clusters to the other metrics which allows a .B PMDA to support more than 1024 metrics, as well as grouping similar metrics together. Therefore, the item numbers for a new cluster may be identical to the item numbers in other clusters. The .B simple PMDA continues to increment the item numbers to permit direct mapping (see .BR pmdaInit (3)). .PP The namespace file should be installed and removed with the agent using .BR pmnsadd (1) and .BR pmnsdel (1). See the later sections on INSTALLATION and REMOVAL. .PP A simple ASCII namespace can be constructed by creating a file similar to .IR $PCP_PMDAS_DIR/simple/root : .PP .nf .ft CW .in +0.5i /* * fake "root" for validating the local PMNS subtree */ #include "$PCP_VAR_DIR/pmns/stdpmid" root { simple } #include "pmns" .in .fi .PP and can be referred to with the .B \-n option in most PCP tools. .SH METRIC DESCRIPTIONS Each metric requires a description .RB ( pmDesc ), which contains its PMID, data type specification, instance domain, semantics and units (see .BR pmLookupDesc (3)). A handle is also provided for application specific information in the .B pmdaMetric structure: .PP .nf .ft CW .in +0.5i /* * Metric description: handle for extending description, * and the description. */ typedef struct { void* m_user; /* for users external use */ pmDesc m_desc; /* metric description */ } pmdaMetric; .in .fi .PP The .B simple PMDA defines the metrics as: .PP .nf .ft CW .in +0.5i static pmdaMetric metrictab[] = { /* numfetch */ { (void *)0, { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { 0,0,0,0,0,0} }, }, /* color */ { (void *)0, { PMDA_PMID(0,1), PM_TYPE_32, COLOR_INDOM, PM_SEM_INSTANT, { 0,0,0,0,0,0} }, }, /* time.user */ { (void*)0, { PMDA_PMID(1,2), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER, { 0, 1, 0, 0, PM_TIME_SEC, 0 } }, }, /* time.sys */ { (void*)0, { PMDA_PMID(1,3), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER, { 0, 1, 0, 0, PM_TIME_SEC, 0 } }, }, /* now */ { NULL, { PMDA_PMID(2,4), PM_TYPE_U32, NOW_INDOM, PM_SEM_INSTANT, { 0,0,0,0,0,0 } }, }, }; .in .fi .PP The macro .B PMDA_PMID (defined in .IR /usr/include/pcp/pmda.h ) is used to specify each metric's .I cluster and .I unit number in the .B __pmID_int structure defined in .IR /usr/include/pcp/impl.h . As with instance domains, the .I domain field is set by .BR pmdaInit (3) at run-time, however, the default domain is assumed to be defined by the .B PMDA in the macro .BR MYDOMAIN . .PP The metric table shown above which is usually passed to .BR pmdaInit (3) does not need to be created if one wants to write one's own Fetch and Descriptor functions. See .BR pmdaInit (3) for more details. .SH DSO PMDA A .B PMDA that is run as a DSO is opened by .BR pmcd (1) with .BR dlopen (3). .B pmcd will call the .BR PMDA "'s" initialization function that is specified in .IR $PCP_PMCDCONF_PATH. This function is passed a pointer to a .B pmdaInterface structure which must be completed. Any callbacks which are .I not the default .B PMDA support library callbacks must be specified in the .B pmdaInterface structure. .PP The .B simple PMDA uses its own store and fetch callback. .BR simple_fetch () calls .BR pmdaFetch (3) which requires a callback to be set with .BR pmdaSetFetchCallBack (3) as can be seen in .IR $PCP_PMDAS_DIR/simple/simple.c . .PP The flag .B _isDSO is used to determine if the .B PMDA is a daemon or a DSO so that the correct initialization routine, .BR pmdaDaemon (3) or .BR pmdaDSO (3), is called. .SH DAEMON PMDA A .B PMDA that is run as a daemon is forked and executed by .BR pmcd (1). Therefore, unlike a DSO .BR PMDA , the starting point for a daemon .B PMDA is .BR main (). The agent should parse the command line arguments, create a log file and initialize some data structures that .B pmcd would initialize for a DSO agent. .PP The .B pmdaInterface structure must be completely defined by the daemon .BR PMDA . The function .BR pmdaDaemon (3) can be called at the start of .BR main () to set most of these fields. Command line parsing can be simplified by using .BR pmdaGetOpt (3), which is similar to .BR getopt (2), but extracts a common set of options into the .B pmdaInterface structure. .I stderr can be mapped to a log file using .BR pmdaOpenLog (3) to simplify debugging and error messages. The connection to .B pmcd can be made with .BR pmdaConnect (3) and the loop which handles the incoming PDUs, .BR pmdaMain (3), should be the last function called. This can be seen in .IR $PCP_PMDAS_DIR/simple/simple.c . .PP The .BR simple_init () routine is common to an agent that can be run as both a Daemon and DSO .BR PMDA . .SH HELP TEXT Each .B PMDA must be able to provide .B pmcd with the help text for each metric. Most .BR PMDA s use specially created files with indexes to support efficient retrieval of the help text. Tools are provided with PCP to create the help text files of appropriate format. See .BR newhelp (1). .SH INSTALLATION AND REMOVAL A series of shell procedures are defined in .I $PCP_SHARE_DIR/lib/pmdaproc.sh which greatly simplify the installation and removal of a .BR PMDA . The .I Install scripts for most .BR PMDAs should only need to specify the name of the .B PMDA in .BR iam , call .B _setup which check licenses and whether the .B PMDA has been previously installed, specify the communication protocols, and finally call .BR _install . The .I Remove scripts are even simpler as the communication protocols are not required. Further information is contained in the .I $PCP_SHARE_DIR/lib/pmdaproc.sh file. .SH DIAGNOSTICS Any .B PMDA which uses this library can set .BR PMAPI (3) debug control variable .B pmDebug (with \-D on the command line) to .B DBG_TRACE_LIBPMDA to enable the display of debugging information which may be useful during development (see .BR pmdbg (1)). .PP The .I status field of the .B pmdaInterface structure should be zero after .BR pmdaDaemon , .BR pmdaDSO , .BR pmdaGetOpt , .BR pmdaConnect and .B pmdaInit are called. A value less than zero indicates that initialization has failed. .PP Some error messages that are common to most functions in this library are: .TP 15 .BI "PMDA interface version " interface " not supported" Most of the functions require that the .I comm.version field of the .B pmdaInterface structure be set to .B PMDA_INTERFACE_2 or later. .B PMDA_INTERFACE_2 or .B PMDA_INTERFACE_3 implies that the .I version.two fields are correctly initialized, while .B PMDA_INTERFACE_4 implies that the .I version.four fields are correctly initialized (see .BR pmdaDaemon (3) and .BR pmdaDSO (3)). .SH CAVEAT Failing to complete any of the data structures or calling any of the library routines out of order may cause unexpected behavior in the .BR PMDA . .PP Due to changes to the .BR PMAPI (3) and .BR PMDA (3) API in the PCP 2.0 release, as described in the product release notes, .BR PMDA s built using PCP 2.0 must specify .B PMDA_INTERFACE_2 or later and link with .I libpcp_pmda.so.2 and .IR libpcp.so.2 . Pre-existing Daemon PMDAs specifying .B PMDA_PROTOCOL_1 will continue to function using the backwards compatible .I libpcp_pmda.so.1 and .I libpcp.so.1 libraries and may be recompiled using the headers installed in .I "/usr/include/pcp1.x/" without any modification. These backwards compatible headers and libraries are contained in the .I pcp.sw.compat subsystem. .SH FILES .TP 10 .I /usr/include/pcp/pmda.h Header file for the .B PMDA support library. .TP .I /usr/lib/libpcp_pmda.so Dynamic library containing .B PMDA support library routines. .TP .I $PCP_PMDAS_DIR/trivial The source of the .BR "trivial PMDA" . .TP .I $PCP_PMDAS_DIR/simple The source of the .BR "simple PMDA" . .TP .I $PCP_PMDAS_DIR/txmon The source of the .BR "txmon PMDA" . .TP .I $PCP_PMCDCONF_PATH Configuration file for .BR pmcd (1). .TP .I $PCP_VAR_DIR/pmns Location of namespace descriptions for every .BR PMDA . .TP .I $PCP_VAR_DIR/pmns/stdpmid The unique domain identifiers for each .BR PMDA . .TP .I $PCP_SHARE_DIR/lib/pmdaproc.sh Shell procedures for installing and removing a .BR PMDA . .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .IR pmGetConfig (3) function. .SH SEE ALSO .BR dbpmda (1), .BR newhelp (1), .BR pmcd (1), .BR pmnsadd (1), .BR pmnsdel (1), .BR PMAPI (3), .BR pmdaConnect (3), .BR pmdaDaemon (3), .BR pmdaDesc (3), .BR pmdaDSO (3), .BR pmdaFetch (3), .BR pmdaGetOpt (3), .BR pmdaInit (3), .BR pmdaInstance (3), .BR pmdaMain (3), .BR pmdaOpenLog (3), .BR pmdaProfile (3), .BR pmdaStore (3), .BR pmdaText (3), .BR pmLookupDesc (3) and .BR pmns (5). .PP For a complete description of the .I pcp_pmda library and the PMDA development process, refer to the Insight book .IR "Performance Co-Pilot Programmer's Guide" . pcp-3.8.12ubuntu1/man/man3/pmdahelp.30000664000000000000000000000503312272262501014072 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAHELP 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaOpenHelp\f1, \f3pmdaGetHelp\f1, \f3pmdaGetInDomHelp\f1, \f3pmdaCloseHelp\f1 \- help text support for a PMDA .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmdaOpenHelp(char *\fIfname\fP); .br char *pmdaGetHelp(int \fIhandle\fP, pmID \fIpmid\fP, int \fItype\fP); .br char *pmdaGetInDomHelp(int \fIhandle\fP, pmInDom \fIindom\fP, int \fItype\fP); .br void pmdaCloseHelp(int \fIhandle\fP); .sp cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION As part of the Performance Metrics Domain Agent (PMDA) API (see .BR PMDA (3)), this group of routines is used to implement the processing of a PMDA's metric help information. .PP These routines are really intended for internal use, and should not need to be called directly from any PMDA code. .PP Briefly, the base name of the help text file (as created by .BR newhelp (1)) is passed in via a .B \-h command line option for a daemon PMDA or as an argument to .BR pmdaDaemon (3) or .BR pmdaDSO (3). Then .B pmdaOpenHelp is called from .BR pmdaInit (3) and returns a .I handle that is used in subsequent calls to identify a particular help text collection (each PMDA typically has only one such collection). .PP Requests for help text are passed to .BR pmdaText (3) which calls .B pmdaGetHelp or .B pmdaGetInDomHelp as required. .PP Other than error cases in .BR pmdaOpenHelp , .B pmdaCloseHelp is not called. .SH DIAGNOSTICS .B pmdaOpenHelp returns a negative value for failure, suitable for decoding with .BR pmErrStr (3). .B pmdaGetHelp and .B pmdaGetInDomHelp return NULL if the corresponding help text does not exist. .SH CAVEAT The PMDA must be using .B PMDA_PROTOCOL_2 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH SEE ALSO .BR newhelp (1), .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaDSO (3), .BR pmdaInit (3), .BR pmdaText (3) and .BR pmErrStr (3). pcp-3.8.12ubuntu1/man/man3/pmigethandle.30000664000000000000000000000425212272262501014743 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIGETHANDLE3 "" "Performance Co-Pilot" .SH NAME \f3pmiGetHandle\f1 \- define a handle for a metric-instance pair .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmiGetHandle(const char *\fIname\fP, const char *\fIinstance\fP); .sp cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .sp $\fIhandle\fP = pmiGetHandle($\fIname\fP, $\fIinstance\fP); .ft 1 .SH DESCRIPTION As part of the Performance Co-Pilot Log Import API (see .BR LOGIMPORT (3)), .B pmiGetHandle creates a handle for a given metric and instance. The handle is returned as the value from the .B pmiGetHandle call and can be used in subsequent calls to .BR pmiPutValueHandle (3). .PP The metric's .I name should match one defined earlier in a call to .BR pmiAddMetric (3). .PP For singular metrics (those defined with an instance domain of .BR PM_INDOM_NULL ), the .I instance should be NULL or an empty string, otherwise .I instance should match the name of an instance defined earlier in a call to .BR pmiAddInstance (3) for the metric's instance domain. .PP When combined with .BR pmiPutValueHandle (3), the use of handles provide a performance improvement over the alternative lookup for a metric name and an instance name for each data value that is required for .BR pmiPutValue (3). .SH DIAGNOSTICS On failure .B pmiGetHandle returns a negative value that can be turned into an error message by calling .BR pmiErrStr (3). .SH SEE ALSO .BR LOGIMPORT (3), .BR pmiAddInstance (3), .BR pmiAddMetric (3), .BR pmiErrStr (3) and .BR pmiPutValueHandle (3). pcp-3.8.12ubuntu1/man/man3/pmfreeprofile.30000664000000000000000000000217512272262501015143 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMFREEPROFILE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmFreeProfile\f1 \- free a PMAPI instance profile .SH "C SYNOPSIS" .ft 3 #include .br #include .sp void __pmFreeProfile(__pmProfile *\fIprof\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .B __pmFreeProfile frees the storage for the PMAPI instance profile .IR prof , assuming the storage was allocated using .BR malloc (3C) according to the scheme used in .BR __pmDecodeProfile (3). .SH SEE ALSO .BR PMAPI (3) and .BR __pmDecodeProfile (3). pcp-3.8.12ubuntu1/man/man3/pmgetindom.30000664000000000000000000000543712272262501014453 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMGETINDOM 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmGetInDom\f1 \- get instance identifiers for a performance metrics instance domain .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmGetInDom(pmInDom \fIindom\fP, int **\fIinstlist\fP, char ***\fInamelist\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. In the current Performance Metrics Application Programming Interface (PMAPI) context, locate the description of the instance domain .IR indom , and return via .I instlist the internal instance identifiers for all instances, and via .I namelist the full external identifiers for all instances. The number of instances found is returned as the function value (else less than zero to indicate an error). .PP The value for the instance domain .I indom is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP The resulting lists of instance identifiers (\c .I instlist and .IR namelist ), and the names that the elements of .I namelist point to, will have been allocated by .B pmGetInDom with two calls to .BR malloc (3C), and it is the responsibility of the caller to .CW free(instlist) and .CW free(namelist) to release the space when it is no longer required. .PP When the result of .B pmGetInDom is less than one, both .I instlist and .I namelist are undefined (no space will have been allocated, and so calling .BR free (3C) is a singularly bad idea). .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR PMAPI (3), .BR pmGetConfig (3), .BR pmGetInDomArchive (3), .BR pmLookupDesc (3), .BR pmLookupInDom (3), .BR pmNameInDom (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .IP \f3PM_ERR_INDOM\f1 .I indom is not a valid instance domain identifier pcp-3.8.12ubuntu1/man/man3/pmdatext.30000664000000000000000000000517612272262501014136 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDATEXT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaText\f1 \- extract metric help text for a PMDA .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmdaText(int \fIident\fP, int \fItype\fP, char **\fIbuffer\fP, pmdaExt *\fIpmda\fP); .sp cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION As part of the Performance Metrics Domain Agent (PMDA) API (see .BR PMDA (3)), .B pmdaText uses the standard .BR PMDA (3) data structures to return the help text for metric .I ident in .IR buffer . The help text must be located in help text files created with .BR newhelp (1), and the associated files are automatically opened by .BR pmdaInit (3). .PP The path to the (basename of the) help text files can be set in the calls to .BR pmdaDSO (3) or .BR pmdaDaemon (3) and overridden by the .B \-h command line option in .BR pmdaGetOpt (3). .PP The encoding of .I ident follows the internal scheme used below the routines .BR pmLookupText (3) and .BR pmLookupInDomText (3), namely .I ident encodes either a metric identifier or an instance domain identifier, according to the value of .IR type . .PP The .I type argument is a bit mask that encodes the interpretation of .I ident and the requested form of help text, as follows: either .B PM_TEXT_PMID if .I ident is a metric identifier, or .B PM_TEXT_INDOM if .I ident is an instance domain identifier, plus either .B PM_TEXT_ONELINE for the one line help text or .B PM_TEXT_HELP for the full help text. .PP The .I buffer is managed internally (usually it is cached), and it should .B not be released or freed by the caller of .BR pmdaText . .SH DIAGNOSTICS If the requested help text could not be obtained, .B pmdaText will return .BR PM_ERR_TEXT . .SH CAVEAT The PMDA must be using .B PMDA_PROTOCOL_2 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH SEE ALSO .BR newhelp (1), .BR malloc (3), .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaDSO (3), .BR pmdaInit (3), .BR pmLookupInDomText (3) and .BR pmLookupText (3). pcp-3.8.12ubuntu1/man/man3/pmdaconnect.30000664000000000000000000000544512272262501014602 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDACONNECT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaConnect\f1 \- establish a connection between a daemon PMDA and PMCD .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp void pmdaConnect(pmdaInterface *\fIdispatch\fP); .sp cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION .B pmdaConnect initializes an IPC channel between a .BR PMDA (3) and the .BR pmcd (1) process on the local host. The type of the connection is dependent on the .I e_io field of the .B pmdaExt structure: .TP 15 .B pmdaPipe Use .BR stdin / stdout to communicate; assumes this is a pipe created by .B pmcd before the .BR PMDA (3) was launched. .TP .B pmdaInet Assume .BR pmcd (1) will establish a connection to an IPv4 internet domain socket set up by the .BR PMDA (3). The name or number of the port must be specified in the .I e_sockname or .I e_port fields of the .B pmdaExt structure, respectively. .TP .B pmdaIPv6 Assume .BR pmcd (1) will establish a connection to an IPv6 internet domain socket set up by the .BR PMDA (3). The name or number of the port must be specified in the .I e_sockname or .I e_port fields of the .B pmdaExt structure, respectively. .TP .B pmdaUnix Assume .BR pmcd (1) will establish a connection to a unix domain socket set up by the .BR PMDA (3). The port number must be specified in the .I e_port field of the .B pmdaExt structure. .TP .B pmdaUnknown The initial value of .I e_io which defaults to using .BR stdin / stdout . .PP The relevant .B pmdaExt fields are initialized by .BR pmdaInit (3) and set by .BR pmdaGetOpt (3), so most PMDAs should not need to access or modify them. .SH DIAGNOSTICS .B pmdaConnect will log the type of connection made to .BR pmcd (1) if the .BR PMAPI (3) debug control variable .RB ( pmDebug ) has the .B DBG_TRACE_LIBPMDA flag set. .PP If an error occurs that is unrecoverable, .I dispatch->status is set to a value less than 0, otherwise it is zero or positive. .SH CAVEAT The PMDA must be using .B PMDA_INTERFACE_2 or later, as specified in the call to .BR pmdaDaemon (3). .SH SEE ALSO .BR pmcd (1), .BR pipe (2), .BR socket (2), .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaGetOpt (3) and .BR pmdaInit (3). pcp-3.8.12ubuntu1/man/man3/pmlookupindomtext.30000664000000000000000000000413212272262501016101 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOOKUPINDOMTEXT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmLookupInDomText\f1 \- return text describing a performance metrics instance domain .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmLookupInDomText(pmInDom \fIindom\fP, int \fIlevel\fP, char **\fIbuffer\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Provided the source of metrics from the current Performance Metrics Application Programming Interface (PMAPI) context is a host, retrieve descriptive text about the performance metrics instance domain identified by .IR indom . .PP The value for the instance domain .I indom is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP The argument .I level should be .BR PM_TEXT_ONELINE for a one-line summary, else .BR PM_TEXT_HELP for a more verbose description, suited to a help dialog. .PP The space pointed to by .I buffer will have been allocated in .B pmLookupInDomText with .BR malloc (3C), and it is the responsibility of the caller to .BR free (3C) the space when it is no longer required. .PP .B pmLookupInDomText returns zero on success. .SH SEE ALSO .BR chkhelp (1), .BR newhelp (1), .BR PMAPI (3), .BR pmGetConfig (3), .BR pmLookupDesc (3), .BR pmLookupText (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOTHOST\f1 if the current PMAPI context is an archive log (help and one-line text is not maintained in the archive logs) pcp-3.8.12ubuntu1/man/man3/pmdadesc.30000664000000000000000000000270412272262501014062 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDADESC 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaDesc\f1 \- get the description of a metric from a PMDA .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmdaDesc(pmID \fIpmid\fP, pmDesc *\fIdesc\fP, pmdaExt *\fIpmda\fP); .sp cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION .B pmdaDesc uses the standard .BR PMDA (3) data structures to return the .B pmDesc description in .I desc for the metric identified by .IR pmid . .SH DIAGNOSTICS If the .I pmid does not correspond to any metric supported by this PMDA, .B pmdaDesc returns .BR PM_ERR_PMID . .SH CAVEAT The PMDA must be using .B PMDA_INTERFACE_2 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH SEE ALSO .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaDSO (3) and .BR pmLookupDesc (3). pcp-3.8.12ubuntu1/man/man3/pmdafetch.30000664000000000000000000002035112272262501014233 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAFETCH 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaFetch\f1, \f3pmdaSetFetchCallBack\f1 \- fill a pmResult structure with the requested metric values .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp .ad l .hy 0 .in +8n .ti -8n int pmdaFetch(int \fInumpmid\fP, pmID *\fIpmidlist\fP, pmResult **\fIresp\fP, pmdaExt\ *\fIpmda\fP); .br .ti -8n void pmdaSetFetchCallBack(pmdaInterface *\fIdispatch\fP, pmdaFetchCallBack\ \fIcallback\fP); .sp .in .hy .ad cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION .B pmdaFetch is a generic callback used by a .BR PMDA (3) to process a fetch request from .BR pmcd (1). The request from .B pmcd is initiated by a client calling .BR pmFetch (3). .PP This is the only generic callback in .I libpcp_pmda (see .BR PMDA (3)) that is incomplete, requiring a further .B pmdaFetchCallBack method of its own. The additional callback should be registered using .B pmdaSetFetchCallBack and the .B pmdaFetchCallBack method has the following prototype: .nf .ft CW .ps -1 int func(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *avp) .ps .ft .fi .PP .B pmdaFetch will allocate and resize the .I resp result structure, to store values for the .I numpmid metrics listed in .IR pmidlist . .PP For each instance listed in the profile (see .BR pmdaProfile (3)) of each metric listed in .IR pmidlist , the .B pmdaFetchCallBack method is called to fill the .B pmAtomValue structure identified by .I avp with a value for a specific metric-instance pair identified by the metric descriptor .I mdesc and the instance .IR inst . This value is then copied into the .B pmResult structure. .PP The .B pmdaFetchCallBack method should return a value less than zero for an error, and the most likely cases would be .B PM_ERR_PMID if the metric identified by .I mdesc is not known to the method, or .B PM_ERR_INST if the method believes the instance .I inst is not known for the metric identified by .IR mdesc . .PP The success error codes depend on the version of .B PMDA_INTERFACE the PMDA is using. .PP If the PMDA is using .B PMDA_INTERFACE_2 then on success the .B pmdaFetchCallBack method should return .BR 0 . .PP If the PMDA is using .B PMDA_INTERFACE_3 or .B PMDA_INTERFACE_4 then on success the .B pmdaFetchCallBack method should return .B 1 if a value is returned via .IR avp , else .B 0 if no values are currently available for the requested metric-instance pair although .I mdesc and .I inst both seem reasonable. .PP If the PMDA is using .B PMDA_INTERFACE_5 or later then on success the .B pmdaFetchCallBack method should return .B PMDA_FETCH_STATIC (\c .BR 1 ) if the value returned via .I avp can be ignored by .B pmdaFetch once it has been copied into the .B pmResult structure, else .B PMDA_FETCH_DYNAMIC (\c .BR 2 ) if the value returned via .I avp uses the either the .B vp or .B cp fields of the .B pmAtomValue and the associated value (buffer) was allocated using one of .BR malloc (3), .BR calloc (3), .BR realloc (3), .B strdup (3) etc. and .B pmdaFetch should release the memory by calling .IR free (3) once a new buffer has been allocated and the value copied, else .B PMDA_FETCH_NOVALUES (\c .BR 0 ) if no values are currently available for the requested metric-instance pair although .I mdesc and .I inst both seem reasonable. .PP If the .B pmdaFetchCallBack method returns a value for an instance of a metric of type .B PM_TYPE_STRING or .B PM_TYPE_AGGREGATE some special care is needed \(en the method should either use a static buffer, set .I avp->cp or .I avp->vp to the address of the buffer and return .BR PMDA_FETCH_STATIC , or use a dynamically allocated buffer, keep a static reference to the buffer's address, return .B PMDA_FETCH_STATIC and .I free (3) or .I realloc (3) or reuse the buffer the next time the .B pmdaFetchCallBack method is called, else use a dynamically allocated buffer and return .BR PMDA_FETCH_DYNAMIC . .SH EXAMPLE .PP The following code fragments are for a hypothetical PMDA has with metrics (A, B, C and D) and an instance domain (X) with two instances (X1 and X2). The instance domain and metrics description tables (see .BR pmdaInit (3)) could be defined as: .PP .nf .ft CW .ps -1 .in +0.5i static pmdaInstid _X[] = { { 0, "X1" }, { 1, "X2" } }; .sp 0.5v static pmdaIndom indomtab[] = { #define X_INDOM 0 { 0, 2, _X }, }; .sp 0.5v static pmdaMetric metrictab[] = { /* A */ { (void *)0, { PMDA_PMID(0,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} }, }, /* B */ { (void *)0, { PMDA_PMID(0,1), PM_TYPE_DOUBLE, X_INDOM, PM_SEM_INSTANT, {0,1,0,0,PM_TIME_SEC,0} }, }, /* C */ { (void *)0, { PMDA_PMID(0,2), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} }, }, /* D */ { (void *)0, { PMDA_PMID(0,3), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} }, }, }; .in .ps .ft .fi .br .PP A .B pmdaFetchCallBack method to be called from .B pmdaFetch could be defined as: .PP .nf .ft CW .ps -1 .in +0.5i int myFetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *avp) { static char sbuf[20]; // reuse this buffer char *dbuf; // malloc'd .sp 0.5v switch (pmid_item(mdesc->m_desc.pmid)) { case 0: /* assign some value for metric A */; avp->l = ... break; case 1: switch (inst) { case 0: /* assign a value for metric B, instance X1 */; avp->d = ... break; case 1: /* assign a value for metric B, instance X2 */; avp->d = ... break; default: return PM_ERR_INST; } case 2: /* place value for metric C in dbuf[] */ memcpy(dbuf, ...); avp->cp = dbuf; break; case 3: avp->cp = (char *)malloc(somesize); /* place value in avp->cp */ snprintf(avp->cp, somesize, ...); return PMDA_FETCH_DYNAMIC; .sp 0.5v default: return PM_ERR_PMID; } return PMDA_FETCH_STATIC; } .in .ps .ft .fi .PP .SH DIAGNOSTICS The following error messages indicate that there is discrepancy between the namespace, .B pmdaMetric and .B pmdaIndom tables passed to .BR pmdaInit (3), and the registered fetch callback: .TP 15 .BI "pmdaFetch: Requested metric " metric " is not defined" A requested metric .I metric is not listed in the .B pmdaMetric table. The namespace for this .BR PMDA (3) may contain additional metrics. .TP .BI "pmdaFetch: PMID " pmid " not handled by fetch callback" The .B pmdaFetchCallBack method has returned .BR PM_ERR_PMID . This indicates that a metric may be listed in the .B pmdaMetric table, but is not supported by the callback method. .TP .BI "pmdaFetch: Instance " inst " of PMID " pmid " not handled by fetch callback" The .B pmdaFetchCallBack method has returned .BR PM_ERR_INST . This indicates that an instance of metric is listed in the .B pmdaIndom table, but is not supported by the callback method. .TP .B pmdaFetch: Fetch callback error: The .B pmdaFetchCallBack method returned a result other than .BR PMDA_FETCH_NOVALUES , .BR PMDA_FETCH_STATIC , .BR PMDA_FETCH_DYNAMIC , .B PM_ERR_PMID or .BR PM_ERR_INST . .TP .BI "pmdaFetch: Descriptor type (" type ") for metric " pmid " is bad" The data type .I type specified for the metric .I pmid in the .B pmdaMetric table is illegal. .PP .B pmdaFetch will return .B \-errno if an error occurred while allocating the .B pmResult structure or copying the value from the .BR pmAtomValue . .SH CAVEAT The PMDA must be using .B PMDA_INTERFACE_2 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH SEE ALSO .BR pmcd (1), .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaDSO (3), .BR pmdaInit (3) and .BR pmFetch (3). pcp-3.8.12ubuntu1/man/man3/pmloadnamespace.30000664000000000000000000000611712272262501015435 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOADNAMESPACE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmLoadNameSpace\f1 \- load a local PMNS for an application .SH "C SYNOPSIS" .ft 3 #include .sp int pmLoadNameSpace(const char *\fIfilename\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION If the application wants to force using a local Performance Metrics Name Space (PMNS) instead of a distributed PMNS then it must load the PMNS using .B pmLoadNameSpace or .BR pmLoadASCIINameSpace (3). If the application is to use a distributed PMNS, then it should NOT make a call to load the PMNS explicitly. .PP The .I filename argument designates the PMNS of interest. For applications not requiring a tailored PMNS, the special value .B PM_NS_DEFAULT may be used for .IR filename , to force the default local PMNS to be loaded. .PP The default local PMNS is found in the file .I $PCP_VAR_DIR/pmns/root unless the environment variable .B PMNS_DEFAULT is set, in which case the value is assumed to be the pathname to the file containing the default local PMNS. .PP Externally a PMNS is stored in an ASCII format as described in .BR pmns (5). .PP By default, multiple names in the PMNS are not allowed to be associated with a single Performance Metrics Identifier (PMID). .BR pmLoadASCIINameSpace (3) provides an alternative interface with user-defined control over the processing of duplicate PMIDs in the PMNS. .PP .B pmLoadNameSpace returns zero on success. .SH FILES .IP \f2$PCP_VAR_DIR/pmns/root\f1 2.5i the default local PMNS, when the environment variable .B PMNS_DEFAULT is unset .RE .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .IR pmGetConfig (3) function. .SH SEE ALSO .BR PMAPI (3), .BR pmGetConfig (3), .BR pmLoadASCIINameSpace (3), .BR pmTrimNameSpace (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR pmns (5). .SH DIAGNOSTICS Syntax and other errors in the parsing of the PMNS are reported on .I stderr with a message of the form ``Error Parsing ASCII PMNS: ...''. .PP .B PM_ERR_DUPPMNS .IP It is an error to try and load more than one PMNS, or to call either .B pmLoadNameSpace and/or .BR pmLoadASCIINameSpace (3) more than once. .PP .B PM_ERR_PMNS .IP Syntax error in the PMNS file. pcp-3.8.12ubuntu1/man/man3/pmidstr.30000664000000000000000000000502612272262501013764 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMIDSTR 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmIDStr\f1, \f3pmIDStr_r\f1 \- convert a performance metric identifier into a string .SH "C SYNOPSIS" .ft 3 #include .sp const char *pmIDStr(pmID \fIpmid\fP); .br char *pmIDStr_r(pmID \fIpmid\fP, char *\fIbuf\fP, int \fIbuflen\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. For use in error and diagnostic messages, .B pmIDStr returns a `human readable' version of the specified Performance Metric Identifier (PMID). The .B pmIDStr_r function does the same, but stores the result in a user-supplied buffer .I buf of length .IR buflen , which should have room for at least 20 bytes. .PP Internally, a PMID is encoded as follows; .PP .ft CW .nf .in +0.5i typedef struct { int pad:2; unsigned int domain:8; unsigned int cluster:12; unsigned int item:10; } __pmID_int; .in .fi .ft 1 .PP .B pmIDStr returns a string with each of the .CW domain , .CW cluster and .CW item subfields appearing as decimal numbers, separated by periods. .PP The string value result from .B pmIDStr is held in a single static buffer, so the returned value is only valid until the next call to .BR pmIDStr . .SH NOTES .B pmIDStr returns a pointer to a static buffer and hence is not thread-safe. Multi-threaded applications should use .B pmIDStr_r instead. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR PMAPI (3), .BR pmGetConfig (3), .BR pmInDomStr (3), .BR pmLookupDesc (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man3/pmdastore.30000664000000000000000000000320012272262501014270 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDASTORE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaStore\f1 \- store a value into a metric for a PMDA .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp int pmdaStore(pmResult *\fIresult\fP, pmdaExt *\fIpmda\fP); .sp cc ... \-lpcp_pmda \-lpcp .ft 1 .SH DESCRIPTION As part of the Performance Metrics Domain Agent (PMDA) API (see .BR PMDA (3)), .BR pmdaStore is the generic callback for storing a value into a metric. .B pmdaStore is usually a no-op as, by default, no metrics can be altered. Also, the implementation of a store callback which does permit metrics to be altered by .BR pmstore (1) is very application dependent. .SH DIAGNOSTICS .B pmdaStore returns .B PM_ERR_PERMISSION to indicate that no metrics may be modified. .SH CAVEAT The PMDA must be using .B PMDA_PROTOCOL_2 or later, as specified in the call to .BR pmdaDSO (3) or .BR pmdaDaemon (3). .SH SEE ALSO .BR pmstore (1), .BR PMAPI (3), .BR PMDA (3), .BR pmdaDaemon (3), .BR pmdaDSO (3) and .BR pmStore (3). pcp-3.8.12ubuntu1/man/man3/pmdiscoverservices.30000664000000000000000000000567312272262501016231 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2014 Red Hat. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDISCOVERSERVICES 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmDiscoverServices\f1 \- discover PCP services on the network .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmDiscoverServices(const char *\fIservice\fP, const char *\fImechanism\fP, char ***\fIurls\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Given a PCP service name, as identified by .IR service , and using the type of discovery optionally specified in .IR mechanism , .B pmDiscoverServices returns, via .IR urls , a list of URLs representing the services discovered on the network. .PP .I service specifies the PCP service to be discovered. Currently, only .B PM_SERVER_SERVICE_SPEC is supported, which searches for .BR pmcd (1) servers. .PP .IR mechanism specifies the style of discovery to be used. Currently, only \fB"avahi"\fP is supported. This searches for services which are broadcasting using mDNS via .BR avahi-daemon (8). .IR mechanism may also be NULL, which means to use all available discovery mechanisms. .PP Normally, .B pmDiscoverServices will return the number of services discovered, else a value less than zero for an error. The value zero indicates that no services were discovered. .PP The resulting list of pointers, .IR urls , .B and the values (the URLs) that the pointers reference will have been allocated by .B pmDiscoverServices with a single call to .BR malloc (3C), and it is the responsibility of the .B pmDiscoverServices caller to .BR free (\c .IR urls ) to release the space when it is no longer required. .PP When an error occurs, or no services are discovered, .I urls is undefined (no space will have been allocated, and so calling .BR free (3C) is a singularly bad idea). .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR PMAPI (3), .BR pmcd (1), .BR pmfind (1), .BR pmGetConfig (3), .BR pcp.conf (5), .BR pcp.env (5) and .BR avahi-daemon (8). .SH DIAGNOSTICS .IP \f3EOPNOTSUPP\f1 The specified \fImechanism\fP is not supported. pcp-3.8.12ubuntu1/man/man3/pmparsectime.30000664000000000000000000000375312272262501015000 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMPARSECTIME 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmParseCtime\f1 \- convert \fBctime\fR(3) string to \fBtm\fR structure .SH "C SYNOPSIS" .ft 3 #include .br #include .sp int __pmParseCtime(const char *\fIstring\fP, struct tm *\fIrslt\fP, char **\fIerrmsg\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .B __pmParseCtime reverses the .BR asctime (3C) function. It accepts a .B string specifying a time, and fills in the given .B tm structure. .PP Either a fully specified .BR asctime (3C) string like "Mon Mar 4 13:07:47 1996" or a partially specified time like '1996", "Mar 1996", "Mar 4 1996", "Mar", "13:07:47", "13:07", "Mar 4 13:07:47",... is accepted. In addition, the seconds component may be a floating point number, for example "13:07:47.5". The 12 hour clock is also supported, so "13:07" and "1:07 pm" are equivalent. .PP .B __pmParseCtime returns 0 if successful. It returns \-1 and a dynamically allocated error message string in .BR errmsg , if the given .B string does not parse. Be sure to .BR free (3C) the error message string. .PP The .B tm structure returned in .B rslt should only be used as an argument to the .B __pmConvertTime function, as it contains encoded information that will only be correctly interpreted by .BR __pmConvertTime . .SH SEE ALSO .BR PMAPI (3), .BR pmParseInterval (3), .BR __pmConvertTime (3) and .BR __pmParseTime (3). pcp-3.8.12ubuntu1/man/man3/pmlookupindom.30000664000000000000000000000363412272262501015202 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOOKUPINDOM 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmLookupInDom\f1 \- translate an instance name into an instance identifier .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmLookupInDom(pmInDom \fIindom\fP, const char *\fIname\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. For the instance domain .IR indom , in the current Performance Metrics Application Programming Interface (PMAPI) context, locate the instance with the external identification given by .IR name , and return the internal instance identifier. .PP Only the leading non-space characters of .I name will be used to identify the instance. .PP The value for the instance domain .I indom is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP .B pmLookupInDom will return a positive instance identifier on success. .SH SEE ALSO .BR PMAPI (3), .BR pmGetConfig (3), .BR pmGetInDom (3), .BR pmLookupDesc (3), .BR pmLookupInDomArchive (3), .BR pmNameInDom (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .IP \f3PM_ERR_INDOM\f1 .I indom is not a valid instance domain identifier .IP \f3PM_ERR_INST\f1 The external instance .I name is not known for the instance domain .I indom in the current PMAPI context pcp-3.8.12ubuntu1/man/man3/pmdamain.30000664000000000000000000002115112272262501014065 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDAMAIN 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmdaMain\f1, \f3pmdaGetContext\f1, \f3pmdaSetResultCallBack\f1, \f3pmdaSetCheckCallBack\f1, \f3pmdaSetDoneCallBack\f1, \f3pmdaSetEndContextCallBack\f1 \- generic PDU processing for a PMDA .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp cc ... \-lpcp_pmda \-lpcp .sp .ad l .hy 0 .in +8n .ti -8n void pmdaMain(pmdaInterface *\fIdispatch\fP); .br .ti -8n void pmdaSetCheckCallBack(pmdaInterface *\fIdispatch\fP, pmdaCheckCallBack\ \fIcallback\fP); .br .ti -8n void pmdaSetDoneCallBack(pmdaInterface *\fIdispatch\fP, pmdaDoneCallBack\ \fIcallback\fP); .br .ti -8n void pmdaSetResultCallBack(pmdaInterface *\fIdispatch\fP, pmdaResultCallBack\ \fIcallback\fP); .br .ti -8n void pmdaSetEndContextCallBack(pmdaInterface *\fIdispatch\fP, pmdaEndContextCallBack\ \fIcallback\fP); .br .ti -8n int pmdaGetContext(void); .sp .in .hy .ad .ft 1 .SH DESCRIPTION For Performance Metric Domain Agents .RB ( PMDA (3)) using the binary PDU protocols to communicate with .BR pmcd (1), the routine .B pmdaMain provides a generic implementation of the PDU-driven main loop. .PP .I dispatch describes how to process each incoming PDU. It is a vector of function pointers, one per request PDU type, as used in the DSO interface for a PMDA, namely: .PP .nf .ft CW /* * Interface Definitions for PMDA Methods */ typedef struct { int domain; /* set/return performance metrics domain id here */ struct { unsigned int pmda_interface: 8; /* PMDA DSO interface version */ unsigned int pmapi_version : 8; /* PMAPI version */ unsigned int flags : 16; /* optional feature flags */ } comm; /* set/return communication and version info */ int status; /* return initialization status here */ union { struct { /* PMDA_INTERFACE_2 or _3 */ pmdaExt *ext; int (*profile)(__pmProfile *, pmdaExt *); int (*fetch)(int, pmID *, pmResult **, pmdaExt *); int (*desc)(pmID, pmDesc *, pmdaExt *); int (*instance)(pmInDom, int, char *, __pmInResult **, pmdaExt *); int (*text)(int, int, char **, pmdaExt *); int (*store)(pmResult *, pmdaExt *); } two, three; struct { /* PMDA_INTERFACE_4 or _5 */ pmdaExt *ext; int (*profile)(__pmProfile *, pmdaExt *); int (*fetch)(int, pmID *, pmResult **, pmdaExt *); int (*desc)(pmID, pmDesc *, pmdaExt *); int (*instance)(pmInDom, int, char *, __pmInResult **, pmdaExt *); int (*text)(int, int, char **, pmdaExt *); int (*store)(pmResult *, pmdaExt *); int (*pmid)(char *, pmID *, pmdaExt *); int (*name)(pmID, char ***, pmdaExt *); int (*children)(char *, int, char ***, int **, pmdaExt *); } four, five; struct { /* PMDA_INTERFACE_6 */ pmdaExt *ext; int (*profile)(__pmProfile *, pmdaExt *); int (*fetch)(int, pmID *, pmResult **, pmdaExt *); int (*desc)(pmID, pmDesc *, pmdaExt *); int (*instance)(pmInDom, int, char *, __pmInResult **, pmdaExt *); int (*text)(int, int, char **, pmdaExt *); int (*store)(pmResult *, pmdaExt *); int (*pmid)(char *, pmID *, pmdaExt *); int (*name)(pmID, char ***, pmdaExt *); int (*children)(char *, int, char ***, int **, pmdaExt *); int (*attribute)(int, int, const char *, int, pmdaExt *); } six; } version; } pmdaInterface; .fi .PP This structure has been extended to incorporate the multiple interface versions that have evolved over time. For .BR pmdaMain, .I dispatch->domain and .I dispatch->status are ignored. The .I comm.pmda_interface field is used to determine the interface used by the PMDA. Setting this field to .B PMDA_INTERFACE_2 or .B PMDA_INTERFACE_3 will force .B pmdaMain to use the callbacks in the .I version.two or .I version.three structure. A setting of .B PMDA_INTERFACE_4 or .B PMDA_INTERFACE_5 will force .B pmdaMain to use the callbacks in the .I version.four or .I version.five structure, and similarly a .B PMDA_INTERFACE_6 setting forces .B pmdaMain to use the callbacks in the .I version.six structure. Any other value will result in an error and termination of .BR pmdaMain . .PP Note that the use of .B dispatch as the interface between the .BR pmcd (1) and the methods of the PMDA allows each PMDA to be implemented as though it were a DSO, with .B pmdaMain providing a convenient wrapper that may be used to convert from the DSO interface to the binary PDU (daemon PMDA) interface. .PP .B pmdaMain executes as a continuous loop, returning only when an end of file is encountered on the PDU input file descriptor. .SH CALLBACKS In addition to the individual PDU processing callbacks \- .BR pmdaProfile (3), .BR pmdaFetch (3), .BR pmdaDesc (3), .BR pmdaInstance (3), .BR pmdaText (3), .BR pmdaStore (3), .BR pmdaPMID (3), .BR pmdaName (3), .BR pmdaChildren (3), and .BR pmdaAttribute (3) there are other callbacks that can affect or inform all PDU processing within a PMDA, namely .IR check , .I done and .IR end . These callbacks should be set with .BR pmdaSetCheckCallBack , .B pmdaSetDoneCallBack and .BR pmdaSetEndContextCallBack . .PP If not null, .I check is called after each PDU is received (but before it was processed), and .I done is called after each PDU is sent. If .I check returns a value less than zero (typically PM_ERR_AGAIN), the PDU processing is skipped and in most cases the function value is returned as an error PDU to .BR pmcd (1) \- this may be used for PMDAs that require some sort of deferred connection or reconnect protocols for the underlying sources of performance metrics, e.g. a DBMS. The error indication from .I check is not passed back to .BR pmcd (1) in the cases where no acknowledgment is expected, e.g. for a PDU_PROFILE. .PP The .I end callback allows a PMDA to keep track of state for individual clients that are requesting it to perform actions (PDU processing). Using .B pmdaGetContext a PMDA can determine, at any point, an integer identifier that uniquely identifies the client tools at the remote end of PMCD (for local context modes, this identifier is always zero). This becomes very important for handling event metrics, where each event must be propogated once only to each interested client. It also underlies the mechanism whereby connection information is passed to the PMDA, such as the the credentials (user and group identifiers) for the client tool. .PP One final callback mechanism is provided for handling the .B pmResult built for a PDU_RESULT in response to a PDU_FETCH request. By default, .B pmdaMain will free the .B pmResult once the result has been sent to the .BR pmcd (1). For some PMDAs this is inappropriate, e.g. the .B pmResult is statically allocated, or contains a hybrid of pinned PDU buffer information and dynamically allocated information. .B pmdaSetResultCallback may be used to define an alternative .B callback from .BR pmdaMain . .SH DIAGNOSTICS These messages may be appended to the PMDA's log file: .TP 25 .BI "PMDA interface version " interface " not supported" The .I interface version is not supported by .BR pmdaMain . .TP .B Unrecognized pdu type The PMDA received a PDU from .B pmcd that it does not recognize. This may indicate that the .B pmcd process is using a more advanced interface than .BR pmdaMain . .PP If the .BR PMAPI (3) debug control variable .RB ( pmdebug ) has the DBG_TRACE_LIBPMDA flag set then each PDU that is received is reported in the PMDA's log file. .SH SEE ALSO .BR pmcd (1), .BR PMAPI (3), .BR PMDA (3), .BR pmdaProfile (3), .BR pmdaFetch (3), .BR pmdaDesc (3), .BR pmdaInstance (3), .BR pmdaText (3), .BR pmdaStore (3), .BR pmdaPMID (3), .BR pmdaName (3), .BR pmdaChildren (3), and .BR pmdaAttribute (3). pcp-3.8.12ubuntu1/man/man3/pmspeclocalpmda.30000664000000000000000000000504212272262501015444 0ustar '\"macro stdmacro .TH PMSPECLOCALPMDA 3 "" "Performance Co-Pilot" .SH NAME \f3__pmSpecLocalPMDA\f1 \- process command-line argument for the table of DSO PMDAs .SH "C SYNOPSIS" .ft 3 #include .br #include .sp char *__pmSpecLocalPMDA(const char *\fIspec\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION PCP contexts of type .B PM_CONTEXT_LOCAL are used by clients that wish to fetch metrics directly from one or more PMDAs on the local host without involving .BR pmcd (1). .PP .B __pmSpecLocalPMDA provides a convenience wrapper to be used by applications that wish to use a command line argument (usually with .BR -K ) to control the DSO PMDAs that are available for a .B PM_CONTEXT_LOCAL context. .PP The .I spec argument specifies actions for one or more DSO PMDAs using up to four fields separated by commas (``,''), namely: .PD 0 .TP 3n .IP \- an opcode with one of the values .B add (add a new entry), .B del (delete an existing entry) or .B clear (clear all entries from the table). .IP \- the PMDA's domain number .IP \- the path to the PMDA DSO (may be absolute or relative to the $PCP_VAR_DIR/pmdas directory and the DSO suffix is optional), and .IP \- the name of the PMDA's initialization routine. .PD .PP All fields are required to add a new entry. To delete an entry the opcode is required plus either or both of the domain number and path fields. To clear all entries, only the opcode is required. .PP If .I spec is parsed successfully, then .BR __pmLocalPMDA (3) is called with the extracted arguments. .SH "RETURN VALUE" On success, .B __pmSpecLocalPMDA will return NULL. .PP On error or failure, .B __pmSpecLocalPMDA will return a pointer to a static error message. .SH EXAMPLES Some examples of valid .I spec strings: .TP .ft CW clear .ft Delete all entries from the DSO table. .TP .ft CW add,123,foo/foo_pmda,foo_init .ft Add the ``foo'' PMDA using domain 123. The PMDA's DSO is most likely in below the directory .B $PCP_PMDAS_DIR and named .I foo/foo_pmda.so (for ELF-style platforms) or .I foo/foo_pmda.dylib (for BSD-style platforms) or .I foo\\foo_pmda.dll (for Windows-style platforms). The initialization routine for the ``foo'' PMDA is .IR foo_init (). .TP .ft CW del,123 Delete the entry for the DSO with domain 123. .TP .ft CW del,,foo/foo_pmda Delete the entry with a pathname to the DSO that matches .IR foo/foo_pmda . .TP .ft CW del,123,foo/foo_pmda Delete the entry for the DSO with either domain 123 and/or a pathname to the DSO that matches .IR foo/foo_pmda . .SH SEE ALSO .BR PMAPI (3), .BR __pmLocalPMDA (3) and .BR pmNewContext (3). pcp-3.8.12ubuntu1/man/man3/pmgetcontexthostname.30000664000000000000000000000523012272262501016557 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2013 Red Hat. .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMGETCONTEXTHOSTNAME 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmGetContextHostName\f1 \- return the hostname associated with a Performance Co-Pilot context .SH "C SYNOPSIS" .ft 3 #include .sp const char *pmGetContextHostName(int \fIid\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION Given a valid PCP context identifier previously created with .BR pmNewContext (3) or .BR pmDupContext (3), the .B pmGetContextHostName function returns the hostname associated with .IR id . .PP If the context .I id is associated with an archive source of data, the hostname returned is extracted from the archive label using .BR pmGetArchiveLabel (3). .PP For live contexts, an attempt will first be made to retrieve the hostname from the PCP collector system using .BR pmFetch (3) with the .I pmcd.hostname metric. This allows client tools using this interface to retrieve an accurate host identifier even in the presence of port forwarding and tunnelled connections. .PP Should this not succeed, then a fallback method is used. For local contexts \- with local meaning any of DSO, ``localhost'' or Unix domain socket connection \- a hostname will be sought via .BR gethostname (3). For other contexts, the hostname extracted from the initial context host specification will be used. .SH "RETURN VALUE" If .I id is not a valid PCP context identifier, this function returns a zero length string and hence never fails. .SH "PCP ENVIRONMENT" Environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR PCPIntro (1), .BR PMAPI (3), .BR gethostname (3), .BR pmDupContext (3), .BR pmFetch (3), .BR pmGetArchiveLabel (3), .BR pmNewContext (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man3/pmlookupindomarchive.30000664000000000000000000000440512272262501016541 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOOKUPINDOMARCHIVE 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmLookupInDomArchive\f1 \- translate an instance name into an instance identifier .SH "C SYNOPSIS" .ft 3 #include .sp int pmLookupInDomArchive(pmInDom \fIindom\fP, const char *\fIname\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. Provided the current Performance Metrics Application Programming Interface (PMAPI) context is associated with an archive log, .B pmLookupInDomArchive will scan the union of all the instance domain metadata for the instance domain .IR indom , locate the first instance with the external identification given by .IR name , and return the internal instance identifier. .PP This routine is a specialized version of the more general PMAPI routine .BR pmLookupInDom . .PP Only the leading non-space characters of .I name will be used to identify the instance. .PP The value for the instance domain .I indom is typically extracted from a .CW pmDesc structure, following a call to .BR pmLookupDesc (3) for a particular performance metric. .PP .B pmLookupInDomArchive will return a positive instance identifier on success. .SH SEE ALSO .BR PMAPI (3), .BR pmGetConfig (3), .BR pmGetInDomArchive (3), .BR pmLookupDesc (3), .BR pmLookupInDom (3), .BR pmNameInDomArchive (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOTARCHIVE\f1 the current PMAPI context is not associated with an archive log .IP \f3PM_ERR_INDOM_LOG\f1 .I indom is not a defined instance domain identifier for the archive log .IP \f3PM_ERR_INST_LOG\f1 the external instance .I name is not known for the instance domain .I indom in the archive log pcp-3.8.12ubuntu1/man/man3/pmdestroycontext.30000664000000000000000000000407112272262501015734 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMDESTROYCONTEXT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmDestroyContext\f1 \- destroy a PMAPI context .SH "C SYNOPSIS" .ft 3 #include .sp int pmDestroyContext(int \fIhandle\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. An application using the Performance Metrics Application Programming Interface (PMAPI) may manipulate several concurrent contexts, each associated with a source of performance metrics, e.g. \c .BR pmcd (1) on some host, or an archive log of performance metrics as created by .BR pmlogger (1). .PP .B pmDestroyContext destroys the PMAPI context identified by .IR handle . Typically this would imply some termination of a connection to a PMCD or closing an archive log file, and orderly clean-up. .PP The context must have been previously created using .BR pmNewContext (3) or .BR pmDupContext (3). .PP On success, .B pmDestroyContext returns zero. If .I handle was the current PMAPI context, then the current context becomes undefined. This means the application must explicitly re-establish a valid PMAPI context with .BR pmUseContext (3), or create a new context with .BR pmNewContext (3) or .BR pmDupContext (3), before the next PMAPI operation that requires a PMAPI context. .SH SEE ALSO .BR PMAPI (3), .BR pmDupContext (3), .BR pmNewContext (3), .BR pmUseContext (3) and .BR pmWhichContext (3). .SH DIAGNOSTICS .P .B PM_ERR_NOCONTEXT .IP .I handle does not identify a valid PMAPI context pcp-3.8.12ubuntu1/man/man3/pmapi.30000664000000000000000000003615512272262501013417 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMAPI 3 "PCP" "Performance Co-Pilot" .SH NAME \f3PMAPI\f1 \- introduction to the Performance Metrics Application Programming Interface .SH "C SYNOPSIS" .ft 3 #include .sp .ft 1 \& ... assorted routines ... .ft 3 .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .de CW .ie t \f(CW\\$1\f1\\$2 .el \fI\\$1\f1\\$2 .. .\" add in the -me strings for super and subscripts .ie n \{\ . ds [ \u\x'-0.25v' . ds ] \d . ds { \d\x'0.25v' . ds } \u .\} .el \{\ . ds [ \v'-0.4m'\x'-0.2m'\s-3 . ds ] \s0\v'0.4m' . ds { \v'0.4m'\x'0.2m'\s-3 . ds } \s0\v'-0.4m' .\} Within the framework of the Performance Co-Pilot (PCP), client applications are developed using the Performance Metrics Application Programming Interface (PMAPI) that defines a procedural interface with services suited to the development of applications with a particular interest in performance metrics. .PP This description presents an overview of the PMAPI and the context in which PMAPI applications are run. The PMAPI is more fully described in the .IR "Performance Co-Pilot Programmer's Guide" , and the manual pages for the individual PMAPI routines. .SH "PERFORMANCE METRICS \- NAMES AND IDENTIFIERS" For a description of the Performance Metrics Name Space (PMNS) and associated terms and concepts, see .BR PCPIntro (1). .PP Not all PMIDs need be represented in the PMNS of every application. For example, an application which monitors disk traffic will likely use a name space which references only the PMIDs for I/O statistics. .PP Applications which use the PMAPI may have independent versions of a PMNS, constructed from an initialization file when the application starts; see .BR pmLoadASCIINameSpace (3), .BR pmLoadNameSpace (3), and .BR pmns (5). .PP Internally (below the PMAPI) the implementation of the Performance Metrics Collection System (PMCS) uses only the PMIDs, and a PMNS provides an external mapping from a hierarchic taxonomy of names to PMIDs that is convenient in the context of a particular system or particular use of the PMAPI. For the applications programmer, the routines .BR pmLookupName (3) and .BR pmNameID (3) translate between names in a PMNS and PMIDs, and vice versa. The PMNS may be traversed using .BR pmGetChildren (3). .SH "PMAPI CONTEXT" An application using the PMAPI may manipulate several concurrent contexts, each associated with a source of performance metrics, e.g. \c .BR pmcd (1) on some host, or an archive log of performance metrics as created by .BR pmlogger (1). .PP Contexts are identified by a ``handle'', a small integer value that is returned when the context is created; see .BR pmNewContext (3) and .BR pmDupContext (3). Some PMAPI functions require an explicit ``handle'' to identify the correct context, but more commonly the PMAPI function is executed in the ``current'' context. The current context may be discovered using .BR pmWhichContext (3) and changed using .BR pmUseContext (3). .PP If a PMAPI context has not been explicitly established (or the previous current context has been closed using .BR pmDestroyContext (3)) then the current PMAPI context is undefined. .PP In addition to the source of the performance metrics, the context also includes the instance profile and collection time (both described below) which controls how much information is returned, and when the information was collected. .SH "INSTANCE DOMAINS" When performance metric values are returned across the PMAPI to a requesting application, there may be more than one value for a particular metric. Multiple values, or .BR instances , for a single metric are typically the result of instrumentation being implemented for each instance of a set of similar components or services in a system, e.g. independent counts for each CPU, or each process, or each disk, or each system call type, etc. This multiplicity of values is not enumerated in the name space but rather, when performance metrics are delivered across the PMAPI by .BR pmFetch (3), the format of the result accommodates values for one or more instances, with an instance-value pair encoding the metric value for a particular instance. .PP The instances are identified by an internal identifier assigned by the agent responsible for instantiating the values for the associated performance metric. Each instance identifier has a corresponding external instance identifier name (an ASCII string). The routines .BR pmGetInDom (3), .BR pmLookupInDom (3) and .BR pmNameInDom (3) may be used to enumerate all instance identifiers, and to translate between internal and external instance identifiers. .PP All of the instance identifiers for a particular performance metric are collectively known as an instance domain. Multiple performance metrics may share the same instance domain. .PP If only one instance is ever available for a particular performance metric, the instance identifier in the result from .BR pmFetch (3) assumes the special value .B PM_IN_NULL and may be ignored by the application, and only one instance-value pair appears in the result for that metric. Under these circumstances, the associated instance domain (as returned via .BR pmLookupDesc (3)) is set to .B PM_INDOM_NULL to indicate that values for this metric are singular. .PP The difficult issue of transient performance metrics (e.g. per-filesystem information, hot-plug replaceable hardware modules, etc.) means that repeated requests for the same PMID may return different numbers of values, and/or some changes in the particular instance identifiers returned. This means applications need to be aware that metric instantiation is guaranteed to be valid at the time of collection only. Similar rules apply to the transient semantics of the associated metric values. In general however, it is expected that the bulk of the performance metrics will have instantiation semantics that are fixed over the execution life-time of any PMAPI client. .SH "THE TYPE OF METRIC VALUES" The PMAPI supports a wide range of format and type encodings for the values of performance metrics, namely signed and unsigned integers, floating point numbers, 32-bit and 64-bit encodings of all of the above, ASCII strings (C-style, NULL byte terminated), and arbitrary aggregates of binary data. .PP The .CW type field in the .CW pmDesc structure returned by .BR pmLookupDesc (3) identifies the format and type of the values for a particular performance metric within a particular PMAPI context. .PP Note that the encoding of values for a particular performance metric may be different for different PMAPI contexts, due to differences in the underlying implementation for different contexts. However it is expected that the vast majority of performance metrics will have consistent value encoding across all versions of all implementations, and hence across all PMAPI contexts. .PP The PMAPI supports routines to automate the handling of the various value formats and types, particularly for the common case where conversion to a canonical format is desired, see .BR pmExtractValue (3) and .BR pmPrintValue (3). .SH "THE DIMENSIONALITY AND SCALE OF METRIC VALUES" Independent of how the value is encoded, the value for a performance metric is assumed to be drawn from a set of values that can be described in terms of their dimensionality and scale by a compact encoding as follows. The dimensionality is defined by a power, or index, in each of 3 orthogonal dimensions, namely Space, Time and Count (or Events, which are dimensionless). For example I/O throughput might be represented as Space/Time, while the running total of system calls is Count, memory allocation is Space and average service time is Time/Count. In each dimension there are a number of common scale values that may be used to better encode ranges that might otherwise exhaust the precision of a 32-bit value. This information is encoded in the .CW pmUnits structure which is embedded in the .CW pmDesc structure returned from .BR pmLookupDesc (3). .PP The routine .BR pmConvScale (3) is provided to convert values in conjunction with the .CW pmUnits structures that defines the dimensionality and scale of the values for a particular performance metric as returned from .BR pmFetch (3), and the desired dimensionality and scale of the value the PMAPI client wishes to manipulate. .SH "INSTANCE PROFILE" The set of instances for performance metrics returned from a .BR pmFetch (3) call may be filtered or restricted using an instance profile. There is one instance profile for each PMAPI context the application creates, and each instance profile may include instances from one or more instance domains. .PP The routines .BR pmAddProfile (3) and .BR pmDelProfile (3) may be used to dynamically adjust the instance profile. .SH "COLLECTION TIME" For each set of values for performance metrics returned via .BR pmFetch (3) there is an associated ``timestamp'' that serves to identify when the performance metric values were collected; for metrics being delivered from a real-time source (i.e. \c .BR pmcd (1) on some host) this would typically be not long before they were exported across the PMAPI, and for metrics being delivered from an archive log, this would be the time when the metrics were written into the archive log. .PP There is an issue here of exactly when individual metrics may have been collected, especially given their origin in potentially different Performance Metric Domains, and variability in the metric updating frequency at the lowest level of the Performance Metric Domain. The PMCS opts for the pragmatic approach, in which the PMAPI implementation undertakes to return all of the metrics with values accurate as of the timestamp, to the best of our ability. The belief is that the inaccuracy this introduces is small, and the additional burden of accurate individual timestamping for each returned metric value is neither warranted nor practical (from an implementation viewpoint). .PP Of course, in the case of collection of metrics from multiple hosts the PMAPI client must assume the sanity of the timestamps is constrained by the extent to which clock synchronization protocols are implemented across the network. .PP A PMAPI application may call .BR pmSetMode (3) to vary the requested collection time, e.g. to rescan performance metrics values from the recent past, or to ``fast-forward'' through an archive log. .SH "GENERAL ISSUES OF PMAPI PROGRAMMING STYLE" Across the PMAPI, all arguments and results involving a ``list of something'' are declared to be arrays with an associated argument or function value to identify the number of elements in the list. This has been done to avoid both the .BR varargs (3) approach and sentinel-terminated lists. .PP Where the size of a result is known at the time of a call, it is the caller's responsibility to allocate (and possibly free) the storage, and the called function will assume the result argument is of an appropriate size. Where a result is of variable size and that size cannot be known in advance (e.g. for .BR pmGetChildren (3), .BR pmGetInDom (3), .BR pmNameInDom (3), .BR pmNameID (3), .BR pmLookupText (3) and .BR pmFetch (3)) the PMAPI implementation uses a range of dynamic allocation schemes in the called routine, with the caller responsible for subsequently releasing the storage when no longer required. In some cases this simply involves calls to .BR free (3C), but in others (most notably for the result from .BR pmFetch (3)), special routines (e.g. \c .BR pmFreeResult (3)) should be used to release the storage. .PP As a general rule, if the called routine returns an error status then no allocation will have been done, and any pointer to a variable sized result is undefined. .SH DIAGNOSTICS Where error conditions may arise, the functions that comprise the PMAPI conform to a single, simple error notification scheme, as follows; .IP + 3n the function returns an integer .IP + 3n values >= 0 indicate no error, and perhaps some positive status, e.g. the number of things really processed .IP + 3n values < 0 indicate an error, with a global table of error conditions and error messages .PP The PMAPI routine .BR pmErrStr (3) translates error conditions into error messages. By convention, the small negative values are assumed to be negated versions of the Unix error codes as defined in .B and the strings returned are as per .BR strerror (3C). The larger, negative error codes are PMAPI error conditions. .PP One error, common to all PMAPI routines that interact with .BR pmcd (1) on some host is .BR PM_ERR_IPC , which indicates the communication link to .BR pmcd (1) has been lost. .SH "MULTI-THREADED APPLICATIONS" The original design for PCP was based around single-threaded applications, or more strictly applications in which only one thread was ever expected to call the PCP libraries. This restriction has been relaxed for .B libpcp to allow the most common PMAPI routines to be safely called from any thread in a multi-threaded application. .PP However the following groups of functions and services in .B libpcp are still restricted to being called from a single-thread, and this is enforced by returning .B PM_ERR_THREAD when an attempt to call the routines in each group from more than one thread is detected. .TP 4n 1. Any use of a .B PM_CONTEXT_LOCAL context, as the DSO PMDAs that are called directly from .B libpcp may not be thread-safe. .TP 4n 2. The interval timer services use global state with semantics that demand it is only used in the context of a single thread, so .BR __pmAFregister (3), .BR __pmAFunregister (3), .BR __pmAFblock (3), .B __pmAFunblock (3) and .BR __pmAFisempty (3). .TP 4n 3. The following (undocumented) access control manipulation routines that are principally intended for single-threaded applications: .BR __pmAccAddOp , .BR __pmAccSaveHosts , .BR __pmAccRestoreHosts , .BR __pmAccFreeSavedHosts , .BR __pmAccAddHost , .BR __pmAccAddClient , .B __pmAccDelClient and .BR __pmAccDumpHosts . .TP 4n 4. The following (undocumented) routines that identify .I pmlogger control ports and are principally intended for single-threaded applications: .B __pmLogFindPort and .BR __pmLogFindLocalPorts . .SH "PCP ENVIRONMENT" Most environment variables are described in .BR PCPIntro (1). In addition, environment variables with the prefix .B PCP_ are used to parameterize the file and directory names used by PCP. On each installation, the file .I /etc/pcp.conf contains the local values for these variables. The .B $PCP_CONF variable may be used to specify an alternative configuration file, as described in .BR pcp.conf (5). Values for these variables may be obtained programmatically using the .BR pmGetConfig (3) function. .SH SEE ALSO .BR PCPIntro (1), .BR PCPIntro (3), .BR PMAPI (3), .BR pmda (3), .BR pmGetConfig (3), .BR pcp.conf (5) and .BR pcp.env (5). pcp-3.8.12ubuntu1/man/man3/pmparsedebug.30000664000000000000000000000352712272262501014764 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMPARSEDEBUG 3 "PCP" "Performance Co-Pilot" .SH NAME \f3__pmParseDebug\f1 \- convert a list of debug flags into an integer .SH "C SYNOPSIS" .ft 3 #include .br #include .sp int __pmParseDebug(const char *\fIspec\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .B __pmParseDebug parses .I spec assuming it to be a comma separated list of PCP debug flags. .PP Each flag may be specified as an integer or the trailing portion of the symbolic name of the corresponding flag as reported by .BR pmdbg (1). Symbolic names are stripped of the ``DBG_TRACE_'' prefix and may appear in either case. .PP As a special case, the values ``\-1'' and ``ALL'' are treated as synonyms for turning on all bits except the sign bit in the result, i.e. \c .B INT_MAX from .IR . .PP For example the debug flag .B DBG_TRACE_FETCH is defined in .I /usr/include/pcp/impl.h and may be specified in .I spec as .BR 2 , .B FETCH or .BR fetch . .SH SEE ALSO .BR pmdbg (1) .SH DIAGNOSTICS If successful, .B __pmParseDebug returns the value computed by the bit-wise ``or'' of each flag in the .IR spec , suitable for assigning to the global debug trace control variable .BR pmDebug . Otherwise the return value is less than 0 to indicate a parsing error. pcp-3.8.12ubuntu1/man/man3/pmtime.30000664000000000000000000001313212272262501013572 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2009 Aconex. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMTIME 3 "Aconex" "Performance Co-Pilot" .SH NAME \f3pmtime\f1, \f3pmTimeConnect\f1, \f3pmTimeDisconnect\f1, \f3pmTimeRecv\f1, \f3pmTimeSendAck\f1, \f3pmTimeShowDialog\f1 \- time control functions for synchronizing the archive position and update interval between one or more applications .SH "C SYNOPSIS" .ft 3 #include .sp int pmTimeConnect(int \fIport\fP, pmTime *\fIstate\fP); .br int pmTimeDisconnect(int \fIfd\fP); .br int pmTimeSendAck(int \fIfd\fP, struct timeval *\fIfetchTime\fP); .br int pmTimeShowDialog(int \fIfd\fP, int \fIshow\fP); .br int pmTimeRecv(int \fIfd\fP, pmTime *\fIstate\fP); .sp cc ... \-lpcp_gui .ft 1 .SH DESCRIPTION These functions form part of the Performance Metrics Applications Programming Interface (PMAPI) and are intended to provide a uniform mechanism for applications to both replay archive data and report live data in a time synchronized manner. .PP The .I pmTime structure has the following fields: .sp 0.5v .ft CW .nf .in +0.25i typedef struct { unsigned int magic; unsigned int length; pm_tctl_command command; pm_tctl_source source; pm_tctl_state state; pm_tctl_mode mode; struct timeval delta; struct timeval position; struct timeval start; /* archive only */ struct timeval end; /* archive only */ char data[0]; /* arbitrary length info (TZ) */ } pmTime; .in -0.25i .fi .ft R .PP In the simplest case, the application should call .B pmTimeConnect to connect to the time control server, .BR pmtime (1), and then repeatedly call .B pmTimeRecv in the main loop of the application. On success, .B pmTimeConnect returns a non-negative file descriptor. In applications which have multiple threads of control, rather than simply blocking in .BR pmTimeRecv , the file descriptor may be used in calls to .BR select (2). In graphical applications, the file descriptor may be used to interface with the event loop. .PP The .I port parameter to .B pmTimeConnect is the port number of the socket on which the time control server is (or will be) listening for new connections. .PP The state parameter to .B pmTimeConnect is used to initialize a new time control server or to pass additional information to an existing time control server. The .I start and .I finish fields indicate the chronological bounds interesting to the application. The .I showdialog field indicates whether the time control server should initially show or hide the dialog. The .IR position , .IR delta, and .I data fields indicate the initial archive position, update interval, time zone string and time zone label string. .PP .B pmTimeRecv blocks until the time control server sends a command message. It then updates the state parameter and returns one of the PM_TCTL command identifiers. .PP The PM_TCTL_SET command indicates the application should seek to the archive position (see .BR pmSetMode (3)) returned in the position field of the state parameter. .PP The PM_TCTL_STEP command indicates the application should perform an update, i.e. advance (or rewind, if delta is negative) to the time indicated by position and then fetch new metric values, update the display or whatever. In order for several application to remain synchronized, the time control server will wait until all applications have acknowledged that they have completed the step command. Applications should call pmTimeSendAck when the step command has been processed. Note that PM_TCTL_STEP is the only command that requires an explicit acknowledgement. .PP The PM_TCTL_VCRMODE command is used by the time control server to indicate the current VCR mode. .PP The value is returned in the vcrmode field of the state parameter passed to .BR pmTimeRecv , and remains valid until the next PM_TCTL_VCRMODE command is received. .PP The PM_TCTL_TZ command indicates the application should use a new time- zone, as indicated in the .I tz and .I tzlabel fields of the state parameter. .PP The PM_TCTL_BOUNDS command is sent to all applications when the time control server changes its chronological bounds. This may occur when a new application connects to the time control server or the user changes the bounds manually. Most applications will ignore this command. .PP The PM_TCTL_SHOWDIALOG command will be sent to all applications when the visibility of the time control server changes. This allows applications to alter the text in menus or buttons to reflect this change. Applications may change the visibility of the time control dialog using the .B pmTimeShowDialog function. The initial visibility is determined when the time control dialog is first created by an application calling .B pmTimeConnect with the showdialog field in the state parameter set to the desired value. .PP The .B pmTimeDisconnect function may be used to close the command socket to the time control server. This is useful when applications need to change the connection mode, e.g. to divorce the current time control server and connect to a new one. .SH SEE ALSO .BR pmtime (1), .BR PMAPI (3) and .BR pmSetMode (3). pcp-3.8.12ubuntu1/man/man3/pmlookuptext.30000664000000000000000000000347212272262501015060 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMLOOKUPTEXT 3 "PCP" "Performance Co-Pilot" .SH NAME \f3pmLookupText\f1 \- return text describing a performance metric .SH "C SYNOPSIS" .ft 3 #include .sp .nf int pmLookupText(pmID \fIpmid\fP, int \fIlevel\fP, char **\fIbuffer\fP); .fi .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION Provided the source of metrics from the current Performance Metrics Application Programming Interface (PMAPI) context is a host, retrieve descriptive text about the performance metric identified by .IR pmid . .PP The argument .I level should be .BR PM_TEXT_ONELINE for a one-line summary, else .BR PM_TEXT_HELP for a more verbose description, suited to a help dialog. .PP The space pointed to by .I buffer will have been allocated in .B pmLookupText with .BR malloc (3C), and it is the responsibility of the caller to .BR free (3C) the space when it is no longer required. .PP .B pmLookupText returns zero on success. .SH SEE ALSO .BR chkhelp (1), .BR newhelp (1), .BR PMAPI (3), .BR pmGetConfig (3), .BR pmLookupDesc (3), .BR pmLookupInDomText (3), .BR pcp.conf (5) and .BR pcp.env (5). .SH DIAGNOSTICS .IP \f3PM_ERR_NOTHOST\f1 if the current PMAPI context is an archive log (help and one-line text is not maintained in the archive logs) pcp-3.8.12ubuntu1/man/man3/logimport.30000664000000000000000000000604112272262501014314 0ustar '\"macro stdmacro .\" .\" Copyright (c) 2010 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH LOGIMPORT 3 "" "Performance Co-Pilot" .SH NAME \f3LOGIMPORT\f1 \- introduction to the library for importing data and creating a PCP archive .SH "C SYNOPSIS" .ft 3 #include .br #include .br #include .sp cc ... \-lpcp_import \-lpcp .ft 1 .SH "Perl SYNOPSIS" .ft 3 use PCP::LogImport; .ft 1 .SH DESCRIPTION The Performance Co-Pilot Log Import (LOGIMPORT) API is a library (and Perl wrapper) that supports the creation of PCP archives from external sources of performance data, either in the form of historical logs and spreadsheets or from real-time sources that are .B not integrated as a Performance Metrics Domain Agent (PMDA) under the control of .BR pmcd (1). .PP The typical usage for LOGIMPORT would involve: .IP \(bu 3n An initial call to .BR pmiStart (3). .IP \(bu 3n Optional calls to .BR pmiSetHostname (3) and/or .BR pmiSetTimezone (3) to set the hostname and timezone for the source of the performance data. .IP \(bu 3n One or more calls to .BR pmiAddMetric (3) to define performance metrics. .IP \(bu 3n One or more calls to .BR pmiAddInstance (3) to define instances associated with the metrics. .IP \(bu 3n Optional calls to .BR pmiGetHandle (3) to defined convenience handles for metric-instance pairs. .IP \(bu 3n A main loop in which performance data is injested and for each sample time interval, the PCP archive record is constructed by calls to .BR pmiPutValue (3) and/or .BR pmiPutValueHandle (3), followed by a call to .BR pmiWrite (3) to flush all data and any associated new metadata to the PCP archive. Alternatively, .BR pmiPutResult (3) could be used to package and process all the data for one sample time interval. .IP \(bu 3n Once the input source of data has been consumed, calling .BR pmiEnd (3) to complete the PCP archive creation and close all open files. .PP If new metrics and/or instances are discovered during the data injestion, these can be added by subsequent calls to .BR pmiAddMetric (3) and/or .BR pmiAddInstance (3), provided all the metrics and instances have been defined before a call to .BR pmiGetHandle (3), .BR pmiPutValue (3) or .BR pmiPutResult (3) that references those metrics and instances. .SH SEE ALSO .BR pmcd (1), .BR pmlogger (1), .BR pmiGetHandle (3), .BR pmiAddInstance (3), .BR pmiAddMetric (3), .BR pmiEnd (3), .BR pmiErrStr (3), .BR pmiPutResult (3), .BR pmiPutValue (3), .BR pmiPutValueHandle (3), .BR pmiSetHostname (3), .BR pmiSetTimezone (3), .BR pmiStart (3) and .BR pmiWrite (3). pcp-3.8.12ubuntu1/man/man3/pmregisterderived.30000664000000000000000000002543312272262501016032 0ustar '\"! tbl | mmdoc '\"macro stdmacro .\" .\" Copyright (c) 2009 Ken McDonell. All Rights Reserved. .\" .\" This program is free software; you can redistribute it and/or modify it .\" under the terms of the GNU General Public License as published by the .\" Free Software Foundation; either version 2 of the License, or (at your .\" option) any later version. .\" .\" This program is distributed in the hope that it will be useful, but .\" WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY .\" or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License .\" for more details. .\" .\" .TH PMREGISTERDERIVED 3 "" "Performance Co-Pilot" .SH NAME \f3pmRegisterDerived\f1 \- register a derived metric name and definition .SH "C SYNOPSIS" .ft 3 #include .sp char *pmRegisterDerived(char *\fIname\fP, char *\fIexpr\fP); .sp cc ... \-lpcp .ft 1 .SH DESCRIPTION .PP Derived metrics provide a way of extending the Performance Metrics Name Space (PMNS) with new metrics defined at the PCP client-side using arithmetic expressions over the existing performance metrics. .PP Typical uses would be to aggregate a number of similar metrics to provide a higher-level summary metric or to support the ``delta V over delta V'' class of metrics that are not possible in the base data semantics of PCP. An example of the latter class would be the average I/O size, defined as .br .ce .ft CW delta(disk.dev.total_bytes) / delta(disk.dev.total) .ft R where both of the .ft CW disk.dev .ft R metrics are counters, and what is required is to to sample both metrics, compute the difference between the current and previous values and then calculate the ratio of these differences. .PP The arguments to .B pmRegisterDerived are the .I name of the new derived metric and .I expr is an arithmetic expression defining how the values of .I name should be computed. .PP .I name should follow the syntactic rules for the names of performance metrics, namely one or more components separated with a dot (``.''), and each component must begin with an alphabetic followed by zero or more characters drawn from the alphabetics, numerics and underscore (``_''). For more details, refer to .BR PCPIntro (1) and .BR pmns (5). .PP .I name must be unique across all derived metrics and should .B not match the name of any regular metric in the PMNS. It is acceptable for .I name to share some part of its prefix with an existing subtree of the PMNS, e.g. the average I/O size metric above could be named .ft CW disk.dev.avgsz .ft R which would place it amongst the other .ft CW disk.dev .ft R metrics in the PMNS. Alternatively, derived metrics could populate their own subtree of the PMNS, e.g. the average I/O size metric above could be named .ft CW my.summary.disk.avgsz\c .ft R \&. .PP The expression .I expr follows these syntactic rules: .IP * 2n Terminal elements are either names of existing metrics or integer constants. Recursive definitions are not allowed, so only the names of regular metrics (not other derived metrics) may be used. Integer constants are constrained to the precision of 32-bit unsigned integers. .IP * 2n The usual binary arithmetic operators are supported, namely \- addition (``+''), subtraction (``-''), multiplication (``*'') and division (``/'') with the normal precedence rules where multiplication and division have higher precedence than addition and subtraction, so .ft CW a+b*c .ft R is evaluated as .ft CW a+(b*c)\c .ft R . .IP * 2n Parenthesis may be used for grouping. .IP * 2n The following unary functions operate on a single performance metric and return one or more values. For all functions (except .ft CW count()\c .ft R ), the type of the operand metric must be arithmetic (integer of various sizes and signedness, float or double). .TS box,center; cf(R) | cf(R)w(5i) lf(CW) | lf(R). Function Value _ avg(x) T{ .fi A singular instance being the average value across all instances for the metric x. T} _ count(x) T{ .fi A singular instance being the count of the number of instances for the metric x. T} _ delta(x) T{ .fi Returns the difference in values for the metric x between one call to .BR pmFetch (3) and the next. There is one value in the result for each instance that appears in both the current and the previous sample. T} _ max(x) T{ .fi A singular instance being the maximum value across all instances for the metric x. T} _ min(x) T{ .fi A singular instance being the minimum value across all instances for the metric x. T} _ sum(x) T{ .fi A singular instance being the sum of the values across all instances for the metric x. T} .TE .IP * 2n White space is ignored. .PP Syntactic checking is performed at the time .B pmRegisterDerived is called, but semantic checking is deferred until each new context is created with .BR pmNewContext (3) or re-establised with .BR pmReconnectContext (3), at which time the PMNS and metadata is available to allow semantic checking and the metadata of the derived metrics to be established. .SH "SEMANTIC CHECKS AND RULES" .PP There are a number of conversions required to determine the metadata for a derived metric and to ensure the semantics of the expressions are sound. .PP In a binary expression, if the semantics of both operands is not a counter (i.e. PM_SEM_INSTANT or PM_SEM_DISCRETE) then the result will have semantics PM_SEM_INSTANT unless both operands are PM_SEM_DISCRETE in which case the result is also PM_SEM_DISCRETE. .PP The mapping of the pmUnits of the metadata uses the following rules: .IP * 2n If both operands have a dimension of COUNT and the scales are not the same, use the larger scale and convert the values of the operand with the smaller scale. .IP * 2n If both operands have a dimension of TIME and the scales are not the same, use the larger scale and convert the values of the operand with the smaller scale. .IP * 2n If both operands have a dimension of SPACE and the scales are not the same, use the larger scale and convert the values of the operand with the smaller scale. .IP * 2n For addition and subtraction all dimensions for each of the operands and result are identical. .IP * 2n For multiplication, the dimensions of the result are the sum of the dimensions of the operands. .IP * 2n For division, the dimensions of the result are the difference of the dimensions of the operands. .PP Scale conversion involves division if the dimension is positive else multiplication if the dimension is negative. If scale conversion is applied to either of the operands, the result is promoted to type PM_TYPE_DOUBLE. .PP Putting all of this together in an example, consider the derived metric defined as follows: .br .ad c .ft CW x = network.interface.speed - delta(network.interface.in.bytes) / delta(sample.milliseconds) .ft R .br .ad l The type, dimension and scale settings would propagate up the expression tree as follows. .TS box,center; cf(R) | cf(R) | cf(R) | cf(R) lf(CW) | lf(CW) | lf(R) | lf(R). Expression Type T{ .fi Dimension & Scale T} T{ .fi Scale Factor(s) T} _ sample.milliseconds DOUBLE millisec delta(...) DOUBLE millisec network...bytes U64 byte delta(...) U64 byte delta(...) / delta(...) DOUBLE byte/millisec T{ .fi /1048576 and *1000 T} network...speed FLOAT Mbyte/sec x DOUBLE Mbyte/sec .TE .PP Because semantic checking cannot be done at the time .B pmRegisterDerived is called, errors found during semantic checking are reported using .BR pmprintf (3). These include: .TP Error: derived metric : operand: : There was a problem calling .BR pmLookupName (3) to identify the operand metric used in the definition of the derived metric . .TP Error: derived metric : operand ( []): There was a problem calling .BR pmLookupDesc (3) to identify the operand metric with PMID used in the definition of the derived metric . .TP Semantic error: derived metric : : Illegal operator for counters If both operands have the semantics of counter, only addition or subtraction make sense, so multiplication and division are not allowed. .TP Semantic error: derived metric : : Illegal operator for counter and non-counter Only multiplication or division are allowed if the left operand has the semantics of a counter and the right operand is .B not a counter. .TP Semantic error: derived metric : : Illegal operator for non-counter and counter Only multiplication is allowed if the right operand has the semantics of a counter and the left operand is .B not a counter. .TP Semantic error: derived metric : : Non-arithmetic type for operand The binary arithmetic operators are only allowed with operands with an arithmetic type (integer of various sizes and signedness, float or double). .TP Semantic error: derived metric : (): Non-arithmetic operand for function The unary functions are only defined if the operand has arithmetic type. .SH "EXPRESSION EVALUATION" For the binary arithmetic operators, if either operand must be scaled (e.g. convert bytes to Kbytes) then the result is promoted to PM_TYPE_DOUBLE. Otherwise the type of the result is determined by the types of the operands, as per the following table which is evaluated from top to bottom until a match is found. .TS box,center; cf(R) | cf(R) | cf(R) lf(R) | lf(R) | lf(R). Operand Types Operator Result Type _ either is PM_TYPE_DOUBLE any PM_TYPE_DOUBLE _ any division PM_TYPE_DOUBLE _ either is PM_TYPE_FLOAT any PM_TYPE_FLOAT _ either is PM_TYPE_U64 any PM_TYPE_U64 _ either is PM_TYPE_64 any PM_TYPE_64 _ either is PM_TYPE_U32 any PM_TYPE_U32 _ T{ .fi otherwise (both are PM_TYPE_32) T} any PM_TYPE_32 .TE .SH CAVEATS .PP Unary negation is not supported, so the following expressions would be syntactically incorrect, .ft CW \-3*abc .ft R and .ft CW \-this.number\c .ft R . .PP Derived metrics are not available when using .BR pmFetchArchive (3) as this routine does not use a target list of PMIDs that could be remapped (as is done for .BR pmFetch (3)). .PP .B pmRegisterDerived does not apply retrospectively to any open contexts, so the normal use would be to make all calls to .B pmRegisterDerived (possibly via .BR pmLoadDerivedConfig (3)) and then call .BR pmNewContext (3). .PP There is no .B pmUnregisterDerived method, so once registered a derived metric persists for the life of the application. .SH DIAGNOSTICS .PP On success, .B pmRegisterDerived returns NULL. .PP If a syntactic error is found at the time of registration, the value returned by .B pmRegisterDerived is a pointer into .I expr indicating .B where the error was found. To identify .B what the error was, the application should call .BR pmDerivedErrStr (3) to retrieve the corresponding parser error message. .SH SEE ALSO .BR PCPIntro (1), .BR PMAPI (3), .BR pmDerivedErrStr (3), .BR pmFetch (3), .BR pmLoadDerivedConfig (3), .BR pmNewContext (3) and .BR pmReconnectContext (3). pcp-3.8.12ubuntu1/configure.in0000664000000000000000000017521212272262501013123 0ustar dnl dnl Copyright (c) 2012-2013 Red Hat. dnl Copyright (c) 2008 Aconex. All Rights Reserved. dnl Copyright (c) 2000-2004,2008 Silicon Graphics, Inc. All Rights Reserved. dnl dnl This program is free software; you can redistribute it and/or modify it dnl under the terms of the GNU General Public License as published by the dnl Free Software Foundation; either version 2 of the License, or (at your dnl option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY dnl or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License dnl for more details. dnl dnl unpacking check - this file must exist AC_INIT(src/include/pcp/pmapi.h) AC_PREREQ([2.60])dnl dnl Irix build issue ... use the tools from the local filesystems unset ROOT TOOLROOT AC_ARG_WITH( [64bit], [AS_HELP_STRING([--with-64bit], [turn on 64 bit compilation mode (default is platform dependent)])], [use_64bit=$withval; PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --with-64bit=$withval"]) AC_ARG_WITH( [threads], [AC_HELP_STRING([--with-threads], [enable support for multiple threads (default is on)])], [do_threads=$withval; PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --with-threads=$withval"], [do_threads=check]) AC_ARG_WITH( [secure-sockets], [AC_HELP_STRING([--with-secure-sockets], [enable support for secure sockets (default is on)])], [do_secure=$withval; PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --with-secure-sockets=$withval"], [do_secure=check]) AC_ARG_WITH( [static-probes], [AC_HELP_STRING([--with-static-probes], [enable support for static probes (default is on)])], [do_probes=$withval; PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --with-static-probes=$withval"], [do_probes=check]) AC_ARG_WITH( [infiniband], [AC_HELP_STRING([--with-infiniband], [enable support for Infiniband metrics (default is on)])], [do_infiniband=$withval; PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --with-infiniband=$withval"], [do_infiniband=check]) AC_ARG_WITH( [user], [AS_HELP_STRING([--with-user], [user account under which daemons run (default is pcp)])], [pcp_user=$withval; PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --with-user-account=$withval"], [pcp_user=pcp]) AC_SUBST(pcp_user) AC_ARG_WITH( [group], [AS_HELP_STRING([--with-group], [user group under which daemons run (default is pcp)])], [pcp_group=$withval; PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --with-group-account=$withval"], [pcp_group=pcp]) AC_SUBST(pcp_group) AC_ARG_WITH([discovery], [AC_HELP_STRING([--with-discovery], [enable support for service discovery (default is on)])], [do_discovery=$withval; PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --with-discovery=$withval"], [do_discovery=check]) # # Note: the following environment variables may be # set to override the defaults. # # MAKE CC CPP LD LEX YACC INSTALL AWK SED ECHO # dnl Guess target platfrom AC_CANONICAL_SYSTEM if test -z "$target" then echo echo ' FATAL ERROR: Cannot guess your target, try explicit specification using --target or, if that fails, add it to config.guess and send a copy to pcp@oss.sgi.com.' rm -rf conftest conftest.* exit 1 else dnl Remove 4th name component, if present, from target, target_os, dnl build and build_os. Squash all x86 cpus into one LCD form - i386 target=`echo $target | sed '[s/^\([^-][^-]*-[^-][^-]*-[^-][^-]*\)-.*$/\1/]'` target_os=`echo $target_os | sed '[s/solaris2\..*/solaris/]'` target_os=`echo $target_os | sed '[s/^\([^-][^-]*\)-.*$/\1/]' | sed '[s/[\.0-9]*//g]'` target_cpu=`echo $target_cpu | sed '[s/i[3-6]86/i386/]' | sed '[s/powerpc/ppc/]'` build=`echo $build | sed '[s/^\([^-][^-]*-[^-][^-]*-[^-][^-]*\)-.*$/\1/]'` build_os=`echo $build_os | sed '[s/solaris2\..*/solaris/]'` build_os=`echo $build_os | sed '[s/^\([^-][^-]*\)-.*$/\1/]'` build_cpu=`echo $build_cpu | sed '[s/i[3-6]86/i386/]' | sed '[s/powerpc/ppc/]'` fi echo Building on $build for $target echo "Build: os=$build_os cpu=$build_cpu" echo "Target: os=$target_os cpu=$target_cpu" dnl CFLAGS setting is a co-dependency between here and PCFLAGS in dnl src/include/builddefs.in ... need to be the same in both places target_distro=$target_os if test $target_os = linux then AC_DEFINE(IS_LINUX) test -f /etc/SuSE-release && target_distro=suse test -f /etc/fedora-release && target_distro=fedora test -f /etc/redhat-release && target_distro=redhat test -f /etc/debian_version && target_distro=debian test -f /etc/slackware-version && target_distro=slackware test -f /etc/gentoo-release && target_distro=gentoo test -f /etc/mandriva-release && target_distro=mandriva export CFLAGS="-fPIC -fno-strict-aliasing -D_GNU_SOURCE" elif test $target_os = darwin then AC_DEFINE(IS_DARWIN) target_distro=macosx version=`sw_vers -productVersion | sed -e 's/\.//' -e 's/\..*//g'` CFLAGS="-fPIC -no-cpp-precomp -fno-strict-aliasing -arch i386" if test $version -ge 106 then target_distro=cocoa CFLAGS="$CFLAGS -arch x86_64" fi export CFLAGS elif test $target_os = mingw then AC_DEFINE(IS_MINGW) CFLAGS="-fno-strict-aliasing" export CPPFLAGS="$CPPFLAGS -I$PCP_DIR/include -I$PCP_DIR/local/include" export CFLAGS="$CFLAGS -I$PCP_DIR/include -I$PCP_DIR/local/include" export LDFLAGS="$LDFLAGS -L$PCP_DIR/lib -L$PCP_DIR/local/lib" export PATH="$PATH:$PCP_DIR/bin:$PCP_DIR/local/bin" elif test $target_os = solaris then AC_DEFINE(IS_SOLARIS) export PATH="$PATH:/opt/SunStudioExpress/bin" export CFLAGS_IF_GCC="-fPIC -fno-strict-aliasing" export CFLAGS_IF_SUNCC="-fPIC -xalias_level=any" elif test $target_os = aix then AC_DEFINE(IS_AIX) export CFLAGS="-qcpluscmt" elif test $target_os = freebsd || test $target_os = kfreebsd then AC_DEFINE(IS_FREEBSD) test -f /etc/debian_version && target_distro=debian export CFLAGS="-fPIC -fno-strict-aliasing -D_GNU_SOURCE" elif test $target_os = netbsdelf then target_os=netbsd AC_DEFINE(IS_NETBSD) export CFLAGS="-fPIC -fno-strict-aliasing -D_GNU_SOURCE -D_NETBSD_SOURCE" else echo echo "FATAL ERROR: need platform-specific customization for \"$target_os\"" rm -rf conftest conftest.* exit 1 fi # Add some security-related gcc flags AC_ARG_ENABLE([ssp], [AS_HELP_STRING([--disable-ssp], [disable gcc stack-protector])]) AS_IF([test "x$enable_ssp" != xno],[ save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fstack-protector-all -D_FORTIFY_SOURCE=2" AC_COMPILE_IFELSE([AC_LANG_SOURCE([int something ();])], [ AC_MSG_NOTICE([Compiling with gcc -fstack-protector-all et al.]) CFLAGS="$save_CFLAGS -fstack-protector-all -D_FORTIFY_SOURCE=2"],[ AC_MSG_NOTICE([Compiler does not support -fstack-protector-all et al.]) CFLAGS="$save_CFLAGS"])]) # Check for even more security-related gcc/linker flags, useful for daemons AC_ARG_ENABLE([pie], [AS_HELP_STRING([--disable-pie], [disable position-independent-executable])]) AS_IF([test "x$enable_pie" != xno],[ PIECFLAGS='-fPIE' PIELDFLAGS='-pie -Wl,-z,relro -Wl,-z,now' save_CFLAGS="$CFLAGS" save_LDFLAGS="$LDFLAGS" CFLAGS="$CFLAGS $PIECFLAGS" LDFLAGS="$LDFLAGS $PIELDFLAGS" AC_LINK_IFELSE([AC_LANG_SOURCE([void main () {}])], [ AC_MSG_NOTICE([Compiling with gcc pie et al.]) ], [ AC_MSG_NOTICE([Compiler does not support -pie et al.]) PIECFLAGS="" PIELDFLAGS="" ]) CFLAGS="$save_CFLAGS" LDFLAGS="$save_LDFLAGS" ]) AC_SUBST(PIELDFLAGS) AC_SUBST(PIECFLAGS) # Check for support for symbol hiding via gcc flags AC_ARG_ENABLE([visibility], [AS_HELP_STRING([--disable-visibility], [disable gcc symbol visibility])]) AS_IF([test "x$enable_visibility" != xno],[ INVISIBILITY="-fvisibility=hidden" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -c $INVISIBILITY" AC_COMPILE_IFELSE([AC_LANG_SOURCE([int visible () { return 0; }])], [ AC_MSG_NOTICE([Compiling DSO PMDAs with gcc -fvisibility=hidden]) ], [ AC_MSG_NOTICE([Compiler does not support -fvisibility.]) INVISIBILITY="" ]) CFLAGS="$save_CFLAGS" ]) AC_SUBST(INVISIBILITY) # Prevent shared libaries from being built for libpcp and other core libraries AC_ARG_ENABLE([shared], [AS_HELP_STRING([--disable-shared], [disable core shared libary generation])], [PACKAGE_CONFIGURE="$PACKAGE_CONFIGURE --disable-shared=$withval"]) AC_SUBST(enable_shared) dnl Check for static probes (dtrace, systemtap) if test "$do_probes" = "check" -o "$do_probes" = "yes" then enable_probes=true AC_CHECK_PROGS(DTRACE, dtrace, [enable_probes=false]) if test "$do_probes" = "yes" -a $enable_probes = "false" then AC_MSG_ERROR(cannot enable static probes - no toolchain) fi AC_CHECK_HEADERS([sys/sdt.h], [ enable_probes=true if test $target_os = kfreebsd then enable_probes=false fi ], [ enable_probes=false if test "$do_probes" = "yes" then AC_MSG_ERROR(cannot enable static probes - no SDT header) fi ]) if test "$enable_probes" = "true" then AC_DEFINE(HAVE_STATIC_PROBES) fi AC_SUBST(enable_probes) AC_SUBST(DTRACE) fi dnl Check for service discovery mechanisms (DNS-SD, Avahi) AS_IF([test "x$do_discovery" != "xno"], [ # on Mac OS X, dns_sd.h # on Linux, aloha Avahi enable_avahi=true PKG_CHECK_MODULES([avahi], [avahi-client], [AC_CHECK_LIB(avahi-client, avahi_client_new, [lib_for_avahi="-lavahi-common -lavahi-client"], [enable_avahi=false]) ],[enable_avahi=false]) AC_CHECK_HEADERS([avahi-client/publish.h],, [enable_avahi=false]) AC_CHECK_HEADERS([avahi-common/alternative.h],, [enable_avahi=false]) if test "$enable_avahi" = "true" then AC_SUBST(lib_for_avahi) AC_SUBST(avahi_CFLAGS) AC_DEFINE(HAVE_AVAHI) enable_discovery=true fi if test "$do_discovery" != "check" -a "$enable_discovery" != "true" then AC_MSG_ERROR(cannot enable service discovery - no supported mechanisms) fi if test "$enable_discovery" = "true" then AC_DEFINE(HAVE_SERVICE_DISCOVERY) fi ]) AC_SUBST(enable_discovery) AC_SUBST(enable_avahi) # setup additional platform-specific binary search PATH components pcp_platform_paths="" case $target_os in aix) pcp_platform_paths='/usr/bin/X11:/usr/local/bin';; linux|kfreebsd) pcp_platform_paths='/usr/bin/X11:/usr/local/bin';; mingw) pcp_platform_paths='';; darwin) pcp_platform_paths='/usr/local/bin';; solaris) pcp_platform_paths='/usr/bin/X11:/usr/local/bin:/opt/sfw/bin:/usr/sfw/bin';; freebsd) pcp_platform_paths='/usr/bin/X11:/usr/bsd';; netbsd) pcp_platform_paths='/usr/pkg/bin';; esac AC_SUBST(pcp_platform_paths) # NB: No AC_PREFIX_DEFAULT is needed, as the default configure invocation # targets a build for non-system directories such as /usr/local. # AC_PREFIX_DEFAULT([]) if test -f VERSION.pcp then . ./VERSION.pcp fi if test -z "$PACKAGE_MAJOR" ; then PACKAGE_MAJOR=1 fi for V in MINOR REVISION BUILD; do P=`eval echo \\$PACKAGE_$i` if test -z "$P"; then eval PACKAGE_${i}=0 fi done PACKAGE_VERSION=${PACKAGE_MAJOR}.${PACKAGE_MINOR}.${PACKAGE_REVISION} AC_SUBST(PACKAGE_VERSION) AC_SUBST(PACKAGE_MAJOR) AC_SUBST(PACKAGE_MINOR) AC_SUBST(PACKAGE_REVISION) AC_SUBST(PACKAGE_BUILD) if test -z "$PACKAGE_BUILD_DATE" ; then PACKAGE_BUILD_DATE=`date +%Y-%m-%d` fi AC_SUBST(PACKAGE_BUILD_DATE) if test -z "$PACKAGE_DISTRIBUTION" ; then PACKAGE_DISTRIBUTION=$target_distro fi AC_SUBST(PACKAGE_DISTRIBUTION) dnl output header with cpp defs HAVE_*, etc AC_CONFIG_HEADER(src/include/pcp/config.h) AC_OUTPUT(src/include/pcp/platform_defs.h) AC_CHECK_PROGS(GIT, git) AC_SUBST(GIT) AC_CHECK_PROGS(PYTHON, python) AC_SUBST(PYTHON) dnl check if user wants their own C compiler cflags_abi= AC_PROG_CC(suncc gcc cc) if test $target_os = solaris then AC_PATH_PROG(CCPATH,$CC,$CC) cc=$CCPATH if test "$GCC" = "yes" then CFLAGS="$CFLAGS $CFLAGS_IF_GCC" else CFLAGS="$CFLAGS $CFLAGS_IF_SUNCC" fi if test "$use_64bit" = "no" then : else AC_MSG_CHECKING([for 64 bit Solaris host]) case `isainfo -k` in amd64|sparcv9) cflags_abi=-m64 CFLAGS="$CFLAGS -m64" LDFLAGS="$LDFLAGS -m64" AC_MSG_RESULT(yes) ;; *) AC_MSG_RESULT(no) ;; esac fi else cc=$CC fi AC_SUBST(cc) cc_is_gcc=$GCC AC_SUBST(cc_is_gcc) AC_SUBST(cflags_abi) PCFLAGS=$CFLAGS AC_SUBST(PCFLAGS) AC_PROG_CXX cxx=$CXX AC_SUBST(cxx) PLDFLAGS=$LDFLAGS AC_SUBST(PLDFLAGS) dnl for cc use locally in configure (not exported via $PCFLAGS), dnl add -O in case -D_FORTIFY_SOURCE has been added to CFLAGS above, dnl as -D_FORTIFY_SOURCE requires -O but we've separated optimization dnl flags out into $CFLAGS_OPT for our build infrastructure CFLAGS="-O $CFLAGS" dnl check if user wants their own make program dnl note: all makefiles in this package use the gmake syntax if test -z "$MAKE" then AC_PATH_PROG(MAKE, gmake) if test -z "$MAKE" then # look elsewhere ... AC_MSG_CHECKING([for GNU make elsewhere]) for f in /usr/local/bin/gmake /usr/freeware/bin/gmake /usr/local/bin/make /opt/sfw/bin/gmake nowhere do if test -x $f then MAKE=$f break fi done if test $f = nowhere then # Check if /usr/bin/make is any good mver=`/usr/bin/make --version 2>/dev/null | sed -n -e1p | cut -c1-8` if test "$mver" != "GNU Make" then echo echo "FATAL ERROR: could not find GNU make anywhere" echo "You need to set \$MAKE as the full path to GNU make " echo "in the environment." rm -rf conftest conftest.* exit 1 else MAKE=/usr/bin/make fi fi AC_MSG_RESULT($MAKE) fi fi make=$MAKE AC_SUBST(make) dnl check if users wants their own CPP if test -z "$CPP"; then AC_PROG_CPP fi cpp=$CPP AC_SUBST(cpp) dnl check if users wants their own linker if test -z "$LD"; then AC_PATH_PROG(LD, ld, /usr/bin/ld) fi ld=$LD AC_SUBST(ld) dnl Provide ways to override owner and group for installed files if test -z "$PCP_USER_INSTALL" ; then pcp_user_install=root else pcp_user_install="$PCP_USER_INSTALL" fi AC_SUBST(pcp_user_install) if test -z "$PCP_GROUP_INSTALL" ; then case "$target_os" in darwin|freebsd|netbsd) pcp_group_install=wheel ;; *) pcp_group_install=root ;; esac else pcp_group_install="$PCP_GROUP_INSTALL" fi AC_SUBST(pcp_group_install) dnl check if the tar program is available if test -z "$TAR"; then AC_PATH_PROGS(TAR, gtar tar, tar) fi if test $target_os = darwin -a -x /usr/bin/gnutar then TAR=/usr/bin/gnutar fi tar=$TAR AC_SUBST(tar) dnl check if the gzip program is available dnl (needed to gzip man pages on some platforms) if test -z "$ZIP"; then AC_PATH_PROG(ZIP, gzip, /bin/gzip) fi test ! -x "$ZIP" && ZIP=/usr/local/bin/gzip test ! -x "$ZIP" && ZIP=/usr/freeware/bin/gzip test ! -x "$ZIP" && ZIP=/usr/bin/gzip gzip=$ZIP test -z "$gzip" && gzip=no-gzip AC_SUBST(gzip) dnl check if the bzip2 program is available dnl (needed to bzip2 man pages on some platforms) if test -z "$BZIP2"; then AC_PATH_PROG(BZIP2, bzip2, /bin/bzip2) fi test ! -x "$BZIP2" && BZIP2=/usr/bin/bzip2 test ! -x "$BZIP2" && BZIP2=/usr/local/bin/bzip2 test ! -x "$BZIP2" && BZIP2=/usr/freeware/bin/bzip2 bzip2=$BZIP2 test -z "$bzip2" && bzip2=no-bzip2 AC_SUBST(bzip2) dnl check if the lzma program is available dnl (needed to lzma man pages on some platforms) if test -z "$LZMA"; then AC_PATH_PROG(LZMA, lzma, /bin/lzma) fi test ! -x "$LZMA" && LZMA=/usr/bin/lzma test ! -x "$LZMA" && LZMA=/usr/local/bin/lzma test ! -x "$LZMA" && LZMA=/usr/freeware/bin/lzma lzma=$LZMA test -z "$lzma" && lzma=no-lzma AC_SUBST(lzma) dnl check if the xz program is available dnl (needed to xz man pages on some platforms) if test -z "$XZ"; then AC_PATH_PROG(XZ, xz, /bin/xz) fi test ! -x "$XZ" && XZ=/usr/bin/xz test ! -x "$XZ" && XZ=/usr/local/bin/xz test ! -x "$XZ" && XZ=/usr/freeware/bin/xz xz=$XZ test -z "$xz" && xz=no-xz AC_SUBST(xz) dnl Check for mac PackageMaker AC_MSG_CHECKING([for PackageMaker]) if test -z "$PACKAGE_MAKER" then if test $target_os = darwin then if test -x /Developer/Applications/PackageMaker.app/Contents/MacOS/PackageMaker then # Darwin 6.x package_maker=/Developer/Applications/PackageMaker.app/Contents/MacOS/PackageMaker AC_MSG_RESULT([ yes (darwin 6.x)]) elif test -x /Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker then # Darwin 7.x AC_MSG_RESULT([ yes (darwin 7.x)]) package_maker=/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker else AC_MSG_RESULT([ not found!]) AC_MSG_WARN([PackageMaker not found, mac packages will not be made]) fi else AC_MSG_RESULT([ no]) fi else package_maker="$PACKAGE_MAKER" fi AC_SUBST(package_maker) dnl check if the hdiutil program is available if test -z "$HDIUTIL"; then AC_PATH_PROG(HDIUTIL, hdiutil) fi hdiutil=$HDIUTIL AC_SUBST(hdiutil) dnl check if the mkinstallp program is available (AIX) if test -z "$MKINSTALLP"; then AC_PATH_PROG(MKINSTALLP, mkinstallp) fi mkinstallp=$MKINSTALLP AC_SUBST(mkinstallp) dnl check for the Solaris pmgmk package maker if test -z "$PKGMK"; then AC_PATH_PROG(PKGMK, pkgmk) fi pkgmk=$PKGMK AC_SUBST(pkgmk) dnl check if the dlltool program is available if test -z "$DLLTOOL"; then AC_PATH_PROG(DLLTOOL, dlltool) fi dlltool=$DLLTOOL AC_SUBST(dlltool) dnl check if the rpmbuild program is available if test -z "$RPMBUILD"; then AC_PATH_PROG(RPMBUILD, rpmbuild) fi test $target_distro = slackware && RPMBUILD='' rpmbuild=$RPMBUILD AC_SUBST(rpmbuild) dnl check if the rpm program is available if test -z "$RPM"; then AC_PATH_PROG(RPM, rpm) fi test $target_distro = slackware && RPM='' rpm=$RPM AC_SUBST(rpm) dnl if rpmbuild exists, use it, otherwise use rpm if test -n "$RPMBUILD" -a -x "$RPMBUILD" then rpmprog=$RPMBUILD else rpmprog=$RPM fi AC_SUBST(rpmprog) dnl check if the pod2man program is available (perl man page builder) if test -z "$POD2MAN"; then AC_PATH_PROG(POD2MAN, pod2man) fi pod2man=$POD2MAN AC_SUBST(pod2man) dnl extra check for the Perl MakeMaker package AC_MSG_CHECKING([if ExtUtils::MakeMaker is installed]) perl -e "use ExtUtils::MakeMaker" 2>/dev/null if test $? -eq 0 then AC_MSG_RESULT([ yes]) else AC_MSG_RESULT([ no]) echo echo "FATAL ERROR: Perl ExtUtils::MakeMaker module missing." echo "You can either install this from your distribution, or" echo "download from CPAN (Comprehensive Perl Archive Network)." rm -rf conftest conftest.* exit 1 fi AC_PATH_PROG(TRUEPROG, true) dnl check if the makedepend program is available if test -z "$MAKEDEPEND"; then AC_PATH_PROG(MAKEDEPEND, makedepend, $TRUEPROG) fi makedepend=$MAKEDEPEND AC_SUBST(makedepend) dnl check if the md5sum program is available if test -z "$MD5SUM"; then AC_PATH_PROG(MD5SUM, md5sum, $TRUEPROG) fi md5sum=$MD5SUM AC_SUBST(md5sum) dnl check if the Debian dpkg program is available if test -z "$DPKG"; then AC_PATH_PROG(DPKG, dpkg) fi dpkg=$DKPG AC_SUBST(dpkg) dnl check for the Slackware makepkg packaging tool if test -z "$MAKEPKG"; then AC_PATH_PROG(MAKEPKG, makepkg) fi makepkg=$MAKEPKG AC_SUBST(makepkg) dnl check if symbolic links are supported AC_PROG_LN_S if test $target_os = mingw; then as_ln_s=/bin/true fi dnl check if user wants their own lex, yacc AC_PROG_LEX lex=$LEX AC_SUBST(lex) AC_PROG_YACC yacc=$YACC AC_SUBST(yacc) dnl extra check for lex and yacc as these are often not installed AC_MSG_CHECKING([if yacc is executable]) binary=`echo $yacc | awk '{print $1}'` binary=`which "$binary"` if test -x "$binary" then AC_MSG_RESULT([ yes]) else AC_MSG_RESULT([ no]) echo echo "FATAL ERROR: did not find a valid yacc executable." echo "You can either set \$YACC as the full path to yacc" echo "in the environment, or install a yacc/bison package." rm -rf conftest conftest.* exit 1 fi AC_MSG_CHECKING([if lex is executable]) binary=`echo $lex | awk '{print $1}'` binary=`which "$binary"` if test -x "$binary" then AC_MSG_RESULT([ yes]) else AC_MSG_RESULT([ no]) echo echo "FATAL ERROR: did not find a valid lex executable." echo "You can either set \$LEX as the full path to lex" echo "in the environment, or install a lex/flex package." rm -rf conftest conftest.* exit 1 fi dnl check if user wants their own awk, sed and echo if test -z "$AWK"; then AC_PATH_PROGS(AWK, gawk awk, /usr/bin/awk) fi case "$AWK" in gawk|*/gawk) awk="$AWK --posix" ;; *) awk=$AWK ;; esac AC_SUBST(awk) if test -z "$SED"; then AC_PATH_PROG(SED, sed, /bin/sed) fi sed=$SED AC_SUBST(sed) if test -z "$ECHO"; then AC_PATH_PROG(ECHO, echo, /bin/echo) fi echo=$ECHO AC_SUBST(echo) dnl check we don't get the Windows sort ... AC_MSG_CHECKING([where unix-like sort(1) lives]) if test $target_os = mingw; then for d in /bin /usr/bin /mingw/bin /mingw/usr/bin do if test -x $d/sort; then sort=$d/sort break fi done else sort=`which sort` fi AC_MSG_RESULT($sort) $sort -n /dev/null then if ( $echo -n testing; $echo 1,2,3 ) | sed s/-n/xn/ | grep xn >/dev/null then echo_n= echo_c= AC_MSG_RESULT([neither?]) else echo_n=-n echo_c= AC_MSG_RESULT([ -n]) fi else echo_n= echo_c='\c' AC_MSG_RESULT([backslash-c]) fi AC_SUBST(echo_n) AC_SUBST(echo_c) dnl if /proc is not mounted, try and mount it dnl before trying to run the ps style test below if test -d /proc then test -f /proc/stat || mount /proc >/dev/null 2>&1 fi dnl set platform specific ps if test -n "$PROCPS" then pcp_ps_prog="$PROCPS" else pcp_ps_prog=ps fi AC_SUBST(pcp_ps_prog) dnl ps variants, need $pcp_ps_prog and $awk from above dnl want user in col 1, pid in col 2, and command+ps args at the end AC_MSG_CHECKING([for ps style]) pcp_ps_all_flags='' if $pcp_ps_prog -ef >conftest.out 2>/dev/null then ans=`$awk conftest.out 2>/dev/null then ans=`$awk conftest.out 2>/dev/null then if test $target_os = mingw then pcp_ps_have_bsd=false pcp_ps_all_flags=-eflW AC_MSG_RESULT(MinGW) fi fi if test -z "$pcp_ps_all_flags" then dnl this is bad ... need to expand the cases or relax the tests AC_MSG_RESULT(unknown) echo "FATAL ERROR: could not determine how to get the \"all processes with arguments\"" echo "format output from your ps(1)." rm -rf conftest conftest.* exit 1 fi dnl checking for w(ide) option so more psargs chars if $pcp_ps_prog ${pcp_ps_all_flags}w >/dev/null 2>&1 then if test $target_os != solaris then pcp_ps_all_flags=${pcp_ps_all_flags}w fi fi AC_SUBST(pcp_ps_have_bsd) AC_SUBST(pcp_ps_all_flags) dnl set platform specific event logger if test $target_os = mingw then pcp_syslog_prog=pcp-eventlog else pcp_syslog_prog=logger fi AC_SUBST(pcp_syslog_prog) grep=grep if test $target_os = solaris then test -f /usr/xpg4/bin/grep && grep=/usr/xpg4/bin/grep fi AC_SUBST(grep) if test -n "$WHICH" then which=$WHICH elif sh -c 'type -p sh' >/dev/null 2>&1 then which=type else which=which fi AC_SUBST(which) dnl checks for /proc pseudo file system AC_MSG_CHECKING([for /proc ]) if test -d /proc then AC_DEFINE(HAVE_PROCFS) AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi dnl Checks for C header files. AC_HEADER_DIRENT AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_CHECK_HEADERS(fcntl.h limits.h malloc.h strings.h syslog.h) AC_CHECK_HEADERS(unistd.h stddef.h sched.h dlfcn.h dl.h) AC_CHECK_HEADERS(sys/time.h sys/timeb.h sys/times.h) AC_CHECK_HEADERS(sys/resource.h sys/prctl.h) AC_CHECK_HEADERS(sys/sysinfo.h sys/systeminfo.h) AC_CHECK_HEADERS(endian.h standards.h sys/byteorder.h getopt.h) AC_CHECK_HEADERS(libgen.h sys/param.h sys/mman.h sys/un.h) AC_CHECK_HEADERS(values.h stdint.h ieeefp.h math.h) AC_CHECK_HEADERS(pwd.h grp.h regex.h sys/wait.h) AC_CHECK_HEADERS(termio.h termios.h sys/termios.h sys/ioctl.h) AC_CHECK_HEADERS(netdb.h sys/socket.h netinet/in.h netinet/tcp.h arpa/inet.h) AC_CHECK_HEADERS(windows.h winsock2.h ws2tcpip.h) AC_CHECK_HEADERS(execinfo.h) AC_CHECK_HEADERS(iptypes.h, [], [], [#include ]) dnl Check if we have ... standard way AC_MSG_CHECKING([for sys/endian.h ]) AC_TRY_COMPILE( [ #include ], [ ], AC_DEFINE(HAVE_SYS_ENDIAN_H) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) dnl Check if we have ... MacOSX way AC_MSG_CHECKING([for machine/endian.h ]) AC_TRY_COMPILE( [ #include ], [ ], AC_DEFINE(HAVE_MACHINE_ENDIAN_H) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) dnl Check if we have ... IRIX strangeness AC_MSG_CHECKING([for sys/endian.h (IRIX variant) ]) AC_TRY_COMPILE( [ #include #include ], [ ], AC_DEFINE(HAVE_SYS_ENDIAN_H) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) dnl Checks for typedefs, structures, and compiler characteristics. AC_C_CONST AC_TYPE_OFF_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_HEADER_TIME AC_STRUCT_TM AC_C_INLINE dnl check if regex functions come from libregex (mingw) AC_CHECK_LIB(regex, regcomp) lib_for_regex="" if test $ac_cv_lib_regex_regcomp = yes then lib_for_regex="-lregex" fi AC_SUBST(lib_for_regex) PKG_CHECK_MODULES([SYSTEMD], [libsystemd-journal], [ pmda_systemd=systemd ], [ pmda_systemd= ]) AC_SUBST(PMDA_SYSTEMD, $pmda_systemd) pmda_infiniband= if test "$do_infiniband" = "check" -o "$do_infiniband" = "yes" then AC_CHECK_HEADERS([infiniband/umad.h], [ AC_CHECK_HEADERS([infiniband/mad.h], [pmda_infiniband=infiniband], []) ], []) IB_LIBS="" AC_CHECK_LIB(ibmad, madrpc_init) AC_CHECK_LIB(ibumad, umad_init) if test $ac_cv_lib_ibmad_madrpc_init = yes -a $ac_cv_lib_ibumad_umad_init = yes then IB_LIBS="-libmad -libumad" savedLIBS=$LIBS LIBS="$IB_LIBS" AC_MSG_CHECKING([for port_performance_query_via]) AC_TRY_LINK_FUNC(port_performance_query_via, AC_DEFINE(HAVE_PORT_PERFORMANCE_QUERY_VIA) have_port_performance_query_via=true AC_MSG_RESULT(yes), have_port_performance_query_via=false AC_MSG_RESULT(no)) AC_MSG_CHECKING([for pma_query_via]) AC_TRY_LINK_FUNC(pma_query_via, AC_DEFINE(HAVE_PMA_QUERY_VIA) have_pma_query_via=true AC_MSG_RESULT(yes), have_pma_query_via=false AC_MSG_RESULT(no)) LIBS=$savedLIBS if test $have_pma_query_via -o $have_port_performance_query_via then : else pmda_infiniband= fi else pmda_infiniband= fi AC_SUBST(PMDA_INFINIBAND, $pmda_infiniband) AC_SUBST(IB_LIBS) fi dnl Checks for library functions. AC_TYPE_SIGNAL AC_FUNC_WAIT3 AC_FUNC_VPRINTF AC_CHECK_FUNCS(mktime nanosleep unsetenv) AC_CHECK_FUNCS(select socket gethostname getpeerucred getpeereid) AC_CHECK_FUNCS(uname syslog __clone pipe2 fcntl ioctl) AC_CHECK_FUNCS(prctl setlinebuf waitpid atexit kill) AC_CHECK_FUNCS(chown getcwd scandir mkstemp) AC_CHECK_FUNCS(brk sbrk posix_memalign memalign valloc) AC_CHECK_FUNCS(signal sighold sigrelse tcgetattr) AC_CHECK_FUNCS(regex regcmp regexec regcomp) AC_CHECK_FUNCS(strtod strtol strtoll strtoull strndup) AC_CHECK_FUNCS(getgrent getgrent_r getgrnam getgrnam_r getgrgid getgrgid_r) AC_CHECK_FUNCS(getpwent getpwent_r getpwnam getpwnam_r getpwuid getpwuid_r) AC_CHECK_FUNCS(sysinfo trace_back_stack backtrace) dnl only define readdir64 on non-linux platforms that support it if test $target_os != linux -a $target_os != freebsd -a $target_os != kfreebsd -a $target_os != netbsd; then AC_CHECK_FUNCS(readdir64) fi dnl typedefs missing from sys/types.h, stdlib.h or stddef.h if test $target_os = solaris then AC_CHECK_TYPE(__int32_t, int32_t) AC_CHECK_TYPE(__uint32_t, uint32_t) AC_CHECK_TYPE(__int64_t, int64_t) AC_CHECK_TYPE(__uint64_t, uint64_t) AC_CHECK_TYPE(uint_t, u_int32_t) else AC_CHECK_TYPE(__int32_t, int) AC_CHECK_TYPE(__uint32_t, unsigned int) AC_CHECK_TYPE(__int64_t, long long) AC_CHECK_TYPE(__uint64_t, unsigned long long) AC_CHECK_TYPE(uint_t, unsigned int) fi dnl check if we have a type for the pointer's size integer (__psint_t) AC_MSG_CHECKING([for __psint_t ]) AC_TRY_COMPILE( [ #include #include #include ], [ __psint_t psint; ], AC_DEFINE(HAVE___PSINT_T) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) dnl check if we have a type for pointer difference (ptrdiff_t) AC_MSG_CHECKING([for ptrdiff_t ]) AC_TRY_COMPILE([ #include #ifdef HAVE_MALLOC_H #include #endif ], [ ptrdiff_t ptrdiff; ], AC_DEFINE(HAVE_PTRDIFF_T) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) dnl check if we have types for uid_t, gid_t (POSIX) or SID (Win32) AC_MSG_CHECKING([for uid_t ]) AC_TRY_COMPILE([ #include #ifdef HAVE_PWD_H #include #endif ], [ uid_t uid; ], AC_DEFINE(HAVE_UID_T) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) AC_MSG_CHECKING([for gid_t ]) AC_TRY_COMPILE([ #include #ifdef HAVE_GRP_H #include #endif ], [ gid_t gid; ], AC_DEFINE(HAVE_GID_T) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) AC_MSG_CHECKING([for SID ]) AC_TRY_COMPILE([ #ifdef HAVE_WINDOWS_H #include #endif ], [ SID sid; ], AC_DEFINE(HAVE_SID) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) dnl check if we have a type for socklen_t AC_MSG_CHECKING([for socklen_t ]) AC_TRY_COMPILE([ #include #ifdef HAVE_SYS_SOCKET_H #include #endif ], [ socklen_t len; ], AC_DEFINE(HAVE_SOCKLEN_T) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) dnl check if LL suffix on constants is supported AC_TRY_COMPILE([ #include ], [ long long x = 0LL; ], AC_DEFINE(HAVE_CONST_LONGLONG)) dnl check if _environ is declared globally AC_TRY_LINK([ #include #include ], [ char **x = _environ; ], AC_DEFINE(HAVE_UNDERBAR_ENVIRON)) dnl check for PR_TERMCHILD and PR_SET_PDEATHSIG in AC_MSG_CHECKING([for PR_TERMCHILD constants in sys/prctl.h]) AC_TRY_COMPILE([ #ifdef HAVE_SYS_PRCTL_H #include #endif ], [ int i = PR_TERMCHILD; ], AC_DEFINE(HAVE_PR_TERMCHILD) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) AC_MSG_CHECKING([for PR_SET_PDEATHSIG constants in sys/prctl.h]) AC_TRY_COMPILE([ #ifdef HAVE_SYS_PRCTL_H #include #endif ], [ int i = PR_SET_PDEATHSIG; ], AC_DEFINE(HAVE_PR_SET_PDEATHSIG) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) AC_HEADER_TIOCGWINSZ dnl check if linker needs -rdynamic for dynamically loaded shared dnl libraries to see the symbols in the process loading them. AC_MSG_CHECKING([if linker supports -rdynamic]) cat <conftest.c main() {;} End-of-File rdynamic_flag= $CC -o conftest -rdynamic conftest.c 2>conftest.out test -s conftest.out || rdynamic_flag=-rdynamic AC_SUBST(rdynamic_flag) if test -z "$rdynamic_flag" then AC_MSG_RESULT(no) else AC_MSG_RESULT(yes) fi rm -f conftest.c conftest.o conftest rm -rf conftest.dSYM dnl check if argument to user's select() method in scandir call is const AC_MSG_CHECKING([whether const arg for scandir() select method]) cat <conftest.c #include #include #include static int my_select(const struct dirent *foo) { return 0; } int main() { struct dirent **list; return scandir(".", &list, my_select, NULL); } End-of-File (eval $ac_compile) 2>conftest.out cat conftest.out >&5 if test -s conftest.out then AC_MSG_RESULT(no) else AC_DEFINE(HAVE_CONST_DIRENT) AC_MSG_RESULT(yes) fi rm -f conftest.* dnl check if struct dirent has a d_off (directory offset) field AC_MSG_CHECKING([whether struct dirent has a d_off field]) cat <conftest.c #include #include #include int main() { struct dirent.d; d.d_off = 0; } End-of-File (eval $ac_compile) 2>conftest.out cat conftest.out >&5 if test -s conftest.out then AC_MSG_RESULT(no) else AC_DEFINE(HAVE_DIRENT_D_OFF) AC_MSG_RESULT(yes) fi rm -f conftest.* dnl check if getopt() needs $POSIXLY_CORRECT AC_MSG_CHECKING([if getopt() needs \$POSIXLY_CORRECT]) cat <conftest.c #include #include main(int argc, char **argv) { int c; c = getopt(argc, argv, "x"); if (c == 'x') putchar('n'); if (c == EOF) putchar('y'); putchar('\n'); } End-of-File (eval $ac_compile) 2>&5 (eval $ac_link) 2>&5 unset POSIXLY_CORRECT ans=`./conftest arg -x` echo "./conftest arg -x -> \"$ans\"" >&5 if test "$ans" = n then POSIXLY_CORRECT= export POSIXLY_CORRECT ans=`./conftest arg -x` echo "POSIXLY_CORRECT= ./conftest arg -x -> \"$ans\"" >&5 unset POSIXLY_CORRECT if test "$ans" = y then AC_DEFINE(HAVE_GETOPT_NEEDS_POSIXLY_CORRECT) AC_MSG_RESULT(yes) else AC_MSG_RESULT(unknown) echo "FATAL ERROR: could not coerce your getopt() work correctly" rm -rf conftest conftest.* exit 1 fi elif test "$ans" = y then AC_MSG_RESULT(no) else AC_MSG_RESULT(unknown) echo "FATAL ERROR: could not make your getopt() work at all" rm -rf conftest conftest.* exit 1 fi rm -rf conftest conftest.* dnl check if printf %p has 0x prefix AC_MSG_CHECKING([if printf %p produces 0x prefix]) cat <conftest.c #include main(int argc, char **argv) { printf("%p", argv); exit(0); } End-of-File (eval $ac_compile) 2>&5 (eval $ac_link) 2>&5 ans=`./conftest` echo "./conftest -> \"$ans\"" >&5 case "$ans" in 0x*) AC_DEFINE(HAVE_PRINTF_P_PFX) AC_MSG_RESULT(yes) ;; *) AC_MSG_RESULT(no) ;; esac rm -rf conftest conftest.* _do_type() { # need to deal with this sort of cpp output ... # typedef long pid_t; # typedef unsigned int pid_t; # typedef unsigned int pid_t __attribute__ ((__mode__ (__SI__))); # __extension__ typedef int pid_t; # typedef foo_t # pid_t; # typedef struct { # .... # } pid_t; # typedef ... *pid; # and chaining of the form # typedef long __pid_t; # typedef __pid_t pid_t; # _raw=`$CPP conftest.c \ | $SED \ -e 's/[[ ]]__attribute__ ((.*));/;/' \ -e 's/__extension__[[ ]][[ ]]*//' \ | $AWK ' /bozo/ { print; next } $1 == "typedef" { printf "%s",$0 if ($NF ~ /;$/) { print "" next } wantsemi = 1 if ($0 ~ /{/) depth = 1 next } wantsemi == 1 { printf " %s",$0 if ($0 ~ /{/) depth++ if (depth) { if ($0 ~ /}/) depth-- if (depth > 0) next } if ($NF ~ /;$/) { print "" wantsemi = 0 next } }' \ | $SED \ -e 's/\*/* /g' \ -e 's/^[[ ]]*//' \ -e 's/;[[ ]]*$//' \ | $AWK ' $1 == "typedef" { map[[$NF]] = "" for (i = 2; i < NF; i++) { if (i == 2) map[[$NF]] = $i else map[[$NF]] = map[[$NF]] " " $i } print $NF " -> " map[[$NF]] >"conftest.debug" next } $2 == "bozo" { t = $1 printf "best guess: %s",t >"conftest.debug" while (map[[t]] != "") { t = map[[t]] printf " -> %s",t >"conftest.debug" } print "" >"conftest.debug" print t exit }'` case "$_raw" in int) _fmt='"d"' ;; unsigned|'unsigned int') _fmt='"u"' ;; long|'long int') _fmt='"ld"' ;; 'unsigned long'|'unsigned long int'|'long unsigned int') _fmt='"lu"' ;; *\*) # pointer to a something _fmt='"p"' ;; struct\ *) # not much can be done here ... _fmt='"p"' ;; *) echo echo "FATAL ERROR: don't know what to do with type \"$_raw\"" echo "... typedef mapping ..." cat conftest.debug rm -rf conftest conftest.* exit 1 ;; esac } dnl printf type for pid_t AC_MSG_CHECKING([printf type for pid_t]) cat <conftest.c #include #include pid_t bozo; End-of-File _do_type fmt_pid="$_fmt" AC_MSG_RESULT($fmt_pid) AC_SUBST(fmt_pid) rm -rf conftest.c conftest.debug if test "$do_threads" = "check" -o "$do_threads" = "yes" then AC_CHECK_HEADERS( pthread.h, [], [ if test "$do_threads" = "yes" then AC_MSG_ERROR(cannot enable multi-threaded mode - no pthread.h) fi ]) dnl Check if pthread_mutex_t is defined in pthread.h dnl Ignore the fact that pthread.h could be missing - we don't dnl really care if this test fails because of missing pthread_mutex_t dnl or because of missing headers. AC_MSG_CHECKING([for pthread_mutex_t in pthread.h]) AC_TRY_COMPILE( [#include ], [pthread_mutex_t mymutex;], AC_DEFINE(HAVE_PTHREAD_MUTEX_T) AC_MSG_RESULT(yes), [ if test "$do_threads" = "yes" then AC_MSG_ERROR(cannot enable multi-threaded mode - no mutexes) else AC_MSG_RESULT(no) fi ]) dnl Check which library provide pthread stuff AC_MSG_CHECKING([where pthread_create() is defined]) for cand in "" pthreads pthread ; do savedLIBS=$LIBS if test -n "$cand" then LIBS=`echo $LIBS -l$cand` fi AC_TRY_LINK( [ #include ], [ pthread_create(NULL, NULL, NULL, NULL); ], AC_MSG_RESULT(lib${cand:-c}) if test -z "$cand" then lib_for_pthreads="$cand" else lib_for_pthreads="-l$cand" fi LIBS=$savedLIBS break ) LIBS=$savedLIBS done AC_SUBST(lib_for_pthreads) if test "$ac_cv_header_pthread_h" = "yes" then dnl printf type for pthread_t AC_MSG_CHECKING([printf type for pthread_t]) cat <conftest.c #include pthread_t bozo; End-of-File _do_type fmt_pthread="$_fmt" AC_MSG_RESULT($fmt_pthread) AC_SUBST(fmt_pthread) rm -rf conftest.c conftest.debug dnl check if gcc supports __thread for thread private data AC_MSG_CHECKING([if compiler supports __thread]) dnl __thread support is broken in some places if test $target_os = netbsd then AC_TRY_COMPILE([#include #if __GNUC__ < 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ < 5 ) broken! #else __thread int x; #endif], [], AC_DEFINE(HAVE___THREAD) AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) else AC_TRY_COMPILE([#include __thread int x;], [], AC_DEFINE(HAVE___THREAD) AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) fi dnl Check if pthread_barrier_t is defined in pthread.h AC_MSG_CHECKING([for pthread_barrier_t in pthread.h]) AC_TRY_COMPILE([#include ], [pthread_barrier_t mybarrier;], AC_DEFINE(HAVE_PTHREAD_BARRIER_T) AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) fi fi dnl check sizeof long AC_MSG_CHECKING([sizeof long]) cat <conftest.c #include main() { printf("%d", (int)sizeof(long)); } End-of-File (eval $ac_compile) 2>&5 (eval $ac_link) 2>&5 ans=`./conftest` echo "./conftest -> \"$ans\"" >&5 AC_MSG_RESULT($ans) if test "$ans" = 4; then AC_DEFINE(HAVE_32BIT_LONG) elif test "$ans" = 8; then AC_DEFINE(HAVE_64BIT_LONG) else echo echo "FATAL ERROR: size of long is not 32 or 64 bits, cannot proceed." echo "sizeof(char *) -> $ans" rm -rf conftest conftest.* exit 1 fi rm -rf conftest conftest.* dnl check sizeof pointer AC_MSG_CHECKING([sizeof pointer]) cat <conftest.c #include main() { printf("%d", (int)sizeof(char *)); } End-of-File (eval $ac_compile) 2>&5 (eval $ac_link) 2>&5 ans=`./conftest` echo "./conftest -> \"$ans\"" >&5 AC_MSG_RESULT($ans) if test "$ans" = 4; then AC_DEFINE(HAVE_32BIT_PTR) PCP_PTR_SIZE=32 elif test "$ans" = 8; then AC_DEFINE(HAVE_64BIT_PTR) PCP_PTR_SIZE=64 else echo echo "FATAL ERROR: size of pointer is not 32 or 64 bits, cannot proceed." echo "sizeof(char *) -> $ans" rm -rf conftest conftest.* exit 1 fi rm -rf conftest conftest.* dnl check sizeof int. If not 32, we die AC_MSG_CHECKING([sizeof int]) cat <conftest.c #include main() { printf("%d", (int)sizeof(int)); } End-of-File (eval $ac_compile) 2>&5 (eval $ac_link) 2>&5 ans=`./conftest` echo "./conftest -> \"$ans\"" >&5 AC_MSG_RESULT($ans) if test "$ans" != 4 then echo echo "FATAL ERROR: sizeof(int) is not 32 bits, cannot proceed." echo "Note: 32-bit ints are assumed in the PCP external file formats and" echo " the over-the-wire PDU formats" rm -rf conftest conftest.* exit 1 fi rm -rf conftest conftest.* dnl check bit field allocation order within a word AC_MSG_CHECKING([if bit fields allocated left-to-right]) cat <conftest.c union { struct { unsigned int b:4; unsigned int c:4; } a; int p; } u; main() { u.a.b = 1; u.a.c = 2; printf("%0*x", 2*sizeof(int), u.p); } End-of-File (eval $ac_compile) 2>&5 (eval $ac_link) 2>&5 ans=`./conftest` echo "./conftest -> \"$ans\"" >&5 case "$ans" in 1200*|*0012) # left-to-right starting from MSB (SGI cc on MIPS), or # left-to-right ending at LSB AC_DEFINE(HAVE_BITFIELDS_LTOR) AC_MSG_RESULT(yes) ;; 2100*|*0021) # right-to-left ending at MSB, or # right-to-left starting from LSB (gcc in Intel) AC_MSG_RESULT(no) ;; *) AC_MSG_RESULT(unknown) echo "FATAL ERROR: could not fathom your compiler's bit field allocation scheme" rm -f conftest conftest.* exit 1 ;; esac rm -rf conftest conftest.* dnl check if compile can cast __uint64_t to double AC_TRY_LINK( [ #include #include ], [ __uint64_t x = 0; double y = (double)x; ], AC_DEFINE(HAVE_CAST_U64_DOUBLE)) dnl check if basename and dirname need -lgen, -lpcp or nothing to work dnl (assume both go together) AC_CHECK_FUNCS(basename) if test $ac_cv_func_basename = yes then AC_DEFINE(HAVE_BASENAME) AC_DEFINE(HAVE_DIRNAME) lib_for_basename="" else AC_CHECK_LIB(gen, basename) if test $ac_cv_lib_gen_basename = yes then AC_DEFINE(HAVE_BASENAME) AC_DEFINE(HAVE_DIRNAME) lib_for_basename="-lgen" else lib_for_basename="-lpcp" fi fi AC_SUBST(lib_for_basename) dnl check if dlopen et al need -ldl to work lib_for_dlopen= AC_CHECK_FUNCS(dlopen) if test $ac_cv_func_dlopen = no then AC_CHECK_LIB(dl, dlopen) if test $ac_cv_lib_dl_dlopen = yes then AC_DEFINE(HAVE_DLOPEN) lib_for_dlopen=-ldl fi fi AC_SUBST(lib_for_dlopen) dnl check if flog10, pow, fpclassify and isnanf are available dnl in the maths library lib_for_math= AC_CHECK_FUNCS(flog10) if test $ac_cv_func_flog10 = no then AC_CHECK_LIB(m, flog10) if test $ac_cv_lib_m_flog10 = yes then AC_DEFINE(HAVE_FLOG10) lib_for_math=-lm fi else AC_DEFINE(HAVE_FLOG10) fi AC_CHECK_FUNCS(pow) if test $ac_cv_func_pow = no then AC_CHECK_LIB(m, pow) if test $ac_cv_lib_m_pow = yes then AC_DEFINE(HAVE_POW) lib_for_math=-lm fi else AC_DEFINE(HAVE_POW) fi AC_MSG_CHECKING([for fpclassify()]) ac_cv_func_fpclassify=no AC_TRY_LINK( [ #include ], [ double x = 123.456; if (fpclassify(x) == FP_NAN) exit(1); ], ac_cv_func_fpclassify=yes) AC_MSG_RESULT($ac_cv_func_fpclassify) if test $ac_cv_func_fpclassify = no then dnl try with -lm AC_MSG_CHECKING([for fpclassify() with -lm]) savedLIBS=$LIBS LIBS=-lm AC_TRY_LINK( [ #include ], [ double x = 123.456; if (fpclassify(x) == FP_NAN) exit(1); ], ac_cv_func_fpclassify=yes) AC_MSG_RESULT($ac_cv_func_fpclassify) if test $ac_cv_func_fpclassify = yes then lib_for_math=-lm fi LIBS=$savedLIBS fi if test $ac_cv_func_fpclassify = yes then AC_DEFINE(HAVE_FPCLASSIFY) else dnl prefer fpclassify() but will take isnan() and isnanf() as dnl possible alternates AC_CHECK_FUNCS(isnan) if test $ac_cv_func_isnan = no then AC_CHECK_LIB(m, isnan) if test $ac_cv_lib_m_isnan = yes then AC_DEFINE(HAVE_ISNAN) lib_for_math=-lm fi fi AC_CHECK_FUNCS(isnanf) if test $ac_cv_func_isnanf = no then AC_CHECK_LIB(m, isnanf) if test $ac_cv_lib_m_isnanf = yes then AC_DEFINE(HAVE_ISNANF) lib_for_math=-lm fi fi fi AC_SUBST(lib_for_math) dnl check if we have the SIG_PF typedef AC_TRY_LINK([#include ], [SIG_PF x;], AC_DEFINE(HAVE_SIGPF)) dnl check if we have the SA_SIGINFO #define AC_TRY_LINK([#include ], [int x = SA_SIGINFO;], AC_DEFINE(HAVE_SA_SIGINFO)) dnl check if we support the SIGPIPE signal AC_TRY_LINK([#include ], [int x = SIGPIPE;], AC_DEFINE(HAVE_SIGPIPE)) dnl check if we support the SIGHUP signal AC_TRY_LINK([#include ], [int x = SIGHUP;], AC_DEFINE(HAVE_SIGHUP)) dnl check if we support the SIGBUS signal AC_TRY_LINK([#include ], [int x = SIGBUS;], AC_DEFINE(HAVE_SIGBUS)) dnl check if we need to explicitly include signal.h AC_TRY_LINK([#include ], [ typedef void (*SIGRET)(int); SIGRET x = SIG_IGN; ], AC_DEFINE(HAVE_WAIT_INCLUDES_SIGNAL)) dnl check for name and type of time fields in struct stat dnl IRIX example timespec_t st_mtim; dnl Linux example struct timespec st_mtim; dnl Darwin example struct timespec st_mtimespec; dnl Solaris example timestruc_t st_mtim; dnl FreeBSD (6.1) struct timespec st_mtimespec; dnl struct timespec { dnl time_t tv_sec; dnl long tv_nsec; dnl }; dnl have_stat_type=false have_stat_name=false if test $have_stat_name = false then AC_EGREP_HEADER( changequote(<<, >>)<<[ ]st_mtimespec>>changequote([, ]), sys/stat.h, [ have_stat_name=true; AC_DEFINE(HAVE_ST_MTIME_WITH_SPEC) ]) fi if test $have_stat_name = false -a $target_os != darwin -a $target_os != linux -a $target_os != kfreebsd -a $target_os != netbsd then AC_EGREP_HEADER( changequote(<<, >>)<<[ ]st_mtime>>changequote([, ]), sys/stat.h, [ have_stat_name=true; AC_DEFINE(HAVE_ST_MTIME_WITH_E) ]) fi if test $have_stat_type = false then AC_EGREP_HEADER( changequote(<<, >>)<>changequote([, ]), sys/stat.h, [ have_stat_type=true; AC_DEFINE(HAVE_STAT_TIMESTRUC) ]) fi if test $have_stat_type = false then AC_EGREP_HEADER( changequote(<<, >>)<>changequote([, ]), sys/stat.h, [ have_stat_type=true; AC_DEFINE(HAVE_STAT_TIMESPEC_T) ]) fi if test $have_stat_type = false then AC_EGREP_HEADER( changequote(<<, >>)<>changequote([, ]), sys/stat.h, [ have_stat_type=true; AC_DEFINE(HAVE_STAT_TIMESPEC) ]) fi if test $have_stat_type = false then AC_EGREP_HEADER( changequote(<<, >>)<>changequote([, ]), sys/stat.h, [ have_stat_type=true; AC_DEFINE(HAVE_STAT_TIME_T) ]) fi if test $have_stat_type = false then echo 'FATAL ERROR: Cannot determine stuct stat time types.' echo 'Please send a copy of sys/stat.h to pcp@oss.sgi.com.' rm -rf conftest conftest.* exit 1 fi dnl dnl Work out where to install stuff for this package dnl (and where to find stuff at run-time for add-on packages). dnl dnl dnl Predictable directory containing pcp.conf, or overridden dnl by the $PCP_CONF environment variable. If this is not set dnl (default /etc/pcp.conf), then $PCP_CONF must be set in dnl the environment. dnl dnl The eval echo stuff is used to get around unfavourable dnl elements of the GNU standards, which cause embedding of dnl ${prefix} within many of these various $dirs. dnl http://www.gnu.org/software/autoconf/manual/autoconf.html#Installation-Directory-Variables dnl pcp_etc_dir=`eval echo $sysconfdir` pcp_etc_dir=`eval echo $pcp_etc_dir` AC_SUBST(pcp_etc_dir) pcp_saslconf_dir=`eval echo $sysconfdir/sasl2` pcp_saslconf_dir=`eval echo $pcp_saslconf_dir` AC_SUBST(pcp_saslconf_dir) pcp_sysconf_dir=`eval echo $sysconfdir/pcp` pcp_sysconf_dir=`eval echo $pcp_sysconf_dir` AC_SUBST(pcp_sysconf_dir) pcp_pmcdconf_path=$pcp_sysconf_dir/pmcd/pmcd.conf pcp_pmcdrclocal_path=$pcp_sysconf_dir/pmcd/rc.local pcp_pmcdoptions_path=$pcp_sysconf_dir/pmcd/pmcd.options pcp_pmwebdoptions_path=$pcp_sysconf_dir/pmwebd/pmwebd.options pcp_pmmgroptions_path=$pcp_sysconf_dir/pmmgr/pmmgr.options pcp_pmproxyoptions_path=$pcp_sysconf_dir/pmproxy/pmproxy.options pcp_pmiecontrol_path=$pcp_sysconf_dir/pmie/control pcp_pmsnapcontrol_path=$pcp_sysconf_dir/pmsnap/control pcp_pmloggercontrol_path=$pcp_sysconf_dir/pmlogger/control AC_SUBST(pcp_pmcdconf_path) AC_SUBST(pcp_pmcdoptions_path) AC_SUBST(pcp_pmcdrclocal_path) AC_SUBST(pcp_pmwebdoptions_path) AC_SUBST(pcp_pmmgroptions_path) AC_SUBST(pcp_pmproxyoptions_path) AC_SUBST(pcp_pmiecontrol_path) AC_SUBST(pcp_pmsnapcontrol_path) AC_SUBST(pcp_pmloggercontrol_path) dnl shared PCP files (shareable for diskless) pcp_share_dir=`eval echo $datarootdir/pcp` pcp_share_dir=`eval echo $pcp_share_dir` AC_SUBST(pcp_share_dir) dnl private PCP executables pcp_binadm_dir=`eval echo $libexecdir/pcp/bin` pcp_binadm_dir=`eval echo $pcp_binadm_dir` AC_SUBST(pcp_binadm_dir) dnl non-shared (i.e. system local) PCP files pcp_var_dir=`eval echo $localstatedir/lib/pcp` pcp_var_dir=`eval echo $pcp_var_dir` AC_SUBST(pcp_var_dir) dnl pmcd control and options files AC_ARG_WITH(configdir,[AC_HELP_STRING([--with-configdir],[configuration directory [LOCALSTATEDIR/pcp/config]])], [pcp_config_dir=$withval], [pcp_config_dir=$pcp_var_dir/config]) pcp_pmdas_dir=$pcp_var_dir/pmdas AC_SUBST(pcp_pmdas_dir) dnl runtime shared libraries pcp_lib_dir=`eval echo $libdir` pcp_lib_dir=`eval echo $pcp_lib_dir` pcp_lib32_dir=`echo $pcp_lib_dir | sed -e s,64,, -e s,//,/,` AC_SUBST(pcp_lib_dir) AC_SUBST(pcp_lib32_dir) dnl perl modules AC_ARG_WITH(perl_installdirs,[AC_HELP_STRING([--with-perl_installdirs],[perl installdirs [vendor]])], [perl_installdirs=$withval], [perl_installdirs=vendor]) perl_installdirs=`eval echo $perl_installdirs` perl_installdirs=`eval echo $perl_installdirs` AC_SUBST(perl_installdirs) AC_ARG_WITH(perl_install_base,[AC_HELP_STRING([--with-perl_install_base],[perl install_base [PREFIX]])], [perl_install_base=$withval], [perl_install_base=$prefix]) perl_install_base=`eval echo $perl_install_base` perl_install_base=`eval echo $perl_install_base` AC_SUBST(perl_install_base) AC_ARG_WITH(python_prefix,[AC_HELP_STRING([--with-python_prefix],[python setup.py prefix [PREFIX]])], [python_prefix=$withval], [python_prefix=$prefix]) python_prefix=`eval echo $python_prefix` python_prefix=`eval echo $python_prefix` AC_SUBST(python_prefix) AC_PATH_XTRA pcp_x11_incflags=$X_CFLAGS AC_SUBST(pcp_x11_incflags) pcp_x11_libflags=$X_LIBS AC_SUBST(pcp_x11_libflags) pcp_x11_extra=$X_EXTRA_LIBS AC_SUBST(pcp_x11_extra) pcp_x11_pre=$X_PRE_LIBS AC_SUBST(pcp_x11_pre) dnl man pages (source) have_gzipped_manpages=false have_bzip2ed_manpages=false have_lzmaed_manpages=false have_xzed_manpages=false need_old_tbl_header=false man_header= pcp_man_dir=`eval echo $mandir` pcp_man_dir=`eval echo $pcp_man_dir` dnl guess compression in use for d in /usr/man /usr/share/man $pcp_man_dir do for sd in man1 sman1 do if test -f $d/$sd/man.1.gz then have_gzipped_manpages=true man_header=`$ZIP -d < $d/$sd/man.1.gz | head -1` break elif test -f $d/$sd/man.1.bz2 then have_bzip2ed_manpages=true man_header=`$BZIP2 -d < $d/$sd/man.1.bz2 | head -1` break elif test -f $d/$sd/man.1.lzma then have_lzmaed_manpages=true man_header=`$LZMA -d < $d/$sd/man.1.lzma | head -1` break elif test -f $d/$sd/man.1.xz then have_xzed_manpages=true man_header=`$XZ -d < $d/$sd/man.1.xz | head -1` break elif test -f $d/$sd/man.1 then man_header=`head -1 $d/$sd/man.1` break fi done done if test x"$man_header" = "x'\\\" t" -o x"$man_header" = "x'\\\" te" ; then need_old_tbl_header=true fi AC_SUBST(pcp_man_dir) AC_SUBST(have_gzipped_manpages) AC_SUBST(have_bzip2ed_manpages) AC_SUBST(have_lzmaed_manpages) AC_SUBST(have_xzed_manpages) AC_SUBST(need_old_tbl_header) dnl public binaries pcp_bin_dir=`eval echo $bindir` pcp_bin_dir=`eval echo $pcp_bin_dir` AC_SUBST(pcp_bin_dir) pcp_sbin_dir=`eval echo $sbindir` pcp_sbin_dir=`eval echo $pcp_sbin_dir` AC_SUBST(pcp_sbin_dir) dnl include files pcp_inc_dir=`eval echo $includedir/pcp` pcp_inc_dir=`eval echo $pcp_inc_dir` AC_SUBST(pcp_inc_dir) dnl rc/startup files AC_ARG_WITH(rcdir,[AC_HELP_STRING([--with-rcdir],[rc directory [SYSCONFDIR/rc.d]])], [pcp_rc_dir=$withval], [pcp_rc_dir=$pcp_etc_dir/rc.d]) AC_SUBST(pcp_rc_dir) dnl rc sysconfig dir AC_ARG_WITH(sysconfigdir,[AC_HELP_STRING([--with-sysconfigdir],[sysconfig directory [SYSCONFDIR/sysconfig]])], [pcp_sysconfig_dir=$withval], [pcp_sysconfig_dir=$pcp_etc_dir/sysconfig]) AC_SUBST(pcp_sysconfig_dir) dnl logs AC_ARG_WITH(logdir,[AC_HELP_STRING([--with-logdir],[log directory [LOCALSTATEDIR/log/pcp]])], [pcp_log_dir=$withval], [pcp_log_dir=$localstatedir/log/pcp]) pcp_log_dir=`eval echo $pcp_log_dir` pcp_log_dir=`eval echo $pcp_log_dir` AC_SUBST(pcp_log_dir) AC_ARG_WITH(rundir,[AC_HELP_STRING([--with-rundir],[run directory [LOCALSTATEDIR/run/pcp]])], [pcp_run_dir=$withval], [pcp_run_dir=$localstatedir/run/pcp]) pcp_run_dir=`eval echo $pcp_run_dir` pcp_run_dir=`eval echo $pcp_run_dir` AC_SUBST(pcp_run_dir) dnl world-writeable temporary files directory AC_ARG_WITH(tmpdir,[AC_HELP_STRING([--with-tmpdir],[tmp directory [LOCALSTATEDIR/tmp]])], [pcp_tmpfile_dir=$withval], [pcp_tmpfile_dir=$localstatedir/tmp]) pcp_tmpfile_dir=`eval echo $pcp_tmpfile_dir` pcp_tmpfile_dir=`eval echo $pcp_tmpfile_dir` AC_SUBST(pcp_tmpfile_dir) dnl non-world-writeable status files directory pcp_tmp_dir=`eval echo $pcp_var_dir/tmp` AC_SUBST(pcp_tmp_dir) dnl doc directory AC_ARG_WITH(docdir,[AC_HELP_STRING([--with-docdir],[docs directory [DOCDIR/pcp-VERSION]])], [pcp_doc_dir=$withval], [pcp_doc_dir=$docdir/pcp-${PACKAGE_VERSION}]) pcp_doc_dir=`eval echo $pcp_doc_dir` pcp_doc_dir=`eval echo $pcp_doc_dir` AC_SUBST(pcp_doc_dir) dnl demos directory AC_ARG_WITH(demosdir,[AC_HELP_STRING([--with-demosdir],[run directory [DATADIR/pcp/demos]])], [pcp_demos_dir=$withval], [pcp_demos_dir=$pcp_share_dir/demos]) AC_SUBST(pcp_demos_dir) if test -z "$XCONFIRM" then AC_PATH_PROG(ac_xconfirm_prog, xconfirm, $pcp_bin_dir/pmconfirm) else ac_xconfirm_prog=$XCONFIRM fi AC_SUBST(ac_xconfirm_prog) dnl Check for FNDELAY defined in if test "$ac_cv_header_fcntl_h" = "yes" then AC_MSG_CHECKING([for FNDELAY in fcntl.h]) AC_TRY_COMPILE( [ #include ], [ int i = FNDELAY; ], AC_DEFINE(HAVE_FNDELAY) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) fi dnl Check for Network Security Services (NSS) and dnl Simple Authentication and Security Layer (SASL) if test "$do_secure" = "check" -o "$do_secure" = "yes" then enable_secure=true saved_CFLAGS="$CFLAGS" saved_CPPFLAGS="$CPPFLAGS" NSS_INC_DIRS="-I/usr/include/nss -I/usr/include/nss3" NSPR_INC_DIRS="-I/usr/include/nspr -I/usr/include/nspr4" CFLAGS="$CFLAGS $NSS_INC_DIRS $NSPR_INC_DIRS" CPPFLAGS="$CPPFLAGS $NSS_INC_DIRS $NSPR_INC_DIRS" AC_CHECK_HEADERS([nss/nss.h], [NSSCFLAGS=-I/usr/include/nss], [ AC_CHECK_HEADERS([nss3/nss.h], [NSSCFLAGS=-I/usr/include/nss3], [ enable_secure=false if test "$do_secure" = "yes" then AC_MSG_ERROR(cannot enable secure sockets mode - no NSS header) fi ]) ]) AC_SUBST(NSSCFLAGS) AC_CHECK_HEADERS([nspr/nspr.h], [NSPRCFLAGS=-I/usr/include/nspr], [ AC_CHECK_HEADERS([nspr4/nspr.h], [NSPRCFLAGS=-I/usr/include/nspr4], [ enable_secure=false if test "$do_secure" = "yes" then AC_MSG_ERROR(cannot enable secure sockets mode - no NSPR header) fi ]) ]) AC_SUBST(NSPRCFLAGS) AC_CHECK_HEADERS([sasl/sasl.h], [SASLCFLAGS=-I/usr/include/sasl], [ enable_secure=false if test "$do_secure" = "yes" then AC_MSG_ERROR(cannot enable secure sockets mode - no SASL header) fi ]) AC_SUBST(SASLCFLAGS) AC_CHECK_LIB(sasl2, sasl_server_init, [lib_for_sasl="-lsasl2"], [ enable_secure=false if test "$do_secure" = "yes" then AC_MSG_ERROR(cannot enable secure sockets mode - no SASL library) fi ]) AC_SUBST(lib_for_sasl) AC_CHECK_LIB(ssl, SSL_ImportFD, [lib_for_ssl="-lssl"], [ AC_CHECK_LIB(ssl3, SSL_ImportFD, [lib_for_ssl="-lssl3"], [ enable_secure=false if test "$do_secure" = "yes" then AC_MSG_ERROR(cannot enable secure sockets mode - no SSL library) fi ]) ]) AC_SUBST(lib_for_ssl) AC_CHECK_LIB(nss, NSS_Init, [lib_for_nss="-lnss"], [ AC_CHECK_LIB(nss3, NSS_Init, [lib_for_nss="-lnss3"], [ enable_secure=false if test "$do_secure" = "yes" then AC_MSG_ERROR(cannot enable secure sockets mode - no NSS library) fi ]) ]) AC_SUBST(lib_for_nss) AC_CHECK_LIB(nspr, PR_Init, [lib_for_nspr="-lnspr"], [ AC_CHECK_LIB(nspr4, PR_Init, [lib_for_nspr="-lnspr4"], [ enable_secure=false if test "$do_secure" = "yes" then AC_MSG_ERROR(cannot enable secure sockets mode - no NSPR library) fi ]) ]) AC_SUBST(lib_for_nspr) if test "$enable_secure" = "true" then AC_DEFINE(HAVE_SECURE_SOCKETS) fi AC_SUBST(enable_secure) CPPFLAGS="$saved_CPPFLAGS" CFLAGS="$saved_CFLAGS" fi dnl check for array sessions if test -f /usr/include/sn/arsess.h then pcp_mpi_dirs=libpcp_mpi\ libpcp_mpiread else pcp_mpi_dirs= fi AC_SUBST(pcp_mpi_dirs) dnl check for Unix Domain socket family structure AC_MSG_CHECKING([for struct sockaddr_un in sys/un.h]) AC_TRY_COMPILE([ #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_SYS_UN_H #include #endif ], [ struct sockaddr_un sa; sa.sun_family = AF_UNIX; ], AC_DEFINE(HAVE_STRUCT_SOCKADDR_UN) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) dnl check for Linux Unix Domain socket credential structure AC_MSG_CHECKING([for struct ucred in sys/socket.h]) AC_TRY_COMPILE([ #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_SYS_UN_H #include #endif ], [ struct ucred ucred; ucred.uid = 0; ], AC_DEFINE(HAVE_STRUCT_UCRED) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) dnl check for struct timespec in AC_MSG_CHECKING([for struct timespec in time.h]) AC_TRY_COMPILE([ #include ], [ struct timespec foo; ], AC_DEFINE(HAVE_STRUCT_TIMESPEC) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) dnl check if we have IRIX style altzone AC_MSG_CHECKING([for altzone in time.h]) AC_TRY_COMPILE([ #include ], [ time_t az = altzone; ], AC_DEFINE(HAVE_ALTZONE) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) dnl If there is no altzone, check if strftime can handle %z AC_MSG_CHECKING([if strftime knows about %z]) AC_TRY_RUN( [ #include int main () { char b[32]=""; time_t t = time(NULL); struct tm * t1 = localtime (&t); if (strftime (b, 32, "%z", t1) < 3) return (1); if (strcmp(b, "%z") == 0) return(1); return (0); } ], AC_DEFINE(HAVE_STRFTIME_z) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no), 0) dnl does strerror_r return char * a la GNU dnl (as opposed to the int return for XSI-compliant variants) AC_MSG_CHECKING([if strerror_r returns char *]) AC_TRY_COMPILE( [#include ], [strerror_r(0, NULL, 0)[0];], AC_DEFINE(HAVE_STRERROR_R_PTR) AC_MSG_RESULT(yes), AC_MSG_RESULT(no)) dnl first check for readline on its own then with curses savedLIBS=$LIBS LIBS= lib_for_curses= lib_for_readline= AC_CHECK_FUNC(readline,, [ AC_CHECK_LIB(readline, readline,, [ dnl AC seems to cache lib/func results dnl so use another readline func here AC_CHECK_LIB(readline, add_history,,,[-lcurses]) ]) ]) if test $ac_cv_func_readline = yes then AC_DEFINE(HAVE_READLINE) elif test $ac_cv_lib_readline_readline = yes then AC_DEFINE(HAVE_READLINE) lib_for_readline=-lreadline elif test $ac_cv_lib_readline_add_history = yes then AC_DEFINE(HAVE_READLINE) lib_for_curses=-lcurses lib_for_readline=-lreadline fi AC_SUBST(lib_for_readline) AC_SUBST(lib_for_curses) LIBS=$savedLIBS dnl Check if we have AI_ADDRCONFIG AC_MSG_CHECKING([for AI_ADDRCONFIG]) AC_TRY_COMPILE( [ #include int test = AI_ADDRCONFIG; ], [ ], AC_DEFINE(HAVE_AI_ADDRCONFIG) AC_MSG_RESULT(yes) , AC_MSG_RESULT(no)) savedLIBS=$LIBS AC_CHECK_LIB(rt, timer_gettime) lib_for_rt="" if test $ac_cv_lib_rt_timer_gettime = yes then lib_for_rt="-lrt" fi AC_SUBST(lib_for_rt) LIBS=$savedLIBS dnl Do you have system microhttpd libraries for pmwebapi? savedLIBS=$LIBS AC_MSG_CHECKING([for libmicrohttpd > 0.9.9]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[(void)MHD_RESPMEM_PERSISTENT;]])], [AC_MSG_RESULT([yes]) have_libmicrohttpd=1], [AC_MSG_RESULT([no]) have_libmicrohttpd=0]) dnl AC_CHECK_LIB(microhttpd,MHD_start_daemon,[have_libmicrohttpd=1],[have_libmicrohttpd=0]) AC_SUBST(HAVE_LIBMICROHTTPD,[$have_libmicrohttpd]) LIBS=$savedLIBS dnl Do you have RPM Package Manager libraries for pmdarpm? savedLIBS=$LIBS AC_MSG_CHECKING([for rpmlib > 4.4.2]) AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([[#include ]], [[(void)HEADERGET_EXT;]])], [AC_MSG_RESULT([yes]) have_rpmlib=1], [AC_MSG_RESULT([no]) have_rpmlib=0]) AC_SUBST(HAVE_RPMLIB,[$have_rpmlib]) LIBS=$savedLIBS dnl Do we have the prerequisites for pmmgr? AC_MSG_CHECKING([for pmmgr prerequisites]) if test $target_os != mingw -a "$cxx" != "" then AC_MSG_RESULT([yes]) build_pmmgr=yes else AC_MSG_RESULT([no]) build_pmmgr=no fi AC_SUBST(BUILD_PMMGR,[$build_pmmgr]) dnl Capture special options passed to configure AC_SUBST(PACKAGE_CONFIGURE) dnl dnl output files dnl AC_OUTPUT( dnl Build definitions for use in Makefiles src/include/builddefs dnl PCP paths and other defs src/include/pcp.conf dnl Linux Software Map entry pcp.lsm dnl Preamble for deb install scripts debian/pcp.preinst.head debian/pcp.postinst.head dnl Preamble for tar install scripts build/tar/preinstall.head build/tar/postinstall.head dnl Build definitions for use in packaging build/GNUlocaldefs ) echo config.status: settings dump begin grep '^S.".*=' config.status echo config.status: settings dump end pcp-3.8.12ubuntu1/README0000664000000000000000000000427112272262501011466 0ustar See the file INSTALL (in this directory) for build, installation and post-install configuration steps. Performance Co-Pilot (PCP) is a framework and services to support system-level performance monitoring and performance management. The PCP open source release provides a unifying abstraction for all of the interesting performance data in a system, and allows client applications to easily retrieve and process any subset of that data using a single API. A client-server architecture allows multiple clients to monitor the same host, and a single client to monitor multiple hosts (e.g. in a Beowulf cluster). This enables centralized monitoring of distributed processing. Integrated archive logging and replay so a client application can use the same API to process real-time data from a host or historical data from an archive. The framework supports APIs and configuration file formats that enable the scope of performance monitoring to be extended at all levels. The architecture and services of the base PCP infrastructure are especially attractive for those tackling the harder system-level performance problems. For example this may involve a transient performance degradation, or some complex interaction between resource demands on a single system, or those seeking centralized monitoring of distributed processing (e.g. in a cluster or webserver farm environment), or management of performance on large systems with lots of moving parts. The open source release of PCP includes all of the PCP libraries, infrastructure and daemons, along with a Linux agent that exports a broad range of performance data from most kernels circa 2.0.36 (RedHat 5.2) or later. This includes coverage of activity in the areas of: CPU disk memory swapping network NFS RPC filesystems all the per-process statistics Other agents export performance data from: Apache Web server activity logs arbitrary application-level tracing (via a PCP trace library) Cisco routers sendmail the mail queue the PCP infrastructure itself For more information and details on how to contribute to the PCP project see the web pages at http://oss.sgi.com/projects/pcp/ pcp-3.8.12ubuntu1/aclocal.m40000664000000000000000000001746412272262501012456 0ustar # generated automatically by aclocal 1.13.4 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES # PKG_INSTALLDIR(DIRECTORY) # ------------------------- # Substitutes the variable pkgconfigdir as the location where a module # should install pkg-config .pc files. By default the directory is # $libdir/pkgconfig, but the default can be changed by passing # DIRECTORY. The user can override through the --with-pkgconfigdir # parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ]) dnl PKG_INSTALLDIR # PKG_NOARCH_INSTALLDIR(DIRECTORY) # ------------------------- # Substitutes the variable noarch_pkgconfigdir as the location where a # module should install arch-independent pkg-config .pc files. By # default the directory is $datadir/pkgconfig, but the default can be # changed by passing DIRECTORY. The user can override through the # --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ]) dnl PKG_NOARCH_INSTALLDIR pcp-3.8.12ubuntu1/INSTALL0000664000000000000000000002736612272262501011651 0ustar == INSTALL == A.1 Linux Installation (rpm, deb) .2 Mac OS X Installation .3 AIX Installation .4 Solaris Installation .5 Windows Installation B. Building from source C. Post-install steps D. Non-default build, install and run This document describes how to configure and build the open source PCP ("pcp") package from source, and how to install and finally run it. == A.1 Linux Installation If you are using Debian, or a Debian-based distribution like Ubuntu, PCP is included in the distribution (as of late 2008). Run: # apt-get install pcp If you are using a RPM based distribution and have the binary rpm: # rpm -Uvh pcp-*.rpm ... and skip to the final section (below) - "Post-install steps". Special note for Ubuntu 8.04, 8.10, 9.04, 9.10 and 10.04 I've had to make the changes below to /usr/bin/dpkg-buildpackage. Without these two changes, my pcp builds produce bad binaries with a bizarre array of failure modes! #kenj# my $default_flags = defined $build_opts->{noopt} ? "-g -O0" : "-g -O2"; my $default_flags = defined $build_opts->{noopt} ? "-g -O0" : "-g -O0"; my %flags = ( CPPFLAGS => '', CFLAGS => $default_flags, CXXFLAGS => $default_flags, FFLAGS => $default_flags, #kenj# LDFLAGS => '-Wl,-Bsymbolic-functions', LDFLAGS => '', ); Without these changes, we see QA failures for 039, 061, 072, 091, 135, 147 and 151 ... and the QA 166 goes into a loop until it fills up the root filesystem. -- Ken == A.2 Mac OS X Installation The only unusual step in installing PCP on Mac OS X is the additional dependency on the developer tools (XCode package). The specific need PCP has is to have a C preprocessor available for managing the metric namespace, which on Mac OS X is a frontend to gcc and not installed by default. Once this is installed, installing PCP from the DMG file is as simple as clicking on the icon in a Finder window, and following the prompts from the installer. == A.3 AIX Installation At this stage, noone is making available pre-built AIX packages. A port to AIX has been done, and merged, however - building from the source is currently the only option. The packaging work is also begun on this platform (see the build/aix/ directory in the sources). == A.4 Solaris Installation Prebuild Solaris packages are available from PCP download section. At this stage the package are distributed as SVR4 package datastream and are build on Open Solaris 5.11. You can install the package using 'pkgadd' command, e.g.: # pkgadd -d pcp-X.Y.Z During the installation the following three services are registered with the Solaris' service management facility: # svccfg list \*/pcp/\* application/pcp/pmcd application/pcp/pmlogger application/pcp/pmie application/pcp/pmproxy On the new installation all services are disabled, during the upgrade from the previous version of PCP the state of the services is preserved. Use of 'svcadm' command to enable or disable is preferred over explicit invocation of the pmcd start script. Use 'svcs' command to check the state of the services, e.g.: # svcs -l application/pcp/pcp fmri svc:/application/pcp/pcp:default name Performance Co-Pilot Collector Daemon enabled false state disabled next_state none state_time 20 March 2012 11:33:27 AM EST restarter svc:/system/svc/restarter:default dependency require_all/none svc:/system/filesystem/local:default (online) svc:/milestone/network:default (online) == A.5 Windows Installation Download the native Windows version of PCP from the PCP download section. There are two variants: .zip and .exe. The latter is a self-installing executable, the former a simple compressed PCP image. Run the executable, follow the prompts, and a Startup Menu item with several PCP options will be available - standard DOS shell or POSIX shell (with suitable environment setup), the Perl CPAN configuration tool, links to documentation and online PCP internet resources, and the pmchart utility. == B. Building from source 1. Configure, build and install the package The pcp package uses autoconf/configure and expects a GNU build environment (your platform must at least have gmake). If you just want to spin a .RPM, .DEB, .DMG, .EXE and/or tar file, use the Makepkgs script in the top level directory. This will configure and build the package for your platform and leave binary and src packages in the build/ directory. It will also leave binary and source tar file in the build/tar directory. $ ./Makepkgs --verbose 2. If you want to build the package and install it manually you will first need to ensure the "user" pcp is created so that key parts of the PCP installation can run as a user other than root. For Debian this means the following (equivalent commands are available on all distributions): $ su root # groupadd -r pcp # useradd -c "Performance Co-Pilot" -g pcp -d /var/lib/pcp -M -r -s /usr/sbin/nologin pcp Then use the following steps (use configure options to suit your preferences, refer to the qa/admin/myconfigure script for some guidance and see also section D below for additional details): $ ./configure --prefix=/usr --libexecdir=/usr/lib --sysconfdir=/etc \ --localstatedir=/var --with-rcdir=/etc/init.d $ make $ su root # make install Note 0: PCP services run as non-root by default. Create unprivileged users "pcp" with home directory /var/lib/pcp, and "pcpqa" with home directory such as /var/lib/pcp/testsuite, or as appropriate, or designate other userids in the pcp.conf file. Note 1: that there are so many "install" variants out there that we wrote our own script (see "install-sh" in the top level directory), which works on every platform supported by PCP. Note 2: the Windows build is particularly involved to setup, this is primarily due to build tools not being available by default on that platform. See the PCP Glider scripts and notes in the pcpweb tree to configure your environment before attempting to build from source under Win32. == C. Post-install steps You will need to start the PCP Collection Daemon (PMCD), as root: Linux, AIX: # service pmcd start (or...) # /etc/init.d/pmcd start (or...) # /etc/rc.d/init.d/pmcd start Mac OS X: # /Library/StartupItems/pcp/pmcd start Windows: $PCP_DIR/etc/pmcd start Solaris: # svcadm enable application/pcp/pmcd Once you have started the PMCD daemon, you can list all performance metrics using the pminfo(1) command, E.g. # pminfo -fmdt (you don't have to be root for this, but you may need to type rehash so your shell finds the pminfo command). If you are writing scripts, you may find the output from pmprobe(1) easier to parse than that for pminfo(1). There are numerous other PCP client tools included. PCP can be configured to automatically log certain performance metrics for one or more hosts. The scripts to do this are documented in pmlogger_check(1). By default this facility is not enabled. If you want to use it, you need to # determine which metrics to log and how often you need them # edit $PCP_SYSCONF_DIR/pmlogger/control # edit $PCP_SYSCONF_DIR/pmlogger/config.default # (and any others in same dir) # as root, "crontab -e" and add something like: # -- typical PCP log management crontab entries # daily processing of pmlogger archives and pmie logs 10 0 * * * $PCP_BINADM_DIR/pmlogger_daily 15 0 * * * $PCP_BINADM_DIR/pmie_daily # # every 30 minutes, check pmlogger and pmie instances are running 25,40 * * * * $PCP_BINADM_DIR/pmlogger_check 5,55 * * * * $PCP_BINADM_DIR/pmie_check The pmie (Performance Metrics Inference Engine) daemon is _not_ configured to start by default. To enable it, you may want to (on Linux platforms with chkconfig). # su root # chkconfig pmie on # edit the pmie control file (usually below $PCP_SYSCONF_DIR/pmie) # edit the config file (usually $PCP_SYSCONF_DIR/pmie/config.default) # set up cron scripts similar to those for pmlogger (see above) Configure some optional Performance Metrics Domain Agents (PMDAs) The default installation gives you the metrics for cpu, per-process, file system, swap, network, disk, memory, interrupts, nfs/rpc and others. These metrics are handled using the platform PMDA - namely pmda_linux.so (Linux), pmda_darwin.dylib (Mac), or pmda_windows.dll (Windows). It also gives you the PMCD PMDA, which contains metrics that monitor PCP itself. There are many other optional PMDAs that you can configure, depending on which performance metrics you need to monitor, as follows: Note: $PCP_PMDAS_DIR is normally /var/pcp/pmdas, see pcp.conf(4). Web Server metrics # su root # cd $PCP_PMDAS_DIR/apache (i.e. cd /var/pcp/pmdas/apache) # ./Install # Check everything is working OK # pminfo -fmdt apache Other PMDAs in the pcp package include: apache - monitor apache web server stats cisco - monitor Cisco router stats dbping - query any database, extract response times elasticsearch - monitor an elasticsearch cluster kvm - monitor kernel-based virtual machine stats mailq - monitor the mail queue memcache - monitor memcache server stats mmv - export memory-mapped value stats from an application mounts - keep track of mounted file systems mysql - monitor MySQL relational databases postgres - monitor PostGreSQL relational databases process - keep an eye on critical processes/daemons roomtemp - monitor room temp (needs suitable probe) rsyslog - monitor the reliable system log daemon sendmail - monitor sendmail statistics shping - ping critical system services, extract response times trace - for instrumenting arbitrary applications, see pmtrace(1) txmon - transaction and QOS monitoring sample - for testing simple - example src code if you want to write a new PMDA trivial - even easier src code for a new PMDA. The procedure for configuring all of these is to change to the directory for the PMDA (usually below /var/lib/pcp/pmdas), and then run the ./Install script found therein. None of these PMDAs are configured by default - you choose the PMDAs you need and run the Install script. Installation can be automated (defaults chosen) by touching .NeedInstall in the appropriate pmdas directory and then restarting the pmcd service via its startup script. == D. Non-default build, install and run To run build and run a version of PCP that is installed in a private location (and does not require root privileges), first create the pcp "user" as described in section B.2 above), then $ ./configure --prefix=/some/path This will populate /some/path with a full PCP installation. To use this ensure the following are set in the environment: $ export PCP_DIR=/some/path Amend your shell's $PATH to include the PCP directories, found as follows: $ cd /some/path $ xtra=`grep '^PCP_BIN' etc/pcp.conf | sed -e 's/.*=//' | paste -s -d :` $ PATH=$xtra:$PATH Ensure the new libraries can be found: $ export LD_LIBRARY_PATH=`grep '^PCP_LIB' etc/pcp.conf \ | sed -e 's/.*=//' | uniq | paste -s -d :` Tell Perl where to find loadable modules: $ export PERL5LIB=$PCP_DIR/usr/lib/perl5:$PCP_DIR/usr/share/perl5 Allow man(1) to find the PCP manual pages: $ export MANPATH=`manpath`:$PCP_DIR/usr/share/man If your version is co-exiting with a running PCP in a default install, then alternative port numbers in your environment for pmcd ($PMCD_PORT), pmlogger ($PMLOGGER_PORT) and pmproxy ($PMPROXY_PORT) pcp-3.8.12ubuntu1/VERSION.pcp0000664000000000000000000000020412272262521012431 0ustar # # This file is used by configure to get version information # PACKAGE_MAJOR=3 PACKAGE_MINOR=8 PACKAGE_REVISION=12 PACKAGE_BUILD=1 pcp-3.8.12ubuntu1/config.guess0000775000000000000000000012753412272262501013136 0ustar #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 # Free Software Foundation, Inc. timestamp='2008-01-23' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[456]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:[3456]*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; EM64T | authenticamd) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else echo ${UNAME_MACHINE}-unknown-linux-gnueabi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^LIBC/{ s: ::g p }'`" test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: pcp-3.8.12ubuntu1/CHANGELOG0000664000000000000000000026652312272262521012034 0ustar pcp-3.8.12 (29 January 2014) - Fix recent (3.8.10) regression for certain platforms where important PMNS files ended up not being installed. Impact is on new installs only, not upgrades (so my QA missed it). - pmmgr: add -l (logfile) option to fix a permissions issue. - pmdalinux: fix sigsegv on certain icmp procfs file lines. - Further improvements to pmlogger internal data structures dealing with configuration files with duplicate metrics and/or instances - improved in terms of network fetching, as well as on-disk data layout (all backwards compatible). - pmdarpm: added cumulative rpm.total.{count,bytes} metrics. - Add man pages for all of the PMDAs currently missing one. pcp-3.8.10 (15 January 2014) - Adds pmmgr(1) PCP daemon manager - a cunning new (opt-in) approach to managing farms of pmlogger and pmie processes. - Adds pmfind(1) utility for discovering advertised pmcd services (initially) on the network. - Adds a new pmDiscoverServices(3) PMAPI routine. - Linux pmda: plug memory leak in /proc/interrupts parsing. - systemd pmda: add sd_journal_process() to avoid inotify() driven spinning - Man page rework for some NAME entries, addressing SGI oss bugzilla #972) - Add notes for creating user pcp before make from source, addressing SGI oss bugzilla #1040) - Improve behavior related to Avahi service name collisions. - Dodge another hostname-does-not-resolve bullet in pmlogger. - Fix the configure check for RHEL5 rpmlib for pmdarpm. - An extensive series of spelling fixes to man pages, thanks to Michele Baldessari - Small fixes here and there from Coverity static analysis. - GFS2 pmda: add the complete set of GFS2 tracepoint metrics. - RPM pmda: make instance names unique, add rpm.name metric. - RPM pmda: reduce number of inotify events and rpmdb scans. - Add some heuristics to reduce metric duplication from tasks formed via pmlogger configuration file blocks. pcp-3.8.9 (12 December 2013) - Fix pmdalinux stack blowout during ioctl() for network interfaces. - Add a generic string cache concept for PMDAs to use when needing to perform string value de-duplication. - Add a PMDA for the RPM Package Manager exporting package metadata and state. - Fix bug in pmlogextract handling time windows and metrics with dynamic indoms. - Allow the host part of the host spec to be enclosed with square brackets - needed for IPv6 addresses in order to separate the address from the port. - Fix an Avahi and pmcd conflict when using multiple ports. - Introduce shared library symbol versioning and hidden attributes for all PCP libraries. - Reduce internal API/ABI leakage in libpcp with respect to endian code, locking code, and derived metrics. - Bring the Solaris port back up to date with latest source. - Tag temporary files created by qa tests with test prefix. - Split PCP_TMP_DIR setting into its two distinct use-cases removing the need to install world-writable-sticky-bit-set directories. - Add /proc/cpuinfo flags and cache_alignement fields (x86). - Improvements to the hinv.cpu.model metric value we export. - Ensure pmcpp does not accidentally #include directories. - Better cleanup of uncompressed temporary files in libpcp. - Correct pmdasystemd fd_set usage. - Gracefully handle missing python curses module scenario. - Improvements to pmstat error handling. - Update pmcds config file parser - cleaner quotes handling. - pcp.sh - change formatting for pmie and pmlogger details. - Unknown Host fixups in libpcp __pmHostEnt code. - Add a security philosophy section to PCPIntro(1) man page. - Dodge wchan in Linux proc PMDA if procfs file not found. - Add network.interface.hw_addr metric (exported from sysfs) - Remove a nowadays-empty config directory from installation - Resolve rpm upgrade warning from missing .NeedRebuild file - Add pmdaproc option to skip access checking, for secure / isolated environments. - Make NSS use a stronger default cipher suite. pcp-3.8.8 (3 November 2013) - Dodge Debian build issues related to kfreebsd sys/sdt.h. pcp-3.8.7 (3 November 2013) - Resolve Debian build issues related to pkg-config/Avahi. pcp-3.8.6 (1 November 2013) - Added a new Linux JDB2 PMDA (ext3, ext4, ocfs journals). - Added Linux kernel PMDA mem.util.directMap1G metric. - Rework previous fix for Debian kfreebsd port wrt probes. - Further work on Coverity scan issues, again nothing big. - Further work on removing the hostname-as-DNS-entity, add more use of pmGetContextHostName, more default-to-local: tools. - Initial support for DNS-SD via Avahi in pmcd for service discovery. - Change pcpqa to default to $PCP_VAR_DIR/testsuite as its home directory. pcp-3.8.5 (18 October 2013) - Add jsdemos for the web API into the source tarball. - Resolve Fedora/EPEL build issue for Infiniband PMDA. - Resolve Debian build issue for kfreebsd probes.h - Remove hostname checks in pmie/pmlogger script PID search. - Much work on QA. Zero test failures on release for RHEL6, and there was much rejoicing. - Many Coverity scan issues resolved, nothing major though. - Ensure MMV PMDA entry exists in default pmcd.conf once more. - Add Linux disk.partitions metrics to the default logged set. - New hinv.nlv (logical volume count) metric into Linux PMDA. - Update pmevent to use local: as the default mechanism. - Numerous updates to the GFS2 PMDA. - Reinstate a pmcd sigsegv fix, lost in an earlier merge. - Fix handling multiple concurrent clients in pmdasystemd. - Fix memory leak in pmNewContext failure path seen via pmie. - Make default crontab install cooperate with runlevel settings. - Add a privacy-protecting pmdasystemd uid/gid-filtering mode. - Functional network.interface speed/duplex metrics on older kernels (2.6.32 vintage and earlier, for example). - Support for IPv6 address and scope metrics (ifconfig-style) - Numerous updates to the pmatop utility. - Updates to the PCPIntro(1) manual page. - Improvements to the Linux per-process metrics values for any threads being reported. - Options for restricting Linux pmdaproc to a named cgroup. - Update pmlogger to default to local: connection mode. - Allow opt-out with the default-enabled xfs and proc PMDAs. - Resolve a pmcollectl divide-by-zero (python stack trace). - Fix recursive expansion of child cgroups in Linux pmdaproc. - Fix a pmie core dump with archives, interp and mark records. - Reduce memory footprint of Linux per-process metrics. - Add proc.psinfo metrics for cgroups and security labels. - Use local: connection by default in pmatop and pmcollectl. - Update the python API wrapper to default to local: connection. - Improvements to pmcollectl host name handling. - pmGetContextHostName return to static char[] return value. pcp-3.8.4 (15 September 2013) - Allow numerous of the pmlogconf/tools templates to be probed and enabled. These are Linux tools, so we probe for (remote possibly) Linux hosts only for these. - Numerous QA test updates, resolving small amounts of fallout from the previous release reported by Red Hat QE folks. - Updates to the Samba PMDA. - Improvements to the Debian build - remove Infiniband deps as we're not attempting to build that anymore there (evidently, poor cross platform support? Can revisit if anyone needs it). - Remove Debian dependence on deprecated sysv rc package. - Resolve Debian packaging override disparities. pcp-3.8.3 (9 September 2013) - Split the XFS and XFS quota metrics into a separate PMDA - Optional hash-based metric table lookups for PMDAs - pmdagfs2: updates - pmlogrewrite: add support for indom replication - pmatop: Decrease screen real estate used for display. - Fix the pmdabash shell version support validation code - Add gluster PMDA into the build, really this time - Add hinv.nnode metric to pmdalinux, mirroring the IRIX metric - Add an option allowing custom pmcd.hostname settings - Implement host access checking for unix domain sockets. - Man page updates, esp. to pmcd.1 re access controls. - Add static probe support for pmcd probes (systemtap/dtrace) - Change pmGetContextHostName to be pmcd.hostname aware and thus able to report the correct remote hostname through a tunnel. - Update numerous tools to use pmGetContextHostName now. - Demonstration programs for the MMV API - Add pmdasystemd journal event count and total bytes metrics - Use -fPIC over -fpic, resolving build issues on some platforms. - Ensure Perl refcount bumped on PMDA.pm pmdacache stored variables - Fix pmie/pmlogger control scripts - bad pmproxy handling - Add a mechanism for packaging to avoid chown use, for Debian. pcp-3.8.2 (31 July 2013) - Support for the Unix domain socket transport between pmcd and client tools, using the "unix:" host specifier (and the more forgiving "local:" which falls back to localhost if no platform support exists). - Note: PCP_RUN_DIR is as a result now installed owned by the "pcp" user and group (rather than as "root"). Several other directories are also now installed "pcp"-owned too, after (unrelated) pmie and changes described below. - Support for automatic extraction of client tool credentials with Unix domain sockets, and transfer to interested PMDAs, on Linux, Mac OS X and Solaris. IOWs, PMDAs now know which user they are acting on behalf of for each connection, when this class of socket is used. In a future release, it hoped to make this the default local connection style. - Extensions to pmdaproc to allow it to perform access-control checking and metric value fetches as the user requesting the data, instead of as root, such that kernel-based permission checking is now performed. - Re-enabled pmdaproc by default on Linux. - pmdagfs2: updates to metrics, tests and a new manual page. - pmdagfs2: fixes for distributions without gfs2 trace-points. - pmdalinux: fix hinv.map.lvname realink memory corruption bug. - pmdalinux: fix issue where EPERM passed out as a fetch result with inaccessible filesystem paths. - pmdalinux: rework /proc/net/snmp metric extraction, added new metrics from recent kernels (checksum error counters, icmpmsg). - Linux PMDA SNMP metric type migration support (log rewriter). - pmdasystemd: correct .maxmem metric to PM_SPACE_BYTE - pmdasystemd: limit number of journald entries consumed per poll - pmdamysql: additional status metrics suitable for pmie rules. - pmdamysql: correct units and type for active connection count - MySQL PMDA metric migration support (log rewriting rules). - pmdagluster: new PMDA exporting gluster filesystem metrics, in particular fs operation latency and brick throughput data. - Fixes to the python pmda interface code to allow old python versions as well. - Extensions to python pmda interface to allow pmdaCache(3) use. - pmwebapi: support more general pcp hostname specs, and HTTP Basic authentication. - Throttle the size of the pmatop hardware component display. - Fix pmgui.py on big endian platforms (affects pmcollectl). - Further progress on the log checking tool, pmlogcheck. - Generate default pmlogger and pmie daemon configuration files. - Migrated all static pmlogger configs over to pmlogconf format. - Added pmlogconf config files for metrics used by iostat, ip, mpstat, sar, vmstat. - Install cisco PMDA pmieconf rules into the correct location. - Install default crontab entries for pmlogger and pmie checking and daily archive maintenance, on Linux, running as user "pcp" now (previously, "root"). - pmlogconf scripts: added in automatic NFSv4 logging. - pmlogger scripts: better locking between check and daily - pmlogger control: add -r, -T and increase timeouts by default. - Start a working primary pmlogger with a useful and extensible set of metrics after enabling the service. - Start a working pmie with a useful and extensible set of rules after enabling the service. - Assigned new PANASAS and NVML PMDA domain numbers. - pmlogextract: fix minor bug for empty instance domains - Resolve issue where clients get sigsegv from bad -h options. - Updated pmwtf man page - better explanation for -q option - Massive, massive QA efforts, much better support for non-x86. - iostat2pcp - timestamp rework for European datetime formats. - Fixed debian bugs related to broken library symlink. - Ensure permissions on the NOTICES file allow pcp uid/gid access. - Major updates to the SASL code allowing remote authentication and improvements to username/password interaction process. - Fix SASL related memory leaks, sort out authname mapping. - Ensure SASL errors are easily identifiable as such (pmErrStr_r) - User and groups access control list support in pmcd, augmenting the existing host-based access control list support. - Fix tempfile leak in pmdaproc.sh from accidental $tmp override. - Improve the PCP experience with older versions of NSS (<=RHEL5) - Introduce pmcd self-callstack-tracing capability for the Linux, FreeBSD, and MacOSX platforms (maybe others, via backtrace(3)). pcp-3.8.1 (19 June 2013) - Add support for PMDAs written in python via pcp.pmda package. - Example implementation of pmdasimple using python. - Added new proc.{memory.vmswap,psinfo.threads} metrics. - New collectl2pcp utility and sub-package (deb/rpm) for converting historical data collected with collectl into the PCP archive format for replay and analysis with PCP tools. - Add missing help text for some Linux kernel hinv.map metrics - Added new hinv.map.lvname metric for reverse mapping logical device mapper names to physical device names. - Added new hinv.ninterface metric (pmdalinux and collectl2pcp) - Fixes to pmcollectl handling of PCP logs in archive mode. - Allow pmcollectl metrics to be sourced from a remote host. - Additional gfs2 metrics and tests, thanks to Paul Evans from the gfs2 development team at Red Hat. This makes use of the gfs2 kernel glock event tracing to track hot locks, and also provides a storable mechanism for enabling/disabling tracing on-the-fly. - Updated access control section of pmcd.1 with IPv6 details. - Improve archive integrity checking from libpcp_import, ensure monotonic increasing timestamps presented for single archive. - Improvements to the log import perl API allowing for batched updates (out-of-order), thanks to Marko Myllynen. - Removed a low limit in the libpcp_import auto-PMID generation scheme, now allowing millions of metrics instead of hundreds. - Promote pmlogger and pmlogextract into the default PATH, with backward-compatibility preserving symlinks in PCP_BINADM_DIR. - Support for IPv6 socket communication in libpcp_pmda for pmcd PMDA communication. - Support for IPv6 socket communication testing via dbpmda. - Update man pages to reflect IPv6 support in libpcp_pmda. - Other improvements to the socket-based PMDA mechanisms. - Fix a 64bit big-endian host issue in systemd.maxmem metric - Mac OS X packaging tweaks. pcp-3.8.0 (14 May 2013) - Added the nginx PMDA, thanks to Ryan Doyle. - Fixed memory leak on an error path in profile PDU decoder. - Added pmwebd(1) - a JSON-based bridge providing web tools with access to the PMAPI (both pmcd and archives) via HTTP. - Initial support for client authentication via opt-in protocol extensions, host specification extension, communication to PMDAs via version 6 of the agent interface, dbpmda support. Uses SASL2 as the underlying technology (which provides for plugin-based extension to many authentication mechanisms). - Reworked many aspects of the python APIs - now a pcp package with sub-modules, improved error handling, and much more. - Work toward pylint(1)-clean python code throughout PCP. - Added a new python module for MMV instrumentation. - Initial work on a python module for writing PMDAs. - Added a new python module abstracting commonly needed metric Subsystems, shared by pmatop(1) and pmcollectl(1). - Added new python client tool - pmatop(1) - implementing much of the reporting functionality of atop (www.atoptool.nl). - Additional checks added to metric names allowed into the PCP Log Import library to match the PMNS man page requirements. - Support for parallel make invocations. - Improvements to the secure server code to make it work better and on more platforms. - Improvements to the IPv6 and IPv4 access control wildcards. - Migrate man pages from man4 to man5. - Resolve Fedora bug where the log import API was found to be allowing invalid metric names to be created. pcp-3.7.2 (19 April 2013) - Improved pmie propagation of metadata units. - Extra pmlogger diagnostic when log cannot be created. - Fix Debian python build dependencies. - Avoid mis-sharing outbound pmcd connections if ports do not match (libpcp). - IPv6 presence now checked at run-time as well (pmconfig). - Packaging updates - tarball, slackware, gentoo. - Add several missing man page options, typos and such, found by Red Hat (internal?) checker tools. - Added pmwtf.1 man page. - Make pmdaapache observe a connect timeout as well as its existing request timeout. - Extend pmcd access control with a global wildcard for IPv6. - Make __pmSockAddrIsLoopBack handle IPv6 loopback address. - Resolve bug in too-small pduread recv causing communication failures with secure sockets, but in theory affecting other socket transports as well. - Resolve Debian packaging and build dependency issue. - Resolve Fedora bug where pmstat fails to start when pmcd has never been started (so namespace rebuild script not yet run). pcp-3.7.1 (20 March 2013) - IPv6 addresses and wild cards for host access control. - Add packaging scripts to correctly transition active temp file directories from their old locations. - Resolve a warning from rpm %pre script on new installs. - Convert pmhostname(1) to use the newer networking APIs. - Convert pmproxy(1) to use the newer networking APIs. - Correct the pmlogger heuristics for determining whether it is running as a daemon for *both* pmlogger_{daily,check}. - Add script to handle the tmpdir transition such that folks with running parfait/mmv-instrumented applications continue to see data exported, and for correct pmlogger/pmie daemon tracking across releases. - Fix "Warning: __pmConnectRestoreFlags: cannot restore flags" messages when built with secure-sockets option disabled. pcp-3.7.0 (11 March 2013) - Added hash table iterator interfaces to libpcp. - Added PCP_SYSCONF_DIR, migrated daemon configuration there. - Fix Linux swap metrics problems, thanks to Martins Innus. - Support for IPv6 and revamped networking (libpcp-internal) APIs, in particular making proper use of getaddrinfo now. - Initial version of the NetBSD port - Secure connections are now available as described here: oss.sgi.com/projects/pcp/pcp-gui.git/man/html/lab.secure.html - Added a PCP_USER setting for globally changing the default unprivileged user account used by PCP daemons. - Resolved Debian packaging issues from previous release to do with the pcp-python subpackage. - Improve pmdaapache fetch implementation (reduced overhead) - Close up a file descriptor leak on a pmdaapache error path, thanks to Ryan Doyle. - Added the gfs2 PMDA. - Added the systemd PMDA. - Alignment issues on ia64 resolved. - Create pmlogger and pmie logdirs during install. - Added -L option to pmconfig(1) for reporting libpcp options. - Further workarounds for sar/sadf XML exporting problems. - Updates to MinGW PCP builds for native PCP on Windows. - Use initgroups() to correctly set up supplementary groups in PCP daemons that are changing user/group from root/root. - Fix memory leak on scandir failure in several PMDAs. - Correctly install the pcp user/group during Mac OS X upgrade - Allow pmdalogger to be installed on multiple platforms - Series of updates to pmie to improve action %h, %v and %i substitutions (amongst other pmie improvements and several corner-case fixes) - MySQL PMDA now re-connects after a database server re-start. - Workaround versioning issues between python and rpmbuild. - Ensure HZ is initialised in Linux proc PMDA, fixing a small regression from the earlier proc/linux PMDA split. - Fix -p option to pcp(1) command reporting pmie instances. - Add one-line help for the proc metrics that did not have it. - Change primary pmlogger control from symlink to link. - Add an interface allowing PMAPI clients to explicitly cleanup (which allows for improved accuracy in valgrind reporting). - Fix race conditions in pmie and pmlogger startup scripts. - Updates to the named (name server) PMDA. - Change __pmSetProcessIdentity to fail more resoundingly. - Fix issues with pmdashping timeouts observed on multi-core x86_64 machines related to signals interacting with pthreads. - Move debian tmpdir settings to match other distros. pcp-3.6.10 (19 November 2012) - Transition daemons to run under an unprivileged account. - Fixes for security advisory CVE-2012-5530: tmpfile flaws. - Fix pcp(1) command short-form pmlogger reporting. - Fix pmdalogger error handling for directory files. - Fix pmstat handling of odd corner case in CPU metrics. - Correct the python ctype used for pmAtomValue 32bit ints. - Add missing RPM spec dependency for python-ctypes. - Corrections to pmdamysql metrics units. - Add pmdamysql slave status metrics. - Improve pmcollectl error messages. - Parameterize pmcollectl CPU counts in interrupt subsys. - Fix generic RPM packaging for powerpc builds. - Fix python API use of reentrant libpcp string routines. - Python code backporting for RHEL5 in qa and pmcollectl. - Fix edge cases in capturing interrupt error counts. pcp-3.6.9 (12 October 2012) - Python wrapper for the pmimport API - Make sar2pcp work with the sysstat versions from RHEL5, RHEL6, and all recent Fedora versions (which is almost all current versions of sysstat verified). - Added a number of additional metrics into the importer for people starting to use it to analyse sar data from real customer incidents. - Rework use of C99 "restrict" keyword in pmdalogger (Debian bug: 689552) - Alot of work on the PCP QA suite, special thanks to Tomas Dohnalek for all his efforts there. - Win32 build updates - Add "raw" disk active metrics so that existing tools like iostat can be emulated - Allow sar2pcp to accept XML input directly (.xml suffix), allowing it to not have to run on the same platform as the sadc/sadf that originally generated it. - Add PMI error codes into the PCP::LogImport perl module. - Fix a typo in pmiUnits man page synopsis section - Resolve pmdalinux ordering issue in NUMA/CPU indom setup (Redhat bug: 858384) - Remove unused pmcollectl imports (Redhat bug: 863210) - Allow event traces to be used in libpcp interpolate mode pcp-3.6.8 (14 September 2012) - Corrects the disk/partition identification for the MMC driver, which makes disk indom handling correct on the Raspberry Pi (http://www.raspberrypi.org/) - Several minor/basic fixes for pmdaoracle. - Improve pmcollectl compatibility. - Make a few clarifications to pmcollectl.1. - Improve python API test coverage. - Numerous updates to the test suite in general. - Allow pmda Install scripts to specify own dso name again. - Reconcile spec file differences between PCP flavours. - Fix handling of multiple contexts with a remote namespace. - Core socket interface abstractions to support NSS (later). - Fix man page SYNOPSIS section for pmUnpackEventRecords. - Add --disable-shared build option for static builds. pcp-3.6.6 (28 August 2012) - Added the python PMAPI bindings and an initial python client in pmcollectl. Separate, new package exists for python libs for those platforms that split out packages (rpm, deb). - Added a pcp-testsuite package for those platforms that might want this (rpm, deb again, mainly) - Re-introduced the pcp/qa subdirectory in pcp and deprecated the external pcpqa git tree. - Fix potential buffer overflow in pmlogger host name handling. - Reworked the configure --prefix handling to be more like the rest of the open source world. - Ensure the __pmDecodeText ident parameter is always set Resolves Red Hat bugzilla bug #841306. pcp-3.6.5 (16 August 2012) - Fixes for security advisory CVE-2012-3418 o Add field validation to PCP instance PDU (Red Hat #841240) o Fix __pmDecodeInstanceReq heap buffer overflow (Red Hat #841284) o Fix __pmDecodeText heap overflow (Red Hat #841249) o Multiple issues in result PDU decoding (Red Hat #841159) o Fix __pmDecodeNameReq buffer overflow (Red Hat #841180) o Add length checks to __pmDecodeLogControl (Red Hat #841290) o Add size check to __pmDecodeIDList (Red Hat #841112) o Fix __pmDecodeNameList buffer overflow (Red Hat #840920) o Add missing __pmDecodeFetch namelen checks (Red Hat #841183) o Add length checks to __pmDecodeProfile (Red Hat #841126) o Add length checks to __pmDecodeCreds (Red Hat #840822) - Workaround for security advisory CVE-2012-3419 o Split the Linux kernel and proc PMDAs to prevent information leakage in default installs - esp. /proc/pid/maps exposure, but other proc metrics as well - and no longer export process metrics by default (Red Hat #841702) - Fixes for security advisory CVE-2012-3420 o Memory leak in pmcd DoFetch error path (Red Hat #841298) o Memory leak in __pmGetPDU in-band signalling (Red Hat #841319) - Fixes for security advisory CVE-2012-3421 o Resolve event-driven programming flaw in pmcd (Red Hat #841706) - Correct buffer unpinning logic in a PMNS traversal error path o Red Hat bugzilla bug #847314. - All of the above issues were identified by Florian Weimer of the Red Hat Security Team, who also assisted extensively in fixing and testing; a huge thank you to Florian from all PCP developers and users! - Add modern gcc/glibc security protection mechanisms where available. Thanks to the Frank Eigler. - Harden all boundary checking in the remaining PDU decoders. - Resolve an issue with configure script checking for the init(1) process on Fedora 17 (and other systems using systemd). Thanks to Lukas Berk. - pmdaelasticsearch only reports on nodes in the cluster now, and not other client nodes. Thanks to Nigel Donaldson. - Added interfaces to PCP::PMDA Perl module to allow PMDAs to use a hash instance domain (instead of int/string array). These make use of the pmdaCacheOp(3) interfaces - the hash keys are the (external) PCP instance names, and the value associated with each key is an opaque reference. - Added an interface to allow PMDAs to register event queues with existing clients (pmdaEventNewActiveQueue). - Initial version of the (experimental) bash tracing PMDA. pcp-3.6.4 (12 June 2012) - Fix build on s390x platform (thanks to Dan Horak) - Rethink order of PATH setting for pcp start scripts, to ensure binaries from other packages with names that conflict with pcp binaries are not found ahead of the same-named pcp binary. pcp-3.6.3 (27 April 2012) - Revert initial attempt at getting configure --prefix option to make sense for local developer PCP installations - Fix RPM changelog typo in in-tree spec file - Further work on Debian/kFreeBSD port (thanks to Robert Millan) pcp-3.6.2 (18 April 2012) - Fix Debian builds on FreeBSD (missing header files) - Resolve Debian startup script (compat) lintian issue - Resolve FreeBSD kernel PMDA build issue with PCP not installed in the build root already. pcp-3.6.1 (12 April 2012) - Resolve final Mac OS X pthreads build issues - Debian packaging improvements for split pmlogger/pmcd scripts, perl module pieces, and other lintian reported issues - Update the startup script dependencies for /var use - Support --prefix=... and --exec-prefix=... configure options - Relaxed the "are you running as root?" test in startup scripts - Win32 build updates and improvements - Cache /proc/stat file handle in Linux kernel agent to reduce syscalls on the most commonly fetched metric subtree pcp-3.6.0 (21 March 2012) - Thread-safe libpcp, including additional re-entrant and thread-safe variants for some routines - Retire all asynchronous routines from libpcp - Retire all V1 protocols and services (archive format, PMAPI and PMDA_INTERFACE) - PMNS moves to ASCII only (no binary PMNS) - Rework "init" scripts, splitting pcp into pmcd and pmlogger - Update elasticsearch PMDA to 0.19+, new transport and shard metrics - Updates to PMDA new event queueing interfaces for agents wishing to export that class of performance data. - First round of Coverity cleanup fixes incorporated. - Initial version of the SNMP PMDA, thanks to Hamish Coleman. - Updates to postgres PMDA to export additional recovery metrics. pcp-3.5.11 (01 December 2011) - Update FSF contact address in copyright notices to keep rpmlint happy. - Fix instance domain checks in elasticsearch PMDA. - Make KVM PMDA to run as root once more (permissions issues). - Integration of pmlogger_daily with pmlogrewrite. - Fix pmlogger_merge corner case for empty archives. pcp-3.5.10 (04 November 2011) - Support new 0.18+ elasticsearch metrics. - Fix handling of elasticsearch version metric cluster. - Fix trace PMDA build issues. - Fix some Win32 build issues. - Run with reduced privileges for more of the perl PMDAs. - Name Solaris load average metric consistently. - Small metric documentation tweaks for Solaris PMDA. pcp-3.5.9 (23 October 2011) - Add rc script support for condrestart, and condrestart the pcp, pmie and pmproxy services after an RPM install or upgrade. - Fix a bug where hinv.ndisk is incorrect if CLUSTER_PARTITIONS hasn't yet been refreshed immediately following a restart. - Implementation of client event queueing logic for all PMDAs to share (all PMDAs wishing to support event metrics, that is). - New manual pages for new PMDA event queueing interfaces. - PostgreSQL PMDA, supporting versions 9.0 and 9.1 (at least). - Reserved ID 111 for Samba Clustered Trivial Database PMDA. - Add perl interface to allow PMDAs to drop priveleges - Add an elasticsearch version metric. - Correct perl module type detection logic for 32/64-bit systems. - Small pmlogconf source and man page fixes. - Rework flex usage to resolve build warnings. - Make Darwin CPU metrics 64 bit. - Add (long) opaque key support to libpcp_pmda. - Add pmdaCacheStoreInst() routine to libpcp_pmda. - Added mssql PMDA for SQL server Dynamic Management View stats. - Add pmlogrewrite(1) to rewrite archives (fix inconsistencies). - Fix a cgroup option parsing error on consecutive fetch calls. pcp-3.5.8 (08 August 2011) - Rework rsyslog PMDA to remove Switch use, very odd behaviour observed on RHEL5.2 (mysteriously failing to compile). - Add in Kens scripting defenses against dodgey toolchains. pcp-3.5.7 (05 August 2011) - Fix build issue on SLES11 SP1 IA64 systems. - Improved rsyslog PMDA handling of queue metrics. - Add open file-descriptor count metric to the Linux PMDA. - Implement logger PMDA line-oriented event mode. - Add regular expression based event filtering in logger PMDA. - The default pmcd.conf now has an access control section, and all remote store operations are blocked by default. - Improve packaging of Perl components. pcp-3.5.6 (21 July 2011) - Fix warning from pmie_daily with some /bin/pwd versions. - Numerous Debian packaging updates for lintian cleanliness. - Fixed typos in several man pages. - Added ElasticSearch PMDA. - Fix build on RHEL4 with older sys/queue.h variant. pcp-3.5.5 (6 July 2011) - Resolve Debian packaging issues preventing new uploads. - Fix warnings from pmie_check with some /bin/pwd versions. pcp-3.5.4 (6 July 2011) - Fix warnings from pmlogger_check with some /bin/pwd versions. pcp-3.5.3 (6 July 2011) - Remove reliance on a cpp binary being installed locally with new pmcpp applicaton. - Ensure compressed pmie log files are also cleaned up daily. - Extend the event store mechanism to be more generally useful. - Add memory limiting functionality to pmdalogger. - Add SQLServer metric for user settable queries. - Fix potential sigsegv in pmprobe fetching multiple live values. - Perl changes for Solaris. - Fix Fedora15 build relating to handling of systemd. - Solaris pmda zpool_vdev_name() api change. - Update sar2pcp for sysstat version 9.1.7. - Resolve realloc issue in event metric handling in libpcp_pmda. pcp-3.5.2 (3 June 2011) - pmlogreduce - fix 2 problems (memory leak, additional mark records) - Initial version of pmdalogger, from David Smith, a log monitoring PMDA exporting event metrics. - Make Windows drive instance domain code less chatty. - RC scripts and pmie_check - Mac OS X porting - pmlogger_check - symbolic link issue fixed - Add in the rsyslog PMDA (http://www.rsyslog.com) - Extend PCP::PMDA so that the log tail mode can be used on named papes. - Numerous updates to the Perl packaging infrastructure - Fix build when $HOME is not set. - pmlogconf - another non-posix awk issue fixed - Darwin pmda - filesys.maxfiles metric - pmie_daily - assorted minor fixups - Unix domain socket issue found on Mac OS X - pmcd config parsing error handling cleanup - Quieten pmevent output in the absence of new events. - Pass process ID out on success of __pmProcessCreate. - pmdaproc.sh - add PMDA_INTERFACE_5 support - pcp_completion.sh - add pmevent for bash metic completion - pmevent - add instance domain support - Bugfix: fetching hinv.cpu.* aborts if cpu indom is not initialized - Rearrange the per-CPU intr metrics on Linux to use dynamic namespace - Add perl modules into Mac OS X installations - Additional vmstat metrics added to Linux kernel PMDA - Fix pmieconf after syscall metrics went away on Linux - pmevent - new util to report event records, with instance domain support - sample PMDA - instance domain for event records metric - pmval, pminfo - man page typo corrections - pmval - fix typo in error message - pmlogextract, pmlogreduce - auto volume switch at 2^31 bytes - pmnscomp - defaults to Version 2 of the compiled PMNS - Remove unconditional diagnostic in MMV agent, log spam - Rework the code that uncompresses archives for Win32 - Updates to Win32 makefiles to get a clean package build - Enable compressed log processing for Windows as well - Sample event consumer code for Windows ETW - Update PDH Win32 headers to use those from current mingw-m64 tree - Win32 socket error messages are reporting correctly - Great strides in getting error reporting correct on Windows - Add Win32 pthread wrapper for threading work on Windows - Add PowerDNS recursor stats to the pdns PMDA pcp-3.5.0 (31 January 2011) - Infrastucture support for doing distributed event tracing with PCP. This includes a new metric type (PM_TYPE_EVENT), cunning mechanisms for encoding event records in pmResults, and providing PMDAs with per-client context connection information allowing agents to track which clients have seen which parts of a trace stream so far. Some reference uses of these extensions can be seen in pmdasample and in the pmcd PMDA as well. - Transparent support for archive de-compression by clients. - Manual page formatting errors corrected. - Fix a pmDupContext memory corruption issue seen with derived metrics. - Added a one-trip optimisation/guard to pcp.env - Improved pmdaFetch and pmdaFetchCallback man pages with respect to return codes and value memory allocation models. - Fix for Windows unintentionally allowing multiple pmcd processes to startup and bind to the same port, with "undefined" results. - Fix Windows services interaction, preventing pmcd service stop. - Fix Mac OS X scandir memory leak on empty directories. - Fix Mac OS X mem.util.wired metric, was exporting the wrong value. - Correct the handling of SLES11 distro identification (lsb-release file not used again, on SuSE Linux distributions). - Fix postfix PMDA log file path handling for Redhat Linux distros. - Extend Perl PMDA interfaces to allow additional metrics to be added at runtime (now makes use of dynamic namespace support). - Set KEEPALIVE option on pmproxy client sockets, mirroring pmcd behaviour and reducing open file descriptor pressure. - Improvements to the native Windows version of pmlogger, preventing it from exiting prematurely thanks to a socket read race condition. - Fix /proc/interrupts parser in Linux PMDA, thanks to Arthur Kepner. pcp-3.4.1 (9 October 2010) - Remove bogus (expected) errors/warnings from Win32 install/remove. - Remove couple of no longer needed local Win32 API wrappers. - Fix rindex code for Win32 so it handles empty strings. pcp-3.4.0 (29 September 2010) - Add new libpcp_import C API library to pcp-libs. - Add perl-PCP-LogImport RPM sub-package for libpcp_import perl binding. - Add pcp-import-* RPM sub-packages containing front-end tools for importing data from sar, iostat, generic speadsheets and mrtg. - Major Solaris PMDA updates: CPUs, vnode ops, disk stats and disk queue stats, switch to using pmid clusters, internal timers, ZFS Adjustable Replacement Cache stats, new help text, memory metrics, fsflush stats. - Use Solaris devinfo to get information about pretty disk names. - Fix a memory leak in Perl PMDA wrapper string handling. - Use correct structure to extrace zpool write counters in Solaris PMDA. - pmafm now supports multiple -a arguments. - Fix pmie multiple -a options bug. - Fix pmdaInit() callback handling where it did not handle all the interface versions correctly. - Quote filenames reported by pmwtf, else awk can get confused. - Fix pmdawindows missing metrics help text. - Add network interface speed metrics into pmdawindows. - Fix pmdalinux handling of long network interface names. - Updated pmdaapache to use cross-platform http library. - Updated pmdaapache install process to allow port selection. pcp-3.3.3 (16 July 2010) - Fix two off-by-one errors in NUMA metrics in Linux PMDA. - Rework timezone environment variable handling to be able to coexist more peacefully with Perl. - Remove Fedora specfile now that this is in Fedora CVS. pcp-3.3.2 (10 July 2010) - Fix FreeBSD build and packaging issues affecting Debian. - Move PCP::Glider Perl code into core PCP with other Perl modules. - Avoid a mingw64-compiler-runtime bug in gettimeofday. - Fix spec file issue in Fedora/RHEL builds. - Add in the gpsd PMDA. pcp-3.3.1 (29 June 2010) - Fix a sigsegv in pmdalinux in the kernel.pernode.cpu metrics. - Don't kill dbpmda if namespace cannot be loaded. - Resolve a Windows build error under latest toolchain. - Some minor pmieconf and pmimport related cleanups. pcp-3.3.0 (25 June 2010) - Rework pmlogconf utility - version 2.0 ondisk format. - Initial support for Linux kernel cgroup subsystem, using dynamic metrics (cpu sets, cpu sched, cpu acct, memory, ...) - Fix per-process I/O (proc.io.*) metric values. - Fix potential SEGV in derived metrics when pmcd connection lost. - Fix to allow pmlogger to log derived metrics. - Fix open file descriptor leak in Linux disk scheduler code. - Postfix PMDA updated to report aggregate stats from mail.log parsing. - Add per-node CPU metrics to Linux kernel agent. - Integrate pmieconf into the build, modernisation and porting work. - Add install-sh to the set of pcp-internal programs for external code. - Improved checking of PMDA domain numbers. - Allow use of SunStudio compiler on Solaris. - Add load average metrics to Solaris kernel agent. - Windows 7 porting work. - Make Win32 build work with more recent versions of gcc and Perl. - Fix pmie [no]match_inst botch, tweak sleepTight reporting. - Allow \$ for pmie regular expressions. - Ensure pmlogger doesn't write extended pmcd host syntax as hostname. - Switch over to not using local context for bash completion. - Improve Lustre agent metric help text. - Added a readonly filesystems metric into Linux kernel agent. - Ensure xfs.buffer metrics are always properly refreshed. - Add Linux kernel statistics related to XFS btree operations. pcp-3.2.1 (3 May 2010) - Export information about ZFS snapshots - Correct accounting of PMNS size in a libpcp_pmda helper routine. pcp-3.2.0 (29 April 2010) - Change how PM_CONTEXT_LOCAL determines available PMDAs: rework local context code to retire $PMDA_LOCAL_*, build DSO table from pmcd.conf at run-time, new __pmLocalPMDA and __pmSpecLocalPMDA routines in libpcp, -K options for pminfo, pmval and pmprobe. - Make some pmda dynamic name operations take (const char *) args. - Fix bash completion so dynamic names expanded, and stderr culled (culling DSO agent initialisation messages). - Improve pmlogger handling of alias names (same PMID, different names). - Honour the -T command line option in pmlogreduce. - Resolve an MMV issue evident in the Mac OS X installer, which resulted in failed dmg (binary) installation attempts. - Solaris startup script improvements. - Add details of the extended hostname syntax to pcpintro(1). - Fix a memory leak in pmdawindows help text handling. - Fix a memory leak in pmdammv help text handling. - Add anonymous huge page Linux memory utilisation metric. - Fix local context reporting of help text. - Solaris man page build changes. - Clean up diagnostic messages in pmlogextract. - Teach pmdaproc about Solaris' ping. - If pmstat fails to connect to local pmcd, fallback to local context. - Mark as const the final (requested units) pmConvScale argument - Clean out SGI-isms from build related files (no longer used by SGI). - Fix mem.numa.util.NFS_Unstable metric. - Removed pmdajstat, this has long been superceded by the capabilities of the Parfait package for instrumenting Java applications with PCP. pcp-3.1.2 (22 March 2010) - Add indom save and restore logic into Windows PMDA. - Fix a typo in the Postfix PMDA. - Update and extend /proc/meminfo stats on Linux. - Improve handling of monitored process in pmdammv, especially when the monitored process exits (pmns not cleaned up before). pcp-3.1.1 (23 February 2010) - Use a better MMV generation number, using all bits available. - Fix a metric count calculation error in pmdammv. - Add precision argument (-p) to pmwtf. - Added an open socket sockname command to dbpmda. - Remove use of grep -q, unavailable on OpenSolaris. - Couple of trivial build fixes for the Win32 platform. pcp-3.1.0 (28 January 2010) - Derived metric support. - Fix a memory leak in the Solaris kernel PMDA. - Extract information about network links on Solaris. - MMV PMDA (DSO) is now installed and enabled by default. - Reintroduced MMV support for cross-(mmap-)file instances. - Bug fix in pmdammv which was capable of causing SIGSEGV. - Add dbpmda readline support (and packaging dependencies). - Add in -Z option to pmwtf, to pass through to pmlogsummary. - Export NUMA memory statistics from the linux kernel. - Make pmie_check work on Solaris. - Make perdisk stats part of the zpool hierarchy. - dbpmda fix for name lookup and dynamic metrics. - Add a new PMDA exporting the Postfix queue lengths. - BuildRequires initscripts for %{_vendor} == redhat. pcp-3.0.2 (2 December 2009) - Improvements and fixes to PCP::PMDA perl module. - Added the SQL Server dtsrun log file parser PMDA. - Switch MMV PMDA to use dynamic namespace interfaces, which resolves long-standing spurious EAGAIN error on reconfiguration. - Separate out the Infiniband and cluster PMDAs into their own package - removing dependencies and configure complexities from pcp into specialised, layered packages. - Configure packaging to use libexecdir for private pcp binaries, if supported on the platform (also honour --libexecdir configure flag) - Add sysfs.kernel metrics cluster to Linux PMDA. pcp-3.0.1 (19 October 2009) - Reverted rc scripts default start/stop settings back to how it was in 2.9.3-1, for Debian bug #544350. On Red Hat platforms, the RPM spec overrides this to be chkconfig off by default. - Lexical analyser tweaks (various tools) to work on Windows. - pmlogextract change timezone selection algorithm, add -f for old behaviour - configure.in clean up more thoroughly on Mac OS X - Get pcp building on Debian GNU/kFreeBSD port. - Add missing return statement causing incorrect mem.util on Win32. - Improved support for Slackware distro makepkg packaging - Solaris fixes: pass information about compiler into Perl PMDA makefiles, don't change pointer types of pmCtime's arguments, deal with default lex - Move Infiniband and Cluster PMDAs to a stand-alone packages - Trim the set of RPM files marked as %config to just those that are actually likely to be edited (rpm -qlcv pcp pcp-libs). pcp-3.0.0 (9 October 2009) - PMDA_INTERFACE_4 and the support of dynamic subtrees of the PMNS where the PMDA (not PMCD) maintains knowledge of the PMNS. - RPM packaging split into pcp, pcp-libs and pcp-libs-devel pcp-libs is common - it's required by pcp and by pcp-libs-devel but pcp and pcp-libs-devel can be installed with or without each other. - Added separate specific licenses for the new subpackages, particularly pcp-libs, which is LGPL. - Added ldconfig %post and %postun scriptlets for -libs - Don't explicitly require Infiniband libs, since they're libs and RPM figures it out - No need to explicitly BuildRequire gcc-c++ libstdc++-devel - Add BuildRequires on perl-ExtUtils-MakeMaker - Remove explicit ia64 Requires: libunwind - Preserve generated gram.tab.c in several places since debuginfo needs it - Create %{_localstatedir}/run/pcp and ship it (so it'll be removed) - Use %doc in spec for CHANGELOG COPYING INSTALL README VERSION.pcp pcp.lsm - Tweak configure to move PCP_BINADM_DIR out of /usr/share, into /usr/lib. Arch dependent binaries should not be installed below /usr/share. - Delete unneeded "explicit script interpreter" in several places to keep rpmlint happy - Remove setuid from pmpost, not needed (and not in debian either) - Nuke the migrate_pcp_var_dir, script and it's %post scriptlet - Default "chkconfig off" for all PCP services (retain settings on upgrade) - Clean-up and simplify the %post scriptlets (rather dramatically) - Don't ship static libraries in Fedora, we have the debug package for that - Install .NeedRebuild, add to %files and remove crud from %post scriptlets - Added %changelog in RPM spec and moved %files to end before %changelog - Move demos, examples and demo PMDAS to the libs-devel package since they are not used for production (but are useful for devel and needed for QA). - Don't install trace demo binaries since src is installed anyway - Reconciled build/rpm/pcp.spec.in with build/rpm/pcp_fedora.spec - Integrated RPM packaging support for perl-PCP-PMDA and perl-PCP-MMV (but perl-PCP-Logsummary is not currently shipped in RPM packages) - RPM build requires perl(ExtUtils::MakeMaker) rather than perl-extutils-makemaker (this is the standard notation) - For easier upgrades, the perl PMDAs only really require pcp >= package version (until we change or extend an API). - ReplacePmnsSubtree fix bad signal handling botch (affecting MMV PMDA) - Fix pmcd.timezone metric such that value updates on daylight savings (or other timezone) changes. - Initial packaging work for Slackware Linux, thanks to Roman Revyakin. pcp-2.9.3 (23 September 2009) - configure.in fix for Windows iptypes.h header. - Fixup Windows SQL Server metrics on 64 bit platforms. pcp-2.9.2 (7 September 2009) - Final iteration on pmval sample count changes. - Build fallout on Mac/Win32 in MMV client library. - Tidy configure.in sys/stat time field/types handling for Alpha builds. pcp-2.9.1 (2 September 2009) - Fix a long-standing pmval sample count miscalculation. - Add missing runlevels and dependencies in start scripts. - Fix a segv observed in the Windows PMDA accessing SQL Server metrics. - Fix logic error causing wrong Windows version to be reported sometimes. - Add kernel.all.uptime to the Windows kernel agent. - Initial version of the (perl-based) Samba PMDA. - Fixes to pmdasimple.pl so it functions correctly on all platforms. - Add PCP::PMDA helper routines for determining native long sizes. - Extend MMV to allow teardown of MMV file, and set errno on failure. - Initial stable (1.00) version of MMV Perl interface. - Correct the metric units for several Windows per-process memory metrics. - Add network metrics to Solaris PMDA - Report ZFS statistics from Solaris PMDA - Export zpool stats from Solaris PMDA - Generate packages for Solaris - Allow user to choose her compiler (proper use of AC_PROG_CC) pcp-2.9.0 (27 July 2009) - Fix Linux PMDA issue with -fstack-protector gcc option. - Get socket daemon PMDAs working with Win32 pmcd. - Bind 9.4 PMDA. - PowerDNS PMDA. - Fix atexit handling in the Perl PMDA module. - Fix a duplicate PMID in the MySQL PMDA. - Infiniband PMDA improvements and man page. - Minor packaging tweaks for rpm and deb formats. pcp-2.8.12 (8 July 2009) - Bug fixes in Zimbra and MySQL PMDAs. - Fix memory leaks in the Perl PMDA interface. - Fix the Mac OS X pmdadarwin metric table direct mapping. pcp-2.8.11 (6 July 2009) - Rework namespace file generation for Perl PMDAs. pcp-2.8.10 (1 July 2009) - RPM packaging fixes for Perl modules. pcp-2.8.9 (1 July 2009) - Remove Cygwin support, we're now committed to native Win32 port - first production install yesterday, hooray! - Further Win32 work - wrapper batch files for shell scripts run as commands, moved daemon configs into $PCP_DIR/etc, bug fixes to process creation code. - Significant work on the MMV PMDA, including revamped API, Perl API, updated on-disk support with string values and help text support, amongst other changes. - Fix build of Perl PMDA module when PCP not installed. - Fix Zimbra PMDA status metrics. pcp-2.8.8 (9 June 2009) - Added a Zimbra Collaboration Suite PMDA. - Build fixes for OpenSolaris. - Perl PMDA fixes in tail mode. - Correct physical memory reporting in Windows PMDA on 32 bit machines. - Other small tweaks and improvements to Windows PMDA also. pcp-2.8.7 (29 May 2009) - Windows PMDA major rework to improve memory footprint. - Yet another Mac OS X build issue resolution. pcp-2.8.6 (26 May 2009) - Fix build on Mac OS X after lex warning cleanups. - Fix pmdate build when PCP headers not in the root. - A single PMNS domain number file now used in-tree. - Added tmpfs filesystem metrics to Linux PMDA. pcp-2.8.5 (21 May 2009) - Packaging tweaks for Debian (builddefs/rules moved). - Make timezone manipulation in Windows work (mimic MSYS). - Numerous warnings fixed. - Several changes to tempfile handling for Vista. - Make setting pcp_rc_dir in configure.in more robust. - Further pathname separator auditing for Windows. - Fixed a libpcp_gui linker issue on Mac OS X. pcp-2.8.4 (12 May 2009) - Descend into src/bashrc. D'oh! pcp-2.8.3 (11 May 2009) - Bash auto-completion of metric names. - Fix a memory leak in xfs project quotas metrics. - Several Win32 fixes for Windows Server 2008. - Add Linux per-CPU and aggregate "guest" CPU utilisation metrics. - Add a pmlogsummary option to report a "header" line (-H). - Add optional pmstat support for time control via pmtime. - Add pmcd.client.* metrics for identifying connected clients. pcp-2.8.2 (24 April 2009) - Fix pmie bug in the handling of && and || operators. - Improve daily pmie/pmlogger script behaviour. pcp-2.8.1 (19 April 2009) - Fix build issue with libpcp_mmv - would not build-from-source if was not in the root filesystem. - Finer control of pmie2col(1) reporting precision. pcp-2.8.0 (9 April 2009) - Linux netfilter (IP connection tracking) PMDA included - Memory Mapped Value (MMV) PMDA and client library included - Linux bonding (bonded network interface) PMDA included - Lustre PMDA included - Added pcp_gui library as pcpmon replacement, supporting the new (open source) version of pmtime for console tools. - Perl PCP::LogSummary module included. - KVM (Linux Kernel Virtualisation layer) PMDA - Infiniband PMDA included - VMware PMDA included - Perl PCP::PMDA module completed, stabilised and incorporated. - Default pmcd and pmproxy ports changed to IANA registered ones. ( The old behaviour - i.e. both original and IANA ports - is still available using PMCD_PORTS and PMPROXY_PORTS variables ). pcp-2.7.7 (5 September 2008) - Infiniband metric enhancements - Handle missing "which" binary during rpm installation - Added new quota metrics (XFS project quota) - Aggregate and per-CPU hypervisor "steal" time metrics added - NFS v4 metrics - commitLimit meminfo metric added - Namespace locking fix in pmdaproc.sh - Additional Windows memory metrics - Several pmie fixes from Ken - Kens pmlogreduce archive corruption fix - Kens pmproxy PDU size fix - Nathan's pmlogsummary sum calulation fix - Added a (cheap) runnable processes metric. pcp-2.7.4 (7 September 2007) - MaxOSX and Debian/Ubuntu build/package fixes - Add sqlserver active_transactions metrics to the Windows PMDA. - Fix a pmie_check typo causing mis-identification of pmie processes. - Allow pmie and/or operators to function with some data missing. - Resolve path naming issues with more recent versions of autoconf. - pmlogsummary report sum option - pmval kmtime support - Additional Linux SNMP metrics - Fix Linux vmstat nr_slab metrics - Make pcp status command report build version - Windows split_io metrics - Fix pmdapmcd empty pmie instance - pmdamailq filename regex - Windows TCP metrics - pmie log file rotation - Changed the default compression program to be bzip2(1) pcp-2.7.3 (July 2007) - add network.ib.control to timeout infiniband stats workthread - add mem.util.anonpages pcp-2.7.2 (8 Jun 2007) - pcp doc updates - pmdalinux death from open file descriptors: pclose needed in network.ib - network.ib stats updated to cope with OFED 1.2 changes - some numa.link fixes for shub2 & NL4 - Improve start/stop times of pmcd,pmlogger,pmie - create portable pmsleep (subsecond sleep) exe pcp-2.7.0 (7 Feb 2007) This log has been allowed to lapse for some time. Blanket catch-up.. the following PVs describe changes made in that time: - 947510 - UNIX95 patches break pcp tools - 948548 - [SUSE#182852] Buffer overflow in linux proc_pmda - 948551 - Update pcp configure and build infrastructure - 948799 - Move telnet-probe to oss part of pcp - 948958 - *nodeid conversions have inconsistent naming - 952623 - possible use-after-free of pmProfile objects used by pmda - 952932 - pcp-open RPM requires libpcp.so.2 but doesn't provide it - 953015 - Promote libpcp_pmc to DSO - 953301 - Update irix pcp bits - 953876 - Use swap.pagesin/pagesout instead of swap.in/.out in pmstat - 954035 - Update macosx build infrastructure - 954165 - pmdumptext reports wrong time with sub-second intervals - 954173 - pmReceiveNamesOfChildren returns bogus value - 954203 - pmnscomp generates bogus binary pmns files - 954342 - Add support for FreeBSD - 954343 - Update windows pmda - 954432 - Use a pidfile to stop pcp - 954652 - telnet-probe ate my arguments - 954842 - Update qa on sles10 for pcp 2.5 and 2.6 - 956190 - add IB traffic stats to linux PMDA - 956199 - pmlogsummary double free causes graph failures - 957598 - add debuginfo to pcp-open build in mangrove - 957758 - valgrind finds "invalid read of size 8" etc in __pmStuffValue - 957884 - need network.ib.status for per-port IB status and description - 958273 - If OFED is installed but no ports are found, return PM_ERR_VALUE from refresh_ib - 958379 - IB PMDA broken (port num appearing twice in perfquery calls) - 958476 - path to pmie_check binary incorrect in pmie crontab config file pcp-2.5.0-2 (15 Jan 2006) - 947602 - pmdas/aix/common.h is missing from the tarball pcp-2.5.0-1 (ProPack4/SP3) - 942325 - bump to version 2.5.0-1 - 936279 - pminfo -f hinv.machine gives 'linux'. Now scans for the SGI hardware IP number from /proc/sgi_prominfo/node0/version and exports that if found. - 936795 - tool to aid PMDA development, see genpmda(1) - 941663 - pmdaInstance broken for name == NULL and inst != PM_IN_NUL - 939448 - pcp rc script needs better handling of .NeedInstall - 857601 - pmview-args uses long lines in value/instance caches - 942030 - Improve efficiency of instance cache in libpcp_pmda pcp-2.4.1-2 (ProPack4/SP2) - bug:928986 support slabinfo v2.1 and earlier for recent 2.6.11 kernels - bug:930708 fix linkstats bandwidth measurements (in pcp-sgi package) - rfe:924904 add fixed format support for numbers reported by pmval - bug:928021 correct handling of -S and -T options when resultant time window is empty - bug:929411 tighten integrity checking in libpcp routine pmGetArchiveEnd() to avoid possible segv - bug:930467 fix fd leak on error path in __pmLogFindLocalPorts() within libpcp - rfe:932180 document pmval -i option syntax - bug:925858 add disk.{dev,all}.{read_merges,write_merges} - bug:931699 added mem.util.other back in, see help text for details - bug:931698 added mem.util.cache_clean, see help text for details - bug:933668 support netif names longer than 6 characters - bug:935490 fix pmcd exposure to attack from malformed PDUs - bug:924909 excise all usage of file(1) and reliance on its "magic" control file ... the old way cannot be made reliable in on all platforms - bug:929411 tighten tests for valid but truncated archives so pmGetArchiveEnd() no longer dumps core - add pmdumptext (and the metric class library libpcp_pmc) to the open source release - bug:935071 fix metrics broken by bug:925858, deprecate support for disk stats collected from /proc/stat (linux 2.2 kernels). - bug:934913 pmdumptext and libpcp_pmc migrated to open source - bug:934332 change save/free profile logic in __pmdaMainPDU() to avoid memory leaks - bug:934333 fix memory leak in __pmdaMainPDU() associated with instance names - bug:936975 merge pmcd.conf with pmcd.conf.rpm{new,old,save} so that foreign (non-pcp) PMDAs will continue to be configured correctly. - bug:937241 update toplevel GNUmakefile to work with modern autoconf. - bug:937243: tg3 pmda doesn't see unconfigured interfaces on sles9 - bug:936506: added new cache functions to libpcp_pmda to make it much easier to implement persistent instance domains. Rolled from libpcp_pmda.so.2 to libpcp_pmda.so.3, retained symlink for v2. Converted proc_net_dev and proc_partitions in the linux PMDA to use the new pmdaCache functionality, see pmdacache(3). - refine pmcd's handling of SIGINT and SIGTERM to use sigaction() and try to report the details of the process terminating pmcd - added the summary PMDA to the open source distribution, to provide high-level summary of system activity for large machines or large clusters of machines. - bug:939275 pmstat output format does not scale for large systems - bug:939284 correct man page source and packaging to ensure all of the man pages are in the correct package, and will be correctly indexed once installed - bug:861705 add pmproxy to support pmcd protocol proxying for clusters with head nodes and for monitoring through a firewall - rfe:919678 added new tool (pmie2col) to convert pmie -v output into pretty multi-column format - bug:939467 pcp needs to explicitly provide libpcp_pmda.so.2 - 940865 - network security probe crashes pmcd pcp-2.4.0-7 (with ProPack4/SP0) - bug:919901 cisco PMDA confused by Description: line containing '>' - bug:920140 inapppropriate glob expansion of "disallow * : all;" in pmcd.conf after PCP upgrade from pcp-2.3.2 to version 2.4.0 - bug:913157 "proc.runq.swapped shows 0 in this state" - updated help text for linux PMDA to indicate that kernel threads are not counted in the "swapped" tally. - bug:918205 fix build issues in SuSE, disallow install-sh ambiguity - bug:921103 correct build issues for SuSE - bug:923770 ProPack 4 pmieconf on Oct 22 image wont start - bug:923777 reconcile changes made to PCP in SLES9 by SuSE - bug:924714 remove disk.xvm metrics. Now handled by xvm PMDA. - bug:923732 added new mem.util metrics from /proc/meminfo for 2.6 kernels - bug:925627 instance domain for proc metrics now includes PNTL threads - bug:924909 excise all references to file(1) and the "magic" file - bug:925865 cleanup makefiles for more consistent modes and remove replicated or questionable directory creations - assorted rework to support SLES9 and RH Fedora Core 2 Linux distributions - clean up of Mac OS X port, including additional O/S metrics - bug:923773: new metrics mem.vmstat from /proc/vmstat for 2.6 kernels This also fixes swap.{pagesin,pagesout,in,out}, which have been deleted from /proc/stat - rfe:926192 add -u option for pmlogger(1) to force unbuffered writes (useful when applications monitoring a growing archive) - rfe:912895 Add pmlogreduce(1) to perform statistical reduction of PCP archives over the temporal domain by increasing the sample interval and greatly reducing the size of long-term archives pcp-2.4.0-1 (5 Aug 2004) - Installation layout changed to conform to FHS on platforms where this is appropriate: Old New /var/pcp /var/lib/pcp /usr/doc /usr/share/doc/pcp - bug:916484: %post script to migrate /var/pcp to /var/lib/pcp and bump to PCP 2.4.0. - bug:916657 mem.util.* metrics were incorrectly exported when zero - add demo program procmemstat to report per-process memory usage - Add Mac OS X support - port libraries, collection and logging infrastructure, provide Mac OS X PMDA. Target is Mac OS X 10.3. - Add Windows support - port libraries, collection and logging infrastructure, provide Windows PMDA using the PDH (Performance Data Helper) APIs. Target is Windows 98 or later, but must have either Cygwin or SFU (aka Interix) run-time installation. - Enhance Solaris support - provide Solaris PMDA using the kstat() APIs. Target is SunOS 5.8. - Add AIX support - port libraries, collection and logging infrastructure, provide AIX PMDA using ther perfstat() APIs. Target is AIX 5.2. - rfe:916189 Improvements to archive interpolation diagnostics under -Dinterp - bug:916189 use snprintf in preference to sprintf to harden defences against possible buffer overrun issues - bug:918878 avoid using file(1) in pmafm and mkaf due to problems with "magic" extensions for PCP file typing on some platforms - Linux "rc" scripts enhanced to support both the SuSE and RedHat regimes - bug:916354 set SO_KEEPALIVE on the pmcd connection socket to stop fd leaks with noisy networks - bug:916189 Fix up handling of tty name (from command line) for roomtemp PMDA pcp-2.3.2-13 (SGI Internal release) - fix bug 902034 for pcp-sgi proprietary package. Added topdisk, topsys and man pages. Fixed shubstats and enhanced pmshub. - support for 2.6 style /proc/diskstats - support 2.6 /proc/stat cpu stats, new metrics: kernel.percpu.cpu.{intr,wait.total} - bug #905010 some minor man page tweaking - bug 907846: pcp cpu.idle metrics wrap prematurely on 2.6 kernels - bug 907673: linux swap.{pagesin,pagesout} metrics are wrong - bug 909111 hinv.machine was wrong for Altix. Also, changed several hinv metrics from instant to discrete. - bug 909141: /etc/init.d/pcp now supports "restart" - bug 911201: PCP network.udp statistics are incorrect - bug:912971: install rc script to /etc/init.d, works on both RH and SuSE - bug:912972: promote network.interface metrics to 64bit unsigned, detect and handle 32bit wraps - bug:914790 parameterize /var/pcp paths, use /var/lib/pcp by default - bug:914555: not all mem.util.* metrics available on all kernels - bug:904478: pcp slabinfo metrics broken for 2.6.x kernels pcp-2.3.2-4 (6th October 2003) - fix - on SGI Altix systems, scan topology from /hw rather than /dev/hw - fix - bug #896808 kernel.{all,percpu}.cpu.idle is unsigned long and is hence exported as a 64bit ascii number in /proc/stat on 64bit kernels. Same fix for the per-process cpu metrics in /proc/*/stat affecting proc.psinfo.{utime,stime,cutime,cstime} - (proprietary) pcp-pro now obsoletes pcp-snia for the Altix platform - deprecate the PCP_LIB_COMPAT_DIR variable in /etc/pcp.conf - add Linux memory metric (mem.util.other) and memory metrics help text - add lockstat PMDA identifier into stdpmid list - add Linux vfs metrics (files, inodes, dentries) - fix - bug #900363 in linux PMDA to handle > 128 CPUs in /proc/stat - minor cleanup in libpcp, bug #901776 pcp-2.3.1-4 (16 July 2003) - fix - repair Linux fallout from TRIX changes - Makepkgs now extracts src tarball from srpm and includes build version in the tar filename - fix - make pmtrace and libpcp_trace endian safe, bug 893884 - fix - don't sum non-disk entries from /proc/partitions in disk.all metrics, and add new SGI XVM metrics below disk.xvm, bug 895611 - minor help text changes in the linux PMDA pcp-2.3.0-17 (for dev testing) - fix - compilation warnings in the mount PMDA. - fix - pmie builds with recent versions of bison. - fix - several XFS metrics to work with the current/previous XFS versions. - fix - build on Redhat 9 wrt errno.h changes. - added several new XFS metrics. - remove inclusion of some kernel headers from the Linux PMDA code. - fix - sginap() macro platform_defs.h overflows causing pmie, pmval and assorted qa tests to hang, bug 891861 - fix - repair fallout from autoconf-2.57 changes in Redhat 9 (broke "echo without newline" detection for pcp.conf), bug 892029 - fix - under rare conditions, pmFetchArchive() may return with a bogus return value, bug 892037 - fix - make pmlogger_check tolerant of hostname(1) returning the fully qualified domain name, bug 892079 - fix race in pmTimeConnect (for pcp-pro only), bug 892827 pcp-2.3.0-15 (21 May 2003) - fix - pmdampi name space issue issue, bug 891599 pcp-2.3.0-14 (27 Feb 2003) - Fix for 882525: Linux pmda fails with openafs module at Fermilab problem in symbol table management, correction also involved removing the regexp() use and cleanup resulting in a 60% speed-up. Thanks to Troy Dawson for helping to track this down. pcp-2.3.0-13 (21 Feb 2003) - portablility changes to enable building the PCP infrastructure on Solaris, based on contributions from Alan Hoyt pcp-2.3.0-12 (17 Feb 2003) - fix segfault for kernels which do not have CONFIG_MODULES reported by David Douthitt pcp-2.3.0-11 (12 Feb 2003) - patch from Anas Nashif to work with glibc 2.3.1 - fix - pmlogger_check failure messages are too verbose - fix - pmclient sometimes reports bad Busy CPU (#) on MP systems - fix - Piggy-back PDU and endian conversion error - fix - Minor problem with error-handling in pmlc-pmlogger connection protocol - fix - cleanup handling of children's exit status for pmie - fix - need better diagnostics to debug trace PMDA - fix - Minor cleanup of PCP man pages - fix - command buffer too small in pmnsdel - Solaris portability changes from Alan Hoyt (qa only so far) - fix - minor warnings and build cleanup - fix - serialize the pcp build pcp-2.3.0-10 (16 December 2002) - Changes to pmlogconf to improve usability - pmie_check fails when log files relocated via symlink reported by Micah Altman - fix linux pcp upgrade saves pmns but doesn't save pmcd.conf - fix pmlc logic error in handling descriptor fetch failures - pmdumplog reports incorrect sizes for PDUs on ia64 - fix /proc scanning for newer 2.4.x kernels and for 2.5.x - pmproxy support in libpcp - change the units of kernel.all.uptime from hours to seconds contributed by Mike Mason - fix pmafm remove does not list all files - Units wrong for proc.psinfo.rss_rlim, Mike Mason - in build/rpm/GNUmakefile, remove '=' from --target since rpm v4 doesn't seem to like it Todd Davis - fix rpm upgrade post install processing for pmieconf rules - large number of new metrics and bug fixes from Mike Mason to support metrics required by libgtop. These include the following: (new) Total idle time since boot kernel.all.idletime (new) current # of user sessions kernel.all.nusers (new) Last pid used kernel.all.lastpid (new) Filesystem blocksize from statfs() filesys.blocksize (new) Filesystem free space available to non-superusers from statfs() filesys.avail (modified) Per process command name proc.psinfo.cmd (new) Per process command line from /proc//cmdline proc.psinfo.psargs (new) Per process CPU number from /proc//stat proc.psinfo.processor (new) Per process wait channel symbol name proc.psinfo.wchan_s (new) Per process signal info from /proc//status proc.psinfo.signal_s proc.psinfo.blocked_s proc.psinfo.sigignore_s proc.psinfo.sigcatch_s (new) Per process map info from /proc//maps proc.memory.maps (new) Per process memory info from /proc//status proc.memory.vmsize proc.memory.vmlock proc.memory.vmrss proc.memory.vmdata proc.memory.vmstack proc.memory.vmexe proc.memory.vmlib (new) Per process user and group ids from /proc//status proc.id.uid proc.id.euid proc.id.suid proc.id.fsuid proc.id.gid proc.id.egid proc.id.sgid proc.id.fsgid (new) Per process user and group ids converted to names proc.id.uid_nm proc.id.euid_nm proc.id.suid_nm proc.id.fsuid_nm proc.id.gid_nm proc.id.egid_nm proc.id.sgid_nm proc.id.fsgid_nm (new) Semaphore limits from semctl()(needed by libgtop) ipc.sem.max_semmap ipc.sem.max_semid ipc.sem.max_sem ipc.sem.num_undo ipc.sem.max_perid ipc.sem.max_ops ipc.sem.max_undoent ipc.sem.sz_semundo ipc.sem.max_semval ipc.sem.max_exit (new) Message queue limits from msgctl()(needed by libgtop) ipc.msg.sz_pool ipc.msg.mapent ipc.msg.max_msgsz ipc.msg.max_defmsgq ipc.msg.max_msgqid ipc.msg.max_msgseg ipc.msg.num_smsghdr ipc.msg.max_seg (new) Shared memory limits from shmctl() (needed by libgtop) ipc.shm.max_segsz ipc.shm.min_segsz ipc.shm.max_seg ipc.shm.max_segproc ipc.shm.max_shmsys - fix libpcp_trace stub library does not build on ia64 - fix make clean doesn't remove all that it should - fix pmlogger gram.y syntax error for newer bison - fix pmstore value "too big" test does not work on 64bit platforms - fix memory leak in pmlogger on 64bit platforms - fix update-magic to recompile the magic file after install - fix pmie alarm actions, suggested by Todd Davis - fix man pages to be compatible with khelpcenter and man2html - use rpmbuild rather than rpm --rebuild for RH8, contributed by Todd Davis - use rpm instead of rpmbuild if rpmbuild isn't available, contributed my Mike Mason - in pmdas/linux/ksyms.c, use __psint and %p format for for address scanning, contributed my Mike Mason - use "make" by default in Makepkgs rather than explicitly gmake - Add top level GNUmakefile check for gmake (stolen from glibc) - Correctly check status in rule for pcp.src in build/GNUmakefile - correctly check rpmbuild exit status in Installpkgs. - fix NULL ptr deref in src/pmdas/linuyx/proc_pid.c for the case where a process exits while we're reading /proc//status pcp-2.2.2-9 (11 December 2001) - fixed mangle-src to catch all copyrights in the open source package - fixes from gilly@exanet.com for /proc/cpuinfo on alpha platform. - change configure.in to work with autoconf version 2.50 - fix configure.in to work when ps gives warnings on stderr; (eg. System.map doesn't match running kernel) - added lmsensors PMDA, contributed by Troy Dawson - added kernel.all.uptime, contributed by Gilly - fixed int overflow with kernel.*.cpu.* metrics. Fix contributed by Gilly - use sysconf(_SC_CLK_TCK) to determine HZ - fix sapic scanning for sn-ia64 in proc_cpuinfo.c - fix from gilly@exanet.com for scanning 2.4.x /proc/stat disk stats - bug 826904 Ensure atomicity of PMNS updates as seen by PMNS readers, and add transactional-level locking to ensure mutual exclusion between PMNS updaters - bug 817376 pmlogger makes too many round trips to pmcd - bug 828416 - pmlogger access control will not accept hostnames containing hyphens - bug 820891 More robust mapping of system error codes to strings to accommodate the growing range of errno values in IRIX and differences between IRIX and Linux - bug 826681 - Having $MAGIC set screws up Linux file(1) with consequent havoc for PCP scripts. Fixes to mkaf and pmie_check. - fix from Brian Harvell to allow pcp.conf.in to be configured with the following cmdline options to the configure script: --datadir --sbindir --localstatedir --libdir --mandir --bindir --includedir and --prefix - fixes from Brian Harvell for incorrectly configured paths in src/pmie/src/pmie.c src/pmns/pmnsdel.c and src/pmns/pmnsmerge.c - from Thomas Graichen , support for bzip2 compressed man pages (such as used in Mandrake 8.x) - from Martin Knoblauch , fix for a problem where if LANG is not "C", the is_chkconfig_on() shell function in rc-proc.sh does not work, causing problems with the rc scripts. src/libpcp/src/pdu.c - 1.3 - bug 836236 in libpcp: better handling of piggy-back PDU in the boundary case where the second PDU is so short that it does not contain even a full PDU header. - fix src RPM build on Turbo Linux. If /usr/lib/rpm/brp-compress exists then always use gzipped man pages. - fix buglet where file-3.35 in RH7.2 uses a compiled magic file - fix buglet where gawk complained about "\{" on Mandrake linux - on SGI SNIA systems, map node number from sapic to cnode in /dev/hw/nodenum - bug 843215, fix pmie's sprintf looking for it's config file - bug 842905, when /var/log/pcp is a symbolic link, pmie_check fails pcp-2.2.1-3 (21 June 2001) - remove unwanted *.rpmorig files after upgrade - fixed bug #827972, pcp root exploit with pmpost - fixed assorted other security issues. pcp-2.2.0-15 (23 May 2001) - don't include linux/kernel_stat.h and avoid __sparc__ conditional code - from Michal Kara: rc will rebuild PMNS if root_* files newer than root - add the roomtemp PMDA for measuring temperatures using the 1-Wire serial network ans sensor technology from Dallas Semiconductor - zero network.tcpconn values before counting them in /proc/net/tcp (Michal Kara's original code was correct - markgw busted it!) - add new LGPL library libpcp_http. Used by permission of the author, Laurent Demailly - minor surgery on apache PMDA to link with -lpcp_http - minor fix diagnostic from __pmLogRead - as reported by Alexander L. Belikoff , it was not possible to disable the primary logger via changes to the /var/pcp/config/pmlogger/control file ... this has been fixed - as reported by Alan Bailey , the assumption that /var/pcp/config/pmlogger/control was version 1.1 was implicit ... this is now documented and the pmlogger_* scripts will warn if the deprecated version 1.0 format is used accidently - from Michal Kara: fix mem leak in apache PMDA - from Michal Kara: install /var/pcp/config/pmlogger/Makefile (src is in src/pmlogctl/Makefile.install). This provides pre-processing of pmlogger config files with cpp. - reintroduction of "impl.h" header, deprecate "pmapi_dev.h" and major makefile surgery to reintegrate the IRIX and Linux PCP source trees - add ia64 support infrastructure. - use -fno-strict-aliasing for correct ia64 compilation - use -fpic to avoid gprel errors linking shlibs on ia64 - don't use -P with cpp, thus preserve line numbers - post-process help text to reformat long lines - pv:789819 fixes to mailq and sendmail PMDAs - fix endian-sensitive IP addr construction in cisco PMDA - fix sscanf unaligned access warnings on ia64 for cisco PMDA - support v1 help text again, conditional on HAVE_NDBM - fix pmval's qsort compare routine for instances - surgery on almost all man pages, merge with IRIX PCP man pages - promote shping to open-source status - fix bug #814989 where disk.all.* not summed correctly (if the sard patch has been applied to running kernel) - with the sard patch applied to the kernel, disk.all metrics were being summed as the total of disk.partitions and disk.dev metrics, resulting in approximately twice the rate of disk I/O for the disk.all metrics - added more disk metrics and update help text - the "cpu" instance domain is now dynamic and supports any number of CPUs - fixed pmie rc and pmie_{check,daily} scripts - a bunch of places were using $PCP_VAR_DIR/config/pmcd/pmcd.conf as the path to pmcd.conf (which is correct). Others were using /etc/pmcd.conf (which is only correct on IRIX). - merged IRIX/Linux versions of pmsocks - mimic the IRIX xconfirm behaviour more closely, pv 817289 - pv:817367 Handle SIGCHLD from xconfirm problem on Linux - minor changes in error messages to make them less IRIX-centric and hence more sensible for Linux - fix weblog link in doc dir logic and old netscape should be detected as CERN not NS_PROXY. - fix weblog so regex in the configuration file is recognized correctly on all platforms - only run weblogconv.sh on linux - conversion to more simple copyright in numerous places - avoid grep -q usage: not supported on early IRIX - pv:803341 Change Creator: for mkaf from mkaf to pmchart to assist with pmafm replay when pcp also installed. - updated man page text for platform-agnostic descriptions. - fix 817880 pmafm remove does not list all files - src/pmie/GNUmakefile Fix busted sed translation of the control file so the logfiles (and hence directories) are ...pmie/ rather than pmie - renamed all Makefiles to GNUmakefile - makefile surgery to allow multiple RPMs to be built from one src tree - fixes to src/pmcd/pmdaproc.sh to not use test -e - pv:815326 fix pcp linux /usr/share/magic doesn't detect pmie config - pv:818381 fix pmie_check fails esp integration - man page for pmlogsummary was in both pcp and pcp-pro - fix to src/pmie/pmie_check.sh, improve pattern to match No such file or directory for linux - fix all linux specs to install root,root rather than root,bin (needed to avoid warnings when installing on redhat7.1) - add GNUmakefile.install for all PMDAs, installed in each PMDA dir - fix src/pmdas/weblog/server.sh to use quotes on -d that was breaking when parameter empty. - pv:807561 change pmprobe -i and -I semantics to call pmGetInDom rather than using the returned indom from pmFetch - add hinv.machine for oview to use - change the cpu instance domain to use the numa names if they are present on the machine, else revert to cpuX syntax - numerous fixes so the src RPM builds on all platforms - pv:824382 - xfs block metrics were scaled incorrectly - add support for /proc/slabinfo metrics (mem.slabinfo.*) - add new "process" and "mounts" PMDAs, contributed by Alan Baily - added GPL copyrights to process and mounts src, fixed makefiles to extract domain number from stdpmid and added install targets, and small change to ignore comments in conf files. - added hinv.pagesize (uses the getpagesize(2) system call) - fixed bug #825229 where rpm upgrade would clobber root pmns for PMDAs pcp-2.1.10-8 (released circa Oct 18 2000, with SGI ACE1.4) - guard against DOS attack by restring incoming PDU size to 64K. - add hinv.map.cpu and hinv.cpu metrics exported by /proc/cpuinfo - fix small error in INSTALL_MAN rule in src/include/builddefs.in - fix for bug #793427 - correct symlinks for man pages with multiple entries in the .SH NAME section. - add network.tcpconn metrics to export counts of tcp connections in each state. Code contributed by Michal Kara (lemming@arthur.plbohnice.cz) - few minor fixes for build on ia64 pcp-2.1.9-12 (released circa Sept 13 2000, with SGI Propack1.4) - for 2.4 without sard, correctly match disk numbers in /proc/stat with major,minor numbers in /proc/partitions. pcp-2.1.9-11 (unreleased) - add pagebuf metrics (Daniel and Nathan) - fixes so the build works if pcp is not already installed - minor security fix to pcp.spec.in (force mode 644 for .NeedRebuild) - make sure the src RPM builds correctly (LSRCFILE issues from LinuxWorld) - fix for bug #797756, upgrade from pcp2.1.6 to any newer version leaves pcp chkconfig off and the name space does not get rebuilt. - extended the weblogs PCP agent so it can report proxy/squid http servers, and added assorted http cache statistics. - fixed the Cisco router PCP agent (it was broken in pp1.3). - add support for disk stats in 2.4.x kernels with "disk_io" field in /proc/stat (only used when sard patch is not installed) - if the pcp-pro package (SGI proprietary) is installed, all libpcp clients on linux are now "authorized" to monitor IRIX systems that do not have a pmcd collector license. pcp-2.1.9-6 (released 2 Aug 2000 for propack1.4 - alpha, not final) - install /usr/share/pcp/lib/rc-proc.sh containing common shell functions for use by rc scripts - these functions are tolerant of the chkconfig command missing (as in SUSE). - update all rc scripts and {pmlogger,pmie}_{check,daily} scripts to use the new rc-proc.sh functions. Remove the /etc/sysconfig stuff entirely (it was not being used anyway). - fix for #795934 : after rpm -U, pcp is chkconfig off. It turned out that an upgrade executes the %post _and_ the %preun scripts, which resulted in pcp being chkconfig'd on then off again. - fix pmie rc scripts so they work, are chkconfig friendly, and cope with _and_ without pmieconf (which is in pcp-pro). Also install /var/pcp/config/pmie/config.default as a simple example to monitor the load average and report to syslog. The pmie daemon is chkconfig off by default. - default run levels for pmcd and pmie (daemon) are now 2345, for SUSE - reconcile troff and groff differences in man page sources - fix for bug #797049 use strftime(%z) to determine timezone offsets w.r.t. daylight savings - portability surgery on src/libpcp_trace, and add new pmtracecounter() function, see pmtracebegin(3) for details. - reconcile pcp.env and pmcd.options from IRIX - fix for bug #797048 update-magic does not fully remove old entries before adding new, hence the magic file would grow after each upgrade - other minor reconciliation work with IRIX - fix build environment to allow proper handling of compressed man pages - add support for RPM version 4. - add support for add kernel.{all,percpu}.syscall metrics (requires kernel patch) - fixed for bug #797164: potential SEGV due to calling realloc on a misused pointer - src/pmdas/weblog/weblog.c - use realpath(3) to resolve devices in /proc/mounts for filesys.* metrics pcp-2.1.8-2 (released 30 June 2000) - fix for bug #793871 pmlogger_check fails after redhat upgrade (because PCP entries in /usr/share/magic were clobbered) - also install /var/pcp/pmdas/linux/pmdalinux (as a non-DSO agent for debugging and profiling purposes). - added pmda.uname (uname -a) and pmda.version (linux pmda version) metrics. The pmda.uname metric is needed by the "pcp" command. - fix for #789025 fix to ensure rpm --verify succeeds immediately after an install, and other errors in pmlogger_check - released with ACE 1.3 (MR 19 Jul 2000) pcp-2.1.7 (internal release for testing) - merged changes from IRIX for multiple namespace support in pmdaproc.sh - parameterized path to pmcd.conf and pmcd.options to avoid having to move these files in IRIX. Use PCP_PMCDCONF_PATH and PCP_PMCDOPTIONS_PATH respectfully. - add new error define PM_ERR_LOGFILE (reconciled from IRIX) - conditional pragma for pmGetConfig (not used in linux) - use if defined(HAVE_OBJECT_STYLE) to guard __pmCheckObjectStyle since it's not used in linux (reconciled with irix code) - correct logic used to scan for pmlogger pid in pmlogger_check in case where pmlogger exits prematurely, part of #789025 - added -Wall to default CFLAGS and LDFLAGS - added xfs metrics (needs kernel support else no values available) extracted from /proc/fs/xfs/stat - added nfs (version 3) metrics, same names as on irix, bug #789669 - fix instance domain for kernel.percpu.interrupts, bug #790372 pcp-2.1.6 (released 3 May 2000) - released with ISE 1.2 (MR 25 May 2000) - released with ISEMAIL 1.0 (MR 24 May 2000) - this is the version shipped with SGI ProPack1.3 - change use of __clone to pthread_create for portability - add support for raid disk stats (previously ignored) - fix for bug #789425 pmie suspect behaviour with "delta" keyword - add support for devfs style scsi disk names - fixed a problem where nfs stats were always showing NFSv3 stats rather than NFSv2 stats. We are not (yet) supporting NFSv3 stats. pcp-2.1.5 (released 12 April 2000) - released with SGI ACE 1.2 (MR 19 Apr 200) - fix bug #786743 filesys metrics are wrong - fix potential segfault bug in timezone handling - tolerate SUSE's location of magic file different to Redhat's - tolerate no chkconfig on SUSE (use %postinstall create rc symlinks) pcp-2.1.4 (released 15 Feb 2000) - fix for segfault src/pmdas/linux/pmda.c on linuxppc, found by Dale F. Brantly - fix build error in src/pmclient, was trying to use pmgenmap without /etc/pcp.env, also found by Dale. - setlinebuf(stdout) for all clients that loop (fixes a buffering problem on alpha-linux). - fixed some missing "{" in conditional variable assignments in src/pmie/etc_init.d_pmie (found by lstep@free.fr) - changed use of pmgenmap in build for pmclient and pmkstat to be consistent (found by lstep@free.fr) - don't assume clock tick rate is 100/second. Use the CLK_TCK macro instead. Rearrange arithmetic in src/pmdas/linux/pmda.c where we divide by CLK_TCK to avoid truncation in conversions from jiffies to milliseconds. - return "no values available" rather than PM_ERR_APPVERSION for the metrics disk.{all,dev}.{read,write,total}_bytes since these are not available on systems without the "sard disk patch". This is now consistent with requests for disk.partitions.* metrics. pcp-2.1.3 (released with 2.1.4) - released with ISE 1.0 (MR 1 Mar 2000) - added hinv.map.scsi metric as a map of SCSI devices (if any) - added disk.dev.{read,write,total}_bytes - filter devpts from filesys.* metrics to avoid FPE errors - added support for new style Apache configuration file and "silent" install to weblog scripts pcp-2.1.2 (released with 2.1.4) - released with SGI ACE 1.0 - fixed date field in LSM - install pmiestats.h for pmieconf - renamed /var/pcp/config/pmafm/pcp-col to /var/pcp/config/pmafm/pcp - added network.{ip,icmp,tcp,udp} metrics extracted from /proc/net/snmp - fixed shell syntax error in pmlogger_daily(1) (changed test -l to test -f) - fixed problem with definition of __psint_t on 64bit machines - fixed timezone problem with daylight saving pcp-2.1.1 (released 7 Dec 1999) - initial pcp-2.1.1 open source release pcp-3.8.12ubuntu1/pcp.lsm.in0000664000000000000000000000332112272262501012505 0ustar Begin4 Title: Performance Co-Pilot Version: @PACKAGE_VERSION@ Entered-date: @PACKAGE_BUILD_DATE@ Description: A system performance monitoring infrastructure that is distributed and extensible. Performance Co-Pilot (PCP) is a framework and services to support system-level performance monitoring and performance management. The PCP open source release provides a unifying abstraction for all of the interesting performance data in a system, and allows client applications to easily retrieve and process any subset of that data using a single API. A client-server architecture allows multiple clients to monitor the same host, and a single client to monitor multiple hosts (e.g. in a Beowulf cluster). This enables centralized monitoring of distributed processing. Archive logging and replay is integrated so a client application can use the same API to process real-time data from a host or historical data from an archive. The framework supports APIs and configuration file formats that enable the scope of performance monitoring to be extended at all levels. The architecture and services of the base PCP infrastructure are especially attractive for those tackling the harder system-level performance problems. Keywords: performance, monitoring, system, status, distributed Author: pcp@oss.sgi.com (Performance Co-Pilot Development Team) Maintained-by: pcp@oss.sgi.com (Performance Co-Pilot Development Team) Primary-site: ftp://oss.sgi.com/www/projects/pcp/download/ Alternate-site: Original-site: ftp://oss.sgi.com/www/projects/pcp/download/ Platforms: Linux, MacOSX, Solaris, AIX, FreeBSD, Windows Copying-policy: GPL (libraries are LGPL) End pcp-3.8.12ubuntu1/src/0000775000000000000000000000000012272262617011401 5ustar pcp-3.8.12ubuntu1/src/pmlogger/0000775000000000000000000000000012272262620013207 5ustar pcp-3.8.12ubuntu1/src/pmlogger/pmlogger_check.sh0000775000000000000000000005174212272262501016526 0ustar #! /bin/sh # # Copyright (c) 2013 Red Hat. # Copyright (c) 1995-2000,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Administrative script to check pmlogger processes are alive, and restart # them as required. # # Get standard environment . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/rc-proc.sh PMLOGGER=pmlogger PMLOGCONF="$PCP_BINADM_DIR/pmlogconf" # error messages should go to stderr, not the GUI notifiers unset PCP_STDERR # constant setup # tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 status=0 echo >$tmp/lock trap "rm -rf \`[ -f $tmp/lock ] && cat $tmp/lock\` $tmp; exit \$status" 0 1 2 3 15 prog=`basename $0` # control file for pmlogger administration ... edit the entries in this # file to reflect your local configuration # CONTROL=$PCP_PMLOGGERCONTROL_PATH # NB: FQDN cleanup; don't guess a 'real name for localhost', and # definitely don't truncate it a la `hostname -s`. Instead now # we use such a string only for the default log subdirectory, ie. # for substituting LOCALHOSTNAME in the fourth column of $CONTROL. # determine path for pwd command to override shell built-in PWDCMND=`which pwd 2>/dev/null | $PCP_AWK_PROG ' BEGIN { i = 0 } / not in / { i = 1 } / aliased to / { i = 1 } { if ( i == 0 ) print } '` [ -z "$PWDCMND" ] && PWDCMND=/bin/pwd eval $PWDCMND -P >/dev/null 2>&1 [ $? -eq 0 ] && PWDCMND="$PWDCMND -P" # default location # logfile=pmlogger.log # option parsing # SHOWME=false MV=mv CP=cp KILL=pmsignal TERSE=false VERBOSE=false VERY_VERBOSE=false CHECK_RUNLEVEL=false START_PMLOGGER=true usage="Usage: $prog [-CNsTV] [-c control]" while getopts c:CNsTV? c do case $c in c) CONTROL="$OPTARG" ;; C) CHECK_RUNLEVEL=true ;; N) SHOWME=true MV="echo + mv" CP="echo + cp" KILL="echo + kill" ;; s) START_PMLOGGER=false ;; T) TERSE=true ;; V) if $VERBOSE then VERY_VERBOSE=true else VERBOSE=true fi ;; ?) echo "$usage" status=1 exit ;; esac done shift `expr $OPTIND - 1` if [ $# -ne 0 ] then echo "$usage" status=1 exit fi QUIETLY=false if [ $CHECK_RUNLEVEL = true ] then # determine whether to start/stop based on runlevel settings - we # need to do this when running unilaterally from cron, else we'll # always start pmlogger up (even when we shouldn't). # QUIETLY=true if is_chkconfig_on pmlogger then START_PMLOGGER=true else START_PMLOGGER=false fi fi if [ $START_PMLOGGER = false ] then # if pmlogger has never been started, there's no work to do to stop it [ ! -d "$PCP_TMP_DIR/pmlogger" ] && exit $QUIETLY || $PCP_BINADM_DIR/pmpost "stop pmlogger from $prog" fi if [ ! -f $CONTROL ] then echo "$prog: Error: cannot find control file ($CONTROL)" status=1 exit fi _error() { echo 2>&1 "$prog: [$CONTROL:$line]" echo 2>&1 "Error: $1" echo 2>&1 "... logging for host \"$host\" unchanged" touch $tmp/err } _warning() { echo 2>&1 "$prog [$CONTROL:$line]" echo 2>&1 "Warning: $1" } _message() { case $1 in restart) $PCP_ECHO_PROG $PCP_ECHO_N "Restarting$iam pmlogger for host \"$host\" ...""$PCP_ECHO_C" ;; esac } _unlock() { rm -f lock echo >$tmp/lock } _get_ino() { # get inode number for $1 # throw away stderr (and return '') in case $1 has been removed by now # stat "$1" 2>/dev/null \ | sed -n '/Device:[ ].*[ ]Inode:/{ s/Device:[ ].*[ ]Inode:[ ]*// s/[ ].*// p }' } _get_configfile() { # extract the pmlogger configuration file (-c) from a list of arguments # echo $@ | sed -n \ -e 's/^/ /' \ -e 's/[ ][ ]*/ /g' \ -e 's/-c /-c/' \ -e 's/.* -c\([^ ]*\).*/\1/p' } _configure_pmlogger() { # update a pmlogger configuration file if it should be created/modified # configfile="$1" hostname="$2" if [ -f "$configfile" ] then # look for "magic" string at start of file, and ensure we created it sed 1q "$configfile" | grep '^#pmlogconf [0-9]' >/dev/null magic=$? grep '^# Auto-generated by pmlogconf' "$configfile" >/dev/null owned=$? if [ $magic -eq 0 -a $owned -eq 0 ] then # pmlogconf file that we own, see if re-generation is needed cp "$configfile" $tmp/pmlogger if $PMLOGCONF -c -q -h $hostname $tmp/pmlogger >$tmp/diag 2>&1 then grep -v "generated by pmlogconf" "$configfile" >$tmp/old grep -v "generated by pmlogconf" $tmp/pmlogger >$tmp/new if ! diff $tmp/old $tmp/new >/dev/null then if [ -w $configfile ] then $VERBOSE && echo "Reconfigured: \"$configfile\" (pmlogconf)" eval $CP $tmp/pmlogger "$configfile" else _warning "no write access to pmlogconf file \"$configfile\", skip reconfiguration" ls -l "$configfile" fi fi else _warning "pmlogconf failed to reconfigure \"$configfile\"" cat "s;$tmp/pmlogger;$configfile;g" $tmp/diag echo "=== start pmlogconf file ===" cat $tmp/pmlogger echo "=== end pmlogconf file ===" fi fi elif [ ! -e "$configfile" ] then # file does not exist, generate it, if possible if $SHOWME then echo "+ $PMLOGCONF -c -q -h $hostname $configfile" elif ! $PMLOGCONF -c -q -h $hostname "$configfile" >$tmp/diag 2>&1 then _warning "pmlogconf failed to generate \"$configfile\"" cat $tmp/diag echo "=== start pmlogconf file ===" cat "$configfile" echo "=== end pmlogconf file ===" else (id "$PCP_USER" && chown $PCP_USER:$PCP_GROUP "$configfile") >/dev/null 2>&1 fi fi } _get_logfile() { # looking for -lLOGFILE or -l LOGFILE in args # want=false for a in $args do if $want then logfile="$a" want=false break fi case "$a" in -l) want=true ;; -l*) logfile=`echo "$a" | sed -e 's/-l//'` break ;; esac done } _check_archive() { if [ ! -e "$logfile" ] then echo "$prog: Error: cannot find pmlogger output file at \"$logfile\"" if $TERSE then : else logdir=`dirname "$logfile"` echo "Directory (`cd "$logdir"; $PWDCMND`) contents:" LC_TIME=POSIX ls -la "$logdir" fi elif [ -f "$logfile" ] then echo "Contents of pmlogger output file \"$logfile\" ..." cat "$logfile" fi } _check_logger() { $VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N " [process $1] ""$PCP_ECHO_C" # wait until pmlogger process starts, or exits # delay=5 [ ! -z "$PMCD_CONNECT_TIMEOUT" ] && delay=$PMCD_CONNECT_TIMEOUT x=5 [ ! -z "$PMCD_REQUEST_TIMEOUT" ] && x=$PMCD_REQUEST_TIMEOUT # wait for maximum time of a connection and 20 requests # delay=`expr \( $delay + 20 \* $x \) \* 10` # tenths of a second while [ $delay -gt 0 ] do if [ -f $logfile ] then # $logfile was previously removed, if it has appeared again # then we know pmlogger has started ... if not just sleep and # try again # if echo "connect $1" | pmlc 2>&1 | grep "Unable to connect" >/dev/null then : else $VERBOSE && echo " done" return 0 fi _plist=`_get_pids_by_name pmlogger` _found=false for _p in `echo $_plist` do [ $_p -eq $1 ] && _found=true done if $_found then # process still here, just not accepting pmlc connections # yet, try again : else $VERBOSE || _message restart echo " process exited!" if $TERSE then : else echo "$prog: Error: failed to restart pmlogger" echo "Current pmlogger processes:" $PCP_PS_PROG $PCP_PS_ALL_FLAGS | tee $tmp/tmp | sed -n -e 1p for _p in `echo $_plist` do sed -n -e "/^[ ]*[^ ]* [ ]*$_p /p" < $tmp/tmp done echo fi _check_archive return 1 fi fi pmsleep 0.1 delay=`expr $delay - 1` $VERBOSE && [ `expr $delay % 10` -eq 0 ] && \ $PCP_ECHO_PROG $PCP_ECHO_N ".""$PCP_ECHO_C" done $VERBOSE || _message restart echo " timed out waiting!" if $TERSE then : else sed -e 's/^/ /' $tmp/out fi _check_archive return 1 } # note on control file format version # 1.0 was shipped as part of PCPWEB beta, and did not include the # socks field [this is the default for backwards compatibility] # 1.1 is the first production release, and the version is set in # the control file with a $version=1.1 line (see below) # version='' echo >$tmp/dir rm -f $tmp/err $tmp/pmloggers line=0 cat $CONTROL \ | sed -e "s;PCP_LOG_DIR;$PCP_LOG_DIR;g" \ | while read host primary socks dir args do # NB: FQDN cleanup: substitute the LOCALHOSTNAME marker in the config line # differently for the directory and the pcp -h HOST arguments. dir_hostname=`hostname || echo localhost` dir=`echo $dir | sed -e "s;LOCALHOSTNAME;$dir_hostname;"` if [ "x$host" = "xLOCALHOSTNAME" ] then host=local: fi line=`expr $line + 1` $VERY_VERBOSE && echo "[control:$line] host=\"$host\" primary=\"$primary\" socks=\"$socks\" dir=\"$dir\" args=\"$args\"" case "$host" in \#*|'') # comment or empty continue ;; \$*) # in-line variable assignment $SHOWME && echo "# $host $primary $socks $dir $args" cmd=`echo "$host $primary $socks $dir $args" \ | sed -n \ -e "/='/s/\(='[^']*'\).*/\1/" \ -e '/="/s/\(="[^"]*"\).*/\1/' \ -e '/=[^"'"'"']/s/[;&<>|].*$//' \ -e '/^\\$[A-Za-z][A-Za-z0-9_]*=/{ s/^\\$// s/^\([A-Za-z][A-Za-z0-9_]*\)=/export \1; \1=/p }'` if [ -z "$cmd" ] then # in-line command, not a variable assignment _warning "in-line command is not a variable assignment, line ignored" else case "$cmd" in 'export PATH;'*) _warning "cannot change \$PATH, line ignored" ;; 'export IFS;'*) _warning "cannot change \$IFS, line ignored" ;; *) $SHOWME && echo "+ $cmd" eval $cmd ;; esac fi continue ;; esac if [ -z "$version" -o "$version" = "1.0" ] then if [ -z "$version" ] then echo "$prog: Warning: processing default version 1.0 control format" version=1.0 fi args="$dir $args" dir="$socks" socks=n fi if [ -z "$primary" -o -z "$socks" -o -z "$dir" -o -z "$args" ] then _error "insufficient fields in control file record" continue fi if $VERY_VERBOSE then pflag='' [ $primary = y ] && pflag=' -P' echo "Check pmlogger$pflag -h $host ... in $dir ..." fi # make sure output directory exists # if [ ! -d "$dir" ] then mkdir -p -m 755 "$dir" >$tmp/err 2>&1 if [ ! -d "$dir" ] then cat $tmp/err _error "cannot create directory ($dir) for PCP archive files" else _warning "creating directory ($dir) for PCP archive files" fi chown $PCP_USER:$PCP_GROUP "$dir" 2>/dev/null fi [ ! -d "$dir" ] && continue # check for directory duplicate entries # if [ "`grep $dir $tmp/dir`" = "$dir" ] then _error "Cannot start more than one pmlogger instance for archive directory \"$dir\"" continue else echo "$dir" >>$tmp/dir fi cd "$dir" dir=`$PWDCMND` $SHOWME && echo "+ cd $dir" # ensure pcp user will be able to write there # (id "$PCP_USER" && chown -R $PCP_USER:$PCP_GROUP "$dir") >/dev/null 2>&1 if [ ! -w "$dir" ] then echo "$prog: Warning: no write access in $dir, skip lock file processing" else # demand mutual exclusion # rm -f $tmp/stamp $tmp/out delay=200 # tenths of a second while [ $delay -gt 0 ] do if pmlock -v lock >>$tmp/out 2>&1 then echo $dir/lock >$tmp/lock break else [ -f $tmp/stamp ] || touch -t `pmdate -30M %Y%m%d%H%M` $tmp/stamp if [ -z "`find lock -newer $tmp/stamp -print 2>/dev/null`" ] then if [ -f lock ] then echo "$prog: Warning: removing lock file older than 30 minutes" LC_TIME=POSIX ls -l $dir/lock rm -f lock else # there is a small timing window here where pmlock # might fail, but the lock file has been removed by # the time we get here, so just keep trying # : fi fi fi pmsleep 0.1 delay=`expr $delay - 1` done if [ $delay -eq 0 ] then # failed to gain mutex lock # # maybe pmlogger_daily is running ... check and silently # move on if this is the case # # Note: $PCP_RUN_DIR may not exist (see pmlogger_daily note), but # only if pmlogger_daily has not run, so no chance of a # collision # if [ -f "$PCP_RUN_DIR"/pmlogger_daily.pid ] then # maybe, check pid matches a running /bin/sh # pid=`cat "$PCP_RUN_DIR"/pmlogger_daily.pid` if _get_pids_by_name sh | grep "^$pid\$" >/dev/null then # seems to be still running ... nothing for us to see # or do here # continue fi fi if [ -f lock ] then echo "$prog: Warning: is another PCP cron job running concurrently?" LC_TIME=POSIX ls -l $dir/lock else echo "$prog: `cat $tmp/out`" fi _warning "failed to acquire exclusive lock ($dir/lock) ..." continue fi fi pid='' if [ "X$primary" = Xy ] then # NB: FQDN cleanup: previously, we used to quietly accept several # putative-aliases in the first (hostname) slot for a primary logger, # which were all supposed to refer to the local host. So now we # squash them all to the officially pcp-preferred way to access it. # This does not get used by pmlogger in the end (gets -P and not -h # in the primary logger case), but it *does* matter for pmlogconf. host=local: if test -f "$PCP_TMP_DIR/pmlogger/primary" then if $VERY_VERBOSE then _host=`sed -n 2p <"$PCP_TMP_DIR/pmlogger/primary"` _arch=`sed -n 3p <"$PCP_TMP_DIR/pmlogger/primary"` $PCP_ECHO_PROG $PCP_ECHO_N "... try $PCP_TMP_DIR/pmlogger/primary: host=$_host arch=$_arch""$PCP_ECHO_C" fi primary_inode=`_get_ino $PCP_TMP_DIR/pmlogger/primary` $VERY_VERBOSE && echo primary_inode=$primary_inode for file in $PCP_TMP_DIR/pmlogger/* do case "$file" in */primary|*\*) ;; */[0-9]*) inode=`_get_ino "$file"` $VERY_VERBOSE && echo $file inode=$inode if [ "$primary_inode" = "$inode" ] then pid="`echo $file | sed -e 's/.*\/\([^/]*\)$/\1/'`" break fi ;; esac done if [ -z "$pid" ] then if $VERY_VERBOSE then echo "primary pmlogger process pid not found" ls -l "$PCP_TMP_DIR/pmlogger" fi else if _get_pids_by_name pmlogger | grep "^$pid\$" >/dev/null then $VERY_VERBOSE && echo "primary pmlogger process $pid identified, OK" else $VERY_VERBOSE && echo "primary pmlogger process $pid not running" pid='' fi fi fi else for log in $PCP_TMP_DIR/pmlogger/[0-9]* do [ "$log" = "$PCP_TMP_DIR/pmlogger/[0-9]*" ] && continue if $VERY_VERBOSE then _host=`sed -n 2p <$log` _arch=`sed -n 3p <$log` $PCP_ECHO_PROG $PCP_ECHO_N "... try $log host=$_host arch=$_arch: ""$PCP_ECHO_C" fi # throw away stderr in case $log has been removed by now match=`sed -e '3s/\/[0-9][0-9][0-9][0-9][0-9.]*$//' $log 2>/dev/null \ | $PCP_AWK_PROG ' BEGIN { m = 0 } NR == 3 && $0 == "'$dir'" { m = 2; next } END { print m }'` $VERY_VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N "match=$match ""$PCP_ECHO_C" if [ "$match" = 2 ] then pid=`echo $log | sed -e 's,.*/,,'` if _get_pids_by_name pmlogger | grep "^$pid\$" >/dev/null then $VERY_VERBOSE && echo "pmlogger process $pid identified, OK" break fi $VERY_VERBOSE && echo "pmlogger process $pid not running, skip" pid='' else $VERY_VERBOSE && echo "different directory, skip" fi done fi if [ -z "$pid" -a $START_PMLOGGER = true ] then rm -f Latest if [ "X$primary" = Xy ] then args="-P $args" iam=" primary" # clean up port-map, just in case # PM_LOG_PORT_DIR="$PCP_TMP_DIR/pmlogger" rm -f "$PM_LOG_PORT_DIR/primary" else args="-h $host $args" iam="" fi # each new log started is named yyyymmdd.hh.mm # LOGNAME=`date "+%Y%m%d.%H.%M"` # handle duplicates/aliases (happens when pmlogger is restarted # within a minute and LOGNAME is the same) # suff='' for file in $LOGNAME.* do [ "$file" = "$LOGNAME"'.*' ] && continue # we have a clash! ... find a new -number suffix for the # existing files ... we are going to keep $LOGNAME for the # new pmlogger below # if [ -z "$suff" ] then for xx in 0 1 2 3 4 5 6 7 8 9 do for yy in 0 1 2 3 4 5 6 7 8 9 do [ "`echo $LOGNAME-${xx}${yy}.*`" != "$LOGNAME-${xx}${yy}.*" ] && continue suff=${xx}${yy} break done [ ! -z "$suff" ] && break done if [ -z "$suff" ] then _error "unable to break duplicate clash for archive basename $LOGNAME" fi $VERBOSE && echo "Duplicate archive basename ... rename $LOGNAME.* files to $LOGNAME-$suff.*" fi eval $MV -f $file `echo $file | sed -e "s/$LOGNAME/&-$suff/"` done configfile=`_get_configfile $args` if [ ! -z "$configfile" ] then # if this is a relative path and not relative to cwd, # substitute in the default pmlogger search location. # if [ ! -f "$configfile" -a "`basename $configfile`" = "$configfile" ] then configfile="$PCP_SYSCONF_DIR/pmlogger/$configfile" fi # check configuration file exists and is up to date _configure_pmlogger "$configfile" "$host" fi $VERBOSE && _message restart sock_me='' if [ "$socks" = y ] then # only check for pmsocks if it's specified in the control file have_pmsocks=false if which pmsocks >/dev/null 2>&1 then # check if pmsocks has been set up correctly if pmsocks ls >/dev/null 2>&1 then have_pmsocks=true fi fi if $have_pmsocks then sock_me="pmsocks " else echo "$prog: Warning: no pmsocks available, would run without" sock_me="" fi fi _get_logfile if [ -f $logfile ] then $VERBOSE && $SHOWME && echo eval $MV -f $logfile $logfile.prior fi args="$args -m pmlogger_check" if $SHOWME then echo echo "+ ${sock_me}$PMLOGGER $args $LOGNAME" _unlock continue else $PCP_BINADM_DIR/pmpost "start pmlogger from $prog for host $host" ${sock_me}$PMLOGGER $args $LOGNAME >$tmp/out 2>&1 & pid=$! fi # wait for pmlogger to get started, and check on its health _check_logger $pid # the archive folio Latest is for the most recent archive in # this directory # if [ -f $LOGNAME.0 ] then $VERBOSE && echo "Latest folio created for $LOGNAME" mkaf $LOGNAME.0 >Latest (id "$PCP_USER" && chown $PCP_USER:$PCP_GROUP Latest) >/dev/null 2>&1 else logdir=`dirname $LOGNAME` if $TERSE then echo "$prog: Error: archive file `cd $logdir; $PWDCMND`/$LOGNAME.0 missing" else echo "$prog: Error: archive file $LOGNAME.0 missing" echo "Directory (`cd $logdir; $PWDCMND`) contents:" LC_TIME=POSIX ls -la $logdir fi fi elif [ ! -z "$pid" -a $START_PMLOGGER = false ] then # Send pmlogger a SIGTERM, which is noted as a pending shutdown. # Add pid to list of loggers sent SIGTERM - may need SIGKILL later. # $VERY_VERBOSE && echo "+ $KILL -s TERM $pid" eval $KILL -s TERM $pid $PCP_ECHO_PROG $PCP_ECHO_N "$pid ""$PCP_ECHO_C" >> $tmp/pmloggers fi _unlock done # check all the SIGTERM'd loggers really died - if not, use a bigger hammer. # if $SHOWME then : elif [ $START_PMLOGGER = false -a -s $tmp/pmloggers ] then pmloggerlist=`cat $tmp/pmloggers` if ps -p "$pmloggerlist" >/dev/null 2>&1 then $VERY_VERBOSE && ( echo; $PCP_ECHO_PROG $PCP_ECHO_N "+ $KILL -KILL `cat $tmp/pmies` ...""$PCP_ECHO_C" ) eval $KILL -s KILL $pmloggerlist >/dev/null 2>&1 delay=30 # tenths of a second while ps -f -p "$pmloggerlist" >$tmp/alive 2>&1 do if [ $delay -gt 0 ] then pmsleep 0.1 delay=`expr $delay - 1` continue fi echo "$prog: Error: pmlogger process(es) will not die" cat $tmp/alive status=1 break done fi fi [ -f $tmp/err ] && status=1 exit pcp-3.8.12ubuntu1/src/pmlogger/pmnewlog.sh0000775000000000000000000003311512272262501015377 0ustar #! /bin/sh # # Copyright (c) 1995-2001,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # stop and restart a pmlogger instance # # Get standard environment . $PCP_DIR/etc/pcp.env # error messages should go to stderr, not the GUI notifiers # unset PCP_STDERR tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 status=0 trap "rm -rf $tmp; exit \$status" 0 1 2 3 15 prog=`basename $0` VERBOSE=false SHOWME=false CP=cp MV=mv RM=rm KILL=pmsignal primary=true myname="primary pmlogger" connect=primary access="" config="" saveconfig="" logfile="pmlogger.log" namespace="" args="" sock_me="" usage="Usage: $prog [options] archive options: any combination of pmnewlog and most pmlogger options pmnewlog options: -a accessfile specify access controls for the new pmlogger -C saveconfig save the configuration of new pmlogger in saveconfig -c configfile file to load configuration from -N perform a dry run (like \`make -n') -n pmnsfile use an alternative PMNS -P execute as primary logger instance -p pid restart non-primary logger with pid -s use pmsocks -V turn on verbose reporting of pmnewlog progress" _abandon() { echo echo "Sorry, but this is fatal. No new pmlogger instance has been started." status=1 exit } _check_pid() { if $SHOWME then : else _get_pids_by_name pmlogger | grep "^$1\$" fi } _check_logfile() { if [ ! -f $logfile ] then echo "Cannot find pmlogger output file at \"$logfile\"" else echo "Contents of pmlogger output file \"$logfile\" ..." cat $logfile fi } _check_logger() { # wait until pmlogger process starts, or exits # delay=5 [ ! -z "$PMCD_CONNECT_TIMEOUT" ] && delay=$PMCD_CONNECT_TIMEOUT x=5 [ ! -z "$PMCD_REQUEST_TIMEOUT" ] && x=$PMCD_REQUEST_TIMEOUT # wait for maximum time of a connection and 20 requests # delay=`expr $delay + 20 \* $x` i=0 while [ $i -lt $delay ] do $VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N ".""$PCP_ECHO_C" if $SHOWME then echo "+ echo 'connect $1' | pmlc ..." $VERBOSE && echo " done" return 0 elif echo "connect $1" | pmlc 2>&1 | grep "Unable to connect" >/dev/null then : else sleep 5 $VERBOSE && echo " done" return 0 fi if _get_pids_by_name pmlogger | grep "^$1\$" >/dev/null then : else $VERBOSE || _message restart echo " process exited!" _check_logfile return 1 fi sleep 5 i=`expr $i + 5` done $VERBOSE || _message restart echo " timed out waiting!" sed -e 's/^/ /' $tmp/out _check_logfile return 1 } _message() { case $1 in looking) $PCP_ECHO_PROG $PCP_ECHO_N "Looking for $myname ...""$PCP_ECHO_C" ;; get_host) $PCP_ECHO_PROG $PCP_ECHO_N "Getting logged host name from $myname ...""$PCP_ECHO_C" ;; get_state) $PCP_ECHO_PROG $PCP_ECHO_N "Contacting $myname to get logging state ...""$PCP_ECHO_C" ;; restart) $PCP_ECHO_PROG $PCP_ECHO_N "Waiting for new pmlogger to start ..""$PCP_ECHO_C" ;; esac } _do_cmd() { if $SHOWME then echo "+ $1" else eval $1 fi } # option parsing # # pmlogger, without -V version which is redefined as -V (verbose) # and -s exit_size which is redefined as -s (pmsocks), and ignore # [ -h host ] and [ -x fd ] as they make no sense in the argument # part of the pmlogger control file for a long-running pmlogger. # while getopts "a:C:c:D:Ll:Nm:n:Pp:rst:T:Vv:" c do case $c in # pmnewlog options and flags # a) access="$OPTARG" if [ ! -f $access ] then echo "$prog: Error: cannot find accessfile ($access)" _abandon fi ;; C) saveconfig="$OPTARG" ;; N) SHOWME=true CP="echo + cp" MV="echo + mv" RM="echo + rm" KILL="echo + kill" ;; p) pid=$OPTARG primary=false myname="pmlogger (process $pid)" connect=$pid ;; s) if which pmsocks >/dev/null 2>&1 then sock_me="pmsocks " else echo "$prog: Warning: no pmsocks available, would run without" sock_me="" fi ;; V) VERBOSE=true ;; # pmlogger options and flags that need special handling # c) config="$OPTARG" if [ ! -f $config ] then if [ -f $PCP_SYSCONF_DIR/pmlogger/$config ] then config="$PCP_SYSCONF_DIR/pmlogger/$config" else echo "$prog: Error: cannot find configfile ($config)" _abandon fi fi ;; l) logfile="$OPTARG" ;; n) namespace="-n $OPTARG" args="$args-$c $OPTARG " ;; P) primary=true myname="primary pmlogger" ;; # pmlogger flags passed through # L|r) args="$args-$c " ;; D|m|t|T|v) args="$args-$c $OPTARG " ;; # oops # \?) echo "$usage" _abandon ;; esac done shift `expr $OPTIND - 1` if [ $# -ne 1 ] then echo "$usage" echo echo "Not enough arguments" _abandon fi # initial sanity checking for new archive name # archive=$1 # check that designated pmlogger is really running # $VERBOSE && _message looking $PCP_PS_PROG $PCP_PS_ALL_FLAGS \ | if $primary then grep 'pmlogger .*-P' | grep -v grep else $PCP_AWK_PROG '$2 == '"$pid"' && /pmlogger/ { print }' fi >$tmp/out if [ -s $tmp/out ] then $VERBOSE && echo " found" $VERBOSE && cat $tmp/out pid=`$PCP_AWK_PROG '{ print $2 }' <$tmp/out` else if $VERBOSE then : else _message looking echo fi echo "$prog: Error: process not found" _abandon fi # pass primary/not primary down # $primary && args="$args-P " # pass logfile option down # args="$args-l $logfile " # if not a primary pmlogger, get name of pmcd host pmlogger is connected to # if $primary then host=localhost else # start critical section ... no interrupts due to pmlogger SIGPIPE # bug in PCP 1.1 # trap "echo; echo $prog:' Interrupt! ... I am talking to pmlogger, please wait ...'" 1 2 3 15 $VERBOSE && _message get_host _do_cmd "( echo 'connect $connect' ; echo status ) | pmlc 2>$tmp/err >$tmp/out" # end critical section # trap "rm -rf $tmp; exit \$status" 0 1 2 3 15 if $SHOWME || [ ! -s $tmp/err ] then $VERBOSE && echo " done" else if grep "Unable to connect" $tmp/err >/dev/null then $VERBOSE || _message get_host echo " failed to connect" echo sed -e 's/^/ /' $tmp/err _abandon else $VERBOSE || _message get_host echo echo "$prog: Warning: errors from talking to $myname via pmlc" sed -e 's/^/ /' $tmp/err echo echo "continuing ..." fi fi host=`sed -n -e '/^pmlogger/s/.* from host //p' <$tmp/out` if [ "X$host" = X ] then echo "$prog: Error: failed to get host name from $myname" echo "This is what was collected from $myname." echo sed -e 's/^/ /' $tmp/out _abandon fi args="$args-h $host " fi # extract/construct config file if required # if [ "X$config" = X ] then # start critical section ... no interrupts due to pmlogger SIGPIPE # bug in PCP 1.1 # trap "echo; echo $prog:' Interrupt! ... I am talking to pmlogger, please wait ...'" 1 2 3 15 $VERBOSE && _message get_state # iterate over top-level names in pmns, and query pmlc for # current configuration ... note exclusion of "proc" metrics # ... others may be excluded in a similar fashion # if $SHOWME then echo "+ ( echo 'connect $connect'; echo 'query ...'; ... ) | pmlc $namespace | $PCP_AWK_PROG ..." else ( echo "connect $connect" ; for top in `pminfo -h $host $namespace \ | sed -e 's/\..*//' -e '/^proc$/d' \ | sort -u` do echo "query $top" done \ ) \ | pmlc $namespace 2>$tmp/err \ | $PCP_AWK_PROG >$tmp/out ' /^[^ ]/ { metric = $1; next } $1 == "mand" || ( $1 == "adv" && $2 == "on" ) { print $0 " " metric }' fi # end critical section # trap "rm -rf $tmp; exit \$status" 0 1 2 3 15 if $SHOWME || [ ! -s $tmp/err ] then $VERBOSE && echo " done" else if grep "Unable to connect" $tmp/err >/dev/null then $VERBOSE || _message get_state echo " failed to connect" echo sed -e 's/^/ /' $tmp/err _abandon else $VERBOSE || _message get_state echo echo "$prog: Warning: errors from talking to $myname via pmlc" sed -e 's/^/ /' $tmp/err echo echo "continuing ..." fi fi if [ ! -s $tmp/out ] then if $SHOWME then : else echo "$prog: Error: failed to collect configuration info from $myname" echo "Most likely this pmlogger instance is inactive." _abandon fi fi # convert to a pmlogger config file # if $SHOWME then echo "+ create new pmlogger config file ..." else sed <$tmp/out >$tmp/config \ -e 's/ on nl/ on/' \ -e 's/ off nl/ off/'\ -e 's/ *mand *\(o[nf]*\) /log mandatory \1 /' \ -e 's/ *adv *on /log advisory on/' \ -e 's/\[[0-9][0-9]* or /[/' \ -e 's/\(\[[^]]*]\) \([^ ]*\)/\2 \1/' \ -e 's/ */ /g' if [ ! -s $tmp/config ] then echo "$prog: Error: failed to generate a pmlogger configuration file for pmlogger" echo "This is what was collected from $myname." echo sed -e 's/^/ /' $tmp/out _abandon fi fi config=$tmp/config fi # optionally append access control specifications # if [ "X$access" != X ] then if grep '\[access]' $config >/dev/null then echo "$prog: Error: pmlogger configuration file already contains an" echo " access control section, specifications from \"$access\" cannot" echo " be applied." _abandon fi cat $access >>$config fi # add config file to the args, save config file if -C # args="$args-c $config " if [ "X$saveconfig" != X ] then if eval $CP $config $saveconfig then echo "New pmlogger configuration file saved as $saveconfig" else echo "$prog: Warning: unable to save configuration file as $saveconfig" fi fi # kill off existing pmlogger # $VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N "Terminating $myname ...""$PCP_ECHO_C" for sig in USR1 TERM KILL do $VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N " SIG$sig ...""$PCP_ECHO_C" eval $KILL -s $sig $pid sleep 5 [ "`_check_pid $pid`" = "" ] && break done if [ "`_check_pid $pid`" = "" ] then $VERBOSE && echo " done" else echo " failed!" _abandon fi # the archive folio Latest is for the most recent archive in this directory # dir=`dirname $archive` eval $RM -f $dir/Latest # clean up port-map, just in case # PM_LOG_PORT_DIR="$PCP_TMP_DIR/pmlogger" eval $RM -f $PM_LOG_PORT_DIR/$pid $primary && eval $RM -f $PM_LOG_PORT_DIR/primary # finally do it, ... # cd $dir $SHOWME && echo "+ cd $dir" [ "X$dir" = X. ] && dir=`pwd` archive=`basename $archive` # handle duplicates/aliases (happens when pmlogger is restarted # within a minute and basename is the same) # suff='' for file in $archive.* do [ "$file" = "$archive"'.*' ] && continue # we have a clash! ... find a new -number suffix for the # existing files ... we are going to keep $archive for the # new pmlogger below # if [ -z "$suff" ] then for xx in 0 1 2 3 4 5 6 7 8 9 do for yy in 0 1 2 3 4 5 6 7 8 9 do [ "`echo $archive-${xx}${yy}.*`" != "$archive-${xx}${yy}.*" ] && continue suff=${xx}$yy break done [ ! -z "$suff" ] && break done if [ -z "$suff" ] then echo "$prog: Error: unable to break duplicate clash for archive basename \"$archive\"" _abandon fi $VERBOSE && echo "Duplicate archive basename ... rename $archive.* files to $archive-$suff.*" fi eval $MV -f $file `echo $file | sed -e "s/$archive/&-$suff/"` done $VERBOSE && echo "Launching new pmlogger in directory \"$dir\" as ..." [ -f $logfile ] && eval $MV -f $logfile $logfile.prior $VERBOSE && echo "${sock_me}pmlogger $args$archive" if $SHOWME then echo "+ ${sock_me}pmlogger $args$archive &" echo "+ ... assume pid is 12345" new_pid=12345 else ${sock_me}pmlogger $args$archive & new_pid=$! fi # stall a bit ... # STALL_TIME=10 sleep $STALL_TIME $VERBOSE && _message restart if _check_logger $new_pid || $SHOWME then $VERBOSE && echo "New pmlogger status ..." $VERBOSE && _do_cmd "( echo 'connect $new_pid'; echo status ) | pmlc" # make the "Latest" archive folio # i=0 failed=true WAIT_TIME=10 while [ $i -lt $WAIT_TIME ] do if $SHOWME || [ -f $archive.0 -a -f $archive.meta -a $archive.index ] then _do_cmd "mkaf $archive.0 >Latest" 2>$tmp/err if [ -s $tmp/err ] then # errors from mkaf typically result from race conditions # at the start of pmlogger, e.g. # Warning: cannot extract hostname from archive "..." ... # # simply keep trying : else failed=false break fi fi sleep 1 i=`expr $i + 1` done if $failed then ELAPSED=`expr $STALL_TIME + $WAIT_TIME` echo "Warning: pmlogger [pid=$new_pid host=$host] failed to create archive files within $ELAPSED seconds" if [ -f $tmp/err ] then echo "Warnings/errors from mkaf ..." cat $tmp/err fi fi else _abandon fi exit pcp-3.8.12ubuntu1/src/pmlogger/pmlogger_daily.sh0000775000000000000000000005132012272262501016543 0ustar #! /bin/sh # # Copyright (c) 1995-2000,2003 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2013 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Daily administrative script for PCP archive logs # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/rc-proc.sh # error messages should go to stderr, not the GUI notifiers # unset PCP_STDERR # constant setup # tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 status=0 echo >$tmp/lock trap "rm -rf \`[ -f $tmp/lock ] && cat $tmp/lock\` $PCP_RUN_DIR/pmlogger_daily.pid $tmp; exit \$status" 0 1 2 3 15 prog=`basename $0` if is_chkconfig_on pmlogger then PMLOGGER_CTL=on else PMLOGGER_CTL=off fi # control file for pmlogger administration ... edit the entries in this # file to reflect your local configuration (see also -c option below) # CONTROL=$PCP_PMLOGGERCONTROL_PATH # default number of days to keep archive logs # CULLAFTER=14 # default compression program # COMPRESS=bzip2 COMPRESSAFTER="" COMPRESSREGEX=".meta$|.index$|.Z$|.gz$|.bz2$|.zip$" # threshold size to roll $PCP_LOG_DIR/NOTICES # NOTICES=$PCP_LOG_DIR/NOTICES ROLLNOTICES=20480 # mail addresses to send daily NOTICES summary to # MAILME="" MAILFILE=$PCP_LOG_DIR/NOTICES.daily # search for your mail agent of choice ... # MAIL='' for try in Mail mail email do if which $try >/dev/null 2>&1 then MAIL=$try break fi done # NB: FQDN cleanup; don't guess a 'real name for localhost', and # definitely don't truncate it a la `hostname -s`. Instead now # we use such a string only for the default log subdirectory, ie. # for substituting LOCALHOSTNAME in the fourth column of $CONTROL. # determine path for pwd command to override shell built-in # (see BugWorks ID #595416). PWDCMND=`which pwd 2>/dev/null | $PCP_AWK_PROG ' BEGIN { i = 0 } / not in / { i = 1 } / aliased to / { i = 1 } { if ( i == 0 ) print } '` if [ -z "$PWDCMND" ] then # Looks like we have no choice here... # force it to a known IRIX location PWDCMND=/bin/pwd fi eval $PWDCMND -P >/dev/null 2>&1 [ $? -eq 0 ] && PWDCMND="$PWDCMND -P" _usage() { cat - <.trace # exec 1>$PCP_LOG_DIR/pmlogger/daily.`date "+%Y%m%d.%H.%M"`.trace 2>&1 VERBOSE=true VERY_VERBOSE=true MYARGS="$MYARGS -V -V" ;; V) if $VERBOSE then VERY_VERBOSE=true else VERBOSE=true fi MYARGS="$MYARGS -V" ;; x) COMPRESSAFTER="$OPTARG" check=`echo "$COMPRESSAFTER" | sed -e 's/[0-9]//g'` if [ ! -z "$check" ] then echo "Error: -x option ($COMPRESSAFTER) must be numeric" status=1 exit fi ;; X) COMPRESS="$OPTARG" ;; Y) COMPRESSREGEX="$OPTARG" ;; ?) _usage ;; esac done shift `expr $OPTIND - 1` [ $# -ne 0 ] && _usage if [ ! -f $CONTROL ] then echo "$prog: Error: cannot find control file ($CONTROL)" status=1 exit fi # each new archive log started by pmnewlog or pmlogger_check is named # yyyymmdd.hh.mm # LOGNAME=`date "+%Y%m%d.%H.%M"` _error() { _report Error "$1" } _warning() { _report Warning "$1" } _report() { echo "$prog: $1: $2" echo "[$CONTROL:$line] ... logging for host \"$host\" unchanged" touch $tmp/err } _unlock() { rm -f lock echo >$tmp/lock } # filter file names to leave those that look like PCP archives # managed by pmlogger_check and pmlogger_daily, namely they begin # with a datestamp # # need to handle both the year 2000 and the old name formats, and # possible ./ prefix (from find .) # _filter_filename() { sed -n \ -e 's/^\.\///' \ -e '/^[12][0-9][0-9][0-9][0-1][0-9][0-3][0-9][-.]/p' \ -e '/^[0-9][0-9][0-1][0-9][0-3][0-9][-.]/p' } _get_ino() { # get inode number for $1 # throw away stderr (and return '') in case $1 has been removed by now # stat "$1" 2>/dev/null \ | sed -n '/Device:[ ].*[ ]Inode:/{ s/Device:[ ].*[ ]Inode:[ ]*// s/[ ].*// p }' } # mails out any entries for the previous 24hrs from the PCP notices file # if [ ! -z "$MAILME" ] then # get start time of NOTICES entries we want - all earlier are discarded # args=`pmdate -1d '-v yy=%Y -v my=%b -v dy=%d'` args=`pmdate -1d '-v Hy=%H -v My=%M'`" $args" args=`pmdate '-v yt=%Y -v mt=%b -v dt=%d'`" $args" # # Basic algorithm: # from NOTICES head, look for a DATE: entry for yesterday or today; # if its yesterday, find all HH:MM timestamps which are in the window, # until the end of yesterday is reached; # copy out the remainder of the file (todays entries). # # initially, entries have one of three forms: # DATE: weekday mon day HH:MM:SS year # Started by pmlogger_daily: weekday mon day HH:MM:SS TZ year # HH:MM message # # preprocess to provide a common date separator - if new date stamps are # ever introduced into the NOTICES file, massage them first... # rm -f $tmp/pcp $PCP_AWK_PROG ' /^Started/ { print "DATE:",$4,$5,$6,$7,$9; next } { print } ' $NOTICES | \ $PCP_AWK_PROG -F ':[ \t]*|[ \t]+' $args ' $1 == "DATE" && $3 == mt && $4 == dt && $8 == yt { tday = 1; print; next } $1 == "DATE" && $3 == my && $4 == dy && $8 == yy { yday = 1; print; next } { if ( tday || (yday && $1 > Hy) || (yday && $1 == Hy && $2 >= My) ) print }' >$tmp/pcp if [ -s $tmp/pcp ] then if [ ! -z "$MAIL" ] then $MAIL -s "PCP NOTICES summary for `hostname`" $MAILME <$tmp/pcp else echo "$prog: Warning: cannot find a mail agent to send mail ..." echo "PCP NOTICES summary for `hostname`" cat $tmp/pcp fi [ -w `dirname "$NOTICES"` ] && mv $tmp/pcp "$MAILFILE" fi fi # Roll $PCP_LOG_DIR/NOTICES -> $PCP_LOG_DIR/NOTICES.old if larger # that 10 Kbytes, and you can write in $PCP_LOG_DIR # if [ -s "$NOTICES" -a -w `dirname "$NOTICES"` ] then if [ "`wc -c <"$NOTICES"`" -ge $ROLLNOTICES ] then if $VERBOSE then echo "Roll $NOTICES -> $NOTICES.old" echo "Start new $NOTICES" fi if $SHOWME then echo "+ mv -f $NOTICES $NOTICES.old" echo "+ touch $NOTICES" else echo >>"$NOTICES" echo "*** rotated by $prog: `date`" >>"$NOTICES" mv -f "$NOTICES" "$NOTICES.old" echo "Started by $prog: `date`" >"$NOTICES" (id "$PCP_USER" && chown $PCP_USER:$PCP_GROUP "$NOTICES") >/dev/null 2>&1 fi fi fi # Keep our pid in $PCP_RUN_DIR/pmlogger_daily.pid ... this is checked # by pmlogger_check when it fails to obtain the lock should it be run # while pmlogger_daily is running # # For most packages, $PCP_RUN_DIR is included in the package, # but for Debian and cases where /var/run is a mounted filesystem # it may not exist, so create it here before it is used to create # any pid/lock files # # $PCP_RUN_DIR creation is also done in pmcd startup, but pmcd may # not be running on this system # if [ -d "$PCP_RUN_DIR" ] then mkdir -p -m 775 "$PCP_RUN_DIR" chown $PCP_USER:$PCP_GROUP "$PCP_RUN_DIR" fi echo $$ >"$PCP_RUN_DIR"/pmlogger_daily.pid # note on control file format version # 1.0 was shipped as part of PCPWEB beta, and did not include the # socks field [this is the default for backwards compatibility] # 1.1 is the first production release, and the version is set in # the control file with a $version=1.1 line (see below) # rm -f $tmp/err line=0 version='' cat $CONTROL \ | sed -e "s;PCP_LOG_DIR;$PCP_LOG_DIR;g" \ | while read host primary socks dir args do # NB: FQDN cleanup: substitute the LOCALHOSTNAME marker in the config line # differently for the directory and the pcp -h HOST arguments. dir_hostname=`hostname || echo localhost` dir=`echo $dir | sed -e "s;LOCALHOSTNAME;$dir_hostname;"` if [ "x$host" = "xLOCALHOSTNAME" ] then host=local: fi line=`expr $line + 1` $VERY_VERBOSE && echo "[control:$line] host=\"$host\" primary=\"$primary\" socks=\"$socks\" dir=\"$dir\" args=\"$args\"" case "$host" in \#*|'') # comment or empty continue ;; \$*) # in-line variable assignment $SHOWME && echo "# $host $primary $socks $dir $args" cmd=`echo "$host $primary $socks $dir $args" \ | sed -n \ -e "/='/s/\(='[^']*'\).*/\1/" \ -e '/="/s/\(="[^"]*"\).*/\1/' \ -e '/=[^"'"'"']/s/[;&<>|].*$//' \ -e '/^\\$[A-Za-z][A-Za-z0-9_]*=/{ s/^\\$// s/^\([A-Za-z][A-Za-z0-9_]*\)=/export \1; \1=/p }'` if [ -z "$cmd" ] then # in-line command, not a variable assignment _warning "in-line command is not a variable assignment, line ignored" else case "$cmd" in 'export PATH;'*) _warning "cannot change \$PATH, line ignored" ;; 'export IFS;'*) _warning "cannot change \$IFS, line ignored" ;; *) $SHOWME && echo "+ $cmd" eval $cmd ;; esac fi continue ;; esac if [ -z "$version" -o "$version" = "1.0" ] then if [ -z "$version" ] then echo "$prog: Warning: processing default version 1.0 control format" version=1.0 fi args="$dir $args" dir="$socks" socks=n fi if [ -z "$primary" -o -z "$socks" -o -z "$dir" -o -z "$args" ] then _error "insufficient fields in control file record" continue fi if $VERY_VERBOSE then pflag='' [ $primary = y ] && pflag=' -P' echo "Check pmlogger$pflag -h $host ... in $dir ..." fi if [ ! -d $dir ] then _error "archive directory ($dir) does not exist" continue fi cd $dir dir=`$PWDCMND` $SHOWME && echo "+ cd $dir" if $VERBOSE then echo echo "=== daily maintenance of PCP archives for host $host ===" echo fi if [ ! -w $dir ] then echo "$prog: Warning: no write access in $dir, skip lock file processing" else # demand mutual exclusion # fail=true rm -f $tmp/stamp for try in 1 2 3 4 do if pmlock -v lock >$tmp/out then echo $dir/lock >$tmp/lock fail=false break else if [ ! -f $tmp/stamp ] then touch -t `pmdate -30M %Y%m%d%H%M` $tmp/stamp fi if [ ! -z "`find lock -newer $tmp/stamp -print 2>/dev/null`" ] then : else echo "$prog: Warning: removing lock file older than 30 minutes" LC_TIME=POSIX ls -l $dir/lock rm -f lock fi fi sleep 5 done if $fail then # failed to gain mutex lock # if [ -f lock ] then echo "$prog: Warning: is another PCP cron job running concurrently?" LC_TIME=POSIX ls -l $dir/lock else echo "$prog: `cat $tmp/out`" fi _warning "failed to acquire exclusive lock ($dir/lock) ..." continue fi fi pid='' if [ X"$primary" = Xy ] then # NB: FQDN cleanup: previously, we used to quietly accept several # putative-aliases in the first (hostname) slot for a primary logger, # which were all supposed to refer to the local host. So now we # squash them all to the officially pcp-preferred way to access it. host=local: if test -f "$PCP_TMP_DIR/pmlogger/primary" then $VERY_VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N "... try $PCP_TMP_DIR/pmlogger/primary: ""$PCP_ECHO_C" primary_inode=`_get_ino $PCP_TMP_DIR/pmlogger/primary` $VERY_VERBOSE && echo primary_inode=$primary_inode for file in $PCP_TMP_DIR/pmlogger/* do case "$file" in */primary|*\*) ;; */[0-9]*) inode=`_get_ino "$file"` $VERY_VERBOSE && echo $file inode=$inode if [ "$primary_inode" = "$inode" ] then pid="`echo $file | sed -e 's/.*\/\([^/]*\)$/\1/'`" break fi ;; esac done if [ -z "$pid" ] then if $VERY_VERBOSE then echo "primary pmlogger process pid not found" ls -l "$PCP_TMP_DIR/pmlogger" fi else if _get_pids_by_name pmlogger | grep "^$pid\$" >/dev/null then $VERY_VERBOSE && echo "primary pmlogger process $pid identified, OK" else $VERY_VERBOSE && echo "primary pmlogger process $pid not running" pid=`` fi fi fi else for log in $PCP_TMP_DIR/pmlogger/[0-9]* do [ "$log" = "$PCP_TMP_DIR/pmlogger/[0-9]*" ] && continue $VERY_VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N "... try $log: ""$PCP_ECHO_C" match=`sed -e '3s/\/[0-9][0-9][0-9][0-9][0-9.]*$//' $log \ | $PCP_AWK_PROG ' BEGIN { m = 0 } NR == 3 && $0 == "'$dir'" { m = 2; next } END { print m }'` $VERY_VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N "match=$match ""$PCP_ECHO_C" if [ "$match" = 2 ] then pid=`echo $log | sed -e 's,.*/,,'` if _get_pids_by_name pmlogger | grep "^$pid\$" >/dev/null then $VERY_VERBOSE && echo "pmlogger process $pid identified, OK" break fi $VERY_VERBOSE && echo "pmlogger process $pid not running, skip" pid='' else $VERY_VERBOSE && echo "different directory, skip" fi done fi if [ -z "$pid" ] then if [ "$PMLOGGER_CTL" = "on" ] then _error "no pmlogger instance running for host \"$host\"" fi else # now execute pmnewlog to "roll the archive logs" # [ X"$primary" != Xy ] && args="-p $pid $args" # else: -P is already the default [ X"$socks" = Xy ] && args="-s $args" args="$args -m pmlogger_daily" $SHOWME && echo "+ pmnewlog$MYARGS $args $LOGNAME" if pmnewlog$MYARGS $args $LOGNAME then : else _error "problems executing pmnewlog for host \"$host\"" touch $tmp/err fi fi $VERBOSE && echo # Merge archive logs. # # Will work for new style YYYYMMDD.HH.MM[-NN] archives and old style # YYMMDD.HH.MM[-NN] archives. # Note: we need to handle duplicate-breaking forms like # YYYYMMDD.HH.MM-seq# (even though pmlogger_merge already picks most # of these up) in case the base YYYYMMDD.HH.MM archive is for some # reason missing here # # Assume if .meta file is present then other archive components are # also present (if not the case it is a serious process botch, and # pmlogger_merge will fail below) # # Find all candidate input archives, remove any that contain today's # date and group the remainder by date. # TODAY=`date +%Y%m%d` find *.meta \ \( -name "*.[0-2][0-9].[0-5][0-9].meta" \ -o -name "*.[0-2][0-9].[0-5][0-9]-[0-9][0-9].meta" \ \) \ -print 2>/dev/null \ | sed \ -e "/^$TODAY\./d" \ -e 's/\.meta//' \ | sort -n \ | $PCP_AWK_PROG ' { if (lastdate != "" && match($1, "^" lastdate "\\.") == 1) { # same date as previous one inlist = inlist " " $1 next } else { # different date as previous one if (inlist != "") print lastdate,inlist inlist = $1 lastdate = $1 sub(/\..*/, "", lastdate) } } END { if (inlist != "") print lastdate,inlist }' >$tmp/list if $OFLAG then # -o option, preserve the old semantics, and only process the # previous day's archives ... aim for a time close to midday # yesterday and report that date # now_hr=`pmdate %H` hr=`expr 12 + $now_hr` grep "^[0-9]*`pmdate -${hr}H %y%m%d` " $tmp/list >$tmp/tmp mv $tmp/tmp $tmp/list fi # pmlogrewrite if no -r on command line and # (a) pmlogrewrite exists in the same directory that the input # archives are found, or # (b) if $PCP_VAR_LIB/config/pmlogrewrite exists # "exists" => file, directory or symbolic link # rewrite='' if $RFLAG then : else for type in -f -d -L do if [ $type "$dir/pmlogrewrite" ] then rewrite="$dir/pmlogrewrite" break fi done if [ -z "$rewrite" ] then for type in -f -d -L do if [ $type "$PCP_VAR_DIR/config/pmlogrewrite" ] then rewrite="$PCP_VAR_DIR/config/pmlogrewrite" break fi done fi fi rm -f $tmp/skip if [ ! -s $tmp/list ] then if $VERBOSE then echo "$prog: Warning: no archives found to merge" $VERY_VERBOSE && ls -l fi else cat $tmp/list \ | while read outfile inlist do if [ -f $outfile.0 -o -f $outfile.index -o -f $outfile.meta ] then echo "$prog: Warning: output archive ($outfile) already exists" echo "[$CONTROL:$line] ... skip log merging, culling and compressing for host \"$host\"" touch $tmp/skip break else if [ -n "$rewrite" ] then $VERY_VERBOSE && echo "Rewriting input archives using $rewrite" for arch in $inlist do if pmlogrewrite -iq -c "$rewrite" $arch then : else echo "$prog: Warning: rewrite for $arch using -c $rewrite failed" echo "[$CONTROL:$line] ... skip log merging, culling and compressing for host \"$host\"" touch $tmp/skip break fi done fi if $VERY_VERBOSE then for arch in $inlist do echo "Input archive $arch ..." pmdumplog -L $arch done fi if $SHOWME then echo "+ pmlogger_merge$MYARGS -f $inlist $outfile" else if pmlogger_merge$MYARGS -f $inlist $outfile then if $VERY_VERBOSE then echo "Merged output archive $outfile ..." pmdumplog -L $outfile fi else _error "problems executing pmlogger_merge for host \"$host\"" fi fi fi done fi if [ -f $tmp/skip ] then # this is sufficiently serious that we don't want to remove # the lock file, so problems are not compounded the next time # the script is run $VERY_VERBOSE && echo "Skip culling and compression ..." continue fi # and cull old archives # if [ X"$CULLAFTER" != X"forever" ] then find . -type f -mtime +$CULLAFTER \ | _filter_filename \ | sort >$tmp/list if [ -s $tmp/list ] then if $VERBOSE then echo "Archive files older than $CULLAFTER days being removed ..." fmt <$tmp/list | sed -e 's/^/ /' fi if $SHOWME then cat $tmp/list | xargs echo + rm -f else cat $tmp/list | xargs rm -f fi else $VERY_VERBOSE && echo "$prog: Warning: no archive files found to cull" fi fi # and compress old archive data files # (after cull - don't compress unnecessarily) # if [ ! -z "$COMPRESSAFTER" ] then find . -type f -mtime +$COMPRESSAFTER \ | _filter_filename \ | egrep -v "$COMPRESSREGEX" \ | sort >$tmp/list if [ -s $tmp/list ] then if $VERBOSE then echo "Archive files older than $COMPRESSAFTER days being compressed ..." fmt <$tmp/list | sed -e 's/^/ /' fi if $SHOWME then cat $tmp/list | xargs echo + $COMPRESS else cat $tmp/list | xargs $COMPRESS fi else $VERY_VERBOSE && echo "$prog: Warning: no archive files found to compress" fi fi # and cull old trace files (from -t option) # if [ "$TRACE" -gt 0 ] then find $PCP_LOG_DIR/pmlogger -type f -mtime +$TRACE \ | sed -n -e '/pmlogger\/daily\..*\.trace/p' \ | sort >$tmp/list if [ -s $tmp/list ] then if $VERBOSE then echo "Trace files older than $TRACE days being removed ..." fmt <$tmp/list | sed -e 's/^/ /' fi if $SHOWME then cat $tmp/list | xargs echo + rm -f else cat $tmp/list | xargs rm -f fi else $VERY_VERBOSE && echo "$prog: Warning: no trace files found to cull" fi fi _unlock done [ -f $tmp/err ] && status=1 exit pcp-3.8.12ubuntu1/src/pmlogger/crontab.in0000664000000000000000000000045712272262501015173 0ustar # # Performance Co-Pilot crontab entries for a monitored site # with one or more pmlogger instances running # # daily processing of archive logs 10 0 * * * @user@ @path@/pmlogger_daily # every 30 minutes, check pmlogger instances are running 25,55 * * * * @user@ @path@/pmlogger_check -C pcp-3.8.12ubuntu1/src/pmlogger/src/0000775000000000000000000000000012272262620013776 5ustar pcp-3.8.12ubuntu1/src/pmlogger/src/preamble.c0000664000000000000000000001315412272262501015733 0ustar /* * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "logger.h" #include "pmda.h" /* * this routine creates the "fake" pmResult to be added to the * start of the archive log to identify information about the * archive beyond what is in the archive label. */ /* encode the domain(x), cluster (y) and item (z) parts of the PMID */ #define PMID(x,y,z) ((x<<22)|(y<<10)|z) /* encode the domain(x) and serial (y) parts of the pmInDom */ #define INDOM(x,y) ((x<<22)|y) /* * Note: these pmDesc entries MUST correspond to the corrsponding * entries from the real PMDA ... * We fake it out here to accommodate logging from PCP 1.1 * PMCD's and to avoid round-trip dependencies in setting up * the preamble */ static pmDesc desc[] = { /* pmcd.pmlogger.host */ { PMID(2,3,3), PM_TYPE_STRING, INDOM(2,1), PM_SEM_DISCRETE, {0,0,0,0,0,0} }, /* pmcd.pmlogger.port */ { PMID(2,3,0), PM_TYPE_U32, INDOM(2,1), PM_SEM_DISCRETE, {0,0,0,0,0,0} }, /* pmcd.pmlogger.archive */ { PMID(2,3,2), PM_TYPE_STRING, INDOM(2,1), PM_SEM_DISCRETE, {0,0,0,0,0,0} }, }; /* names added for version 2 archives */ static char* names[] = { "pmcd.pmlogger.host", "pmcd.pmlogger.port", "pmcd.pmlogger.archive" }; static int n_metric = sizeof(desc) / sizeof(desc[0]); int do_preamble(void) { int sts; int i; int j; pid_t mypid = getpid(); pmResult *res; __pmPDU *pb; pmAtomValue atom; __pmTimeval tmp; char path[MAXPATHLEN]; char host[MAXHOSTNAMELEN]; /* start to build the pmResult */ res = (pmResult *)malloc(sizeof(pmResult) + (n_metric - 1) * sizeof(pmValueSet *)); if (res == NULL) return -oserror(); res->numpmid = n_metric; last_stamp = res->timestamp = epoch; /* struct assignment */ tmp.tv_sec = (__int32_t)epoch.tv_sec; tmp.tv_usec = (__int32_t)epoch.tv_usec; for (i = 0; i < n_metric; i++) res->vset[i] = NULL; for (i = 0; i < n_metric; i++) { res->vset[i] = (pmValueSet *)malloc(sizeof(pmValueSet)); if (res->vset[i] == NULL) { sts = -oserror(); goto done; } res->vset[i]->pmid = desc[i].pmid; res->vset[i]->numval = 1; /* special case for each value 0 .. n_metric-1 */ if (desc[i].pmid == PMID(2,3,3)) { /* my fully qualified hostname, cloned from the pmcd PMDA */ struct hostent *hep = NULL; (void)gethostname(host, MAXHOSTNAMELEN); host[MAXHOSTNAMELEN-1] = '\0'; hep = gethostbyname(host); if (hep != NULL) atom.cp = hep->h_name; else atom.cp = host; } else if (desc[i].pmid == PMID(2,3,0)) { /* my control port number, from ports.c */ atom.l = ctlport; } else if (desc[i].pmid == PMID(2,3,2)) { /* * the full pathname to the base of the archive, cloned * from GetPort() in ports.c */ if (__pmAbsolutePath(archBase)) atom.cp = archBase; else { if (getcwd(path, MAXPATHLEN) == NULL) atom.cp = archBase; else { strcat(path, "/"); strcat(path, archBase); atom.cp = path; } } } sts = __pmStuffValue(&atom, &res->vset[i]->vlist[0], desc[i].type); if (sts < 0) goto done; res->vset[i]->vlist[0].inst = (int)mypid; res->vset[i]->valfmt = sts; } if ((sts = __pmEncodeResult(fileno(logctl.l_mfp), res, &pb)) < 0) goto done; __pmOverrideLastFd(fileno(logctl.l_mfp)); /* force use of log version */ /* and start some writing to the archive log files ... */ sts = __pmLogPutResult(&logctl, pb); __pmUnpinPDUBuf(pb); if (sts < 0) goto done; for (i = 0; i < n_metric; i++) { if ((sts = __pmLogPutDesc(&logctl, &desc[i], 1, &names[i])) < 0) goto done; if (desc[i].indom == PM_INDOM_NULL) continue; for (j = 0; j < i; j++) { if (desc[i].indom == desc[j].indom) break; } if (j == i) { /* need indom ... force one with my PID as the only instance */ int *instid; char **instname; if ((instid = (int *)malloc(sizeof(*instid))) == NULL) { sts = -oserror(); goto done; } *instid = (int)mypid; snprintf(path, sizeof(path), "%" FMT_PID, mypid); if ((instname = (char **)malloc(sizeof(char *)+strlen(path)+1)) == NULL) { free(instid); sts = -oserror(); goto done; } /* * this _is_ correct ... instname[] is a one element array * with the string value immediately following */ instname[0] = (char *)&instname[1]; strcpy(instname[0], path); /* * Note. DO NOT free instid and instname ... they get hidden * away in addindom() below __pmLogPutInDom() */ if ((sts = __pmLogPutInDom(&logctl, desc[i].indom, &tmp, 1, instid, instname)) < 0) goto done; } } /* fudge the temporal index */ fflush(logctl.l_mfp); fseek(logctl.l_mfp, sizeof(__pmLogLabel)+2*sizeof(int), SEEK_SET); fflush(logctl.l_mdfp); fseek(logctl.l_mdfp, sizeof(__pmLogLabel)+2*sizeof(int), SEEK_SET); __pmLogPutIndex(&logctl, &tmp); fseek(logctl.l_mfp, 0L, SEEK_END); fseek(logctl.l_mdfp, 0L, SEEK_END); sts = 0; /* * and now free stuff */ done: for (i = 0; i < n_metric; i++) { if (res->vset[i] != NULL) free(res->vset[i]); } free(res); return sts; } pcp-3.8.12ubuntu1/src/pmlogger/src/error.c0000664000000000000000000000210712272262501015271 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "logger.h" void yywarn(char *s) { fprintf(stderr, "Warning [%s, line %d]\n%s\n", configfile, lineno, s); } void yyerror(char *s) { fprintf(stderr, "Specification error in configuration file (%s)\n", configfile); fprintf(stderr, "[line %d] %s\n", lineno, s); exit(1); } pcp-3.8.12ubuntu1/src/pmlogger/src/logger.h0000664000000000000000000001161512272262521015432 0ustar /* * Copyright (c) 2014 Red Hat. * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _LOGGER_H #define _LOGGER_H #include "pmapi.h" #include "impl.h" #include /* * a task is a bundle of fetches to be done together - it * originally corresponded one-to-one with a configuration * file curly-brace-enclosed block, but no longer does. */ typedef struct task_s { struct task_s *t_next; struct timeval t_delta; int t_state; /* logging state */ int t_numpmid; int t_numvalid; pmID *t_pmidlist; char **t_namelist; pmDesc *t_desclist; fetchctl_t *t_fetch; int t_afid; int t_size; } task_t; extern task_t *tasklist; /* master list of tasks */ extern __pmLogCtl logctl; /* global log control */ /* config file parser states */ #define GLOBAL 0 #define INSPEC 1 /* generic error messages */ extern char *chk_emess[]; extern void die(char *, int); /* * hash control for per-metric (really per-metric per-log specification) * -- used to establish and maintain state for ControlLog operations */ extern __pmHashCtl pm_hash; /* another hash list used for maintaining information about all metrics and * instances that have EVER appeared in the log as opposed to just those * currently being logged. It's a history list. */ extern __pmHashCtl hist_hash; typedef struct { int ih_inst; int ih_flags; } insthist_t; typedef struct { pmID ph_pmid; pmInDom ph_indom; int ph_numinst; insthist_t *ph_instlist; } pmidhist_t; /* access control goo */ #define PM_OP_LOG_ADV 0x1 #define PM_OP_LOG_MAND 0x2 #define PM_OP_LOG_ENQ 0x4 #define PM_OP_NONE 0x0 #define PM_OP_ALL 0x7 #define PMLC_SET_MAYBE(val, flag) \ val = ((val) & ~0x10) | (((flag) & 0x1) << 4) #define PMLC_GET_MAYBE(val) \ (((val) & 0x10) >> 4) /* volume switch types */ #define VOL_SW_SIGHUP 0 #define VOL_SW_PMLC 1 #define VOL_SW_COUNTER 2 #define VOL_SW_BYTES 3 #define VOL_SW_TIME 4 #define VOL_SW_MAX 5 /* flush requested via SIGUSR1 */ extern int wantflush; /* unbuffered writes requested via -u */ extern int unbuffered; /* initial time of day from remote PMCD */ extern struct timeval epoch; /* offset to start of last written pmResult */ extern int last_log_offset; /* yylex() gets input from here ... */ extern FILE *fconfig; extern FILE *yyin; extern char *configfile; extern int lineno; extern int myFetch(int, pmID *, __pmPDU **); extern void yyerror(char *); extern void yywarn(char *); extern int yylex(void); extern int yyparse(void); extern void yyend(void); extern void buildinst(int *, int **, char ***, int, char *); extern void freeinst(int *, int *, char **); extern void linkback(task_t *); extern optreq_t *findoptreq(pmID, int); extern void log_callback(int, void *); extern int chk_one(task_t *, pmID, int); extern int chk_all(task_t *, pmID); extern int newvolume(int); extern void disconnect(int); #if CAN_RECONNECT extern int reconnect(void); #endif extern int do_preamble(void); extern void run_done(int,char *); extern __pmPDU *rewrite_pdu(__pmPDU *, int); extern int putmark(void); extern int do_flush(void); extern void dumpit(void); #include extern char pmlc_host[]; #define LOG_DELTA_ONCE -1 #define LOG_DELTA_DEFAULT -2 /* command line parameters */ extern char *archBase; /* base name for log files */ extern char *pmcd_host; /* collecting from PMCD on this host */ extern char *pmcd_host_conn; /* ... and this is how we connected to it */ extern int primary; /* Non-zero for primary logger */ extern int rflag; extern struct timeval delta; /* default logging interval */ extern int ctlport; /* pmlogger control port number */ extern char *note; /* note for port map file */ /* pmlc support */ extern void init_ports(void); extern int control_req(void); extern int client_req(void); extern __pmHashCtl hist_hash; extern unsigned int clientops; /* access control (deny ops) */ extern struct timeval last_stamp; extern int clientfd; extern int ctlfd; extern int exit_samples; extern int vol_switch_samples; extern __int64_t vol_switch_bytes; extern int vol_samples_counter; extern int archive_version; extern int parse_done; extern __int64_t exit_bytes; extern __int64_t vol_bytes; /* event record handling */ extern int do_events(pmValueSet *); /* QA testing and error injection support ... see do_request() */ extern int qa_case; #define QA_OFF 100 #define QA_SLEEPY 101 #endif /* _LOGGER_H */ pcp-3.8.12ubuntu1/src/pmlogger/src/util.c0000664000000000000000000000320212272262521015114 0ustar /* * Copyright (c) 2014 Red Hat. * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "logger.h" void buildinst(int *numinst, int **intlist, char ***extlist, int intid, char *extid) { char **el; int *il; int num = *numinst; if (num == 0) { il = NULL; el = NULL; } else { il = *intlist; el = *extlist; } el = (char **)realloc(el, (num+1)*sizeof(el[0])); il = (int *)realloc(il, (num+1)*sizeof(il[0])); il[num] = intid; if (extid == NULL) el[num] = NULL; else { if (*extid == '"') { char *p; p = ++extid; while (*p && *p != '"') p++; *p = '\0'; } el[num] = strdup(extid); } *numinst = ++num; *intlist = il; *extlist = el; } void freeinst(int *numinst, int *intlist, char **extlist) { int i; if (*numinst) { free(intlist); for (i = 0; i < *numinst; i++) free(extlist[i]); free(extlist); *numinst = 0; } } /* * Link the new fetch groups back to their task structure */ void linkback(task_t *tp) { fetchctl_t *fcp; for (fcp = tp->t_fetch; fcp != NULL; fcp = fcp->f_next) fcp->f_aux = (void *)tp; } pcp-3.8.12ubuntu1/src/pmlogger/src/fetch.c0000664000000000000000000001165412272262501015240 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Thread-safe note * * myFetch() returns a PDU buffer that is pinned from _pmGetPDU() or * __pmEncodeResult() and this needs to be unpinned by the myFetch() * caller when safe to do so. */ #include "logger.h" int myFetch(int numpmid, pmID pmidlist[], __pmPDU **pdup) { int n = 0; int ctx; __pmPDU *pb; __pmContext *ctxp; if (numpmid < 1) return PM_ERR_TOOSMALL; if ((ctx = pmWhichContext()) >= 0) { ctxp = __pmHandleToPtr(ctx); if (ctxp == NULL) return PM_ERR_NOCONTEXT; if (ctxp->c_type != PM_CONTEXT_HOST) { PM_UNLOCK(ctxp->c_lock); return PM_ERR_NOTHOST; } } else return PM_ERR_NOCONTEXT; #if CAN_RECONNECT if (ctxp->c_pmcd->pc_fd == -1) { /* lost connection, try to get it back */ n = reconnect(); if (n < 0) { PM_UNLOCK(ctxp->c_lock); return n; } } #endif if (ctxp->c_sent == 0) { /* * current profile is _not_ already cached at other end of * IPC, so send current profile */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PROFILE) fprintf(stderr, "myFetch: calling __pmSendProfile, context: %d\n", ctx); #endif if ((n = __pmSendProfile(ctxp->c_pmcd->pc_fd, FROM_ANON, ctx, ctxp->c_instprof)) >= 0) ctxp->c_sent = 1; } if (n >= 0) { int newcnt; pmID *newlist = NULL; int have_dm; /* for derived metrics, may need to rewrite the pmidlist */ have_dm = newcnt = __pmPrepareFetch(ctxp, numpmid, pmidlist, &newlist); if (newcnt > numpmid) { /* replace args passed into myFetch */ numpmid = newcnt; pmidlist = newlist; } n = __pmSendFetch(ctxp->c_pmcd->pc_fd, FROM_ANON, ctx, &ctxp->c_origin, numpmid, pmidlist); if (n >= 0){ int changed = 0; do { n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb); /* * expect PDU_RESULT or * PDU_ERROR(changed > 0)+PDU_RESULT or * PDU_ERROR(real error < 0 from PMCD) or * 0 (end of file) * < 0 (local error or IPC problem) * other (bogus PDU) */ if (n == PDU_RESULT) { /* * Success with a pmResult in a pdubuf. * * Need to process derived metrics, if any. * This is ugly, we need to decode the pdubuf, rebuild * the pmResult and encode back into a pdubuf ... the * fastpath of not doing all of this needs to be * preserved in the common case where derived metrics * are not being logged. */ if (have_dm) { pmResult *result; __pmPDU *npb; int sts; if ((sts = __pmDecodeResult(pb, &result)) < 0) { n = sts; } else { __pmFinishResult(ctxp, sts, &result); if ((sts = __pmEncodeResult(ctxp->c_pmcd->pc_fd, result, &npb)) < 0) n = sts; else { /* using PDU with derived metrics */ __pmUnpinPDUBuf(pb); *pdup = npb; } } } else *pdup = pb; } else if (n == PDU_ERROR) { __pmDecodeError(pb, &n); if (n > 0) { /* PMCD state change protocol */ changed = n; n = 0; } else { fprintf(stderr, "myFetch: ERROR PDU: %s\n", pmErrStr(n)); disconnect(PM_ERR_IPC); } __pmUnpinPDUBuf(pb); } else if (n == 0) { fprintf(stderr, "myFetch: End of File: PMCD exited?\n"); disconnect(PM_ERR_IPC); } else if (n < 0) { fprintf(stderr, "myFetch: __pmGetPDU: Error: %s\n", pmErrStr(n)); disconnect(PM_ERR_IPC); } else { fprintf(stderr, "myFetch: Unexpected %s PDU from PMCD\n", __pmPDUTypeStr(n)); disconnect(PM_ERR_IPC); __pmUnpinPDUBuf(pb); } } while (n == 0); if (changed & PMCD_ADD_AGENT) { /* * PMCD_DROP_AGENT does not matter, no values are returned. * Trying to restart (PMCD_RESTART_AGENT) is less interesting * than when we actually start (PMCD_ADD_AGENT) ... the latter * is also set when a successful restart occurs, but more * to the point the sequence Install-Remove-Install does * not involve a restart ... it is the second Install that * generates the second PMCD_ADD_AGENT that we need to be * particularly sensitive to, as this may reset counter * metrics ... */ int sts; if ((sts = putmark()) < 0) { fprintf(stderr, "putmark: %s\n", pmErrStr(sts)); exit(1); } } } if (newlist != NULL) free(newlist); } if (n < 0 && ctxp->c_pmcd->pc_fd != -1) { disconnect(n); } PM_UNLOCK(ctxp->c_lock); return n; } pcp-3.8.12ubuntu1/src/pmlogger/src/rewrite.c0000664000000000000000000000273012272262501015623 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "logger.h" /* * PDU for pmResult (PDU_RESULT) -- from libpcp/src/p_fetch.c */ typedef struct { pmID pmid; int numval; /* no. of vlist els to follow, or error */ int valfmt; /* insitu or pointer */ __pmValue_PDU vlist[1]; /* zero or more */ } vlist_t; typedef struct { __pmPDUHdr hdr; __pmTimeval timestamp; /* when returned */ int numpmid; /* no. of PMIDs to follow */ __pmPDU data[1]; /* zero or more */ } result_t; __pmPDU * rewrite_pdu(__pmPDU *pb, int version) { if (version == PM_LOG_VERS02) return pb; fprintf(stderr, "Errors: do not know how to re-write the PDU buffer for a version %d archive\n", version); exit(1); } pcp-3.8.12ubuntu1/src/pmlogger/src/pmlogger.c0000664000000000000000000007736012272262521015773 0ustar /* * Copyright (c) 2012-2014 Red Hat. * Copyright (c) 1995-2001,2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include "logger.h" char *configfile; __pmLogCtl logctl; int exit_samples = -1; /* number of samples 'til exit */ __int64_t exit_bytes = -1; /* number of bytes 'til exit */ __int64_t vol_bytes; /* total in earlier volumes */ struct timeval exit_time; /* time interval 'til exit */ int vol_switch_samples = -1; /* number of samples 'til vol switch */ __int64_t vol_switch_bytes = -1; /* number of bytes 'til vol switch */ struct timeval vol_switch_time; /* time interval 'til vol switch */ int vol_samples_counter; /* Counts samples - reset for new vol*/ int vol_switch_afid = -1; /* afid of event for vol switch */ int parse_done; int primary; /* Non-zero for primary pmlogger */ char *archBase; /* base name for log files */ char *pmcd_host; char *pmcd_host_conn; struct timeval epoch; int archive_version = PM_LOG_VERS02; /* Type of archive to create */ int linger; /* linger with no tasks/events */ int rflag; /* report sizes */ struct timeval delta = { 60, 0 }; /* default logging interval */ int unbuffered; /* is -u specified? */ int qa_case; /* QA error injection state */ char *note; /* note for port map file */ static int pmcdfd; /* comms to pmcd */ static __pmFdSet fds; /* file descriptors mask for select */ static int numfds; /* number of file descriptors in mask */ static int rsc_fd = -1; /* recording session control see -x */ static int rsc_replay; static time_t rsc_start; static char *rsc_prog = ""; static char *folio_name = ""; static char *dialog_title = "PCP Archive Recording Session"; /* * flush stdio buffers */ int do_flush(void) { int sts; sts = 0; if (fflush(logctl.l_mdfp) != 0) sts = oserror(); if (fflush(logctl.l_mfp) != 0 && sts == 0) sts = oserror(); if (fflush(logctl.l_tifp) != 0 && sts == 0) sts = oserror(); return sts; } void run_done(int sts, char *msg) { #ifdef PCP_DEBUG if (msg != NULL) fprintf(stderr, "pmlogger: %s, exiting\n", msg); else fprintf(stderr, "pmlogger: End of run time, exiting\n"); #endif /* * write the last last temportal index entry with the time stamp * of the last pmResult and the seek pointer set to the offset * _before_ the last log record */ if (last_stamp.tv_sec != 0) { __pmTimeval tmp; tmp.tv_sec = (__int32_t)last_stamp.tv_sec; tmp.tv_usec = (__int32_t)last_stamp.tv_usec; fseek(logctl.l_mfp, last_log_offset, SEEK_SET); __pmLogPutIndex(&logctl, &tmp); } exit(sts); } static void run_done_callback(int i, void *j) { run_done(0, NULL); } static void vol_switch_callback(int i, void *j) { newvolume(VOL_SW_TIME); } static int maxfd(void) { int max = ctlfd; if (clientfd > max) max = clientfd; if (pmcdfd > max) max = pmcdfd; if (rsc_fd > max) max = rsc_fd; return max; } /* * tolower_str - convert a string to all lowercase */ static void tolower_str(char *str) { char *s = str; while (*s) { *s = tolower((int)*s); s++; } } /* * ParseSize - parse a size argument given in a command option * * The size can be in one of the following forms: * "40" = sample counter of 40 * "40b" = byte size of 40 * "40Kb" = byte size of 40*1024 bytes = 40 kilobytes * "40Mb" = byte size of 40*1024*1024 bytes = 40 megabytes * time-format = time delta in seconds * */ static int ParseSize(char *size_arg, int *sample_counter, __int64_t *byte_size, struct timeval *time_delta) { long x = 0; /* the size number */ char *ptr = NULL; char *interval_err; *sample_counter = -1; *byte_size = -1; time_delta->tv_sec = -1; time_delta->tv_usec = -1; x = strtol(size_arg, &ptr, 10); /* must be positive */ if (x <= 0) return -1; if (*ptr == '\0') { /* we have consumed entire string as a long */ /* => we have a sample counter */ *sample_counter = x; return 1; } /* we have a number followed by something else */ if (ptr != size_arg) { int len; tolower_str(ptr); /* chomp off plurals */ len = strlen(ptr); if (ptr[len-1] == 's') ptr[len-1] = '\0'; /* if bytes */ if (strcmp(ptr, "b") == 0 || strcmp(ptr, "byte") == 0) { *byte_size = x; return 1; } /* if kilobytes */ if (strcmp(ptr, "k") == 0 || strcmp(ptr, "kb") == 0 || strcmp(ptr, "kbyte") == 0 || strcmp(ptr, "kilobyte") == 0) { *byte_size = x*1024; return 1; } /* if megabytes */ if (strcmp(ptr, "m") == 0 || strcmp(ptr, "mb") == 0 || strcmp(ptr, "mbyte") == 0 || strcmp(ptr, "megabyte") == 0) { *byte_size = x*1024*1024; return 1; } /* if gigabytes */ if (strcmp(ptr, "g") == 0 || strcmp(ptr, "gb") == 0 || strcmp(ptr, "gbyte") == 0 || strcmp(ptr, "gigabyte") == 0) { *byte_size = ((__int64_t)x)*1024*1024*1024; return 1; } } /* Doesn't fit pattern above, try a time interval */ if (pmParseInterval(size_arg, time_delta, &interval_err) >= 0) return 1; /* error message not used here */ free(interval_err); /* Doesn't match anything, return an error */ return -1; } /* time manipulation */ static void tsub(struct timeval *a, struct timeval *b) { a->tv_usec -= b->tv_usec; if (a->tv_usec < 0) { a->tv_usec += 1000000; a->tv_sec--; } a->tv_sec -= b->tv_sec; if (a->tv_sec < 0) { /* clip negative values at zero */ a->tv_sec = 0; a->tv_usec = 0; } } static char * do_size(double d) { static char nbuf[100]; if (d < 10 * 1024) snprintf(nbuf, sizeof(nbuf), "%ld bytes", (long)d); else if (d < 10.0 * 1024 * 1024) snprintf(nbuf, sizeof(nbuf), "%.1f Kbytes", d/1024); else if (d < 10.0 * 1024 * 1024 * 1024) snprintf(nbuf, sizeof(nbuf), "%.1f Mbytes", d/(1024 * 1024)); else snprintf(nbuf, sizeof(nbuf), "%ld Mbytes", (long)d/(1024 * 1024)); return nbuf; } /* * add text identified by p to the malloc buffer at bp[0] ... bp[nchar -1] * return the length of the result or -1 for an error */ static int add_msg(char **bp, int nchar, char *p) { int add_len; if (nchar < 0 || p == NULL) return nchar; add_len = (int)strlen(p); if (nchar == 0) add_len++; if ((*bp = realloc(*bp, nchar+add_len)) == NULL) return -1; if (nchar == 0) strcpy(*bp, p); else strcat(&(*bp)[nchar-1], p); return nchar+add_len; } /* * generate dialog/message when launching application wishes to break * its association with pmlogger * * cmd is one of the following: * D detach pmlogger and let it run forever * Q terminate pmlogger * ? display status * X fatal error or application exit ... user must decide * to detach or quit */ void do_dialog(char cmd) { FILE *msgf = NULL; time_t now; static char lbuf[100+MAXPATHLEN]; double archsize; char *q; char *p = NULL; int nchar; char *msg; #if HAVE_MKSTEMP char tmp[MAXPATHLEN]; #endif /* * flush archive buffers so size is accurate */ do_flush(); time(&now); now -= rsc_start; if (now == 0) /* hack is close enough! */ now = 1; archsize = vol_bytes + ftell(logctl.l_mfp); nchar = add_msg(&p, 0, ""); p[0] = '\0'; snprintf(lbuf, sizeof(lbuf), "PCP recording for the archive folio \"%s\" and the host", folio_name); nchar = add_msg(&p, nchar, lbuf); snprintf(lbuf, sizeof(lbuf), " \"%s\" has been in progress for %ld %s", pmcd_host, now < 240 ? now : now/60, now < 240 ? "seconds" : "minutes"); nchar = add_msg(&p, nchar, lbuf); nchar = add_msg(&p, nchar, " and in that time the pmlogger process has created an"); nchar = add_msg(&p, nchar, " archive of "); q = do_size(archsize); nchar = add_msg(&p, nchar, q); nchar = add_msg(&p, nchar, "."); if (rsc_replay) { nchar = add_msg(&p, nchar, "\n\nThis archive may be replayed with the following command:\n"); snprintf(lbuf, sizeof(lbuf), " $ pmafm %s replay", folio_name); nchar = add_msg(&p, nchar, lbuf); } if (cmd == 'D') { nchar = add_msg(&p, nchar, "\n\nThe application that launched pmlogger has asked pmlogger"); nchar = add_msg(&p, nchar, " to continue independently and the PCP archive will grow at"); nchar = add_msg(&p, nchar, " the rate of "); q = do_size((archsize * 3600) / now); nchar = add_msg(&p, nchar, q); nchar = add_msg(&p, nchar, " per hour or "); q = do_size((archsize * 3600 * 24) / now); nchar = add_msg(&p, nchar, q); nchar = add_msg(&p, nchar, " per day."); } if (cmd == 'X') { nchar = add_msg(&p, nchar, "\n\nThe application that launched pmlogger has exited and you"); nchar = add_msg(&p, nchar, " must decide if the PCP recording session should be terminated"); nchar = add_msg(&p, nchar, " or continued. If recording is continued the PCP archive will"); nchar = add_msg(&p, nchar, " grow at the rate of "); q = do_size((archsize * 3600) / now); nchar = add_msg(&p, nchar, q); nchar = add_msg(&p, nchar, " per hour or "); q = do_size((archsize * 3600 * 24) / now); nchar = add_msg(&p, nchar, q); nchar = add_msg(&p, nchar, " per day."); } if (cmd == 'Q') { nchar = add_msg(&p, nchar, "\n\nThe application that launched pmlogger has terminated"); nchar = add_msg(&p, nchar, " this PCP recording session.\n"); } if (cmd != 'Q') { nchar = add_msg(&p, nchar, "\n\nAt any time this pmlogger process may be terminated with the"); nchar = add_msg(&p, nchar, " following command:\n"); snprintf(lbuf, sizeof(lbuf), " $ pmsignal -s TERM %" FMT_PID "\n", getpid()); nchar = add_msg(&p, nchar, lbuf); } if (cmd == 'X') nchar = add_msg(&p, nchar, "\n\nTerminate this PCP recording session now?"); if (nchar > 0) { char * xconfirm = __pmNativePath(pmGetConfig("PCP_XCONFIRM_PROG")); int fd = -1; #if HAVE_MKSTEMP snprintf(tmp, sizeof(tmp), "%s%cmsgXXXXXX", pmGetConfig("PCP_TMPFILE_DIR"), __pmPathSeparator()); msg = tmp; fd = mkstemp(tmp); #else if ((msg = tmpnam(NULL)) != NULL) fd = open(msg, O_WRONLY|O_CREAT|O_EXCL, 0600); #endif if (fd >= 0) msgf = fdopen(fd, "w"); if (msgf == NULL) { fprintf(stderr, "\nError: failed create temporary message file for recording session dialog\n"); fprintf(stderr, "Reason? %s\n", osstrerror()); if (fd != -1) close(fd); goto failed; } fputs(p, msgf); fclose(msgf); msgf = NULL; if (cmd == 'X') snprintf(lbuf, sizeof(lbuf), "%s -c -header \"%s - %s\" -file %s -icon question " "-B Yes -b No 2>/dev/null", xconfirm, dialog_title, rsc_prog, msg); else snprintf(lbuf, sizeof(lbuf), "%s -c -header \"%s - %s\" -file %s -icon info " "-b Close 2>/dev/null", xconfirm, dialog_title, rsc_prog, msg); if ((msgf = popen(lbuf, "r")) == NULL) { fprintf(stderr, "\nError: failed to start command for recording session dialog\n"); fprintf(stderr, "Command: \"%s\"\n", lbuf); goto failed; } if (fgets(lbuf, sizeof(lbuf), msgf) == NULL) { fprintf(stderr, "\n%s: pmconfirm(1) failed for recording session dialog\n", cmd == '?' ? "Warning" : "Error"); failed: fprintf(stderr, "Dialog:\n"); fputs(p, stderr); strcpy(lbuf, "Yes"); } else { /* strip at first newline */ for (q = lbuf; *q && *q != '\n'; q++) ; *q = '\0'; } if (msgf != NULL) pclose(msgf); unlink(msg); } else { fprintf(stderr, "Error: failed to create recording session dialog message!\n"); fprintf(stderr, "Reason? %s\n", osstrerror()); strcpy(lbuf, "Yes"); } free(p); if (cmd == 'Q' || (cmd == 'X' && strcmp(lbuf, "Yes") == 0)) { run_done(0, "Recording session terminated"); } if (cmd != '?') { /* detach, silently go off to the races ... */ close(rsc_fd); __pmFD_CLR(rsc_fd, &fds); rsc_fd = -1; } } int main(int argc, char **argv) { int c; int sts; int sep = __pmPathSeparator(); int errflag = 0; int isdaemon = 0; char *pmnsfile = PM_NS_DEFAULT; char *username; char *logfile = "pmlogger.log"; /* default log (not archive) file name */ char *endnum; int i; task_t *tp; optcost_t ocp; __pmFdSet readyfds; char *p; char *runtime = NULL; int ctx; /* handle corresponding to ctxp below */ __pmContext *ctxp; /* pmlogger has just this one context */ __pmSetProgname(argv[0]); __pmGetUsername(&username); /* * Warning: * If any of the pmlogger options change, make sure the * corresponding changes are made to pmnewlog when pmlogger * options are passed through from the control file */ while ((c = getopt(argc, argv, "c:D:h:l:Lm:n:Prs:T:t:uU:v:V:x:?")) != EOF) { switch (c) { case 'c': /* config file */ if (access(optarg, F_OK) == 0) configfile = optarg; else { /* does not exist as given, try the standard place */ char *sysconf = pmGetConfig("PCP_SYSCONF_DIR"); int sz = strlen(sysconf)+strlen("/pmlogger/")+strlen(optarg)+1; if ( (configfile = (char *)malloc(sz)) == NULL ) { __pmNoMem("config file name", sz, PM_FATAL_ERR); } snprintf(configfile, sz, "%s%c" "pmlogger" "%c%s", sysconf, sep, sep, optarg); if (access(configfile, F_OK) != 0) { /* still no good, error handling happens below */ free(configfile); configfile = optarg; } } break; case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case 'h': /* hostname for PMCD to contact */ pmcd_host_conn = optarg; break; case 'l': /* log file name */ logfile = optarg; break; case 'L': /* linger if not primary logger */ linger = 1; break; case 'm': /* note for port map file */ note = optarg; isdaemon = ((strcmp(note, "pmlogger_check") == 0) || (strcmp(note, "pmlogger_daily") == 0)); break; case 'n': /* alternative name space file */ pmnsfile = optarg; break; case 'P': /* this is the primary pmlogger */ primary = 1; isdaemon = 1; break; case 'r': /* report sizes of pmResult records */ rflag = 1; break; case 's': /* exit size */ if (ParseSize(optarg, &exit_samples, &exit_bytes, &exit_time) < 0) { fprintf(stderr, "%s: illegal size argument '%s' for -s\n", pmProgname, optarg); errflag++; } if (exit_time.tv_sec > 0) { __pmAFregister(&exit_time, NULL, run_done_callback); } break; case 'T': /* end time */ runtime = optarg; break; case 't': /* change default logging interval */ if (pmParseInterval(optarg, &delta, &p) < 0) { fprintf(stderr, "%s: illegal -t argument\n", pmProgname); fputs(p, stderr); free(p); errflag++; } break; case 'U': /* run as named user */ username = optarg; isdaemon = 1; break; case 'u': /* flush output buffers after each fetch */ unbuffered = 1; break; case 'v': /* volume switch after given size */ if (ParseSize(optarg, &vol_switch_samples, &vol_switch_bytes, &vol_switch_time) < 0) { fprintf(stderr, "%s: illegal size argument '%s' for -v\n", pmProgname, optarg); errflag++; } if (vol_switch_time.tv_sec > 0) { vol_switch_afid = __pmAFregister(&vol_switch_time, NULL, vol_switch_callback); } break; case 'V': archive_version = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0' || archive_version != PM_LOG_VERS02) { fprintf(stderr, "%s: -V requires a version number of " "%d\n", pmProgname, PM_LOG_VERS02); errflag++; } break; case 'x': /* recording session control fd */ rsc_fd = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0' || rsc_fd < 0) { fprintf(stderr, "%s: -x requires a non-negative numeric argument\n", pmProgname); errflag++; } time(&rsc_start); break; case '?': default: errflag++; break; } } if (errflag || optind != argc-1) { fprintf(stderr, "Usage: %s [options] archive\n\ \n\ Options:\n\ -c configfile file to load configuration from\n\ -h host metrics source is PMCD on host\n\ -l logfile redirect diagnostics and trace output\n\ -L linger, even if not primary logger instance and nothing to log\n\ -m note note to be added to the port map file\n\ -n pmnsfile use an alternative PMNS\n\ -P execute as primary logger instance\n\ -r report record sizes and archive growth rate\n\ -s endsize terminate after endsize has been accumulated\n\ -t interval default logging interval [default 60.0 seconds]\n\ -T endtime terminate at given time\n\ -u output is unbuffered\n\ -U username in daemon mode, run as named user [default pcp]\n\ -v volsize switch log volumes after volsize has been accumulated\n\ -V version version for archive (default and only version is 2)\n\ -x fd control file descriptor for application launching pmlogger\n\ via pmRecordControl(3)\n", pmProgname); exit(1); } if (primary && pmcd_host != NULL) { fprintf(stderr, "%s: -P and -h are mutually exclusive ... use -P only when running\n%s on the same (local) host as the PMCD to which it connects.\n", pmProgname, pmProgname); exit(1); } if (rsc_fd != -1 && note == NULL) { /* add default note to indicate running with -x */ static char xnote[10]; snprintf(xnote, sizeof(xnote), "-x %d", rsc_fd); note = xnote; } /* if we are running as a daemon, change user early */ if (isdaemon) __pmSetProcessIdentity(username); __pmOpenLog("pmlogger", logfile, stderr, &sts); if (sts != 1) { fprintf(stderr, "%s: Warning: log file (%s) creation failed\n", pmProgname, logfile); /* continue on ... writing to stderr */ } /* base name for archive is here ... */ archBase = argv[optind]; if (pmcd_host_conn == NULL) pmcd_host_conn = "local:"; /* initialise access control */ if (__pmAccAddOp(PM_OP_LOG_ADV) < 0 || __pmAccAddOp(PM_OP_LOG_MAND) < 0 || __pmAccAddOp(PM_OP_LOG_ENQ) < 0) { fprintf(stderr, "%s: access control initialisation failed\n", pmProgname); exit(1); } if (pmnsfile != PM_NS_DEFAULT) { if ((sts = pmLoadNameSpace(pmnsfile)) < 0) { fprintf(stderr, "%s: Cannot load namespace from \"%s\": %s\n", pmProgname, pmnsfile, pmErrStr(sts)); exit(1); } } if ((ctx = pmNewContext(PM_CONTEXT_HOST, pmcd_host_conn)) < 0) { fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", pmProgname, pmcd_host_conn, pmErrStr(ctx)); exit(1); } pmcd_host = (char *)pmGetContextHostName(ctx); if (rsc_fd == -1) { /* no -x, so register client id with pmcd */ __pmSetClientIdArgv(argc, argv); } /* * discover fd for comms channel to PMCD ... */ if ((ctxp = __pmHandleToPtr(ctx)) == NULL) { fprintf(stderr, "%s: botch: __pmHandleToPtr(%d) returns NULL!\n", pmProgname, ctx); exit(1); } pmcdfd = ctxp->c_pmcd->pc_fd; PM_UNLOCK(ctxp->c_lock); if (configfile != NULL) { if ((yyin = fopen(configfile, "r")) == NULL) { fprintf(stderr, "%s: Cannot open config file \"%s\": %s\n", pmProgname, configfile, osstrerror()); exit(1); } } else { /* **ANY** Lex would read from stdin automagically */ configfile = ""; } __pmOptFetchGetParams(&ocp); ocp.c_scope = 1; __pmOptFetchPutParams(&ocp); /* prevent early timer events ... */ __pmAFblock(); if (yyparse() != 0) exit(1); if (configfile != NULL) fclose(yyin); yyend(); #ifdef PCP_DEBUG fprintf(stderr, "Config parsed\n"); #endif fprintf(stderr, "Starting %slogger for host \"%s\" via \"%s\"\n", primary ? "primary " : "", pmcd_host, pmcd_host_conn); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "optFetch Cost Parameters: pmid=%d indom=%d fetch=%d scope=%d\n", ocp.c_pmid, ocp.c_indom, ocp.c_fetch, ocp.c_scope); fprintf(stderr, "\nAfter loading config ...\n"); for (tp = tasklist; tp != NULL; tp = tp->t_next) { if (tp->t_numvalid == 0) continue; fprintf(stderr, " state: %sin log, %savail, %s, %s", PMLC_GET_INLOG(tp->t_state) ? "" : "not ", PMLC_GET_AVAIL(tp->t_state) ? "" : "un", PMLC_GET_MAND(tp->t_state) ? "mand" : "adv", PMLC_GET_ON(tp->t_state) ? "on" : "off"); fprintf(stderr, " delta: %ld usec", (long)1000 * tp->t_delta.tv_sec + tp->t_delta.tv_usec); fprintf(stderr, " numpmid: %d\n", tp->t_numpmid); for (i = 0; i < tp->t_numpmid; i++) { fprintf(stderr, " %s (%s):\n", pmIDStr(tp->t_pmidlist[i]), tp->t_namelist[i]); } __pmOptFetchDump(stderr, tp->t_fetch); } } #endif if (!primary && tasklist == NULL && !linger) { fprintf(stderr, "Nothing to log, and not the primary logger instance ... good-bye\n"); exit(1); } if ((sts = __pmLogCreate(pmcd_host, archBase, archive_version, &logctl)) < 0) { fprintf(stderr, "__pmLogCreate: %s\n", pmErrStr(sts)); exit(1); } else { /* * try and establish $TZ and hostname from the remote PMCD ... * Note the label record has been set up, but not written yet */ char *names[2] = {"pmcd.timezone", "pmcd.hostname"}; pmID pmids[2]; pmResult *resp; __pmtimevalNow(&epoch); sts = pmUseContext(ctx); if (sts >= 0) sts = pmLookupName(2, names, pmids); if (sts >= 0) { sts = pmFetch(2, pmids, &resp); } if (sts >= 0) { if (resp->vset[0]->numval > 0) { /* pmcd.timezone present */ strcpy(logctl.l_label.ill_tz, resp->vset[0]->vlist[0].value.pval->vbuf); /* prefer to use remote time to avoid clock drift problems */ epoch = resp->timestamp; /* struct assignment */ pmNewZone(logctl.l_label.ill_tz); } #ifdef PCP_DEBUG else if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "main: Could not get timezone from host %s\n", pmcd_host); } #endif if (resp->vset[1]->numval > 0) { /* pmcd.hostname present */ strncpy(logctl.l_label.ill_hostname, resp->vset[1]->vlist[0].value.pval->vbuf, PM_LOG_MAXHOSTLEN-1); logctl.l_label.ill_hostname[PM_LOG_MAXHOSTLEN-1] = '\0'; } #ifdef PCP_DEBUG else if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "main: Could not get hostname from host %s\n", pmcd_host); } #endif pmFreeResult(resp); } } /* do ParseTimeWindow stuff for -T */ if (runtime) { struct timeval res_end; /* time window end */ struct timeval start; struct timeval end; struct timeval last_delta; char *err_msg; /* parsing error message */ time_t now; struct timeval now_tv; time(&now); now_tv.tv_sec = now; now_tv.tv_usec = 0; start = now_tv; end.tv_sec = INT_MAX; end.tv_usec = INT_MAX; sts = __pmParseTime(runtime, &start, &end, &res_end, &err_msg); if (sts < 0) { fprintf(stderr, "%s: illegal -T argument\n%s", pmProgname, err_msg); exit(1); } last_delta = res_end; tsub(&last_delta, &now_tv); __pmAFregister(&last_delta, NULL, run_done_callback); last_stamp = res_end; } fprintf(stderr, "Archive basename: %s\n", archBase); #ifndef IS_MINGW /* detach yourself from the launching process */ setpgid(getpid(), 0); #endif /* set up control port */ init_ports(); __pmFD_ZERO(&fds); __pmFD_SET(ctlfd, &fds); #ifndef IS_MINGW __pmFD_SET(pmcdfd, &fds); #endif if (rsc_fd != -1) __pmFD_SET(rsc_fd, &fds); numfds = maxfd() + 1; if ((sts = do_preamble()) < 0) fprintf(stderr, "Warning: problem writing archive preamble: %s\n", pmErrStr(sts)); sts = 0; /* default exit status */ parse_done = 1; /* enable callback processing */ __pmAFunblock(); for ( ; ; ) { int nready; __pmFD_COPY(&readyfds, &fds); nready = __pmSelectRead(numfds, &readyfds, NULL); if (wantflush) { /* * flush request via SIGUSR1 */ do_flush(); wantflush = 0; } if (nready > 0) { /* block signals to simplify IO handling */ __pmAFblock(); /* handle request on control port */ if (__pmFD_ISSET(ctlfd, &readyfds)) { if (control_req()) { /* new client has connected */ __pmFD_SET(clientfd, &fds); if (clientfd >= numfds) numfds = clientfd + 1; } } if (clientfd >= 0 && __pmFD_ISSET(clientfd, &readyfds)) { /* process request from client, save clientfd in case client * closes connection, resetting clientfd to -1 */ int fd = clientfd; if (client_req()) { /* client closed connection */ __pmFD_CLR(fd, &fds); __pmCloseSocket(clientfd); clientfd = -1; numfds = maxfd() + 1; qa_case = 0; } } #ifndef IS_MINGW if (pmcdfd >= 0 && __pmFD_ISSET(pmcdfd, &readyfds)) { /* * do not expect this, given synchronous commumication with the * pmcd ... either pmcd has terminated, or bogus PDU ... or its * Win32 and we are operating under the different conditions of * our AF.c implementation there, which has to deal with a lack * of signal support on Windows - race condition exists between * this check and the async event timer callback. */ __pmPDU *pb; __pmPDUHdr *php; sts = __pmGetPDU(pmcdfd, ANY_SIZE, TIMEOUT_NEVER, &pb); if (sts <= 0) { if (sts < 0) fprintf(stderr, "Error: __pmGetPDU: %s\n", pmErrStr(sts)); disconnect(sts); } else { php = (__pmPDUHdr *)pb; fprintf(stderr, "Error: Unsolicited %s PDU from PMCD\n", __pmPDUTypeStr(php->type)); disconnect(PM_ERR_IPC); } if (sts > 0) __pmUnpinPDUBuf(pb); } #endif if (rsc_fd >= 0 && __pmFD_ISSET(rsc_fd, &readyfds)) { /* * some action on the recording session control fd * end-of-file means launcher has quit, otherwise we * expect one of these commands * V\n - version * F\n - folio name * P\n - launcher's name * R\n - launcher can replay * D\n - detach from launcher * Q\n - quit pmlogger */ char rsc_buf[MAXPATHLEN]; char *rp = rsc_buf; char myc; int fake_x = 0; for (rp = rsc_buf; ; rp++) { if (read(rsc_fd, &myc, 1) <= 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "recording session control: eof\n"); #endif if (rp != rsc_buf) { *rp = '\0'; fprintf(stderr, "Error: incomplete recording session control message: \"%s\"\n", rsc_buf); } fake_x = 1; break; } if (rp >= &rsc_buf[MAXPATHLEN]) { fprintf(stderr, "Error: absurd recording session control message: \"%100.100s ...\"\n", rsc_buf); fake_x = 1; break; } if (myc == '\n') { *rp = '\0'; break; } *rp = myc; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { if (fake_x == 0) fprintf(stderr, "recording session control: \"%s\"\n", rsc_buf); } #endif if (fake_x) do_dialog('X'); else if (strcmp(rsc_buf, "Q") == 0 || strcmp(rsc_buf, "D") == 0 || strcmp(rsc_buf, "?") == 0) do_dialog(rsc_buf[0]); else if (rsc_buf[0] == 'F') folio_name = strdup(&rsc_buf[1]); else if (rsc_buf[0] == 'P') rsc_prog = strdup(&rsc_buf[1]); else if (strcmp(rsc_buf, "R") == 0) rsc_replay = 1; else if (rsc_buf[0] == 'V' && rsc_buf[1] == '0') { /* * version 0 of the recording session control ... * this is all we grok at the moment */ ; } else { fprintf(stderr, "Error: illegal recording session control message: \"%s\"\n", rsc_buf); do_dialog('X'); } } __pmAFunblock(); } else if (nready < 0 && neterror() != EINTR) fprintf(stderr, "Error: select: %s\n", netstrerror()); } } int newvolume(int vol_switch_type) { FILE *newfp; int nextvol = logctl.l_curvol + 1; time_t now; static char *vol_sw_strs[] = { "SIGHUP", "pmlc request", "sample counter", "sample byte size", "sample time", "max data volume size" }; vol_samples_counter = 0; vol_bytes += ftell(logctl.l_mfp); if (exit_bytes != -1) { if (vol_bytes >= exit_bytes) run_done(0, "Byte limit reached"); } /* * If we are not part of a callback but instead a * volume switch from "pmlc" or a "SIGHUP" then * get rid of pending volume switch in event queue * as it will now be wrong, and schedule a new * volume switch event. */ if (vol_switch_afid >= 0 && vol_switch_type != VOL_SW_TIME) { __pmAFunregister(vol_switch_afid); vol_switch_afid = __pmAFregister(&vol_switch_time, NULL, vol_switch_callback); } if ((newfp = __pmLogNewFile(archBase, nextvol)) != NULL) { if (logctl.l_state == PM_LOG_STATE_NEW) { /* * nothing has been logged as yet, force out the label records */ __pmtimevalNow(&last_stamp); logctl.l_label.ill_start.tv_sec = (__int32_t)last_stamp.tv_sec; logctl.l_label.ill_start.tv_usec = (__int32_t)last_stamp.tv_usec; logctl.l_label.ill_vol = PM_LOG_VOL_TI; __pmLogWriteLabel(logctl.l_tifp, &logctl.l_label); logctl.l_label.ill_vol = PM_LOG_VOL_META; __pmLogWriteLabel(logctl.l_mdfp, &logctl.l_label); logctl.l_label.ill_vol = 0; __pmLogWriteLabel(logctl.l_mfp, &logctl.l_label); logctl.l_state = PM_LOG_STATE_INIT; } #if 0 if (last_stamp.tv_sec != 0) { __pmTimeval tmp; tmp.tv_sec = (__int32_t)last_stamp.tv_sec; tmp.tv_usec = (__int32_t)last_stamp.tv_usec; __pmLogPutIndex(&logctl, &tmp); } #endif fclose(logctl.l_mfp); logctl.l_mfp = newfp; logctl.l_label.ill_vol = logctl.l_curvol = nextvol; __pmLogWriteLabel(logctl.l_mfp, &logctl.l_label); fflush(logctl.l_mfp); time(&now); fprintf(stderr, "New log volume %d, via %s at %s", nextvol, vol_sw_strs[vol_switch_type], ctime(&now)); return nextvol; } else return -oserror(); } void disconnect(int sts) { time_t now; #if CAN_RECONNECT int ctx; __pmContext *ctxp; #endif time(&now); if (sts != 0) fprintf(stderr, "%s: Error: %s\n", pmProgname, pmErrStr(sts)); fprintf(stderr, "%s: Lost connection to PMCD on \"%s\" at %s", pmProgname, pmcd_host, ctime(&now)); #if CAN_RECONNECT if (primary) { fprintf(stderr, "This is fatal for the primary logger."); exit(1); } close(pmcdfd); __pmFD_CLR(pmcdfd, &fds); pmcdfd = -1; numfds = maxfd() + 1; if ((ctx = pmWhichContext()) >= 0) ctxp = __pmHandleToPtr(ctx); if (ctx < 0 || ctxp == NULL) { fprintf(stderr, "%s: disconnect botch: cannot get context: %s\n", pmProgname, pmErrStr(ctx)); exit(1); } ctxp->c_pmcd->pc_fd = -1; PM_UNLOCK(ctxp->c_lock); #else exit(1); #endif } #if CAN_RECONNECT int reconnect(void) { int sts; int ctx; __pmContext *ctxp; if ((ctx = pmWhichContext()) >= 0) ctxp = __pmHandleToPtr(ctx); if (ctx < 0 || ctxp == NULL) { fprintf(stderr, "%s: reconnect botch: cannot get context: %s\n", pmProgname, pmErrStr(ctx)); exit(1); } sts = pmReconnectContext(ctx); if (sts >= 0) { time_t now; time(&now); fprintf(stderr, "%s: re-established connection to PMCD on \"%s\" at %s\n", pmProgname, pmcd_host, ctime(&now)); pmcdfd = ctxp->c_pmcd->pc_fd; __pmFD_SET(pmcdfd, &fds); numfds = maxfd() + 1; } PM_UNLOCK(ctxp->c_lock); return sts; } #endif pcp-3.8.12ubuntu1/src/pmlogger/src/check.c0000664000000000000000000001037412272262521015224 0ustar /* * Copyright (c) 2014 Red Hat. * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "logger.h" char *chk_emess[] = { "No error", "Request for (advisory) ON conflicts with current (mandatory) ON state", "Request for (advisory) OFF conflicts with current (mandatory) ON state", "Request for (advisory) ON conflicts with current (mandatory) OFF state", "Request for (advisory) OFF conflicts with current (mandatory) OFF state", }; static void undo(task_t *tp, optreq_t *rqp, int inst) { int j; int k; int sts; if (rqp->r_numinst >= 1) { /* remove instance from list of instance */ for (k =0, j = 0; j < rqp->r_numinst; j++) { if (rqp->r_instlist[j] != inst) rqp->r_instlist[k++] = rqp->r_instlist[j]; } rqp->r_numinst = k; if ((sts = __pmOptFetchDel(&tp->t_fetch, rqp)) < 0) die("undo: __pmOptFetchDel", sts); if (rqp->r_numinst == 0) { /* no more instances, remove specification */ if (tp->t_fetch == NULL) { /* no more specifications, remove task */ task_t *xtp; task_t *ltp = NULL; for (xtp = tasklist; xtp != NULL; xtp = xtp->t_next) { if (xtp == tp) { if (ltp == NULL) tasklist = tp->t_next; else ltp->t_next = tp->t_next; break; } ltp = xtp; } } __pmHashDel(rqp->r_desc->pmid, (void *)rqp, &pm_hash); free(rqp); } else /* re-insert modified specification */ __pmOptFetchAdd(&tp->t_fetch, rqp); } else { /* * TODO ... current specification is for all instances, * need to remove this instance from the set ... * this requires some enhancement to optFetch * * pro tem, this metric-instance pair may continue to get * logged, even though the logging state is recorded as * OFF (this is the worst thing that can happen here) */ } } int chk_one(task_t *tp, pmID pmid, int inst) { optreq_t *rqp; task_t *ctp; rqp = findoptreq(pmid, inst); if (rqp == NULL) return 0; ctp = rqp->r_fetch->f_aux; if (ctp == NULL || ctp == tp) /* * can only happen if same metric+inst appears more than once * in the same group ... this can never be a conflict */ return 1; if (PMLC_GET_MAND(ctp->t_state)) { if (PMLC_GET_ON(ctp->t_state)) { if (PMLC_GET_MAND(tp->t_state) == 0 && PMLC_GET_MAYBE(tp->t_state) == 0) { if (PMLC_GET_ON(tp->t_state)) return -1; else return -2; } } else { if (PMLC_GET_MAND(tp->t_state) == 0 && PMLC_GET_MAYBE(tp->t_state) == 0) { if (PMLC_GET_ON(tp->t_state)) return -3; else return -4; } } /* * new mandatory, over-rides the old mandatory */ undo(ctp, rqp, inst); } else { /* * new anything, over-rides the old advisory */ undo(ctp, rqp, inst); } return 0; } int chk_all(task_t *tp, pmID pmid) { optreq_t *rqp; task_t *ctp; rqp = findoptreq(pmid, 0); /*TODO, not right!*/ if (rqp == NULL) return 0; ctp = rqp->r_fetch->f_aux; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "chk_all: pmid=%s task=" PRINTF_P_PFX "%p state=%s%s%s%s delta=%d.%06d\n", pmIDStr(pmid), tp, PMLC_GET_INLOG(tp->t_state) ? " " : "N", PMLC_GET_AVAIL(tp->t_state) ? " " : "N", PMLC_GET_MAND(tp->t_state) ? "M" : "A", PMLC_GET_ON(tp->t_state) ? "Y" : "N", (int)tp->t_delta.tv_sec, (int)tp->t_delta.tv_usec); if (ctp == NULL) fprintf(stderr, "compared to: NULL\n"); else fprintf(stderr, "compared to: optreq task=" PRINTF_P_PFX "%p state=%s%s%s%s delta=%d.%06d\n", ctp, PMLC_GET_INLOG(ctp->t_state) ? " " : "N", PMLC_GET_AVAIL(ctp->t_state) ? " " : "N", PMLC_GET_MAND(ctp->t_state) ? "M" : "A", PMLC_GET_ON(ctp->t_state) ? "Y" : "N", (int)ctp->t_delta.tv_sec, (int)ctp->t_delta.tv_usec); } #endif return 0; } pcp-3.8.12ubuntu1/src/pmlogger/src/dopdu.c0000664000000000000000000012144312272262521015262 0ustar /* * Copyright (c) 2012-2014 Red Hat. * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "logger.h" /* return one of these when a status request is made from a PCP 1.x pmlc */ typedef struct { __pmTimeval ls_start; /* start time for log */ __pmTimeval ls_last; /* last time log written */ __pmTimeval ls_timenow; /* current time */ int ls_state; /* state of log (from __pmLogCtl) */ int ls_vol; /* current volume number of log */ __int64_t ls_size; /* size of current volume */ char ls_hostname[PM_LOG_MAXHOSTLEN]; /* name of pmcd host */ char ls_tz[40]; /* $TZ at collection host */ char ls_tzlogger[40]; /* $TZ at pmlogger */ } __pmLoggerStatus_v1; #ifdef PCP_DEBUG /* This crawls over the data structure looking for weirdness */ void reality_check(void) { __pmHashNode *hp; task_t *tp; task_t *tp2; fetchctl_t *fp; optreq_t *rqp; pmID pmid; int i = 0, j, k; /* check that all fetch_t's f_aux point back to their parent task */ for (tp = tasklist; tp != NULL; tp = tp->t_next, i++) { if (tp->t_fetch == NULL) fprintf(stderr, "task[%d] @" PRINTF_P_PFX "%p has no fetch group\n", i, tp); j = 0; for (fp = tp->t_fetch; fp != NULL; fp = fp->f_next) { if (fp->f_aux != (void *)tp) fprintf(stderr, "task[%d] fetch group[%d] has invalid task pointer\n", i, j); j++; } /* check that all optreq_t's in hash list have valid r_fetch->f_aux * pointing to a task in the task list. */ for (j = 0; j < tp->t_numpmid; j++) { pmid = tp->t_pmidlist[j]; for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; hp = hp->next) { if (pmid != (pmID)hp->key) continue; rqp = (optreq_t *)hp->data; for (tp2 = tasklist; tp2 != NULL; tp2 = tp2->t_next) if (rqp->r_fetch->f_aux == (void *)tp2) break; if (tp2 == NULL) { fprintf(stderr, "task[%d] pmid %s optreq " PRINTF_P_PFX "%p for [", i, pmIDStr(pmid), rqp); if (rqp->r_numinst == 0) fputs("`all instances' ", stderr); else for (k = 0; k < rqp->r_numinst; k++) fprintf(stderr, "%d ", rqp->r_instlist[k]); fputs("] bad task pointer\n", stderr); } } } } } void dumpit(void) { int i; task_t *tp; reality_check(); for (tp = tasklist, i = 0; tp != NULL; tp = tp->t_next, i++) { fprintf(stderr, "\ntask[%d] @" PRINTF_P_PFX "%p: %s %s \ndelta = %f\n", i, tp, PMLC_GET_MAND(tp->t_state) ? "mandatory " : "advisory ", PMLC_GET_ON(tp->t_state) ? "on " : "off ", tp->t_delta.tv_sec + (float)tp->t_delta.tv_usec / 1.0e6); __pmOptFetchDump(stderr, tp->t_fetch); } } /* * stolen from __pmDumpResult */ static void dumpcontrol(FILE *f, const pmResult *resp, int dovalue) { int i; int j; fprintf(f,"LogControl dump from " PRINTF_P_PFX "%p", resp); fprintf(f, " numpmid: %d\n", resp->numpmid); for (i = 0; i < resp->numpmid; i++) { pmValueSet *vsp = resp->vset[i]; fprintf(f," %s :", pmIDStr(vsp->pmid)); if (vsp->numval == 0) { fprintf(f, " No values!\n"); continue; } else if (vsp->numval < 0) { fprintf(f, " %s\n", pmErrStr(vsp->numval)); continue; } fprintf(f, " numval: %d", vsp->numval); fprintf(f, " valfmt: %d", vsp->valfmt); for (j = 0; j < vsp->numval; j++) { pmValue *vp = &vsp->vlist[j]; if (vsp->numval > 1 || vp->inst != PM_INDOM_NULL) { fprintf(f," inst [%d]", vp->inst); } else fprintf(f, " singular"); if (dovalue) { fprintf(f, " value "); pmPrintValue(f, vsp->valfmt, PM_TYPE_U32, vp, 1); } fputc('\n', f); } } } #endif /* Called when optFetch or _pmHash routines fail. This is terminal. */ void die(char *name, int sts) { __pmNotifyErr(LOG_ERR, "%s error unrecoverable: %s\n", name, pmErrStr(sts)); exit(1); } optreq_t * findoptreq(pmID pmid, int inst) { __pmHashNode *hp; optreq_t *rqp; optreq_t *all_rqp = NULL; int j; /* * Note: * The logic here assumes that for each metric-inst pair, there is * at most one optreq_t structure, corresponding to the logging * state of ON (mandatory or advisory) else OFF (mandatory). Other * requests change the data structures, but do not leave optreq_t * structures lying about, i.e. MAYBE (mandatory) is the default, * and does not have to be explicitly stored, while OFF (advisory) * reverts to MAYBE (mandatory). * There is one exception to the above assumption, namely for * cases where the initial specification includes "all" instances, * then some later concurrent specification may refer to specific * instances ... in this case, the specific optreq_t structure is * the one that applies. */ for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; hp = hp->next) { if (pmid != (pmID)hp->key) continue; rqp = (optreq_t *)hp->data; if (rqp->r_numinst == 0) { all_rqp = rqp; continue; } for (j = 0; j < rqp->r_numinst; j++) if (inst == rqp->r_instlist[j]) return rqp; } if (all_rqp != NULL) return all_rqp; else return NULL; } /* Determine whether a metric is currently known. Returns * -1 if metric not known * inclusive OR of the flags below if it is known */ #define MF_HAS_INDOM 0x1 /* has an instance domain */ #define MF_HAS_ALL 0x2 /* has an "all instances" */ #define MF_HAS_INST 0x4 /* has specific instance(s) */ #define MF_HAS_MAND 0x8 /* has at least one inst with mandatory */ /* logging (or is mandatory if no indom) */ static int find_metric(pmID pmid) { __pmHashNode *hp; optreq_t *rqp; int result = 0; int found = 0; for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; hp = hp->next) { if (pmid != (pmID)hp->key) continue; rqp = (optreq_t *)hp->data; if (found++ == 0) if (rqp->r_desc->indom != PM_INDOM_NULL) { result |= MF_HAS_INDOM; if (rqp->r_numinst == 0) result |= MF_HAS_ALL; else result |= MF_HAS_INST; } if (PMLC_GET_MAND(((task_t *)(rqp->r_fetch->f_aux))->t_state)) result |= MF_HAS_MAND; } return found ? result : -1; } /* Find an optreq_t suitable for adding a new instance */ /* Add a new metric (given a pmValueSet and a pmDesc) to the specified task. * Allocate and return a new task_t if the specified task pointer is nil. * * Note that this should only be called for metrics not currently in the * logging data structure. All instances in the pmValueSet are added! */ static int add_metric(pmValueSet *vsp, task_t **result) { pmID pmid = vsp->pmid; task_t *tp = *result; optreq_t *rqp; pmDesc *dp; char *name; int sts, i, need = 0; dp = (pmDesc *)malloc(sizeof(pmDesc)); if (dp == NULL) { __pmNoMem("add_metric: new pmDesc malloc", sizeof(pmDesc), PM_FATAL_ERR); } if ((sts = pmLookupDesc(pmid, dp)) < 0) die("add_metric: lookup desc", sts); if ((sts = pmNameID(pmid, &name)) < 0) die("add_metric: lookup name", sts); /* allocate a new task if null task pointer passed in */ if (tp == NULL) { tp = calloc(1, sizeof(task_t)); if (tp == NULL) { __pmNoMem("add_metric: new task calloc", sizeof(task_t), PM_FATAL_ERR); } *result = tp; } /* add metric (and any instances specified) to task */ i = tp->t_numpmid++; need = tp->t_numpmid * sizeof(pmID); if (!(tp->t_pmidlist = (pmID *)realloc(tp->t_pmidlist, need))) __pmNoMem("add_metric: new task pmidlist realloc", need, PM_FATAL_ERR); need = tp->t_numpmid * sizeof(char *); if (!(tp->t_namelist = (char **)realloc(tp->t_namelist, need))) __pmNoMem("add_metric: new task namelist realloc", need, PM_FATAL_ERR); need = tp->t_numpmid * sizeof(pmDesc); if (!(tp->t_desclist = (pmDesc *)realloc(tp->t_desclist, need))) __pmNoMem("add_metric: new task desclist realloc", need, PM_FATAL_ERR); tp->t_pmidlist[i] = pmid; tp->t_namelist[i] = name; tp->t_desclist[i] = *dp; /* struct assignment */ rqp = (optreq_t *)calloc(1, sizeof(optreq_t)); if (rqp == NULL) { __pmNoMem("add_metric: new task optreq calloc", need, PM_FATAL_ERR); } rqp->r_desc = dp; /* Now copy instances if required. Remember that metrics with singular * values actually have one instance specified to distinguish them from the * "all instances" case (which has no instances). Use the pmDesc to check * for this. */ if (dp->indom != PM_INDOM_NULL) need = rqp->r_numinst = vsp->numval; if (need) { need *= sizeof(rqp->r_instlist[0]); rqp->r_instlist = (int *)malloc(need); if (rqp->r_instlist == NULL) { __pmNoMem("add_metric: new task optreq instlist malloc", need, PM_FATAL_ERR); } for (i = 0; i < vsp->numval; i++) rqp->r_instlist[i] = vsp->vlist[i].inst; } /* Add new metric to task's fetchgroup(s) and global hash table */ __pmOptFetchAdd(&tp->t_fetch, rqp); linkback(tp); if ((sts = __pmHashAdd(pmid, (void *)rqp, &pm_hash)) < 0) die("add_metric: __pmHashAdd", sts); return 0; } /* Return true if a request for a new logging state (newstate) will be honoured * when current state is curstate. */ static int update_ok(int curstate, int newstate) { /* If new state is advisory and current is mandatory, reject request. * Any new mandatory state is accepted. If the new state is advisory * and the current state is advisory, it is accepted. * Note that a new state of maybe (mandatory maybe) counts as mandatory */ if (PMLC_GET_MAND(newstate) == 0 && PMLC_GET_MAYBE(newstate) == 0 && PMLC_GET_MAND(curstate)) return 0; else return 1; } /* Given a task and a pmID, find an optreq_t associated with the task suitable * for inserting a new instance into. * The one with the smallest number of instances is chosen. We could also * have just used the first, but smallest-first gives a more even distribution. */ static optreq_t * find_instoptreq(task_t *tp, pmID pmid) { optreq_t *result = NULL; optreq_t *rqp; int ni = 0; __pmHashNode *hp; for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; hp = hp->next) { if (pmid != (pmID)hp->key) continue; rqp = (optreq_t *)hp->data; if ((task_t *)rqp->r_fetch->f_aux != tp) continue; if (rqp->r_numinst == 0) continue; /* don't want "all instances" cases */ if (ni == 0 || rqp->r_numinst < ni) { result = rqp; ni = rqp->r_numinst; } } return result; } /* Delete an optreq_t from its task, free it and remove it from the hash list. */ static void del_optreq(optreq_t *rqp) { int sts; task_t *tp = (task_t *)rqp->r_fetch->f_aux; if ((sts = __pmOptFetchDel(&tp->t_fetch, rqp)) < 0) die("del_optreq: __pmOptFetchDel", sts); if ((sts = __pmHashDel(rqp->r_desc->pmid, (void *)rqp, &pm_hash)) < 0) die("del_optreq: __pmHashDel", sts); free(rqp->r_desc); if (rqp->r_numinst) free(rqp->r_instlist); free(rqp); /* TODO: remove pmid from task if that was the last optreq_t for it */ /* TODO: remove task if last pmid removed */ } /* Delete every instance of a given metric from the data structure. * The pmid is deleted from the pmidlist of every task containing an instance. * Return a pointer to the first pmDesc found (the only thing salvaged from the * smoking ruins), or nil if no instances were found. */ static pmDesc * del_insts(pmID pmid) { optreq_t *rqp; __pmHashNode *hp; task_t *tp; pmDesc *dp = NULL; int i, sts, keep; for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; ) { /* Do that BEFORE we nuke the node */ __pmHashNode * nextnode = hp->next; if (pmid == (pmID)hp->key) { rqp = (optreq_t *)hp->data; tp = (task_t *)rqp->r_fetch->f_aux; if ((sts = __pmOptFetchDel(&tp->t_fetch, rqp)) < 0) die("del_insts: __pmOptFetchDel", sts); if ((sts = __pmHashDel(pmid, (void *)rqp, &pm_hash)) < 0) die("del_insts: __pmHashDel", sts); /* save the first pmDesc pointer for return and subsequent * re-use, but free all the others */ if (dp != NULL) free(rqp->r_desc); else dp = rqp->r_desc; if (rqp->r_numinst) free(rqp->r_instlist); free(rqp); /* remove pmid from the task's pmid list */ for (i = 0; i < tp->t_numpmid; i++) if (tp->t_pmidlist[i] == pmid) break; keep = (tp->t_numpmid - 1 - i) * sizeof(tp->t_pmidlist[0]); if (keep) { memmove(&tp->t_pmidlist[i], &tp->t_pmidlist[i+1], keep); memmove(&tp->t_desclist[i], &tp->t_desclist[i+1], keep); memmove(&tp->t_namelist[i], &tp->t_namelist[i+1], keep); } /* don't bother shrinking the pmidlist */ tp->t_numpmid--; if (tp->t_numpmid == 0) { /* TODO: nuke the task if that was the last pmID */ } } hp = nextnode; } return dp; } /* Update an existing metric (given a pmValueSet) adding it to the specified * task. Allocate and return a new task_t if the specified task pointer is nil. */ static int update_metric(pmValueSet *vsp, int reqstate, int mflags, task_t **result) { pmID pmid = vsp->pmid; task_t *ntp = *result; /* pointer to new task */ task_t *ctp; /* pointer to current task */ optreq_t *rqp; pmDesc *dp; int i, j, inst; int sts, need = 0; int addpmid = 0; int freedp; /* allocate a new task if null task pointer passed in */ if (ntp == NULL) { ntp = calloc(1, sizeof(task_t)); if (ntp == NULL) { __pmNoMem("update_metric: new task calloc", sizeof(task_t), PM_FATAL_ERR); } *result = ntp; } if ((mflags & MF_HAS_INDOM) == 0) { rqp = findoptreq(pmid, 0); ctp = (task_t *)(rqp->r_fetch->f_aux); if (!update_ok(ctp->t_state, reqstate)) return 1; /* if the new state is advisory off, just remove the metric */ if ((PMLC_GET_MAYBE(reqstate)) || (PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_ON(reqstate) == 0)) del_optreq(rqp); else { /* update the optreq. For single valued metrics there are no * instances involved so the sole optreq can just be re-used. */ if ((sts = __pmOptFetchDel(&ctp->t_fetch, rqp)) < 0) die("update_metric: 1 metric __pmOptFetchDel", sts); __pmOptFetchAdd(&ntp->t_fetch, rqp); linkback(ntp); addpmid = 1; } } else { /* metric has an instance domain */ if (vsp->numval > 0) { /* tricky: since optFetch can't handle instance profiles of the * form "all except these specific instances", and managing it * manually is just too hard, reject requests for specific * metric instances if "all instances" of the metric are already * being logged. * Note: advisory off "all instances" is excepted since ANY request * overrides and advisory off. E.g. "advisory off all" followed by * "advisory on someinsts" turns on advisory logging for * "someinsts". mflags will be zero for "advisory off" metrics. */ if (mflags & MF_HAS_ALL) return 1; /* can't turn "all" into specific insts */ for (i = 0; i < vsp->numval; i++) { dp = NULL; freedp = 0; inst = vsp->vlist[i].inst; rqp = findoptreq(pmid, inst); if (rqp != NULL) { dp = rqp->r_desc; ctp = (task_t *)(rqp->r_fetch->f_aux); /* no work required if new task and current are the same */ if (ntp == ctp) continue; if (!update_ok(ctp->t_state, reqstate)) continue; /* remove inst's group from current task */ if ((sts = __pmOptFetchDel(&ctp->t_fetch, rqp)) < 0) die("update_metric: instance add __pmOptFetchDel", sts); /* put group back if there are any instances left */ if (rqp->r_numinst > 1) { /* remove inst from group */ for (j = 0; j < rqp->r_numinst; j++) if (inst == rqp->r_instlist[j]) break; /* don't call memmove to move zero bytes */ if (j < rqp->r_numinst - 1) memmove(&rqp->r_instlist[j], &rqp->r_instlist[j+1], (rqp->r_numinst - 1 - j) * sizeof(rqp->r_instlist[0])); rqp->r_numinst--; /* (don't bother realloc-ing the instlist to a smaller size) */ __pmOptFetchAdd(&ctp->t_fetch, rqp); linkback(ctp); /* no need to update hash list, rqp already there */ } /* if that was the last instance, free the group */ else { if (( sts = __pmHashDel(pmid, (void *)rqp, &pm_hash)) < 0) die("update_metric: instance __pmHashDel", sts); freedp = 1; free(rqp->r_instlist); free(rqp); } } /* advisory off (mandatory maybe) metrics don't get put into * the data structure */ if (PMLC_GET_MAYBE(reqstate) || (PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_ON(reqstate) == 0)) { if (freedp) free(dp); continue; } addpmid = 1; /* try to find an existing optreq_t for the instance */ rqp = find_instoptreq(ntp, pmid); if (rqp != NULL) { if ((sts = __pmOptFetchDel(&ntp->t_fetch, rqp)) < 0) die("update_metric: instance add __pmOptFetchDel", sts); } /* no existing optreq_t found, allocate & populate a new one */ else { rqp = (optreq_t *)calloc(1, sizeof(optreq_t)); if (rqp == NULL) { __pmNoMem("update_metric: optreq calloc", sizeof(optreq_t), PM_FATAL_ERR); } /* if the metric existed but the instance didn't, we don't * have a valid pmDesc (dp), so find one. */ if (dp == NULL) { /* find metric and associated pmDesc */ __pmHashNode *hp; for (hp = __pmHashSearch(pmid, &pm_hash); hp != NULL; hp = hp->next) { if (pmid == (pmID)hp->key) break; } assert(hp != NULL); dp = ((optreq_t *)hp->data)->r_desc; } /* recycle pmDesc from the old group, if possible */ if (freedp) { rqp->r_desc = dp; freedp = 0; } /* otherwise allocate & copy a new pmDesc via dp */ else { need = sizeof(pmDesc); rqp->r_desc = (pmDesc *)malloc(need); if (rqp->r_desc == NULL) { __pmNoMem("update_metric: new inst pmDesc malloc", need, PM_FATAL_ERR); } memcpy(rqp->r_desc, dp, need); } if ((sts = __pmHashAdd(pmid, (void *)rqp, &pm_hash)) < 0) die("update_metric: __pmHashAdd", sts); } need = (rqp->r_numinst + 1) * sizeof(rqp->r_instlist[0]); rqp->r_instlist = (int *)realloc(rqp->r_instlist, need); if (rqp->r_instlist == NULL) { __pmNoMem("update_metric: inst list resize", need, PM_FATAL_ERR); } rqp->r_instlist[rqp->r_numinst++] = inst; __pmOptFetchAdd(&ntp->t_fetch, rqp); linkback(ntp); if (freedp) free(dp); } } /* the vset has numval == 0, a request for "all instances" */ else { /* if the metric is a singular instance that has mandatory logging * or has at least one instance with mandatory logging on, a * request for advisory logging cannot be honoured */ if ((mflags & MF_HAS_MAND) && PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_MAYBE(reqstate) == 0) return 1; if (mflags & MF_HAS_ALL) { /* if there is an "all instances" for the metric, it will be * the only optreq_t for the metric */ rqp = findoptreq(pmid, 0); ctp = (task_t *)rqp->r_fetch->f_aux; /* if the metric is "advisory on, all instances" and the * request is for "mandatory maybe, all instances" the current * advisory logging state of the metric is retained */ if (PMLC_GET_MAND(ctp->t_state) == 0 && PMLC_GET_MAYBE(reqstate)) return 0; /* advisory off & mandatory maybe metrics don't get put into * the data structure */ if (PMLC_GET_MAYBE(reqstate) || (PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_ON(reqstate) == 0)) { del_optreq(rqp); return 0; } addpmid = 1; if ((sts = __pmOptFetchDel(&ctp->t_fetch, rqp)) < 0) die("update_metric: all inst __pmOptFetchDel", sts); /* don't delete from hash list, rqp re-used */ __pmOptFetchAdd(&ntp->t_fetch, rqp); linkback(ntp); } else { /* there are one or more specific instances for the metric. * The metric cannot have an "all instances" at the same time. * * if the request is for "mandatory maybe, all instances" and * the only instances of the metric all have advisory logging * on, retain the current advisory semantics. */ if (PMLC_GET_MAYBE(reqstate) && (mflags & MF_HAS_INST) && !(mflags & MF_HAS_MAND)) return 0; dp = del_insts(pmid); /* advisory off (mandatory maybe) metrics don't get put into * the data structure */ if (PMLC_GET_MAYBE(reqstate) || (PMLC_GET_MAND(reqstate) == 0 && PMLC_GET_ON(reqstate) == 0)) { free(dp); return 0; } addpmid = 1; rqp = (optreq_t *)calloc(1, sizeof(optreq_t)); if (rqp == NULL) { __pmNoMem("update_metric: all inst calloc", sizeof(optreq_t), PM_FATAL_ERR); } rqp->r_desc = dp; __pmOptFetchAdd(&ntp->t_fetch, rqp); linkback(ntp); if ((sts = __pmHashAdd(pmid, (void *)rqp, &pm_hash)) < 0) die("update_metric: all inst __pmHashAdd", sts); } } } if (!addpmid) return 0; /* add pmid to new task if not already there */ for (i = 0; i < ntp->t_numpmid; i++) if (pmid == ntp->t_pmidlist[i]) break; if (i >= ntp->t_numpmid) { pmDesc desc; char *name; int need; if ((sts = pmLookupDesc(pmid, &desc)) < 0) die("update_metric: cannot lookup desc", sts); if ((sts = pmNameID(pmid, &name)) < 0) die("update_metric: cannot lookup name", sts); need = (ntp->t_numpmid + 1) * sizeof(pmID); if (!(ntp->t_pmidlist = (pmID *)realloc(ntp->t_pmidlist, need))) __pmNoMem("update_metric: grow task pmidlist", need, PM_FATAL_ERR); need = (ntp->t_numpmid + 1) * sizeof(char *); if (!(ntp->t_namelist = (char **)realloc(ntp->t_namelist, need))) __pmNoMem("update_metric: grow task namelist", need, PM_FATAL_ERR); need = (ntp->t_numpmid + 1) * sizeof(pmDesc); if (!(ntp->t_desclist = (pmDesc *)realloc(ntp->t_desclist, need))) __pmNoMem("update_metric: grow task desclist", need, PM_FATAL_ERR); i = ntp->t_numpmid; ntp->t_pmidlist[i] = pmid; ntp->t_namelist[i] = name; ntp->t_desclist[i] = desc; ntp->t_numpmid++; } return 0; } /* Given a state and a delta, return the first matching task. * Return NULL if a matching task was not found. */ task_t * find_task(int state, struct timeval *delta) { task_t *tp; for (tp = tasklist; tp != NULL; tp = tp->t_next) { if (state == (tp->t_state & 0x3) && /* MAND|ON */ delta->tv_sec == tp->t_delta.tv_sec && delta->tv_usec == tp->t_delta.tv_usec) break; } return tp; } /* Return a mask containing the history flags for a given metric/instance. * the history flags indicate whether the metric/instance is in the log at all * and whether the last fetch of the metric/instance was successful. * * The result is suitable for ORing into the result returned by a control log * request. */ static int gethistflags(pmID pmid, int inst) { __pmHashNode *hp; pmidhist_t *php; insthist_t *ihp; int i, found; int val; for (hp = __pmHashSearch(pmid, &hist_hash); hp != NULL; hp = hp->next) if ((pmID)hp->key == pmid) break; if (hp == NULL) return 0; php = (pmidhist_t *)hp->data; ihp = &php->ph_instlist[0]; val = 0; if (php->ph_indom != PM_INDOM_NULL) { for (i = 0; i < php->ph_numinst; i++, ihp++) if (ihp->ih_inst == inst) break; found = i < php->ph_numinst; } else found = php->ph_numinst > 0; if (found) { PMLC_SET_INLOG(val, 1); val |= ihp->ih_flags; /* only "available flag" is ever set */ } return val; } /* take a pmResult (from a control log request) and half-clone it: return a * pointer to a new pmResult struct which shares the pmValueSets in the * original that have numval > 0, and has null pointers for the pmValueSets * in the original with numval <= 0 */ static pmResult * siamise_request(pmResult *request) { int i, need; pmValueSet *vsp; pmResult *result; need = sizeof(pmResult) + (request->numpmid - 1) * sizeof(pmValueSet *); result = (pmResult *)malloc(need); if (result == NULL) { __pmNoMem("siamise_request: malloc pmResult", need, PM_FATAL_ERR); } for (i = 0; i < request->numpmid; i++) { vsp = request->vset[i]; if (vsp->numval > 0) result->vset[i] = request->vset[i]; else result->vset[i] = NULL; } result->timestamp = request->timestamp; /* structure assignment */ result->numpmid = request->numpmid; return result; } /* Temporarily borrow a bit in the metric/instance history to indicate that * the instance currently exists in the instance domain. The macros below * set and get the bit, which is cleared after we are finished with it here. */ #define PMLC_SET_USEINDOM(val, flag) (val = (val & ~0x1000) | (flag << 12 )) #define PMLC_GET_USEINDOM(val) ((val & 0x1000) >> 12) /* create a pmValueSet large enough to contain the union of the current * instance domain of the specified metric and any previous instances from * the history list. */ static pmValueSet * build_vset(pmID pmid, int usehist) { __pmHashNode *hp; pmidhist_t *php = NULL; insthist_t *ihp; int need = 0; int i, numindom = 0; pmDesc desc; int have_desc; int *instlist = NULL; char **namelist = NULL; pmValueSet *vsp; if (usehist) { /* find the number of instances of the metric in the history (1 if * single-valued metric) */ for (hp = __pmHashSearch(pmid, &hist_hash); hp != NULL; hp = hp->next) if ((pmID)hp->key == pmid) break; if (hp != NULL) { php = (pmidhist_t *)hp->data; need = php->ph_numinst; } } /* * get the current instance domain, so that if the metric hasn't been * logged yet a sensible result is returned. */ if ((have_desc = pmLookupDesc(pmid, &desc)) < 0) goto no_info; if (desc.indom == PM_INDOM_NULL) need = 1; /* will be same in history */ else { int j; if ((numindom = pmGetInDom(desc.indom, &instlist, &namelist)) < 0) { have_desc = numindom; goto no_info; } /* php will be null if usehist is false or there is no history yet */ if (php == NULL) need = numindom; /* no history => use indom */ else for (i = 0; i < numindom; i++) { int inst = instlist[i]; for (j = 0; j < php->ph_numinst; j++) if (inst == php->ph_instlist[j].ih_inst) break; /* * if instance is in history but not instance domain, leave * extra space for it in vset, otherwise use the USEINDOM * flag to avoid another NxM comparison when building the vset * instances later. */ if (j >= php->ph_numinst) need++; else PMLC_SET_USEINDOM(php->ph_instlist[j].ih_flags, 1); } } no_info: need = sizeof(pmValueSet) + (need - 1) * sizeof(pmValue); vsp = (pmValueSet *)malloc(need); if (vsp == NULL) { __pmNoMem("build_vset for control/enquire", need, PM_FATAL_ERR); } vsp->pmid = pmid; if (have_desc < 0) { vsp->numval = have_desc; } else if (desc.indom == PM_INDOM_NULL) { vsp->vlist[0].inst = PM_IN_NULL; vsp->numval = 1; } else { int j; i = 0; /* get instances out of instance domain first */ if (numindom > 0) for (j = 0; j < numindom; j++) vsp->vlist[i++].inst = instlist[j]; /* then any not in instance domain from history */ if (php != NULL) { ihp = &php->ph_instlist[0]; for (j = 0; j < php->ph_numinst; j++, ihp++) if (PMLC_GET_USEINDOM(ihp->ih_flags)) /* it's already in the indom */ PMLC_SET_USEINDOM(ihp->ih_flags, 0); else vsp->vlist[i++].inst = ihp->ih_inst; } vsp->numval = i; } if (instlist) free(instlist); if (namelist) free(namelist); return vsp; } static int do_control(__pmPDU *pb) { int sts; int control; int state; int delta; pmResult *request; pmResult *result; int siamised = 0; /* the verb from siamese (as in twins) */ int i; int j; int val; pmValueSet *vsp; optreq_t *rqp; task_t *tp; time_t now; int reqstate = 0; /* * TODO - encoding for logging interval in requests and results? */ if ((sts = __pmDecodeLogControl(pb, &request, &control, &state, &delta)) < 0) return sts; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "do_control: control=%d state=%d delta=%d request ...\n", control, state, delta); dumpcontrol(stderr, request, 0); } #endif if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) { time(&now); fprintf(stderr, "\n%s", ctime(&now)); fprintf(stderr, "pmlc request from %s: %s", pmlc_host, control == PM_LOG_MANDATORY ? "mandatory" : "advisory"); if (state == PM_LOG_ON) { if (delta == 0) fprintf(stderr, " on once\n"); else fprintf(stderr, " on %.1f sec\n", (float)delta/1000); } else if (state == PM_LOG_OFF) fprintf(stderr, " off\n"); else fprintf(stderr, " maybe\n"); } /* * access control checks */ sts = 0; switch (control) { case PM_LOG_MANDATORY: if (clientops & PM_OP_LOG_MAND) sts = PM_ERR_PERMISSION; break; case PM_LOG_ADVISORY: if (clientops & PM_OP_LOG_ADV) sts = PM_ERR_PERMISSION; break; case PM_LOG_ENQUIRE: if (clientops & PM_OP_LOG_ENQ) sts = PM_ERR_PERMISSION; break; default: fprintf(stderr, "Bad control PDU type %d\n", control); sts = PM_ERR_IPC; break; } if (sts < 0) { if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) fprintf(stderr, "Error: %s\n", pmErrStr(sts)); if ((sts = __pmSendError(clientfd, FROM_ANON, sts)) < 0) __pmNotifyErr(LOG_ERR, "do_control: error sending Error PDU to client: %s\n", pmErrStr(sts)); pmFreeResult(request); return sts; } /* handle everything except PM_LOG_ENQUIRE */ if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) { /* update the logging status of metrics */ task_t *newtp = NULL; /* task for metrics/insts in request */ struct timeval tdelta = { 0 }; int newtask; int mflags; /* convert state and control to the bitmask used in pmlogger and values * returned in results. Remember that reqstate starts with nothing on. */ if (state == PM_LOG_ON) PMLC_SET_ON(reqstate, 1); else PMLC_SET_ON(reqstate, 0); if (control == PM_LOG_MANDATORY) { if (state == PM_LOG_MAYBE) /* mandatory+maybe => maybe+advisory+off */ PMLC_SET_MAYBE(reqstate, 1); else PMLC_SET_MAND(reqstate, 1); } /* try to find an existing task for the request * Never return a "once only" task, it may have gone off already and just * be hanging around like a bad smell. */ if (delta != 0) { tdelta.tv_sec = delta / 1000; tdelta.tv_usec = (delta % 1000) * 1000; newtp = find_task(reqstate, &tdelta); } newtask = (newtp == NULL); for (i = 0; i < request->numpmid; i++) { vsp = request->vset[i]; if (vsp->numval < 0) /* * request is malformed, as we cannot control logging * for an undefined instance ... there is no way to * return an error from here, so simply ignore this * metric */ continue; mflags = find_metric(vsp->pmid); if (mflags < 0) { /* only add new metrics if they are ON or MANDATORY OFF * Careful: mandatory+maybe is mandatory+maybe+off */ if (PMLC_GET_ON(reqstate) || (PMLC_GET_MAND(reqstate) && !PMLC_GET_MAYBE(reqstate))) add_metric(vsp, &newtp); } else /* already a specification for this metric */ update_metric(vsp, reqstate, mflags, &newtp); } /* schedule new logging task if new metric(s) specified */ if (newtask && newtp != NULL) { if (newtp->t_fetch == NULL) { /* the new task ended up with no fetch groups, throw it away */ if (newtp->t_pmidlist != NULL) free(newtp->t_pmidlist); free(newtp); } else { /* link new task into tasklist */ newtp->t_next = tasklist; tasklist = newtp; /* use only the MAND/ADV and ON/OFF bits of reqstate */ newtp->t_state = PMLC_GET_STATE(reqstate); if (PMLC_GET_ON(reqstate)) { newtp->t_delta = tdelta; newtp->t_afid = __pmAFregister(&tdelta, (void *)newtp, log_callback); } else newtp->t_delta.tv_sec = newtp->t_delta.tv_usec = 0; linkback(newtp); } } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) dumpit(); #endif /* just ignore advisory+maybe---the returned pmResult will have the metrics * in their original state indicating that the request could not be * satisfied. */ result = request; result->timestamp.tv_sec = result->timestamp.tv_usec = 0; /* for purify */ /* write the current state of affairs into the result _pmResult */ for (i = 0; i < request->numpmid; i++) { if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) { char *p; sts = pmNameID(request->vset[i]->pmid, &p); if (sts < 0) fprintf(stderr, " metric: %s", pmIDStr(request->vset[i]->pmid)); else { fprintf(stderr, " metric: %s", p); free(p); } } if (request->vset[i]->numval <= 0 && !siamised) { result = siamise_request(request); siamised = 1; } /* * pmids with numval <= 0 in the request have a null vset ptr in the * in the corresponding place in the siamised result. */ if (result->vset[i] != NULL) vsp = result->vset[i]; else { /* the result should also contain the history for an all instances * enquire request. Control requests just get the current indom * since the user of pmlc really wants to see what's being logged * now rather than in the past. */ vsp = build_vset(request->vset[i]->pmid, control == PM_LOG_ENQUIRE); result->vset[i] = vsp; } vsp->valfmt = PM_VAL_INSITU; for (j = 0; j < vsp->numval; j++) { rqp = findoptreq(vsp->pmid, vsp->vlist[j].inst); val = 0; if (rqp == NULL) { PMLC_SET_STATE(val, 0); PMLC_SET_DELTA(val, 0); } else { tp = rqp->r_fetch->f_aux; PMLC_SET_STATE(val, tp->t_state); PMLC_SET_DELTA(val, (tp->t_delta.tv_sec*1000 + tp->t_delta.tv_usec/1000)); } val |= gethistflags(vsp->pmid, vsp->vlist[j].inst); vsp->vlist[j].value.lval = val; if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) { int expstate = 0; int statemask = 0; int expdelta; if (rqp != NULL && rqp->r_desc->indom != PM_INDOM_NULL) { char *p; if (j == 0) fputc('\n', stderr); if (pmNameInDom(rqp->r_desc->indom, vsp->vlist[j].inst, &p) >= 0) { fprintf(stderr, " instance: %s", p); free(p); } else fprintf(stderr, " instance: #%d", vsp->vlist[j].inst); } else { /* no pmDesc ... punt */ if (vsp->numval > 1 || vsp->vlist[j].inst != PM_IN_NULL) { if (j == 0) fputc('\n', stderr); fprintf(stderr, " instance: #%d", vsp->vlist[j].inst); } } if (state != PM_LOG_MAYBE) { if (control == PM_LOG_MANDATORY) PMLC_SET_MAND(expstate, 1); else PMLC_SET_MAND(expstate, 0); if (state == PM_LOG_ON) PMLC_SET_ON(expstate, 1); else PMLC_SET_ON(expstate, 0); PMLC_SET_MAND(statemask, 1); PMLC_SET_ON(statemask, 1); } else { PMLC_SET_MAND(expstate, 0); PMLC_SET_MAND(statemask, 1); } expdelta = PMLC_GET_ON(expstate) ? delta : 0; if ((PMLC_GET_STATE(val) & statemask) != expstate || PMLC_GET_DELTA(val) != expdelta) fprintf(stderr, " [request failed]"); fputc('\n', stderr); } } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { __pmDumpResult(stderr, result); } #endif if ((sts = __pmSendResult(clientfd, FROM_ANON, result)) < 0) __pmNotifyErr(LOG_ERR, "do_control: error sending Error PDU to client: %s\n", pmErrStr(sts)); if (siamised) { for (i = 0; i < request->numpmid; i++) if (request->vset[i]->numval <= 0) free(result->vset[i]); free(result); } pmFreeResult(request); return 0; } /* * sendstatus */ static int sendstatus(void) { int rv; int end; int version; static int firsttime = 1; static char *tzlogger; struct timeval now; if (firsttime) { tzlogger = __pmTimezone(); firsttime = 0; } if ((version = __pmVersionIPC(clientfd)) < 0) return version; if (version >= LOG_PDU_VERSION2) { __pmLoggerStatus ls; if ((ls.ls_state = logctl.l_state) == PM_LOG_STATE_NEW) ls.ls_start.tv_sec = ls.ls_start.tv_usec = 0; else memcpy(&ls.ls_start, &logctl.l_label.ill_start, sizeof(ls.ls_start)); memcpy(&ls.ls_last, &last_stamp, sizeof(ls.ls_last)); __pmtimevalNow(&now); ls.ls_timenow.tv_sec = (__int32_t)now.tv_sec; ls.ls_timenow.tv_usec = (__int32_t)now.tv_usec; ls.ls_vol = logctl.l_curvol; ls.ls_size = ftell(logctl.l_mfp); assert(ls.ls_size >= 0); /* be careful of buffer size mismatches when copying strings */ end = sizeof(ls.ls_hostname) - 1; strncpy(ls.ls_hostname, logctl.l_label.ill_hostname, end); ls.ls_hostname[end] = '\0'; /* BTW, that string should equal pmcd_host[]. */ /* NB: FQDN cleanup: there is no such thing as 'the fully qualified domain name' of a server: it may have several or none; the set may have changed since the time the log archive was collected. Now that we store the then-current pmcd.hostname in the ill_hostname (and thus get it reported in ls_hostname), we could pass something else informative in the ls_fqdn slot. Namely, pmcd_host_conn[], which is the access path pmlogger's using to get to the pmcd. */ end = sizeof(ls.ls_fqdn) - 1; strncpy(ls.ls_fqdn, pmcd_host_conn, end); ls.ls_fqdn[end] = '\0'; end = sizeof(ls.ls_tz) - 1; strncpy(ls.ls_tz, logctl.l_label.ill_tz, end); ls.ls_tz[end] = '\0'; end = sizeof(ls.ls_tzlogger) - 1; if (tzlogger != NULL) strncpy(ls.ls_tzlogger, tzlogger, end); else end = 0; ls.ls_tzlogger[end] = '\0'; rv = __pmSendLogStatus(clientfd, &ls); } else rv = PM_ERR_IPC; return rv; } static int do_request(__pmPDU *pb) { int sts; int type; if ((sts = __pmDecodeLogRequest(pb, &type)) < 0) { __pmNotifyErr(LOG_ERR, "do_request: error decoding PDU: %s\n", pmErrStr(sts)); return PM_ERR_IPC; } switch (type) { case LOG_REQUEST_STATUS: sts = sendstatus(); break; case LOG_REQUEST_NEWVOLUME: sts = newvolume(VOL_SW_PMLC); if (sts >= 0) sts = logctl.l_label.ill_vol; __pmSendError(clientfd, FROM_ANON, sts); break; case LOG_REQUEST_SYNC: sts = do_flush(); __pmSendError(clientfd, FROM_ANON, sts); break; /* * QA support ... intended for error injection * If the request is > QA_OFF then this is a code to enable * a specific style of error behaviour. If the request * is QA_OFF, this disables the error behaviour. * * Supported behaviours. * QA_SLEEPY * After this exchange with pmlc, sleep for 5 seconds * after each incoming pmlc request ... allows testing * of timeout logic in pmlc */ case QA_OFF: qa_case = 0; __pmSendError(clientfd, FROM_ANON, 0); break; case QA_SLEEPY: qa_case = type; __pmSendError(clientfd, FROM_ANON, 0); break; default: fprintf(stderr, "do_request: bad request type %d\n", type); sts = PM_ERR_IPC; break; } return sts; } static int do_creds(__pmPDU *pb) { int i; int sts; int version = UNKNOWN_VERSION; int credcount; int sender; __pmCred *credlist = NULL; if ((sts = __pmDecodeCreds(pb, &sender, &credcount, &credlist)) < 0) { __pmNotifyErr(LOG_ERR, "do_creds: error decoding PDU: %s\n", pmErrStr(sts)); return PM_ERR_IPC; } for (i = 0; i < credcount; i++) { if (credlist[i].c_type == CVERSION) { version = credlist[i].c_vala; if ((sts = __pmSetVersionIPC(clientfd, version)) < 0) { free(credlist); return sts; } } } if (credlist) free(credlist); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) fprintf(stderr, "do_creds: pmlc version=%d\n", version); #endif return sts; } /* * Service a request from the pmlogger client. * Return non-zero if the client has closed the connection. */ int client_req(void) { int sts; __pmPDU *pb; __pmPDUHdr *php; int pinpdu; if ((pinpdu = sts = __pmGetPDU(clientfd, ANY_SIZE, TIMEOUT_DEFAULT, &pb)) <= 0) { if (sts != 0) fprintf(stderr, "client_req: %s\n", pmErrStr(sts)); return 1; } if (qa_case == QA_SLEEPY) { /* error injection - delay before processing and responding */ sleep(5); } php = (__pmPDUHdr *)pb; sts = 0; switch (php->type) { case PDU_CREDS: /* version 2 PDU */ sts = do_creds(pb); break; case PDU_LOG_REQUEST: /* version 2 PDU */ sts = do_request(pb); break; case PDU_LOG_CONTROL: /* version 2 PDU */ sts = do_control(pb); break; default: /* unknown PDU */ fprintf(stderr, "client_req: bad PDU type 0x%x\n", php->type); sts = PM_ERR_IPC; break; } if (pinpdu > 0) __pmUnpinPDUBuf(pb); if (sts >= 0) return 0; else { /* the client isn't playing by the rules */ __pmSendError(clientfd, FROM_ANON, sts); return 1; } } pcp-3.8.12ubuntu1/src/pmlogger/src/events.c0000664000000000000000000000714612272262501015454 0ustar /* * Unpack an array of event records * Free space from unpack * * Copyright (c) 2010 Ken McDonell. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "logger.h" /* * Handle event records. * * Walk the packed array of events using similar logic to * pmUnpackEventRecords() but we don't need any allocations. * * For each embedded event parameter, make sure the metadata for * the associated metric is added to the archive. */ int do_events(pmValueSet *vsp) { pmEventArray *eap; char *base; pmEventRecord *erp; pmEventParameter *epp; int r; /* records */ int p; /* parameters in a record ... */ int i; /* instances ... */ int sts; pmDesc desc; for (i = 0; i < vsp->numval; i++) { if ((sts = __pmCheckEventRecords(vsp, i)) < 0) { __pmDumpEventRecords(stderr, vsp, i); return sts; } eap = (pmEventArray *)vsp->vlist[i].value.pval; if (eap->ea_nrecords == 0) return 0; base = (char *)&eap->ea_record[0]; for (r = 0; r < eap->ea_nrecords; r++) { erp = (pmEventRecord *)base; base += sizeof(erp->er_timestamp) + sizeof(erp->er_flags) + sizeof(erp->er_nparams); if (erp->er_flags & PM_EVENT_FLAG_MISSED) { /* * no event "parameters" here, just a missed records count * in er_nparams */ continue; } for (p = 0; p < erp->er_nparams; p++) { epp = (pmEventParameter *)base; base += sizeof(epp->ep_pmid) + PM_PDU_SIZE_BYTES(epp->ep_len); sts = __pmLogLookupDesc(&logctl, epp->ep_pmid, &desc); if (sts < 0) { int numnames; char **names; numnames = pmNameAll(epp->ep_pmid, &names); if (numnames < 0) { /* * Event parameter metric not defined in the PMNS. * This should not happen, but is probably not fatal, so * issue a warning and make up a name based on the pmid * event_param... */ char *name; size_t name_size = strlen("event_param")+3+1+4+1+4+1; names = (char **)malloc(sizeof(char*) + name_size); if (names == NULL) return -oserror(); name = (char *)&names[1]; names[0] = name; snprintf(name, name_size, "event_param.%s", pmIDStr(epp->ep_pmid)); fprintf(stderr, "Warning: metric %s has no name, using %s\n", pmIDStr(epp->ep_pmid), name); } sts = pmLookupDesc(epp->ep_pmid, &desc); if (sts < 0) { /* Event parameter metric does not have a pmDesc. * This should not happen, but is probably not entirely * fatal (although more serious than not having a metric * name), issue a warning and construct a minimalist * pmDesc */ desc.pmid = epp->ep_pmid; desc.type = PM_TYPE_AGGREGATE; desc.indom = PM_INDOM_NULL; desc.sem = PM_SEM_DISCRETE; memset(&desc.units, '\0', sizeof(desc.units)); fprintf(stderr, "Warning: metric %s (%s) has no descriptor, using a default one\n", names[0], pmIDStr(epp->ep_pmid)); } if ((sts = __pmLogPutDesc(&logctl, &desc, numnames, names)) < 0) { fprintf(stderr, "__pmLogPutDesc: %s\n", pmErrStr(sts)); exit(1); } free(names); } } } } return 0; } pcp-3.8.12ubuntu1/src/pmlogger/src/GNUmakefile0000664000000000000000000000256512272262501016056 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs CMDTARGET = pmlogger$(EXECSUFFIX) CFILES = pmlogger.c fetch.c util.c error.c callback.c ports.c \ dopdu.c check.c preamble.c rewrite.c events.c HFILES = logger.h LFILES = lex.l YFILES = gram.y LCFLAGS += $(PIECFLAGS) LLDFLAGS += $(PIELDFLAGS) LLDLIBS = $(PCPLIB) $(LIB_FOR_PTHREADS) LDIRT = *.log foo.* gram.h lex.c y.tab.? $(YFILES:%.y=%.tab.?) $(CMDTARGET) default: $(CMDTARGET) include $(BUILDRULES) install: $(CMDTARGET) $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) $(INSTALL) -S $(PCP_BIN_DIR)/$(CMDTARGET) $(PCP_BINADM_DIR)/$(CMDTARGET) .NOTPARALLEL: YFLAGS += -v gram.tab.h gram.tab.c: gram.y $(YACC) -d -b `basename $< .y` $< lex.o gram.tab.o: gram.tab.h default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmlogger/src/callback.c0000664000000000000000000005306412272262521015706 0ustar /* * Copyright (c) 2014 Red Hat. * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "logger.h" int last_log_offset; /* * pro tem, we have a single context with the pmcd providing the * results, hence need to send the profile each time */ static int one_context = 1; struct timeval last_stamp; __pmHashCtl hist_hash; /* * These structures allow us to keep track of the _last_ fetch * for each fetch in each AF group ... needed to track changes in * instance availability. */ typedef struct _lastfetch { struct _lastfetch *lf_next; fetchctl_t *lf_fp; pmResult *lf_resp; __pmPDU *lf_pb; } lastfetch_t; typedef struct _AFctl { struct _AFctl *ac_next; int ac_afid; lastfetch_t *ac_fetch; } AFctl_t; static AFctl_t *achead = (AFctl_t *)0; /* clear the "metric/instance was available at last fetch" flag for each metric * and instance in the specified fetchgroup. */ static void clearavail(fetchctl_t *fcp) { indomctl_t *idp; pmID pmid; pmidctl_t *pmp; pmidhist_t *php; insthist_t *ihp; __pmHashNode *hp; int i, inst; int j; for (idp = fcp->f_idp; idp != (indomctl_t *)0; idp = idp->i_next) { for (pmp = idp->i_pmp; pmp != (pmidctl_t *)0; pmp = pmp->p_next) { /* find the metric if it's in the history hash table */ pmid = pmp->p_pmid; for (hp = __pmHashSearch(pmid, &hist_hash); hp != (__pmHashNode *)0; hp = hp->next) if (pmid == (pmID)hp->key) break; if (hp == (__pmHashNode *)0) /* not in history, no flags to update */ continue; php = (pmidhist_t *)hp->data; /* now we have the metric's entry in the history */ if (idp->i_indom != PM_INDOM_NULL) { /* * for each instance in the profile for this metric, find * the history entry for the instance if it exists and * reset the "was available at last fetch" flag */ if (idp->i_numinst) for (i = 0; i < idp->i_numinst; i++) { inst = idp->i_instlist[i]; ihp = &php->ph_instlist[0]; for (j = 0; j < php->ph_numinst; j++, ihp++) if (ihp->ih_inst == inst) { PMLC_SET_AVAIL(ihp->ih_flags, 0); break; } } else /* * if the profile specifies "all instances" clear EVERY * instance's "available" flag * NOTE: even instances that don't exist any more */ for (i = 0; i < php->ph_numinst; i++) PMLC_SET_AVAIL(php->ph_instlist[i].ih_flags, 0); } /* indom is PM_INDOM_NULL */ else { /* if the single-valued metric is in the history it will have 1 * instance */ ihp = &php->ph_instlist[0]; PMLC_SET_AVAIL(ihp->ih_flags, 0); } } } } static void setavail(pmResult *resp) { int i; for (i = 0; i < resp->numpmid; i++) { pmID pmid; pmValueSet *vsp; __pmHashNode *hp; pmidhist_t *php; insthist_t *ihp; int j; vsp = resp->vset[i]; pmid = vsp->pmid; for (hp = __pmHashSearch(pmid, &hist_hash); hp != (__pmHashNode *)0; hp = hp->next) if (pmid == (pmID)hp->key) break; if (hp != (__pmHashNode *)0) php = (pmidhist_t *)hp->data; else { /* add new pmid to history if it's pmValueSet is OK */ if (vsp->numval <= 0) continue; /* * use the OTHER hash list to find the pmid's desc and thereby its * indom */ for (hp = __pmHashSearch(pmid, &pm_hash); hp != (__pmHashNode *)0; hp = hp->next) if (pmid == (pmID)hp->key) break; if (hp == (__pmHashNode *)0 || ((optreq_t *)hp->data)->r_desc == (pmDesc *)0) /* not set up properly yet, not much we can do ... */ continue; php = (pmidhist_t *)calloc(1, sizeof(pmidhist_t)); if (php == (pmidhist_t *)0) { __pmNoMem("setavail: new pmid hist entry calloc", sizeof(pmidhist_t), PM_FATAL_ERR); } php->ph_pmid = pmid; php->ph_indom = ((optreq_t *)hp->data)->r_desc->indom; /* * now create a new insthist list for all the instances in the * pmResult and we're done */ php->ph_numinst = vsp->numval; ihp = (insthist_t *)calloc(vsp->numval, sizeof(insthist_t)); if (ihp == (insthist_t *)0) { __pmNoMem("setavail: inst list calloc", vsp->numval * sizeof(insthist_t), PM_FATAL_ERR); } php->ph_instlist = ihp; for (j = 0; j < vsp->numval; j++, ihp++) { ihp->ih_inst = vsp->vlist[j].inst; PMLC_SET_AVAIL(ihp->ih_flags, 1); } if ((j = __pmHashAdd(pmid, (void *)php, &hist_hash)) < 0) { die("setavail: __pmHashAdd(hist_hash)", j); } return; } /* update an existing pmid history entry, adding any previously unseen * instances */ for (j = 0; j < vsp->numval; j++) { int inst = vsp->vlist[j].inst; int k; for (k = 0; k < php->ph_numinst; k++) if (inst == php->ph_instlist[k].ih_inst) break; if (k < php->ph_numinst) ihp = &php->ph_instlist[k]; else { /* allocate new instance if required */ int need = (k + 1) * sizeof(insthist_t); php->ph_instlist = (insthist_t *)realloc(php->ph_instlist, need); if (php->ph_instlist == (insthist_t *)0) { __pmNoMem("setavail: inst list realloc", need, PM_FATAL_ERR); } ihp = &php->ph_instlist[k]; ihp->ih_inst = inst; ihp->ih_flags = 0; php->ph_numinst++; } PMLC_SET_AVAIL(ihp->ih_flags, 1); } } } /* * This has been taken straight from logmeta.c in libpcp. It is required * here to get the timestamp of the indom. * Note that the tp argument is used to return the timestamp of the indom. * It is a merger of __pmLogGetIndom and searchindom. */ int __localLogGetInDom(__pmLogCtl *lcp, pmInDom indom, __pmTimeval *tp, int **instlist, char ***namelist) { __pmHashNode *hp; __pmLogInDom *idp; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) fprintf(stderr, "__localLogGetInDom( ..., %s)\n", pmInDomStr(indom)); #endif if ((hp = __pmHashSearch((unsigned int)indom, &lcp->l_hashindom)) == NULL) return 0; idp = (__pmLogInDom *)hp->data; if (idp == NULL) return PM_ERR_INDOM_LOG; *instlist = idp->instlist; *namelist = idp->namelist; *tp = idp->stamp; return idp->numinst; } /* * compare pmResults for a particular metric, and return 1 if * the set of instances has changed. */ static int check_inst(pmValueSet *vsp, int hint, pmResult *lrp) { int i; int j; pmValueSet *lvsp; /* Make sure vsp->pmid exists in lrp's result */ /* and find which value set in lrp it is. */ if (hint < lrp->numpmid && lrp->vset[hint]->pmid == vsp->pmid) i = hint; else { for (i = 0; i < lrp->numpmid; i++) { if (lrp->vset[i]->pmid == vsp->pmid) break; } if (i == lrp->numpmid) { fprintf(stderr, "check_inst: cannot find PMID %s in last result ...\n", pmIDStr(vsp->pmid)); __pmDumpResult(stderr, lrp); return 0; } } lvsp = lrp->vset[i]; if (lvsp->numval != vsp->numval) return 1; /* compare instances */ for (i = 0; i < lvsp->numval; i++) { if (lvsp->vlist[i].inst != vsp->vlist[i].inst) { /* the hard way */ for (j = 0; j < vsp->numval; j++) { if (lvsp->vlist[j].inst == vsp->vlist[i].inst) break; } if (j == vsp->numval) return 1; } } return 0; } /* * Lookup the first cache index associated with a given PMID in a given task. */ static int lookupTaskCacheIndex(task_t *tp, pmID pmid) { int i; for (i = 0; i < tp->t_numpmid; i++) if (tp->t_pmidlist[i] == pmid) return i; return -1; } /* * Iterate over *all* tasks and return all names for a given PMID. * Returns the number of names found, and nameset allocated in a * single allocation call (which the caller must free). */ static int lookupTaskCacheNames(pmID pmid, char ***namesptr) { int i, numnames = 0, len = 0; char *data, **names = NULL; task_t *tp; for (tp = tasklist; tp != NULL; tp = tp->t_next) { for (i = 0; i < tp->t_numpmid; i++) { if (tp->t_pmidlist[i] != pmid) continue; len += strlen(tp->t_namelist[i]) + 1; numnames++; } } names = (char **)malloc(numnames * sizeof(names[0]) + len); data = (char *)names + (numnames * sizeof(names[0])); for (tp = tasklist, len = 0; tp != NULL; tp = tp->t_next) { for (i = 0; i < tp->t_numpmid; i++) { if (tp->t_pmidlist[i] != pmid) continue; names[len++] = data; strcpy(data, tp->t_namelist[i]); data += (strlen(tp->t_namelist[i]) + 1); } } *namesptr = names; return numnames; } void log_callback(int afid, void *data) { int i; int j; int k; int sts; task_t *tp = (task_t *)data; fetchctl_t *fp; indomctl_t *idp; pmResult *resp; __pmPDU *pb; AFctl_t *acp; lastfetch_t *lfp; lastfetch_t *free_lfp; int needindom; int needti; static int flushsize = 100000; long old_meta_offset; long new_offset; long new_meta_offset; int pdu_bytes = 0; int pdu_metrics = 0; int numinst; int *instlist; char **namelist; __pmTimeval tmp; __pmTimeval resp_tval; unsigned long peek_offset; if (!parse_done) /* ignore callbacks until all of the config file has been parsed */ return; /* find AFctl_t for this afid */ for (acp = achead; acp != (AFctl_t *)0; acp = acp->ac_next) { if (acp->ac_afid == afid) break; } if (acp == (AFctl_t *)0) { acp = (AFctl_t *)calloc(1, sizeof(AFctl_t)); if (acp == (AFctl_t *)0) { __pmNoMem("log_callback: new AFctl_t entry calloc", sizeof(AFctl_t), PM_FATAL_ERR); } acp->ac_afid = afid; acp->ac_next = achead; achead = acp; } else { /* cleanup any fetchgroups that have gone away */ for (lfp = acp->ac_fetch; lfp != (lastfetch_t *)0; lfp = lfp->lf_next) { for (fp = tp->t_fetch; fp != (fetchctl_t *)0; fp = fp->f_next) { if (fp == lfp->lf_fp) break; } if (fp == (fetchctl_t *)0) { lfp->lf_fp = (fetchctl_t *)0; /* mark lastfetch_t as free */ if (lfp->lf_resp != (pmResult *)0) { pmFreeResult(lfp->lf_resp); lfp->lf_resp =(pmResult *)0; } } } } for (fp = tp->t_fetch; fp != (fetchctl_t *)0; fp = fp->f_next) { /* find lastfetch_t for this fetch group, else make a new one */ free_lfp = (lastfetch_t *)0; for (lfp = acp->ac_fetch; lfp != (lastfetch_t *)0; lfp = lfp->lf_next) { if (lfp->lf_fp == fp) break; if (lfp->lf_fp == (fetchctl_t *)0 && free_lfp == (lastfetch_t *)0) free_lfp = lfp; } if (lfp == (lastfetch_t *)0) { /* need new one */ if (free_lfp != (lastfetch_t *)0) lfp = free_lfp; /* lucky */ else { lfp = (lastfetch_t *)calloc(1, sizeof(lastfetch_t)); if (lfp == (lastfetch_t *)0) { __pmNoMem("log_callback: new lastfetch_t entry calloc", sizeof(lastfetch_t), PM_FATAL_ERR); } lfp->lf_next = acp->ac_fetch; acp->ac_fetch = lfp; } lfp->lf_fp = fp; } if (one_context || fp->f_state & OPT_STATE_PROFILE) { /* profile for this fetch group has changed */ pmAddProfile(PM_INDOM_NULL, 0, (int *)0); for (idp = fp->f_idp; idp != (indomctl_t *)0; idp = idp->i_next) { if (idp->i_indom != PM_INDOM_NULL && idp->i_numinst != 0) pmAddProfile(idp->i_indom, idp->i_numinst, idp->i_instlist); } fp->f_state &= ~OPT_STATE_PROFILE; } clearavail(fp); if ((sts = myFetch(fp->f_numpmid, fp->f_pmidlist, &pb)) < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "callback: disconnecting because myFetch failed: %s\n", pmErrStr(sts)); #endif disconnect(sts); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "callback: fetch group %p (%d metrics)\n", fp, fp->f_numpmid); #endif /* * hook to rewrite PDU buffer ... lfp */ pb = rewrite_pdu(pb, archive_version); if (rflag) { /* * bytes = PDU len - sizeof (header) + 2 * sizeof (int) * see __pmLogPutResult for details of how PDU buffer is * reformatted to make len shorter by one int before the * record is written to the external file */ pdu_bytes += ((__pmPDUHdr *)pb)->len - sizeof (__pmPDUHdr) + 2*sizeof(int); pdu_metrics += fp->f_numpmid; } /* * Even without a -v option, we may need to switch volumes * if the data file exceeds 2^31-1 bytes */ peek_offset = ftell(logctl.l_mfp); peek_offset += ((__pmPDUHdr *)pb)->len - sizeof(__pmPDUHdr) + 2*sizeof(int); if (peek_offset > 0x7fffffff) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "callback: new volume based on max size, currently %ld\n", ftell(logctl.l_mfp)); #endif (void)newvolume(VOL_SW_MAX); } /* * would prefer to save this up until after any meta data and/or * temporal index writes, but __pmDecodeResult changes the pointers * in the pdu buffer for the non INSITU values ... sigh */ last_log_offset = ftell(logctl.l_mfp); assert(last_log_offset >= 0); if ((sts = __pmLogPutResult(&logctl, pb)) < 0) { fprintf(stderr, "__pmLogPutResult: %s\n", pmErrStr(sts)); exit(1); } __pmOverrideLastFd(fileno(logctl.l_mfp)); if ((sts = __pmDecodeResult(pb, &resp)) < 0) { fprintf(stderr, "__pmDecodeResult: %s\n", pmErrStr(sts)); exit(1); } setavail(resp); resp_tval.tv_sec = resp->timestamp.tv_sec; resp_tval.tv_usec = resp->timestamp.tv_usec; needti = 0; old_meta_offset = ftell(logctl.l_mdfp); assert(old_meta_offset >= 0); for (i = 0; i < resp->numpmid; i++) { pmValueSet *vsp = resp->vset[i]; pmDesc desc; char **names = NULL; int numnames = 0; sts = __pmLogLookupDesc(&logctl, vsp->pmid, &desc); if (sts < 0) { /* lookup name and descriptor in task cache */ int taskindex = lookupTaskCacheIndex(tp, vsp->pmid); if (taskindex == -1) { fprintf(stderr, "lookupTaskCacheIndex cannot find PMID %s\n", pmIDStr(vsp->pmid)); exit(1); } desc = tp->t_desclist[taskindex]; numnames = lookupTaskCacheNames(vsp->pmid, &names); if ((sts = __pmLogPutDesc(&logctl, &desc, numnames, names)) < 0) { fprintf(stderr, "__pmLogPutDesc: %s\n", pmErrStr(sts)); exit(1); } if (numnames) { free(names); } } if (desc.type == PM_TYPE_EVENT) { /* * Event records need some special handling ... */ if ((sts = do_events(vsp)) < 0) { fprintf(stderr, "Failed to process event records: %s\n", pmErrStr(sts)); exit(1); } } if (desc.indom != PM_INDOM_NULL && vsp->numval > 0) { /* * __pmLogGetInDom has been replaced by __localLogGetInDom so that * the timestamp of the retrieved indom is also returned. The timestamp * is then used to decide if the indom needs to be refreshed. */ __pmTimeval indom_tval; numinst = __localLogGetInDom(&logctl, desc.indom, &indom_tval, &instlist, &namelist); if (numinst < 0) needindom = 1; else { needindom = 0; /* Need to see if result's insts all exist * somewhere in the hashed/cached insts. * Thus a potential numval^2 search. */ for (j = 0; j < vsp->numval; j++) { for (k = 0; k < numinst; k++) { if (vsp->vlist[j].inst == instlist[k]) break; } if (k == numinst) { needindom = 1; break; } } } /* * Check here that the instance domain has not been changed * by a previous iteration of this loop. * So, the timestamp of resp must be after the update timestamp * of the target instance domain. */ if (needindom == 0 && lfp->lf_resp != (pmResult *)0 && __pmTimevalSub(&resp_tval, &indom_tval) < 0 ) needindom = check_inst(vsp, i, lfp->lf_resp); if (needindom) { /* * Note. We do NOT free() instlist and namelist allocated * here ... look for magic below log{Put,Get}InDom ... */ if ((numinst = pmGetInDom(desc.indom, &instlist, &namelist)) < 0) { fprintf(stderr, "pmGetInDom(%s): %s\n", pmInDomStr(desc.indom), pmErrStr(numinst)); exit(1); } tmp.tv_sec = (__int32_t)resp->timestamp.tv_sec; tmp.tv_usec = (__int32_t)resp->timestamp.tv_usec; if ((sts = __pmLogPutInDom(&logctl, desc.indom, &tmp, numinst, instlist, namelist)) < 0) { fprintf(stderr, "__pmLogPutInDom: %s\n", pmErrStr(sts)); exit(1); } needti = 1; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "callback: indom (%s) changed\n", pmInDomStr(desc.indom)); #endif } } } if (ftell(logctl.l_mfp) > flushsize) { needti = 1; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "callback: file size (%d) reached flushsize (%d)\n", (int)ftell(logctl.l_mfp), flushsize); #endif } if (last_log_offset == 0 || last_log_offset == sizeof(__pmLogLabel)+2*sizeof(int)) { /* first result in this volume */ needti = 1; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "callback: first result for this volume\n"); #endif } if (needti) fflush(logctl.l_mdfp); if (needti) { /* * need to unwind seek pointer to start of most recent * result (but if this is the first one, skip the label * record, what a crock), ... ditto for the meta data */ new_offset = ftell(logctl.l_mfp); assert(new_offset >= 0); new_meta_offset = ftell(logctl.l_mdfp); assert(new_meta_offset >= 0); fseek(logctl.l_mfp, last_log_offset, SEEK_SET); fseek(logctl.l_mdfp, old_meta_offset, SEEK_SET); tmp.tv_sec = (__int32_t)resp->timestamp.tv_sec; tmp.tv_usec = (__int32_t)resp->timestamp.tv_usec; __pmLogPutIndex(&logctl, &tmp); /* * ... and put them back */ fseek(logctl.l_mfp, new_offset, SEEK_SET); fseek(logctl.l_mdfp, new_meta_offset, SEEK_SET); flushsize = ftell(logctl.l_mfp) + 100000; } last_stamp = resp->timestamp; /* struct assignment */ if (lfp->lf_resp != (pmResult *)0) { /* * release memory that is allocated and pinned in pmDecodeResult */ pmFreeResult(lfp->lf_resp); } lfp->lf_resp = resp; if (lfp->lf_pb != NULL) __pmUnpinPDUBuf(lfp->lf_pb); lfp->lf_pb = pb; } if (rflag && tp->t_size == 0 && pdu_metrics > 0) { char *name = NULL; int taskindex; int i; tp->t_size = pdu_bytes; if (pdu_metrics > 1) fprintf(stderr, "\nGroup [%d metrics] {\n", pdu_metrics); else fprintf(stderr, "\nMetric "); for (fp = tp->t_fetch; fp != (fetchctl_t *)0; fp = fp->f_next) { for (i = 0; i < fp->f_numpmid; i++) { name = NULL; taskindex = lookupTaskCacheIndex(tp, fp->f_pmidlist[i]); if (taskindex >= 0) name = tp->t_namelist[taskindex]; if (pdu_metrics > 1) fprintf(stderr, "\t"); fprintf(stderr, "%s", name ? name : pmIDStr(fp->f_pmidlist[i])); if (pdu_metrics > 1) fprintf(stderr, "\n"); } if (pdu_metrics > 1) fprintf(stderr, "}"); } fprintf(stderr, " logged "); if (tp->t_delta.tv_sec == 0 && tp->t_delta.tv_usec == 0) fprintf(stderr, "once: %d bytes\n", pdu_bytes); else { if (tp->t_delta.tv_usec == 0) { fprintf(stderr, "every %d sec: %d bytes ", (int)tp->t_delta.tv_sec, pdu_bytes); } else fprintf(stderr, "every %d.%03d sec: %d bytes ", (int)tp->t_delta.tv_sec, (int)tp->t_delta.tv_usec / 1000, pdu_bytes); fprintf(stderr, "or %.2f Mbytes/day\n", ((double)pdu_bytes * 24 * 60 * 60) / (1024 * 1024 * (tp->t_delta.tv_sec + (double)tp->t_delta.tv_usec / 1000000))); } } if (exit_samples > 0) exit_samples--; if (exit_samples == 0) /* run out of samples in sample counter, so stop logging */ run_done(0, "Sample limit reached"); if (exit_bytes != -1 && (vol_bytes + ftell(logctl.l_mfp) >= exit_bytes)) /* reached exit_bytes limit, so stop logging */ run_done(0, "Byte limit reached"); if (vol_switch_samples > 0 && ++vol_samples_counter == vol_switch_samples) { (void)newvolume(VOL_SW_COUNTER); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "callback: new volume based on samples (%d)\n", vol_samples_counter); #endif } if (vol_switch_bytes > 0 && (ftell(logctl.l_mfp) >= vol_switch_bytes)) { (void)newvolume(VOL_SW_BYTES); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "callback: new volume based on size (%d)\n", (int)ftell(logctl.l_mfp)); #endif } if (unbuffered) { /* -u on command line */ do_flush(); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "callback: flush for -u\n"); #endif } } int putmark(void) { struct { __pmPDU hdr; __pmTimeval timestamp; /* when returned */ int numpmid; /* zero PMIDs to follow */ __pmPDU tail; } mark; if (last_stamp.tv_sec == 0 && last_stamp.tv_usec == 0) /* no earlier pmResult, no point adding a mark record */ return 0; mark.hdr = htonl((int)sizeof(mark)); mark.tail = mark.hdr; mark.timestamp.tv_sec = last_stamp.tv_sec; mark.timestamp.tv_usec = last_stamp.tv_usec + 1000; /* + 1msec */ if (mark.timestamp.tv_usec > 1000000) { mark.timestamp.tv_usec -= 1000000; mark.timestamp.tv_sec++; } mark.timestamp.tv_sec = htonl(mark.timestamp.tv_sec); mark.timestamp.tv_usec = htonl(mark.timestamp.tv_usec); mark.numpmid = htonl(0); if (fwrite(&mark, 1, sizeof(mark), logctl.l_mfp) != sizeof(mark)) return -oserror(); else return 0; } pcp-3.8.12ubuntu1/src/pmlogger/src/lex.l0000664000000000000000000000573312272262501014751 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ %{ #include "pmapi.h" #include "impl.h" #include "logger.h" int lineno=1; #include "gram.tab.h" static int ctx(int type) { extern int mystate; if (mystate == GLOBAL) return type; else { yylval.str = yytext; return NAME; } } %} %option noinput %option nounput %{ #ifdef FLEX_SCANNER #ifndef YY_NO_UNPUT #define YY_NO_UNPUT #endif #else #undef input #define input() ((yytchar=fgetc(yyin)) == EOF ? 0 : yytchar) #undef unput #define unput(c) {yytchar=(c); ungetc(yytchar, yyin);} #endif /* FLEX_SCANNER */ %} %% "[" { return LSQB; } "]" { return RSQB; } "," { return COMMA; } "{" { return LBRACE; } "}" { return RBRACE; } ":" { return COLON; } ";" { return SEMICOLON; } milliseconds? { return ctx(MSEC); } mandatory { return ctx(MANDATORY); } advisory { return ctx(ADVISORY); } disallow { return ctx(DISALLOW); } minutes? { return ctx(MINUTE); } seconds? { return ctx(SECOND); } default { return ctx(DEFAULT); } enquire { return ctx(ENQUIRE); } access { return ctx(ACCESS); } except { return ctx(EXCEPT); } allow { return ctx(ALLOW); } every { return ctx(EVERY); } maybe { return ctx(MAYBE); } hours? { return ctx(HOUR); } msecs? { return ctx(MSEC); } mins? { return ctx(MINUTE); } once { return ctx(ONCE); } secs? { return ctx(SECOND); } log { return ctx(LOG); } all { return ctx(ALL); } off { return ctx(OFF); } on { return ctx(ON); } [A-Za-z][A-Za-z0-9_.]* { yylval.str = yytext; return NAME; } [A-Za-z][A-Za-z0-9_.-]* { yylval.str = yytext; return HOSTNAME; } \"[^\"\n][^\"\n]*\" { /* strip quotes before returing */ yytext[strlen(yytext)-1] = '\0'; yylval.str = yytext+1; return STRING; } [0-9]+ { yylval.lval = atol(yytext); return NUMBER; } [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ { yylval.str = yytext; return IPSPEC; } [0-9]+\.[0-9]+\.[0-9]+\.\* { yylval.str = yytext; return IPSPEC; } [0-9]+\.[0-9]+\.\* { yylval.str = yytext; return IPSPEC; } [0-9]+\.\* { yylval.str = yytext; return IPSPEC; } \* { yylval.str = yytext; return IPSPEC; } \#.* { } [ \t\r]+ { } \n { lineno++; } . { char emess[256]; snprintf(emess, sizeof(emess), "Unexpected character '%c'", yytext[0]); yyerror(emess); } %% int yywrap (void) { return 1; } pcp-3.8.12ubuntu1/src/pmlogger/src/gram.y0000664000000000000000000003360512272262521015125 0ustar /* * Copyright (c) 2013-2014 Red Hat. * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * There is a shift/reduced conflict reported by yacc when it cannot * decide whatever it should take 'optinst' route or 'access' one in * the following sutiation: * * log on once foo [access] all * * This conflict considered to be benign, since yacc takes 'the right' option * if optinst is supplied. To work around the issue of access been treated * as an option, enclose the list of metrics in the curly braces, i.e. * * log on once {foo} [access] all */ %{ #include "pmapi.h" #include "impl.h" #include "logger.h" int mystate = GLOBAL; /* config file parser state */ __pmHashCtl pm_hash; task_t *tasklist; static task_t *tp; static int numinst; static int *intlist; static char **extlist; static int state; /* logging state, current block */ static char *metricName; /* current metric, current block */ typedef struct _hl { struct _hl *hl_next; char *hl_name; int hl_line; } hostlist_t; static hostlist_t *hl_root; static hostlist_t *hl_last; static hostlist_t *hlp; static hostlist_t *prevhlp; static int opmask; /* operations mask */ static int specmask; /* specifications mask */ static int allow; /* host allow/disallow state */ static int lookup_metric_name(const char *); static void activate_new_metric(const char *); static void activate_cached_metric(const char *, int); static task_t *findtask(int, struct timeval *); %} %union { long lval; char * str; } %expect 1 %term LSQB RSQB COMMA LBRACE RBRACE COLON SEMICOLON LOG MANDATORY ADVISORY ON OFF MAYBE EVERY ONCE DEFAULT MSEC SECOND MINUTE HOUR ACCESS ENQUIRE ALLOW DISALLOW ALL EXCEPT %token NAME STRING IPSPEC HOSTNAME %token NUMBER %type frequency timeunits action %type hostspec %% config : specopt accessopt ; specopt : spec | /* nothing */ ; spec : stmt | spec stmt ; stmt : dowhat somemetrics { mystate = GLOBAL; if (tp->t_numvalid) linkback(tp); state = 0; } ; dowhat : logopt action { struct timeval delta; delta.tv_sec = $2 / 1000; delta.tv_usec = 1000 * ($2 % 1000); /* * Search for an existing task for this state/interval; * only allocate and setup a new task if none exists. */ if ((tp = findtask(state, &delta)) == NULL) { if ((tp = (task_t *)calloc(1, sizeof(task_t))) == NULL) { char emess[256]; snprintf(emess, sizeof(emess), "malloc failed: %s", osstrerror()); yyerror(emess); } else { tp->t_delta = delta; tp->t_state = state; tp->t_next = tasklist; tasklist = tp; } } state = 0; } ; logopt : LOG | /* nothing */ ; action : cntrl ON frequency { char emess[256]; if ($3 < 0) { snprintf(emess, sizeof(emess), "Logging delta (%ld msec) must be positive",$3); yyerror(emess); } else if ($3 > PMLC_MAX_DELTA) { snprintf(emess, sizeof(emess), "Logging delta (%ld msec) cannot be bigger " "than %d msec", $3, PMLC_MAX_DELTA); yyerror(emess); } PMLC_SET_ON(state, 1); $$ = $3; } | cntrl OFF { PMLC_SET_ON(state, 0);$$ = 0;} | MANDATORY MAYBE { PMLC_SET_MAND(state, 0); PMLC_SET_ON(state, 0); PMLC_SET_MAYBE(state, 1); $$ = 0; } ; cntrl : MANDATORY { PMLC_SET_MAND(state, 1); } | ADVISORY { PMLC_SET_MAND(state, 0); } | /*nothing == advisory*/ { PMLC_SET_MAND(state, 0); } ; frequency : everyopt NUMBER timeunits { $$ = $2*$3; } | ONCE { $$ = 0; } | DEFAULT { extern struct timeval delta; /* default logging interval */ $$ = delta.tv_sec*1000 + delta.tv_usec/1000; } ; everyopt : EVERY | /* nothing */ ; timeunits : MSEC { $$ = 1; } | SECOND { $$ = 1000; } | MINUTE { $$ = 60000; } | HOUR { $$ = 3600000; } ; somemetrics : LBRACE { mystate = INSPEC; } metriclist RBRACE | metricspec ; metriclist : metricspec | metriclist metricspec | metriclist COMMA metricspec ; metricspec : NAME { if ((metricName = strdup($1)) == NULL) { char emess[256]; snprintf(emess, sizeof(emess), "malloc failed: %s", osstrerror()); yyerror(emess); } } optinst { int index, sts; /* * search names for previously seen metrics for this task * (note that name may be non-terminal in the PMNS here); * if already found in this task, skip namespace PDUs. */ if ((index = lookup_metric_name(metricName)) < 0) { if ((sts = pmTraversePMNS(metricName, activate_new_metric)) < 0 ) { char emess[256]; snprintf(emess, sizeof(emess), "Problem with lookup for metric \"%s\" " "... logging not activated", metricName); yywarn(emess); fprintf(stderr, "Reason: %s\n", pmErrStr(sts)); } } else { /* name is cached already, handle instances */ activate_cached_metric(metricName, index); } freeinst(&numinst, intlist, extlist); free(metricName); } ; optinst : LSQB instancelist RSQB | /* nothing */ ; instancelist : instance | instance instancelist | instance COMMA instancelist ; instance : NAME { buildinst(&numinst, &intlist, &extlist, -1, $1); } | NUMBER { buildinst(&numinst, &intlist, &extlist, $1, NULL); } | STRING { buildinst(&numinst, &intlist, &extlist, -1, $1); } ; accessopt : LSQB ACCESS RSQB ctllist | /* nothing */ ; ctllist : ctl | ctl ctllist ; ctl : allow hostlist COLON operation SEMICOLON { prevhlp = NULL; for (hlp = hl_root; hlp != NULL; hlp = hlp->hl_next) { int sts; if (prevhlp != NULL) { free(prevhlp->hl_name); free(prevhlp); } sts = __pmAccAddHost(hlp->hl_name, specmask, opmask, 0); if (sts < 0) { fprintf(stderr, "error was on line %d\n", hlp->hl_line); YYABORT; } prevhlp = hlp; } if (prevhlp != NULL) { free(prevhlp->hl_name); free(prevhlp); } opmask = 0; specmask = 0; hl_root = hl_last = NULL; } ; allow : ALLOW { allow = 1; } | DISALLOW { allow = 0; } ; hostlist : host | host COMMA hostlist ; host : hostspec { size_t sz = sizeof(hostlist_t); hlp = (hostlist_t *)malloc(sz); if (hlp == NULL) { __pmNoMem("adding new host", sz, PM_FATAL_ERR); } if (hl_last != NULL) { hl_last->hl_next = hlp; hl_last = hlp; } else hl_root = hl_last = hlp; hlp->hl_next = NULL; hlp->hl_name = strdup($1); hlp->hl_line = lineno; } ; hostspec : IPSPEC | HOSTNAME | NAME ; operation : operlist { specmask = opmask; if (allow) opmask = ~opmask; } | ALL { specmask = PM_OP_ALL; if (allow) opmask = PM_OP_NONE; else opmask = PM_OP_ALL; } | ALL EXCEPT operlist { specmask = PM_OP_ALL; if (!allow) opmask = ~opmask; } ; operlist : op | op COMMA operlist ; op : ADVISORY { opmask |= PM_OP_LOG_ADV; } | MANDATORY { opmask |= PM_OP_LOG_MAND; } | ENQUIRE { opmask |= PM_OP_LOG_ENQ; } ; %% /* * Search the cache for previously seen metrics for active task. * Returns -1 if not found, else an index into tp->t_namelist. */ static int lookup_metric_name(const char *name) { int j; for (j = 0; j < tp->t_numpmid; j++) if (strcmp(tp->t_namelist[j], name) == 0) return j; return -1; } /* * Assumed calling context ... * tp the correct task for the requested metric * numinst number of instances associated with this request * extlist[] external instance names if numinst > 0 * intlist[] internal instance identifier if numinst > 0 and * corresponding extlist[] entry is NULL */ static void activate_cached_metric(const char *name, int index) { int sts = 0; int inst; int i; int j; int skip = 0; pmID pmid; pmDesc *dp; optreq_t *rqp; char emess[1024]; /* * need new malloc'd pmDesc, even if metric found in cache, as * the fetchctl keeps its own (non-realloc-movable!) pointer. */ dp = (pmDesc *)malloc(sizeof(pmDesc)); if (dp == NULL) goto nomem; if (index < 0) { if ((sts = pmLookupName(1, (char **)&name, &pmid)) < 0 || pmid == PM_ID_NULL) { snprintf(emess, sizeof(emess), "Metric \"%s\" is unknown ... not logged", name); goto snarf; } if ((sts = pmLookupDesc(pmid, dp)) < 0) { snprintf(emess, sizeof(emess), "Description unavailable for metric \"%s\" ... not logged", name); goto snarf; } tp->t_numpmid++; tp->t_namelist = (char **)realloc(tp->t_namelist, tp->t_numpmid * sizeof(char *)); if (tp->t_namelist == NULL) goto nomem; if ((tp->t_namelist[tp->t_numpmid-1] = strdup(name)) == NULL) goto nomem; tp->t_pmidlist = (pmID *)realloc(tp->t_pmidlist, tp->t_numpmid * sizeof(pmID)); if (tp->t_pmidlist == NULL) goto nomem; tp->t_desclist = (pmDesc *)realloc(tp->t_desclist, tp->t_numpmid * sizeof(pmDesc)); if (tp->t_desclist == NULL) goto nomem; tp->t_pmidlist[tp->t_numpmid-1] = pmid; tp->t_desclist[tp->t_numpmid-1] = *dp; /* struct assignment */ } else { *dp = tp->t_desclist[index]; pmid = tp->t_pmidlist[index]; } rqp = (optreq_t *)calloc(1, sizeof(optreq_t)); if (rqp == NULL) goto nomem; rqp->r_desc = dp; rqp->r_numinst = numinst; if (numinst) { /* * malloc here, and keep ... gets buried in optFetch data structures */ rqp->r_instlist = (int *)malloc(numinst * sizeof(rqp->r_instlist[0])); if (rqp->r_instlist == NULL) goto nomem; j = 0; for (i = 0; i < numinst; i++) { if (extlist[i] != NULL) { sts = pmLookupInDom(dp->indom, extlist[i]); if (sts < 0) { snprintf(emess, sizeof(emess), "Instance \"%s\" is not defined for the metric \"%s\"", extlist[i], name); yywarn(emess); rqp->r_numinst--; continue; } inst = sts; } else { char *p; sts = pmNameInDom(dp->indom, intlist[i], &p); if (sts < 0) { snprintf(emess, sizeof(emess), "Instance \"%d\" is not defined for the metric \"%s\"", intlist[i], name); yywarn(emess); rqp->r_numinst--; continue; } free(p); inst = intlist[i]; } if ((sts = chk_one(tp, pmid, inst)) < 0) { snprintf(emess, sizeof(emess), "Incompatible request for metric \"%s\" " "and instance \"%s\"", name, extlist[i]); yywarn(emess); fprintf(stderr, "%s\n", chk_emess[-sts]); rqp->r_numinst--; } else if (sts == 0) rqp->r_instlist[j++] = inst; else /* already have this instance */ skip = 1; } if (rqp->r_numinst == 0) skip = 1; } else { if ((sts = chk_all(tp, pmid)) < 0) { snprintf(emess, sizeof(emess), "Incompatible request for metric \"%s\"", name); yywarn(emess); skip = 1; } } if (!skip) { __pmOptFetchAdd(&tp->t_fetch, rqp); if ((sts = __pmHashAdd(pmid, (void *)rqp, &pm_hash)) < 0) { snprintf(emess, sizeof(emess), "__pmHashAdd failed " "for metric \"%s\" ... logging not activated", name); goto snarf; } tp->t_numvalid++; } else { free(dp); free(rqp); } return; nomem: snprintf(emess, sizeof(emess), "malloc failed: %s", osstrerror()); yyerror(emess); snarf: yywarn(emess); fprintf(stderr, "Reason: %s\n", pmErrStr(sts)); if (dp != NULL) free(dp); return; } static void activate_new_metric(const char *name) { activate_cached_metric(name, lookup_metric_name(name)); } /* * Given a logging state and an interval, return a matching task * or NULL if none exists for that value pair. */ task_t * findtask(int state, struct timeval *delta) { task_t *tp; for (tp = tasklist; tp != NULL; tp = tp->t_next) { if (state == tp->t_state && delta->tv_sec == tp->t_delta.tv_sec && delta->tv_usec == tp->t_delta.tv_usec) break; } return tp; } /* * Complete the delayed processing of task elements, which can only * be done once all configuration file parsing is complete. */ void yyend(void) { for (tp = tasklist; tp != NULL; tp = tp->t_next) { if (tp->t_numvalid == 0) continue; PMLC_SET_MAYBE(tp->t_state, 0); /* clear req */ if (PMLC_GET_ON(tp->t_state)) tp->t_afid = __pmAFregister(&tp->t_delta, (void *)tp, log_callback); } } pcp-3.8.12ubuntu1/src/pmlogger/src/ports.c0000664000000000000000000003501512272262501015313 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2001,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #define _WIN32_WINNT 0x0500 /* for CreateHardLink */ #include #include #include #include "logger.h" #if !defined(SIGRTMAX) #if defined(NSIG) #define SIGRTMAX (NSIG) #else ! bozo neither NSIG nor SIGRTMAX are defined #endif #endif /* The logger will try to allocate port numbers beginning with the number * defined below. If that is in use it will keep adding one and trying again * until it allocates a port. */ #define PORT_BASE 4330 /* Base of range for port numbers */ static char *ctlfile; /* Control directory/portmap name */ static char *linkfile; /* Link name for primary logger */ int ctlfd; /* fd for control port */ int ctlport; /* pmlogger control port number */ int wantflush; /* flush via SIGUSR1 flag */ static void cleanup(void) { if (linkfile != NULL) unlink(linkfile); if (ctlfile != NULL) unlink(ctlfile); } static void sigexit_handler(int sig) { #ifdef PCP_DEBUG fprintf(stderr, "pmlogger: Signalled (signal=%d), exiting\n", sig); #endif cleanup(); exit(1); } #ifndef IS_MINGW static void sigcore_handler(int sig) { #ifdef PCP_DEBUG fprintf(stderr, "pmlogger: Signalled (signal=%d), exiting (core dumped)\n", sig); #endif __pmSetSignalHandler(SIGABRT, SIG_DFL); /* Don't come back here */ cleanup(); abort(); } #endif static void sighup_handler(int sig) { /* SIGHUP is used to force a log volume change */ __pmSetSignalHandler(SIGHUP, SIG_IGN); newvolume(VOL_SW_SIGHUP); __pmSetSignalHandler(SIGHUP, sighup_handler); } #ifndef IS_MINGW static void sigpipe_handler(int sig) { /* * just ignore the signal, the write() will fail, and the PDU * xmit will return with an error */ __pmSetSignalHandler(SIGPIPE, sigpipe_handler); } #endif static void sigusr1_handler(int sig) { /* * set the flag ... flush occurs in main event loop when we're * quiescent */ wantflush = 1; #ifndef IS_MINGW __pmSetSignalHandler(SIGUSR1, sigusr1_handler); #endif } #ifndef IS_MINGW /* * if we are launched from pmRecord*() in libpcp, then we * may end up using popen() to run xconfirm(1), and then there * is a chance of us receiving SIGCHLD ... just ignore this signal */ static void sigchld_handler(int sig) { } #endif typedef struct { int sig; void (*func)(int); } sig_map_t; /* This is used to set the dispositions for the various signals received. * Try to do the right thing for the various STOP/CONT signals. */ static sig_map_t sig_handler[] = { { SIGHUP, sighup_handler }, /* Exit Hangup [see termio(7)] */ { SIGINT, sigexit_handler }, /* Exit Interrupt [see termio(7)] */ #ifndef IS_MINGW { SIGQUIT, sigcore_handler }, /* Core Quit [see termio(7)] */ { SIGILL, sigcore_handler }, /* Core Illegal Instruction */ { SIGTRAP, sigcore_handler }, /* Core Trace/Breakpoint Trap */ { SIGABRT, sigcore_handler }, /* Core Abort */ #ifdef SIGEMT { SIGEMT, sigcore_handler }, /* Core Emulation Trap */ #endif { SIGFPE, sigcore_handler }, /* Core Arithmetic Exception */ { SIGKILL, sigexit_handler }, /* Exit Killed */ { SIGBUS, sigcore_handler }, /* Core Bus Error */ { SIGSEGV, sigcore_handler }, /* Core Segmentation Fault */ { SIGSYS, sigcore_handler }, /* Core Bad System Call */ { SIGPIPE, sigpipe_handler }, /* Exit Broken Pipe */ { SIGALRM, sigexit_handler }, /* Exit Alarm Clock */ #endif { SIGTERM, sigexit_handler }, /* Exit Terminated */ { SIGUSR1, sigusr1_handler }, /* Exit User Signal 1 */ #ifndef IS_MINGW { SIGUSR2, sigexit_handler }, /* Exit User Signal 2 */ { SIGCHLD, sigchld_handler }, /* NOP Child stopped or terminated */ #ifdef SIGPWR { SIGPWR, SIG_DFL }, /* Ignore Power Fail/Restart */ #endif { SIGWINCH, SIG_DFL }, /* Ignore Window Size Change */ { SIGURG, SIG_DFL }, /* Ignore Urgent Socket Condition */ #ifdef SIGPOLL { SIGPOLL, sigexit_handler }, /* Exit Pollable Event [see streamio(7)] */ #endif { SIGSTOP, SIG_DFL }, /* Stop Stopped (signal) */ { SIGTSTP, SIG_DFL }, /* Stop Stopped (user) */ { SIGCONT, SIG_DFL }, /* Ignore Continued */ { SIGTTIN, SIG_DFL }, /* Stop Stopped (tty input) */ { SIGTTOU, SIG_DFL }, /* Stop Stopped (tty output) */ { SIGVTALRM, sigexit_handler }, /* Exit Virtual Timer Expired */ { SIGPROF, sigexit_handler }, /* Exit Profiling Timer Expired */ { SIGXCPU, sigcore_handler }, /* Core CPU time limit exceeded [see getrlimit(2)] */ { SIGXFSZ, sigcore_handler} /* Core File size limit exceeded [see getrlimit(2)] */ #endif }; /* Create socket for incoming connections and bind to it an address for * clients to use. Only returns if it succeeds (exits on failure). */ static int GetPort(char *file) { int fd; int mapfd; FILE *mapstream; int sts; __pmSockAddr *myAddr; static int port_base = -1; fd = __pmCreateSocket(); if (fd < 0) { fprintf(stderr, "GetPort: socket failed: %s\n", netstrerror()); exit(1); } if (port_base == -1) { /* * get optional stuff from environment ... * PMLOGGER_PORT */ char *env_str; if ((env_str = getenv("PMLOGGER_PORT")) != NULL) { char *end_ptr; port_base = strtol(env_str, &end_ptr, 0); if (*end_ptr != '\0' || port_base < 0) { fprintf(stderr, "GetPort: ignored bad PMLOGGER_PORT = '%s'\n", env_str); port_base = PORT_BASE; } } else port_base = PORT_BASE; } /* * try to allocate ports from port_base. If port already in use, add one * and try again. */ if ((myAddr = __pmSockAddrAlloc()) == NULL) { fprintf(stderr, "GetPort: __pmSockAddrAlloc out of memory\n"); exit(1); } for (ctlport = port_base; ; ctlport++) { __pmSockAddrInit(myAddr, AF_INET, INADDR_ANY, ctlport); sts = __pmBind(fd, (void *)myAddr, __pmSockAddrSize()); if (sts < 0) { if (neterror() != EADDRINUSE) { __pmSockAddrFree(myAddr); fprintf(stderr, "__pmBind(%d): %s\n", ctlport, netstrerror()); exit(1); } } else break; } __pmSockAddrFree(myAddr); sts = __pmListen(fd, 5); /* Max. of 5 pending connection requests */ if (sts == -1) { fprintf(stderr, "__pmListen: %s\n", netstrerror()); exit(1); } /* create and initialize the port map file */ unlink(file); mapfd = open(file, O_WRONLY | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (mapfd == -1) { /* not a fatal error; continue on without control file */ #ifdef DESPERATE fprintf(stderr, "%s: error creating port map file %s: %s. Exiting.\n", pmProgname, file, osstrerror()); #endif return fd; } /* write the port number to the port map file */ if ((mapstream = fdopen(mapfd, "w")) == NULL) { /* not a fatal error; continue on without control file */ close(mapfd); #ifdef DESPERATE perror("GetPort: fdopen"); #endif return fd; } /* first the port number */ fprintf(mapstream, "%d\n", ctlport); /* then the PMCD host (but don't bother try DNS-canonicalize) */ fprintf(mapstream, "%s\n", pmcd_host); /* then the full pathname to the archive base */ __pmNativePath(archBase); if (__pmAbsolutePath(archBase)) fprintf(mapstream, "%s\n", archBase); else { char path[MAXPATHLEN]; if (getcwd(path, MAXPATHLEN) == NULL) fprintf(mapstream, "\n"); else fprintf(mapstream, "%s%c%s\n", path, __pmPathSeparator(), archBase); } /* and finally, the annotation from -m or -x */ if (note != NULL) fprintf(mapstream, "%s\n", note); fclose(mapstream); close(mapfd); return fd; } /* Create the control port for this pmlogger and the file containing the port * number so that other programs know which port to connect to. * If this is the primary pmlogger, create the special link to the * control file. */ void init_ports(void) { int i, j, n, sts; int sep = __pmPathSeparator(); int extlen, baselen; char path[MAXPATHLEN]; pid_t mypid = getpid(); /* * make sure control port files are removed when pmlogger terminates * by trapping all the signals we can */ for (i = 0; i < sizeof(sig_handler)/sizeof(sig_handler[0]); i++) { __pmSetSignalHandler(sig_handler[i].sig, sig_handler[i].func); } /* * install explicit handler for other signals ... we assume all * of the interesting signals we are likely to receive are smaller * than 32 (this is a hack 'cause there is no portable way of * determining the maximum signal number) */ for (j = 1; j < 32; j++) { for (i = 0; i < sizeof(sig_handler)/sizeof(sig_handler[0]); i++) { if (j == sig_handler[i].sig) break; } if (i == sizeof(sig_handler)/sizeof(sig_handler[0])) /* not special cased in seg_handler[] */ __pmSetSignalHandler(j, sigexit_handler); } #if defined(HAVE_ATEXIT) if (atexit(cleanup) != 0) { perror("atexit"); fprintf(stderr, "%s: unable to register atexit cleanup function. Exiting\n", pmProgname); cleanup(); exit(1); } #endif /* create the control port file (make the directory if necessary). */ /* count digits in mypid */ for (n = mypid, extlen = 1; n ; extlen++) n /= 10; /* baselen is directory + trailing / */ snprintf(path, sizeof(path), "%s%cpmlogger", pmGetConfig("PCP_TMP_DIR"), sep); baselen = strlen(path) + 1; /* likewise for PCP_DIR if it is set */ n = baselen + extlen + 1; ctlfile = (char *)malloc(n); if (ctlfile == NULL) __pmNoMem("port file name", n, PM_FATAL_ERR); strcpy(ctlfile, path); /* try to create the port file directory. OK if it already exists */ sts = mkdir2(ctlfile, S_IRWXU | S_IRWXG | S_IRWXO); if (sts < 0) { if (oserror() != EEXIST) { fprintf(stderr, "%s: error creating port file dir %s: %s\n", pmProgname, ctlfile, osstrerror()); exit(1); } } else { chmod(ctlfile, S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX); } /* remove any existing port file with my name (it's old) */ snprintf(ctlfile + (baselen-1), n, "%c%" FMT_PID, sep, mypid); sts = unlink(ctlfile); if (sts == -1 && oserror() != ENOENT) { fprintf(stderr, "%s: error removing %s: %s. Exiting.\n", pmProgname, ctlfile, osstrerror()); exit(1); } /* get control port and write port map file */ ctlfd = GetPort(ctlfile); /* * If this is the primary logger, make the special link for * clients to connect specifically to it. */ if (primary) { baselen = snprintf(path, sizeof(path), "%s%cpmlogger", pmGetConfig("PCP_TMP_DIR"), sep); n = baselen + 9; /* separator + "primary" + null */ linkfile = (char *)malloc(n); if (linkfile == NULL) __pmNoMem("primary logger link file name", n, PM_FATAL_ERR); snprintf(linkfile, n, "%s%cprimary", path, sep); #ifndef IS_MINGW sts = link(ctlfile, linkfile); #else sts = (CreateHardLink(linkfile, ctlfile, NULL) == 0); #endif if (sts != 0) { if (oserror() == EEXIST) fprintf(stderr, "%s: there is already a primary pmlogger running\n", pmProgname); else fprintf(stderr, "%s: error creating primary logger link %s: %s\n", pmProgname, linkfile, osstrerror()); exit(1); } } } /* Service a request on the control port Return non-zero if a new client * connection has been accepted. */ int clientfd = -1; unsigned int clientops = 0; /* for access control (deny ops) */ char pmlc_host[MAXHOSTNAMELEN]; int connect_state = 0; int control_req(void) { int fd, sts; char *abuf; char *hostName; __pmSockAddr *addr; __pmSockLen addrlen; if ((addr = __pmSockAddrAlloc()) == NULL) { fputs("error allocating space for client sockaddr\n", stderr); return 0; } addrlen = __pmSockAddrSize(); fd = __pmAccept(ctlfd, addr, &addrlen); if (fd == -1) { fprintf(stderr, "error accepting client: %s\n", netstrerror()); __pmSockAddrFree(addr); return 0; } __pmSetSocketIPC(fd); if (clientfd != -1) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "control_req: send EADDRINUSE on fd=%d (client already on fd=%d)\n", fd, clientfd); #endif sts = __pmSendError(fd, FROM_ANON, -EADDRINUSE); if (sts < 0) fprintf(stderr, "error sending connection NACK to client: %s\n", pmErrStr(sts)); __pmSockAddrFree(addr); __pmCloseSocket(fd); return 0; } sts = __pmSetVersionIPC(fd, UNKNOWN_VERSION); if (sts < 0) { __pmSendError(fd, FROM_ANON, sts); fprintf(stderr, "error connecting to client: %s\n", pmErrStr(sts)); __pmSockAddrFree(addr); __pmCloseSocket(fd); return 0; } hostName = __pmGetNameInfo(addr); if (hostName == NULL || strlen(hostName) > MAXHOSTNAMELEN-1) { abuf = __pmSockAddrToString(addr); snprintf(pmlc_host, sizeof(pmlc_host), "%s", abuf); free(abuf); } else { /* this is safe, due to strlen() test above */ strcpy(pmlc_host, hostName); free(hostName); } sts = __pmAccAddClient(addr, &clientops); if (sts < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { abuf = __pmSockAddrToString(addr); fprintf(stderr, "client addr: %s\n\n", abuf); free(abuf); __pmAccDumpHosts(stderr); fprintf(stderr, "\ncontrol_req: connection rejected on fd=%d from %s: %s\n", fd, pmlc_host, pmErrStr(sts)); } #endif sts = __pmSendError(fd, FROM_ANON, sts); if (sts < 0) fprintf(stderr, "error sending connection access NACK to client: %s\n", pmErrStr(sts)); sleep(1); /* QA 083 seems like there is a race w/out this delay */ __pmSockAddrFree(addr); __pmCloseSocket(fd); return 0; } __pmSockAddrFree(addr); /* * encode pdu version in the acknowledgement * also need "from" to be pmlogger's pid as this is checked at * the other end */ sts = __pmSendError(fd, (int)getpid(), LOG_PDU_VERSION); if (sts < 0) { fprintf(stderr, "error sending connection ACK to client: %s\n", pmErrStr(sts)); __pmCloseSocket(fd); return 0; } clientfd = fd; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "control_req: connection accepted on fd=%d from %s\n", fd, pmlc_host); #endif return 1; } pcp-3.8.12ubuntu1/src/pmlogger/GNUmakefile0000664000000000000000000000377612272262501015274 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs SUBDIRS = src OTHERS = pmnewlog.sh control rc_pmlogger \ pmlogger_daily.sh pmlogger_check.sh pmlogger_merge.sh LSRCFILES = $(OTHERS) crontab.in LDIRT = crontab ifeq ($(TARGET_OS),linux) CRONTAB_USER = $(PCP_USER) CRONTAB_PATH = $(PCP_ETC_DIR)/cron.d/pcp-pmlogger else CRONTAB_USER = CRONTAB_PATH = $(PCP_SYSCONF_DIR)/pmlogger/crontab endif default: $(SUBDIRS) crontab $(SUBDIRS_MAKERULE) include $(BUILDRULES) install: $(SUBDIRS) crontab $(SUBDIRS_MAKERULE) $(INSTALL) -m 775 -o $(PCP_USER) -g $(PCP_GROUP) -d $(PCP_SYSCONF_DIR)/pmlogger $(INSTALL) -m 664 -o $(PCP_USER) -g $(PCP_GROUP) control $(PCP_PMLOGGERCONTROL_PATH) $(INSTALL) -m 755 pmnewlog.sh $(PCP_BINADM_DIR)/pmnewlog $(INSTALL) -m 755 pmlogger_daily.sh $(PCP_BINADM_DIR)/pmlogger_daily $(INSTALL) -m 755 pmlogger_check.sh $(PCP_BINADM_DIR)/pmlogger_check $(INSTALL) -m 755 pmlogger_merge.sh $(PCP_BINADM_DIR)/pmlogger_merge $(INSTALL) -m 755 rc_pmlogger $(PCP_RC_DIR)/pmlogger $(INSTALL) -m 775 -o $(PCP_USER) -g $(PCP_GROUP) -d $(PCP_LOG_DIR)/pmlogger $(INSTALL) -m 775 -o $(PCP_USER) -g $(PCP_GROUP) -d $(PCP_TMP_DIR)/pmlogger ifeq ($(TARGET_OS),linux) $(INSTALL) -m 755 -d `dirname $(CRONTAB_PATH)` endif $(INSTALL) -m 644 crontab $(CRONTAB_PATH) default_pcp : default install_pcp : install crontab : crontab.in $(SED) -e 's;@user@;'$(CRONTAB_USER)';' -e 's;@path@;'$(PCP_BINADM_DIR)';' $< > $@ pcp-3.8.12ubuntu1/src/pmlogger/pmlogger_merge.sh0000775000000000000000000001310712272262501016541 0ustar #! /bin/sh # # Copyright (c) 1995,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # merge a group of logfiles, e.g. all those for today # # default case, w/out arguments uses the default pmlogger filename # conventions for today's logs, namely `date +%Y%m%d` for both the # input-basename and the output-name # # Get standard environment . $PCP_DIR/etc/pcp.env prog=`basename $0` tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 status=0 trap "rm -rf $tmp; exit \$status" 0 1 2 3 15 force=false VERBOSE=false SHOWME=false RM=rm _abandon() { echo "$prog: These error(s) are fatal, no output archive has been created." status=1 exit } _warning() { echo "$prog: Trying to continue, although output archive may be corrupted." force=false } usage="Usage: $prog [-fNV] [input-basename ... output-name]" # option parsing # while getopts fNV c do case $c in f) force=true ;; N) SHOWME=true RM="echo + rm" ;; V) VERBOSE=true ;; \?) echo "$usage" _abandon ;; esac done shift `expr $OPTIND - 1` if [ $# -eq 0 ] then trylist=`date +%Y%m%d` output=$input elif [ $# -ge 2 ] then trylist="" while [ $# -ge 2 ] do trylist="$trylist $1" shift done output="$1" else echo "$usage" status=1 exit fi fail=false mergelist="" rmlist="" # handle dupicate-breaking name form of the base name # i.e. YYYYMMDD.HH.MM-seq# and ensure no duplicates # rm -f $tmp/input echo >$tmp/input for try in $trylist do grep "^$try\$" $tmp/input >/dev/null || echo "$try" >>$tmp/input for xxx in $try-*.index do [ "$xxx" = "$try-*.index" ] && continue tie=`basename $xxx .index` grep "^$tie\$" $tmp/input >/dev/null || echo "$tie" >>$tmp/input done done for input in `cat $tmp/input` do for file in $input.index do file=`basename $file .index` rmlist="$rmlist $file" empty=0 if [ ! -f "$file.index" ] then echo "$prog: Error: \"index\" file missing for archive \"$file\"" fail=true elif [ ! -s "$file.index" ] then empty=`expr $empty + 1` fi if [ ! -f "$file.meta" ] then echo "$prog: Error: \"meta\" file missing for archive \"$file\"" fail=true elif [ ! -s "$file.meta" ] then empty=`expr $empty + 1` fi if [ ! -f "$file.0" ] then echo "$prog: Error: \"volume 0\" file missing for archive \"$file\"" fail=true elif [ ! -s "$file.0" ] then empty=`expr $empty + 1` fi if [ $empty -eq 3 ] then echo "$prog: Warning: archive \"$file\" is empty and will be skipped" else mergelist="$mergelist $file" fi done done if [ -f $output.index ] then echo "$prog: Error: \"index\" file already exists for output archive \"$output\"" fail=true fi if [ -f $output.meta ] then echo "$prog: Error: \"meta\" file already exists for output archive \"$output\"" fail=true fi if [ -f $output.0 ] then echo "$prog: Error: \"volume 0\" file already exists for output archive \"$output\"" fail=true fi $fail && _abandon i=0 list="" part=0 if [ -z "$mergelist" ] then $VERBOSE && echo "No archives to be merged." else $VERBOSE && echo "Input archives to be merged:" for input in $mergelist do for file in $input.index do if [ $i -ge 35 ] then # this limit requires of the order of 3 x 35 input + 3 x 1 # output = 108 file descriptors which should be well below any # shell-imposed or system-imposed limits # $VERBOSE && echo " -> partial merge to $tmp/$part" cmd="pmlogextract $list $tmp/$part" if $SHOWME then echo "+ $cmd" else if $cmd then : else $VERBOSE || echo " -> partial merge to $tmp/$part" echo "$prog: Directory: `pwd`" echo "$prog: Failed: pmlogextract $list $tmp/$part" _warning fi fi list=$tmp/$part part=`expr $part + 1` i=0 fi file=`basename $file .index` list="$list $file" $VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N " $file""$PCP_ECHO_C" numvol=`echo $file.[0-9]* | wc -w | sed -e 's/ *//g'` if [ $numvol -gt 1 ] then $VERBOSE && echo " ($numvol volumes)" else $VERBOSE && echo fi i=`expr $i + 1` done done cmd="pmlogextract $list $output" if $SHOWME then echo "+ $cmd" else if $cmd then : else echo "$prog: Directory: `pwd`" echo "$prog: Failed: pmlogextract $list $output" _warning fi $VERBOSE && echo "Output archive files:" for file in $output.meta $output.index $output.0 do if [ -f $file ] then $VERBOSE && LC_TIME=POSIX ls -l $file else echo "$prog: Error: file \"$file\" not created" force=false fi done fi fi if $force then $VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N "Removing input archive files ...""$PCP_ECHO_C" for input in $rmlist do for file in $input.index do file=`basename $file .index` [ "$file" = "$output" ] && continue eval $RM -f $file.index $file.meta $file.[0-9]* done done $VERBOSE && echo " done" fi exit pcp-3.8.12ubuntu1/src/pmlogger/rc_pmlogger0000664000000000000000000001573712272262501015445 0ustar #!/bin/sh # # Copyright (c) 2012 Red Hat. # Copyright (c) 2000-2008 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Start or Stop the Performance Co-Pilot pmlogger processes. # # The following is for chkconfig on RedHat based systems # chkconfig: 2345 94 06 # description: pmlogger is a performance metrics logger for the Performance Co-Pilot (PCP) # # The following is for insserv(1) based systems, # e.g. SuSE, where chkconfig is a perl script. ### BEGIN INIT INFO # Provides: pmlogger # Required-Start: $local_fs # Should-Start: $network $remote_fs $syslog $time $pmcd # Required-Stop: $local_fs # Should-Stop: $network $remote_fs $syslog $pmcd # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Control pmlogger (the performance metrics logger for PCP) # Description: Configure and control pmlogger (the performance metrics logger for the Performance Co-Pilot) ### END INIT INFO . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/rc-proc.sh PMLOGCTRL=$PCP_PMLOGGERCONTROL_PATH RUNDIR=$PCP_LOG_DIR/pmcd PMLOGGER=$PCP_BINADM_DIR/pmlogger prog=$PCP_RC_DIR/`basename $0` # search for your mail agent of choice ... # MAIL='' for try in Mail mail email do if which $try >/dev/null 2>&1 then MAIL=$try break fi done tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1 status=1 trap "rm -rf $tmp; exit \$status" 0 1 2 3 15 if is_chkconfig_on pmlogger then PMLOGGER_CTL=on else PMLOGGER_CTL=off fi VERBOSE_CTL=on case "$PCP_PLATFORM" in mingw) # nothing we can usefully do here, skip the test # IAM=0 ;; *) # standard Unix/Linux style test # ID=id IAM=`$ID -u 2>/dev/null` if [ -z "$IAM" ] then # do it the hardway # IAM=`$ID | sed -e 's/.*uid=//' -e 's/(.*//'` fi ;; esac # Note: _start_pmcheck() runs in the background, in parallel with # the rest of the script. It might complete well after the caller # so tmpfile handling is especially problematic. Goal is to speed # bootup by starting potentially slow (remote monitoring) pmlogger # processes in the background. # _start_pmcheck() { bgstatus=0 bgtmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1 trap "rm -rf $bgtmp; exit \$bgstatus" 0 1 2 3 15 pmlogger_check $VFLAG >$bgtmp/pmcheck.out 2>$bgtmp/pmcheck bgstatus=$? if [ -s $bgtmp/pmcheck ] then $PCP_BINADM_DIR/pmpost "pmlogger_check failed in $prog, mailing output to root" if [ ! -z "$MAIL" ] then $MAIL -s "pmlogger_check failed in $prog" root <$bgtmp/pmcheck else echo "$prog: pmlogger_check failed ..." cat $bgtmp/pmcheck fi fi exit $bgstatus # co-process is now complete } _start_pmlogger() { if which pmlogger_check >/dev/null 2>&1 then # pmlogger_check uses $PMLOGCTRL to start everything that is needed # if [ ! -f $PMLOGCTRL ] then echo "$prog:"' Error: PCP archive logger control file '$PMLOGCTRL' is missing! Cannot start any Performance Co-Pilot archive logger(s).' # failure false else # really start the pmlogger instances based on the control file. # done in the background to avoid delaying the init script, # failures are notified by mail # $ECHO $PCP_ECHO_N "Starting pmlogger ..." "$PCP_ECHO_C" _start_pmcheck & # success true fi else echo "$prog:"' Warning: Performance Co-Pilot installation is incomplete (at least the script "pmlogger_check" is missing) and the PCP archive logger(s) cannot be started.' # failure false fi $RC_STATUS -v } _shutdown() { # Is any pmlogger running? # _get_pids_by_name pmlogger >$tmp/tmp if [ ! -s $tmp/tmp ] then [ "$1" = verbose ] && echo "$prog: pmlogger not running" return 0 fi [ "$1" = quietly ] || \ $ECHO $PCP_ECHO_N "Stopping pmlogger ...""$PCP_ECHO_C" # Terminate those pmloggers started by either pmlogger_check or # pmlogger_daily ... relies on the -m option to pmlogger and the # annotation in the (optional) 4th line of the port map files # for pid in `cat $tmp/tmp` do if [ -f "$PCP_TMP_DIR/pmlogger/$pid" ] then note=`sed -n -e 4p <"$PCP_TMP_DIR/pmlogger/$pid"` if [ "$note" = pmlogger_check -o "$note" = pmlogger_daily ] then pmsignal -s TERM $pid fi fi done $RC_STATUS -v $PCP_BINADM_DIR/pmpost "stop pmlogger from $prog" } _usage() { echo "Usage: $prog [-v] {start|restart|condrestart|stop|status|reload|force-reload}" } while getopts v c do case $c in v) # force verbose VERBOSE_CTL=on ;; *) _usage exit 1 ;; esac done shift `expr $OPTIND - 1` if [ $VERBOSE_CTL = on ] then # For a verbose startup and shutdown ECHO=$PCP_ECHO_PROG REBUILDOPT='' VFLAG='-V' else # For a quiet startup and shutdown ECHO=: REBUILDOPT=-s VFLAG= fi if [ "$IAM" != 0 -a "$1" != "status" ] then if [ -n "$PCP_DIR" ] then : running in a non-default installation, do not need to be root else echo "$prog:"' Error: You must be root (uid 0) to start or stop the Performance Co-Pilot loggers.' exit fi fi # First reset status of this service $RC_RESET # Return values acc. to LSB for all commands but status: # 0 - success # 1 - misc error # 2 - invalid or excess args # 3 - unimplemented feature (e.g. reload) # 4 - insufficient privilege # 5 - program not installed # 6 - program not configured # # Note that starting an already running service, stopping # or restarting a not-running service as well as the restart # with force-reload (in case signalling is not supported) are # considered a success. case "$1" in 'start'|'restart'|'condrestart'|'reload'|'force-reload') if [ "$1" = "condrestart" ] && ! is_chkconfig_on pmlogger then status=0 exit fi _shutdown quietly # pmlogger messages should go to stderr, not the GUI notifiers # unset PCP_STDERR if [ -x $PMLOGGER ] then if [ "$PMLOGGER_CTL" = on ] then _start_pmlogger fi fi status=0 ;; 'stop') _shutdown verbose status=0 ;; 'status') # NOTE: $RC_CHECKPROC returns LSB compliant status values. $ECHO $PCP_ECHO_N "Checking for pmlogger:" "$PCP_ECHO_C" if [ -r /etc/rc.status ] then # SuSE $RC_CHECKPROC $PMLOGGER $RC_STATUS -v status=$? else # not SuSE $RC_CHECKPROC $PMLOGGER status=$? if [ $status -eq 0 ] then $ECHO running else $ECHO stopped fi fi ;; *) _usage ;; esac pcp-3.8.12ubuntu1/src/pmlogger/control0000664000000000000000000000324412272262501014613 0ustar # # PCP archive logging configuration/control # # This file is used by various of the PCP archive logging administrative # tools to perform maintenance on the pmlogger instances running on # the local host. # # This file contains one line per host to be logged, fields are # Host name of host to be logged # P(rimary) is this the primary logger? y or n # S(ocks) should this logger be launched with pmsocks? y or n # Directory full pathname to directory where archive logs are # to be maintained ... note all scripts "cd" to here as # a first step # Args optional additional arguments to pmlogger and/or pmnewlog # # === VARIABLE ASSIGNMENTS === # # DO NOT REMOVE OR EDIT THE FOLLOWING LINE $version=1.1 # if pmsocks is being used, edit the IP address for $SOCKS_SERVER #$SOCKS_SERVER=123.456.789.123 # for remote loggers running over a WAN with potentially long delays $PMCD_CONNECT_TIMEOUT=150 $PMCD_REQUEST_TIMEOUT=120 # === LOGGER CONTROL SPECIFICATIONS === # #Host P? S? directory args # local primary logger # # (LOCALHOSTNAME is expanded to local: in the first column, # and to `hostname` in the fourth (directory) column.) # LOCALHOSTNAME y n PCP_LOG_DIR/pmlogger/LOCALHOSTNAME -r -T24h10m -c config.default # Note: if multiple pmloggers for the same host (e.g. both primary and # non-primary loggers are active), then they MUST use different # directories # local non-primary logger #LOCALHOSTNAME n n PCP_LOG_DIR/pmlogger/mysummary -r -T24h10m -c config.Summary # remote host #remote n n PCP_LOG_DIR/pmlogger/remote -r -T24h10m -c config.remote # thru the firewall via socks #distant n y PCP_LOG_DIR/pmlogger/distant -r -T24h10m -c config.distant pcp-3.8.12ubuntu1/src/genpmda/0000775000000000000000000000000012272262617013014 5ustar pcp-3.8.12ubuntu1/src/genpmda/genpmda0000775000000000000000000007261312272262501014356 0ustar #! /bin/sh # # Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # prog=`basename $0` usage() { cat <cp = "hello world"; ## endmetric } EOFEOF exit 1 } dflag=false Dflag="" iflag="" sflag="../../pmns/stdpmid" tflag="../../.." oflag="generated" nflag="" verbose=false while getopts "c:vdD:s:t:i:n:o:" c do case $c in D) Dflag="$OPTARG" ;; d) dflag=true ;; c) cflag="$OPTARG" ;; i) iflag="$OPTARG" ;; s) sflag="$OPTARG" ;; t) tflag="$OPTARG" ;; n) nflag="$OPTARG" ;; o) oflag="$OPTARG" ;; v) verbose=true ;; \?) usage ;; esac done [ -z "$iflag" ] && usage [ ! -f "$cflag" ] && echo "Error: config \"$cflag\" not found" && usage IAM=`echo $iflag | tr a-z A-Z` iam=`echo $IAM | tr A-Z a-z` [ -z "$nflag" ] && nflag="$iam" config="$cflag" for stdpmid in $sflag $tflag/src/pmns/stdpmid ../pmns/stdpmid ../../pmns/stdpmid do [ -f "$stdpmid" ] && break done $verbose && [ -f "$stdpmid" ] && echo Found stdpmid in \"$stdpmid\" [ ! -f "$stdpmid" ] && echo Error: could not find \"stdpmid\" && usage domain=`awk '/^#define[ \t]*'$IAM'/ {print $3}' $stdpmid` if [ -z "$Dflag" ] then [ -z "$domain" ] && echo "Error: domain for \"$IAM\" not found in ../../pmns/stdpmid, please use -D" && usage else domain="$Dflag" fi [ ! -d $oflag ] && mkdir $oflag && $verbose && echo "created output directory \"$oflag\"" # # Generate domain.h # cat <$oflag/domain.h /* * Generated code, do not edit! */ #define $IAM $domain EOFEOF $verbose && echo Wrote $oflag/domain.h # # Generate (the beginning of) pmda.c # cat <$oflag/pmda.c /* * Generated code, do not edit! */ #include #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include "metrictab.h" #include "clusters.h" static int _isDSO = 1; /* =0 I am a daemon */ EOFEOF $verbose && echo Wrote $oflag/pmda.c gnumakefile=GNUmakefile.new gnumakefile_g=GNUmakefile.generic.new install_g=install-generic.new # # Generate Install, Remove and Makefile.install # cat <$oflag/Install #! /bin/sh . \$PCP_DIR/etc/pcp.env . \$PCP_SHARE_DIR/lib/pmdaproc.sh iam=$iam pmda_interface=3 EOFEOF if $dflag then cat <>$oflag/Install # controls for daemon PMDA installation procedures # daemon_opt=true dso_opt=false pipe_opt=true socket_opt=false EOFEOF else cat <>$oflag/Install # controls for DSO installation procedures # daemon_opt=false dso_opt=true pipe_opt=false socket_opt=false EOFEOF fi cat <>$oflag/Install # # override "choose mode" __choose_mode() { do_pmda=true } # # override "choose IPC method" __choose_ipc() { ipc_type=pipe type="pipe binary \$PCP_PMDAS_DIR/\$iam/pmda\$iam" } # Do it # pmdaSetup cat domain.h clusters.h pmns | \$PCP_BINADM_DIR/pmgcc -DPCP_PMNS >\$tmp/pmns pmns_source=\$tmp/pmns pmns_name=\$iam pmdaInstall exit 0 EOFEOF $verbose && echo Wrote $oflag/Install cat <$oflag/Remove #! /bin/sh . \$PCP_DIR/etc/pcp.env . \$PCP_SHARE_DIR/lib/pmdaproc.sh iam=$iam pmdaSetup pmdaRemove exit 0 EOFEOF $verbose && echo Wrote $oflag/Remove cat <<"EOFEOF" >$oflag/Makefile.install SHELL = sh TARGETS = LDIRT = *.log *.pag *.dir default: $(TARGETS) install: default clobber: rm -f $(LDIRT) $(TARGETS) EOFEOF $verbose && echo Wrote $oflag/Makefile.install # # Generate metrictab.[ch] # awk ' BEGIN { mt_h="'$oflag'/metrictab.h" mt_c="'$oflag'/metrictab.c" pmda_c="'$oflag'/pmda.c" clusters_h="'$oflag'/clusters.h" pmns="'$oflag'/pmns" cfiles="CFILES" init_c="init.c.new" printf "/* Generated code, do not edit! */\n\n" >mt_c printf "/* Generated code, do not edit! */\n\n" >mt_h printf "#include \"pmapi.h\"\n" >>mt_c printf "#include \"impl.h\"\n" >>mt_c printf "#include \"pmda.h\"\n" >>mt_c printf "#include \"metrictab.h\"\n\n" >>mt_c printf "#include \"clusters.h\"\n\n" >>mt_c printf "/*\n * Metric Table\n */\npmdaMetric metrictab[] = {\n" >>mt_c printf "init.c" >cfiles printf "/*\n" >init_c printf " * local initialization for the %s PMDA\n", "'$IAM'" >>init_c printf " * ADD CODE HERE\n" >>init_c printf " */\n" >>init_c printf "#include \n" >>init_c printf "#include \n" >>init_c printf "#include \n" >>init_c printf "#include \n" >>init_c printf "#include \n" >>init_c printf "#include \n" >>init_c printf "#include \"pmapi.h\"\n" >>init_c printf "#include \"impl.h\"\n" >>init_c printf "#include \"pmda.h\"\n" >>init_c printf "#include \"'$oflag'/domain.h\"\n" >>init_c printf "#include \"'$oflag'/metrictab.h\"\n" >>init_c printf "#include \"'$oflag'/clusters.h\"\n" >>init_c printf "\n" >>init_c printf "void\n%s_local_init(pmdaInterface *dispatch)\n", "'$iam'" >>init_c printf "{\n" >>init_c printf "\t/* add code for local initialization here, if required */\n" >>init_c printf "}\n" >>init_c } /.*{$/ { nonleaf = $1 } $1 == "##" && $2 == "metric" { metric = nonleaf"."$3 metriclist[metric] = metric leafmetric[metric] = $3 nmetrics++ } $1 == "##" && $2 == "pmid" { pmid[metric] = $3 n = split(pmid[metric], id, ":") current_cluster = id[2] cluster[metric] = current_cluster item[metric] = id[3] s = metric gsub("\\.", "_", s) m = "METRIC_"s if (seen_metric_macro[m]) { printf "FATAL ERROR: cluster_metric \"%s\" is not unique,\n", m printf "Conflicts with metric \"%s\"\n", seen_metric_macro[m] exit 1 } seen_metric_macro[m] = metric metric_macro[metric] = m } $1 == "##" && $2 == "code" { thiscode=$3 for (i=4; i <= NF; i++) thiscode = thiscode " " $i if (!code[metric]) code[metric] = "\t\t"thiscode; else code[metric] = code[metric]"\n\t\t"thiscode } $1 == "##" && $2 == "type" { type[metric] = $3 } $1 == "##" && $2 == "units" { units[metric] = $3 } $1 == "##" && $2 == "semantics" { semantics[metric] = $3 } $1 == "##" && $2 == "indom" { indom[metric] = $3 if (indom[metric] != "PM_INDOM_NULL" && !seen_indom[indom[metric]]) { printf "#define %s %d\n", indom[metric], nindoms >>mt_h seen_indom[indom[metric]]++ nindoms++ indoms[nindoms] = indom[metric] indom_cluster[$3] = current_cluster } } $1 == "##" && $2 == "endmetric" { printf "\t/* %s */\n", metric >>mt_c printf "\t{ (void *)fetch_%s,\n", cluster[metric] >>mt_c printf "\t{PMDA_PMID(%s,%s),\n", cluster[metric], metric_macro[metric] >>mt_c printf "\t %s, %s, %s, %s }, },\n\n", type[metric], indom[metric], semantics[metric], units[metric] >>mt_c } END { printf "};\n" >>mt_c if (nindoms > 0) { printf "\npmdaIndom indomtab[] = {\n" >>mt_c for (i=1; i <= nindoms; i++) printf " { %s, 0, NULL },\n", indoms[i] >>mt_c printf "};\n" >>mt_c } printf "\n#define NMETRICS %d\n", nmetrics >>mt_h printf "extern pmdaMetric metrictab[NMETRICS];\n" >>mt_h printf "\n#define NINDOMS %d\n", nindoms >>mt_h if (nindoms > 0) { printf "extern pmdaIndom indomtab[NINDOMS];\n" >>mt_h } # # Generate clusters.h and first part of pmns # printf "/* Generated code, do not edit! */\n\n" >pmns printf "/* Generated code, do not edit! */\n\n" >clusters_h printf "#ifndef _CLUSTER_H\n" >>clusters_h printf "#define _CLUSTER_H\n" >>clusters_h clustercnt = 0 for (m in cluster) { c = cluster[m] if (seencluster[c]) continue; seencluster[c] = 1 printf "\n/*\n" >>clusters_h printf " * Metrics in the \"%s\" cluster\n", c >>clusters_h printf " */\n" >>clusters_h printf "#define %s\t\t\t%d\n", c, clustercnt >>clusters_h for (metric in metriclist) { if (cluster[metric] == c) { printf "#define %s\t%s /* %s */\n", metric_macro[metric], item[metric], metric >>clusters_h } } clustercnt++ } printf "\n\n#ifndef PCP_PMNS\n" >>clusters_h printf "#define NCLUSTERS\t\t\t%d\n\n", clustercnt >>clusters_h # # Generate the refresh method in pmda.c # for (m in cluster) { c = cluster[m] seencluster[c] = 0; } printf "\nstatic void\n%s_refresh(int *need_refresh)\n{\n", "'$iam'" >>pmda_c for (m in cluster) { c = cluster[m] if (seencluster[c]) continue; seencluster[c] = 1 printf "extern void refresh_%s(void);\n", c >>mt_h printf " if (need_refresh[%s])\n\trefresh_%s();\n", c, c >>pmda_c } printf "}\n\n" >>pmda_c # # Generate the instance method in pmda.c # for (m in cluster) { c = cluster[m] seencluster[c] = 0; } printf "static int\n" >>pmda_c printf "%s_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda)\n", "'$iam'" >>pmda_c printf "{\n" >>pmda_c printf " __pmInDom_int *indomp = (__pmInDom_int *)&indom;\n" >>pmda_c printf " int need_refresh[NCLUSTERS];\n" >>pmda_c printf "\n" >>pmda_c printf " memset(need_refresh, 1, sizeof(need_refresh));\n" >>pmda_c printf " /* TODO: only refresh some clusters */\n" >>pmda_c printf " %s_refresh(need_refresh);\n", "'$iam'" >>pmda_c printf "\n" >>pmda_c printf " return pmdaInstance(indom, inst, name, result, pmda);\n" >>pmda_c printf "}\n\n" >>pmda_c # # Generate the fetch method in pmda.c # printf "int\n" >>pmda_c printf "%s_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda)\n", "'$iam'" >>pmda_c printf "{\n" >>pmda_c printf " int i;\n" >>pmda_c printf " int need_refresh[NCLUSTERS];\n" >>pmda_c printf "\n" >>pmda_c printf " memset(need_refresh, 0, sizeof(need_refresh));\n" >>pmda_c printf " for (i=0; i < numpmid; i++) {\n" >>pmda_c printf " __pmID_int *idp = (__pmID_int *)&(pmidlist[i]);\n" >>pmda_c printf " if (idp->cluster >= 0 && idp->cluster < NCLUSTERS) {\n" >>pmda_c printf " need_refresh[idp->cluster]++;\n" >>pmda_c printf " }\n" >>pmda_c printf " }\n" >>pmda_c printf "\n" >>pmda_c printf " %s_refresh(need_refresh);\n", "'$iam'" >>pmda_c printf " return pmdaFetch(numpmid, pmidlist, resp, pmda);\n" >>pmda_c printf "}\n\n" >>pmda_c # # Generate the generic fetch callback in pmda.c # printf "static int\n" >>pmda_c printf "%s_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom)\n", "'$iam'" >>pmda_c printf "{\n" >>pmda_c printf "\tint (*fetchfunction)(pmdaMetric *, unsigned int, pmAtomValue *) =\n">>pmda_c printf "\t\t(int (*)(pmdaMetric *, unsigned int, pmAtomValue *)) mdesc->m_user;\n">>pmda_c printf "\treturn (*fetchfunction)(mdesc, inst, atom);\n" >>pmda_c printf "}\n\n", pmda_c >>pmda_c # # Generate the init method in pmda.c # printf "void\n" >>pmda_c printf "%s_init(pmdaInterface *dp)\n", "'$iam'" >>pmda_c printf "{\n" >>pmda_c printf " int\tneed_refresh[NCLUSTERS];\n" >>pmda_c printf " extern void\t%s_local_init(pmdaInterface *);\n", "'$iam'" >>pmda_c printf "\n" >>pmda_c printf " if (_isDSO) {\n" >>pmda_c printf " char helppath[MAXPATHLEN];\n" >>pmda_c printf " snprintf(helppath, sizeof(helppath), \"%%s/pmdas/'$iam'/help\",\n" >>pmda_c printf " pmGetConfig(\"PCP_VAR_DIR\"));\n" >>pmda_c printf " pmdaDSO(dp, PMDA_INTERFACE_4, \"%s DSO\", helppath);\n", "'$iam'" >>pmda_c printf " }\n" >>pmda_c printf "\n" >>pmda_c printf " if (dp->status != 0)\n" >>pmda_c printf " return;\n" >>pmda_c printf "\n" >>pmda_c printf " dp->version.two.instance = %s_instance;\n", "'$iam'" >>pmda_c printf " dp->version.two.fetch = %s_fetch;\n", "'$iam'" >>pmda_c printf " pmdaSetFetchCallBack(dp, %s_fetchCallBack);\n", "'$iam'" >>pmda_c printf "\n" >>pmda_c printf " /* local initialization, see init.c */\n" >>pmda_c printf " %s_local_init(dp);\n", "'$iam'" >>pmda_c printf "\n" >>pmda_c printf " /* initially refresh all clusters */\n" >>pmda_c printf " memset(need_refresh, 1, sizeof(need_refresh));\n" >>pmda_c printf " %s_refresh(need_refresh);\n", "'$iam'" >>pmda_c printf "\n" >>pmda_c if (nindoms > 0) { printf " pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), metrictab,\n" >>pmda_c printf " sizeof(metrictab)/sizeof(metrictab[0]));\n" >>pmda_c } else { printf " pmdaInit(dp, NULL, 0, metrictab,\n" >>pmda_c printf " sizeof(metrictab)/sizeof(metrictab[0]));\n" >>pmda_c } printf "}\n" >>pmda_c # # Generate usage() and main() for the daemon PMDA # printf "\nstatic void\n" >>pmda_c printf "usage(void)\n" >>pmda_c printf "{\n" >>pmda_c printf " fprintf(stderr, \"Usage: %%s [options]\\n\\n\", pmProgname);\n" >>pmda_c printf " fputs(\"Options:\\n\"\n" >>pmda_c printf " \" -d domain use domain (numeric) for metrics domain of PMDA\\n\"\n" >>pmda_c printf " \" -l logfile write log into logfile rather than using default log name\\n\",\n" >>pmda_c printf " stderr);\n" >>pmda_c printf " exit(1);\n" >>pmda_c printf "}\n" >>pmda_c printf "\n" >>pmda_c printf "int\n" >>pmda_c printf "main(int argc, char **argv)\n" >>pmda_c printf "{\n" >>pmda_c printf " int err = 0;\n" >>pmda_c printf " int c = 0;\n" >>pmda_c printf " pmdaInterface dispatch;\n" >>pmda_c printf " char helppath[MAXPATHLEN];\n" >>pmda_c printf "\n" >>pmda_c printf " __pmSetProgname(argv[0]);\n" >>pmda_c printf "\n" >>pmda_c printf " _isDSO = 0;\n" >>pmda_c printf "\n" >>pmda_c printf " snprintf(helppath, sizeof(helppath), \"%%s/pmdas/'$iam'/help\", pmGetConfig(\"PCP_VAR_DIR\"));\n" >>pmda_c printf " pmdaDaemon(&dispatch, PMDA_INTERFACE_4, pmProgname, '$IAM', \"'$iam'.log\", helppath);\n" >>pmda_c printf "\n" >>pmda_c printf " if ((c = pmdaGetOpt(argc, argv, \"D:d:l:?\", &dispatch, &err)) != EOF)\n" >>pmda_c printf " err++;\n" >>pmda_c printf "\n" >>pmda_c printf " if (err)\n" >>pmda_c printf " usage();\n" >>pmda_c printf "\n" >>pmda_c printf " pmdaOpenLog(&dispatch);\n" >>pmda_c printf " '$iam'_init(&dispatch);\n" >>pmda_c printf " pmdaConnect(&dispatch);\n" >>pmda_c printf " pmdaMain(&dispatch);\n" >>pmda_c printf "\n" >>pmda_c printf " exit(0);\n" >>pmda_c printf "}\n" >>pmda_c # # Generate the refresh and fetch methods for each cluster # for (m in cluster) { c = cluster[m] seencluster[c] = 0; } for (m in cluster) { c = cluster[m] if (seencluster[c]) continue; seencluster[c] = 1 fetch_c = c".c.new" printf " %s.c", c >>cfiles printf "/*\n" >>fetch_c printf " * Originally generated from \"%s\" using genpmda(1).\n","'$config'" >>fetch_c printf " *\n" >>fetch_c printf " * Refresh and fetch methods for the \"%s\" cluster.\n", c >>fetch_c printf " */\n" >>fetch_c printf "#include \n" >>fetch_c printf "#include \n" >>fetch_c printf "#include \n" >>fetch_c printf "#include \n" >>fetch_c printf "#include \n" >>fetch_c printf "#include \n" >>fetch_c printf "#include \"pmapi.h\"\n" >>fetch_c printf "#include \"impl.h\"\n" >>fetch_c printf "#include \"pmda.h\"\n" >>fetch_c printf "#include \"'$oflag'/domain.h\"\n" >>fetch_c printf "#include \"'$oflag'/metrictab.h\"\n" >>fetch_c printf "#include \"'$oflag'/clusters.h\"\n" >>fetch_c printf "\nvoid\nrefresh_%s(void)\n", c >>fetch_c printf "{\n" >>fetch_c z = 0 if (nindoms > 0) { for (i in indoms) { this = indoms[i]; if (indom_cluster[this] == c) { printf "\tpmInDom indom_%s = indomtab[%s].it_indom;\n", this, this >>fetch_c z++ } } if (z > 0) printf "\tstatic int first = 1;\n" >>fetch_c } printf "\n" >>fetch_c if (z > 0) { printf "\t/* initialize the instance domain cache(s) */\n" >>fetch_c printf "\tif (first) {\n" >>fetch_c for (i in indoms) { this = indoms[i]; if (indom_cluster[this] == c) { printf "\t\tpmdaCacheOp(indom_%s, PMDA_CACHE_LOAD);\n", this >>fetch_c } } printf "\t\tfirst = 0;\n" >>fetch_c printf "\t}\n" >>fetch_c } printf "\n" >>fetch_c if (z > 0) { for (i in indoms) { this = indoms[i]; if (indom_cluster[this] == c) { printf "\t/* inactivate all instances in the %s instance domain */\n", this >>fetch_c printf "\tpmdaCacheOp(indom_%s, PMDA_CACHE_INACTIVE);\n", this >>fetch_c printf "\n" >>fetch_c printf "\t/*\n" >>fetch_c printf "\t * Add code here to refresh the %s instance domain.\n", this >>fetch_c printf "\t * Basically, walk your data and activate each instance, e.g.\n" >>fetch_c printf "\t * inst = pmdaCacheStore(indom_%s, PMDA_CACHE_ADD, name, p);\n", this >>fetch_c printf "\t * where \"name\" is a char buffer naming each instance\n" >>fetch_c printf "\t * and \"p\" points to private anonymous data.\n" >>fetch_c printf "\t */\n" >>fetch_c printf "\t/* ADD CODE HERE */\n\n\n" >>fetch_c printf "\n" >>fetch_c printf "\t/*\n" >>fetch_c printf "\t * Flush the cache for the indom_%s indom. This is\n", this >>fetch_c printf "\t * only strictly needed if there are any _new_ instances.\n" >>fetch_c printf "\t */\n", this >>fetch_c printf "\tpmdaCacheOp(indom_%s, PMDA_CACHE_SAVE);\n", this >>fetch_c } } } else { printf "\t/*\n" >>fetch_c printf "\t * Add code here to refresh your data for this cluster\n" >>fetch_c printf "\t * (no instance domains are defined for this cluster)\n" >>fetch_c printf "\t */\n\n" >>fetch_c printf "\t/* ADD CODE HERE */\n\n\n" >>fetch_c } printf "}\n" >>fetch_c # # Generate the skeletal fetch callback function for each cluster # and the commented skeletal fetch code for each metric. # printf "extern int fetch_%s(pmdaMetric *, unsigned int, pmAtomValue *);\n", c >>clusters_h printf "\nint\nfetch_%s(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom)\n", c >>fetch_c printf "{\n" >>fetch_c printf "\t__pmID_int\t*idp = (__pmID_int *)&(mdesc->m_desc.pmid);\n" >>fetch_c printf "\tvoid\t\t*p = NULL;\n" >>fetch_c printf "\tint\t\tsts = 1; /* return value, success is the default */\n" >>fetch_c printf "\n\tif (inst != PM_INDOM_NULL) {\n" >>fetch_c printf "\t\tif (pmdaCacheLookup(mdesc->m_desc.indom, inst, NULL, (void **)&p) != PMDA_CACHE_ACTIVE || !p)\n" >>fetch_c printf "\t\t\treturn PM_ERR_INST;\n" >>fetch_c printf "\t}\n\n" >>fetch_c printf "\t/*\n" >>fetch_c printf "\t * p now points to the private data for this instance that was\n" >>fetch_c printf "\t * previously stored in refresh_%s(), or will be NULL\n", c >>fetch_c printf "\t * if this is a singular instance domain.\n" >>fetch_c printf "\t */\n" >>fetch_c printf "\n\tswitch(idp->item) {\n" >>fetch_c for (metric in metriclist) { if (cluster[metric] != c) continue printf "\tcase %s:\n", metric_macro[metric] >>fetch_c printf "\t\t/*\n" >>fetch_c printf "\t\t * Fetch code for metric \"" metric "\"\n" >>fetch_c printf "\t\t * PMID : " pmid[metric] "\n" >>fetch_c printf "\t\t * Type : " type[metric] "\n" >>fetch_c printf "\t\t * Indom : " indom[metric] "\n" >>fetch_c printf "\t\t * Units : " units[metric] "\n" >>fetch_c printf "\t\t * Semantics: " semantics[metric] "\n" >>fetch_c printf "\t\t */\n" >>fetch_c if (code[metric]) printf "%s\n", code[metric] >>fetch_c else if (type[metric] == "PM_TYPE_32") printf "\t\tatom->l = 0; /* ADD CODE HERE */\n" >>fetch_c else if (type[metric] == "PM_TYPE_U32") printf "\t\tatom->ul = 0; /* ADD CODE HERE */\n" >>fetch_c else if (type[metric] == "PM_TYPE_64") printf "\t\tatom->ll = 0; /* ADD CODE HERE */\n" >>fetch_c else if (type[metric] == "PM_TYPE_U64") printf "\t\tatom->ull = 0; /* ADD CODE HERE */\n" >>fetch_c else if (type[metric] == "PM_TYPE_FLOAT") printf "\t\tatom->f = 0; /* ADD CODE HERE */\n" >>fetch_c else if (type[metric] == "PM_TYPE_DOUBLE") printf "\t\tatom->d = 0; /* ADD CODE HERE */\n" >>fetch_c else if (type[metric] == "PM_TYPE_STRING") printf "\t\tatom->cp = \"string value\"; /* ADD CODE HERE */\n" >>fetch_c else if (type[metric] == "PM_TYPE_AGGREGATE") printf "\t\tatom->vp = NULL; /* ADD CODE HERE */\n" >>fetch_c else if (type[metric] == "PM_TYPE_AGGREGATE_STATIC") printf "\t\tatom->vp = NULL; /* ADD CODE HERE */\n" >>fetch_c else if (type[metric] == "PM_TYPE_EVENT") printf "\t\tatom->vp = NULL; /* ADD CODE HERE */\n" >>fetch_c printf "\t\tbreak;\n\n" >>fetch_c } printf "\tdefault:\n" >>fetch_c printf "\t\tsts = PM_ERR_PMID;\n" >>fetch_c printf "\t\tbreak;\n" >>fetch_c printf "\t}\n", c >>fetch_c printf "\n", c >>fetch_c printf "\t/*\n", c >>fetch_c printf "\t * Return value:\n", c >>fetch_c printf "\t * < 0 error\n", c >>fetch_c printf "\t * = 0 no values available\n", c >>fetch_c printf "\t * > 0 success\n", c >>fetch_c printf "\t */\n", c >>fetch_c printf "\treturn sts;\n" >>fetch_c printf "}\n" >>fetch_c } printf "#endif /* PCP_PMNS */\n" >>clusters_h printf "\n#endif /* _CLUSTER_H */\n" >>clusters_h printf "\n" >>cfiles }' $config $verbose && echo Wrote $oflag/clusters.h $verbose && echo Wrote $oflag/metrictab.h $verbose && echo Wrote $oflag/metrictab.c # # Generate remainder of pmns # awk ' $1 == "##" { if ($2 == "metric") metric = $3 else if ($2 == "pmid") printf "\t%s\t\t%s\n", metric, $3 next } { print }' <$config >>$oflag/pmns $verbose && echo Wrote $oflag/pmns # # Generate dummy root pmns # cat <$oflag/root /* * Generated code, do not edit! */ #define PCP_PMNS #include "domain.h" #include "clusters.h" root { $nflag } #include "pmns" EOFEOF $verbose && echo Wrote $oflag/root # # Generate help text # awk ' /.*{$/ { nonleaf = $1 } $1 == "##" { if ($2 == "metric") metric = $3 else if ($2 == "briefhelptext") { printf "@ %s.%s", nonleaf, metric for (i=3; i <= NF; i++) printf " %s", $i printf "\n" } else if ($2 == "helptext") { for (i=3; i <= NF; i++) if (i == 3) printf "%s", $i else printf " %s", $i printf "\n" } }' <$config >$oflag/help $verbose && echo Wrote $oflag/help # # Generate generic install script # cat << EOFEOF >$install_g #! /bin/sh usage() { echo "Usage: \$0 [-m mode] [-d dir] [-f srcfile -t destfile]" echo "Required options: both -f and -t, or just -d" exit 1 } mdflag="755" mflag="644" while getopts "m:d:f:t:v" c do case \$c in m) mflag="\$OPTARG" mdflag=\$mflag ;; d) dflag="\$OPTARG" ;; f) fflag="\$OPTARG" ;; t) tflag="\$OPTARG" ;; \?) usage ;; esac done [ -z "\$fflag" -a -z "\$dflag" ] && usage [ -z "\$fflag" -a ! -z "\$tflag" ] && usage [ ! -z "\$fflag" -a -z "\$tflag" ] && usage [ ! -z "\$dflag" ] && mkdir \$dflag && chmod \$mdflag \$dflag [ ! -z "\$fflag" ] && cp \$fflag \$tflag && chmod \$mflag \$tflag exit 0 EOFEOF chmod 755 $install_g # # Generate GNUmakefile # cat << EOFEOF >$gnumakefile TOPDIR = $tflag include \$(TOPDIR)/src/include/builddefs IAM = $iam CMDTARGET= pmda\$(IAM) LIBTARGET= pmda_\$(IAM).so TARGETS = \$(CMDTARGET) \$(LIBTARGET) CFILES = `cat CFILES` HFILES = GCFILES = $oflag/metrictab.c $oflag/pmda.c GHFILES = $oflag/domain.h $oflag/metrictab.h GSRCFILES = $oflag/help $oflag/root $oflag/pmns \ $oflag/Makefile.install $oflag/Install \ $oflag/Remove $oflag/clusters.h OBJECTS += \$(GCFILES:.c=.o) LCFLAGS = LLDLIBS = \$(PCP_PMDALIB) PMDADIR = \$(PCP_PMDAS_DIR)/\$(IAM) LDIRT = generated *.o \$(TARGETS) *.log *.dir *.pag pcp default: pcp help.pag help.dir \$(TARGETS) include \$(BUILDRULES) install: default \$(INSTALL) -m 755 -d \$(PCP_VAR_DIR) \$(INSTALL) -m 755 -d \$(PCP_VAR_DIR)/pmdas \$(INSTALL) -m 755 -d \$(PMDADIR) \$(INSTALL) -m 755 \$(CMDTARGET) \$(PMDADIR)/\$(CMDTARGET) \$(INSTALL) -m 755 \$(LIBTARGET) \$(PMDADIR)/\$(LIBTARGET) \$(INSTALL) -m 755 $oflag/Install \$(PMDADIR)/Install \$(INSTALL) -m 755 $oflag/Remove \$(PMDADIR)/Remove \$(INSTALL) -m 644 $oflag/Makefile.install \$(PMDADIR)/Makefile \$(INSTALL) -m 644 $oflag/pmns \$(PMDADIR)/pmns \$(INSTALL) -m 644 $oflag/root \$(PMDADIR)/root \$(INSTALL) -m 644 $oflag/domain.h \$(PMDADIR)/domain.h \$(INSTALL) -m 644 $oflag/clusters.h \$(PMDADIR)/clusters.h \$(INSTALL) -m 644 $oflag/help \$(PMDADIR)/help \$(INSTALL) -m 644 help.pag \$(PMDADIR)/help.pag \$(INSTALL) -m 644 help.dir \$(PMDADIR)/help.dir pcp: ln -s \$(TOPDIR)/src/include pcp help.dir help.pag : $oflag/help \$(RUN_IN_BUILD_ENV) \$(TOPDIR)/src/newhelp/newhelp -n $oflag/root -v 2 -o help < $oflag/help \$(GCFILES) \$(GHFILES) \$(GSRCFILES) : $config \$(GENPMDA) -v -i $IAM -c $config default_pro: default install_pro: install EOFEOF # # Generate GNUmakefile.generic # cat << EOFEOF >$gnumakefile_g IAM = $iam CONFIG = $config DOMAIN = $domain include /etc/pcp.conf INSTALL ?= ./install-generic GENPMDA ?= /usr/bin/genpmda CMDTARGET= pmda\$(IAM) LIBTARGET= pmda_\$(IAM).so TARGETS = \$(CMDTARGET) \$(LIBTARGET) CFILES = `cat CFILES` GCFILES = $oflag/metrictab.c $oflag/pmda.c GHFILES = $oflag/domain.h $oflag/metrictab.h GSRCFILES = $oflag/help $oflag/root $oflag/pmns \ $oflag/Makefile.install $oflag/Install \ $oflag/Remove $oflag/clusters.h OBJECTS = \$(CFILES:.c=.o) \$(GCFILES:.c=.o) CFLAGS = -I/usr/include/pcp LLDLIBS = -lpcp_pmda -lpcp PMDADIR = \$(PCP_PMDAS_DIR)/\$(IAM) LDIRT = generated *.o \$(TARGETS) *.log *.dir *.pag *.o default: help.pag help.dir \$(TARGETS) install: default \$(INSTALL) -m 755 -d \$(PCP_VAR_DIR) \$(INSTALL) -m 755 -d \$(PCP_VAR_DIR)/pmdas \$(INSTALL) -m 755 -d \$(PMDADIR) \$(INSTALL) -m 755 -f \$(CMDTARGET) \$(PMDADIR)/\$(CMDTARGET) \$(INSTALL) -m 755 -f \$(LIBTARGET) \$(PMDADIR)/\$(LIBTARGET) \$(INSTALL) -m 755 -f $oflag/Install \$(PMDADIR)/Install \$(INSTALL) -m 755 -f $oflag/Remove \$(PMDADIR)/Remove \$(INSTALL) -m 644 -f $oflag/Makefile.install \$(PMDADIR)/Makefile \$(INSTALL) -m 644 -f $oflag/pmns \$(PMDADIR)/pmns \$(INSTALL) -m 644 -f $oflag/root \$(PMDADIR)/root \$(INSTALL) -m 644 -f $oflag/domain.h \$(PMDADIR)/domain.h \$(INSTALL) -m 644 -f $oflag/clusters.h \$(PMDADIR)/clusters.h \$(INSTALL) -m 644 -f $oflag/help \$(PMDADIR)/help \$(INSTALL) -m 644 -f help.pag \$(PMDADIR)/help.pag \$(INSTALL) -m 644 -f help.dir \$(PMDADIR)/help.dir help.dir help.pag : $oflag/help \$(PCP_BINADM_DIR)/newhelp -n $oflag/root -v 2 -o help < $oflag/help \$(GCFILES) \$(GHFILES) \$(GSRCFILES) : \$(CONFIG) \$(GENPMDA) -s \$(PCP_VAR_DIR)/pmns/stdpmid -D \$(DOMAIN) -d -v -i \$(IAM) -c \$(CONFIG) \$(CMDTARGET): \$(OBJECTS) cc -o \$(CMDTARGET) \$(OBJECTS) \$(LLDLIBS) \$(LIBTARGET): \$(OBJECTS) cc -shared -Wl,-soname,\$(LIBTARGET) -o \$(LIBTARGET) \$(OBJECTS) \$(LLDLIBS) -ldl clean clobber: rm -rf \$(LDIRT) EOFEOF # # What needs to be merged? # for f in *.new do b=`basename $f .new` if [ -f "$b" ] then if diff "$b" "$f" >/dev/null 2>&1 then rm -f $f $verbose && echo "Unchanged $b" else echo "MERGE required, gdiff $b $f" fi else mv $f $b $verbose && echo "Wrote $b" fi done rm -f CFILES exit 0 pcp-3.8.12ubuntu1/src/genpmda/GNUmakefile0000664000000000000000000000201412272262501015053 0ustar #!gmake # # Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs TARGETS = genpmda LSRCFILES = genpmda default: $(TARGETS) install: default $(INSTALL) -m 755 genpmda $(PCP_BIN_DIR)/genpmda default_pcp: default install_pcp: install include $(BUILDRULES) pcp-3.8.12ubuntu1/src/libpcp_mmv/0000775000000000000000000000000012272262617013531 5ustar pcp-3.8.12ubuntu1/src/libpcp_mmv/src/0000775000000000000000000000000012272262617014320 5ustar pcp-3.8.12ubuntu1/src/libpcp_mmv/src/mmv_stats.c0000664000000000000000000004042012272262501016471 0ustar /* * Memory Mapped Values PMDA Client API * * Copyright (C) 2001,2009 Silicon Graphics, Inc. All rights reserved. * Copyright (C) 2009 Aconex. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. */ #include "pmapi.h" #include #include "mmv_stats.h" #include "mmv_dev.h" #include "impl.h" static void mmv_stats_path(const char *fname, char *fullpath, size_t pathlen) { int sep = __pmPathSeparator(); snprintf(fullpath, pathlen, "%s%c" "mmv" "%c%s", pmGetConfig("PCP_TMP_DIR"), sep, sep, fname); } static void * mmv_mapping_init(const char *fname, size_t size) { char path[MAXPATHLEN]; void *addr = NULL; mode_t cur_umask; int fd, sts = 0; /* unlink+creat will cause the pmda to reload on next fetch */ mmv_stats_path(fname, path, sizeof(path)); unlink(path); cur_umask = umask(S_IWGRP | S_IWOTH); fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0644); umask(cur_umask); if (fd < 0) return NULL; if (ftruncate(fd, size) != -1) addr = __pmMemoryMap(fd, size, 1); else sts = oserror(); close(fd); setoserror(sts); return addr; } static int mmv_singular(__int32_t indom) { return (indom == 0 || indom == PM_INDOM_NULL); } static mmv_disk_indom_t * mmv_lookup_disk_indom(__int32_t indom, mmv_disk_indom_t *in, int nindoms) { int i; for (i = 0; i < nindoms; i++) if (in[i].serial == indom) return &in[i]; return NULL; } static const mmv_indom_t * mmv_lookup_indom(__int32_t indom, const mmv_indom_t *in, int nindoms) { int i; for (i = 0; i < nindoms; i++) if (in[i].serial == indom) return &in[i]; return NULL; } static __uint64_t mmv_generation(void) { struct timeval now; __uint32_t gen1, gen2; __pmtimevalNow(&now); gen1 = now.tv_sec; gen2 = now.tv_usec; return (((__uint64_t)gen1 << 32) | (__uint64_t)gen2); } void * mmv_stats_init(const char *fname, int cluster, mmv_stats_flags_t fl, const mmv_metric_t *st, int nmetrics, const mmv_indom_t *in, int nindoms) { mmv_disk_instance_t *inlist; mmv_disk_indom_t *domlist; mmv_disk_metric_t *mlist; mmv_disk_string_t *slist; mmv_disk_value_t *vlist; mmv_disk_header_t *hdr; mmv_disk_toc_t *toc; __uint64_t indoms_offset; /* anchor start of indoms section */ __uint64_t instances_offset; /* anchor start of instances section */ __uint64_t metrics_offset; /* anchor start of metrics section */ __uint64_t values_offset; /* anchor start of values section */ __uint64_t strings_offset; /* anchor start of any/all strings */ void *addr; size_t size; int i, j, k, tocidx, stridx; int ninstances = 0; int nstrings = 0; int nvalues = 0; for (i = 0; i < nindoms; i++) { if (mmv_singular(in[i].serial)) { setoserror(ESRCH); return NULL; } ninstances += in[i].count; if (in[i].shorttext) nstrings++; if (in[i].helptext) nstrings++; } for (i = 0; i < nmetrics; i++) { if ((st[i].type < MMV_TYPE_NOSUPPORT) || (st[i].type > MMV_TYPE_ELAPSED) || strlen(st[i].name) == 0) { setoserror(EINVAL); return NULL; } if (st[i].helptext) nstrings++; if (st[i].shorttext) nstrings++; if (!mmv_singular(st[i].indom)) { const mmv_indom_t * mi; if ((mi = mmv_lookup_indom(st[i].indom, in, nindoms)) == NULL) { setoserror(ESRCH); return NULL; } if (st[i].type == MMV_TYPE_STRING) nstrings += mi->count; nvalues += mi->count; } else { if (st[i].type == MMV_TYPE_STRING) nstrings++; nvalues++; } } /* TOC follows header, with enough entries to hold */ /* indoms, instances, metrics, values, and strings */ size = sizeof(mmv_disk_toc_t) * 2; if (nindoms) size += sizeof(mmv_disk_toc_t) * 2; if (nstrings) size += sizeof(mmv_disk_toc_t) * 1; indoms_offset = sizeof(mmv_disk_header_t) + size; /* Following the indom definitions are the actual instances */ size = sizeof(mmv_disk_indom_t) * nindoms; instances_offset = indoms_offset + size; /* Following the instances are the metric definitions */ for (size = 0, i = 0; i < nindoms; i++) size += in[i].count * sizeof(mmv_disk_instance_t); metrics_offset = instances_offset + size; /* Following metric definitions are the actual values */ size = nmetrics * sizeof(mmv_disk_metric_t); values_offset = metrics_offset + size; /* Following the values are the string values and/or help text */ size = nvalues * sizeof(mmv_disk_value_t); strings_offset = values_offset + size; /* End of file follows all of the actual strings */ size = strings_offset + nstrings * sizeof(mmv_disk_string_t); if ((addr = mmv_mapping_init(fname, size)) == NULL) return NULL; /* * We unconditionally clobber the stats file on each restart; * easier this way and the clients deal with counter wraps. * We also write from the start going forward through the file * with an occassional step back to (re)write the TOC page - * this gives the kernel a decent shot at laying out the file * contiguously ondisk (hopefully we dont do much disk I/O on * this file, but it will be written to disk at times so lets * try to minimise that I/O traffic, eh?). */ hdr = (mmv_disk_header_t *) addr; strncpy(hdr->magic, "MMV", 4); hdr->version = MMV_VERSION; hdr->g1 = mmv_generation(); hdr->g2 = 0; hdr->tocs = 2; if (nindoms) hdr->tocs += 2; if (nstrings) hdr->tocs += 1; hdr->flags = fl; hdr->cluster = cluster; hdr->process = (__int32_t)getpid(); toc = (mmv_disk_toc_t *)((char *)addr + sizeof(mmv_disk_header_t)); tocidx = 0; if (nindoms) { toc[tocidx].type = MMV_TOC_INDOMS; toc[tocidx].count = nindoms; toc[tocidx].offset = indoms_offset; tocidx++; toc[tocidx].type = MMV_TOC_INSTANCES; toc[tocidx].count = ninstances; toc[tocidx].offset = instances_offset; tocidx++; } toc[tocidx].type = MMV_TOC_METRICS; toc[tocidx].count = nmetrics; toc[tocidx].offset = metrics_offset; tocidx++; toc[tocidx].type = MMV_TOC_VALUES; toc[tocidx].count = nvalues; toc[tocidx].offset = values_offset; tocidx++; if (nstrings) { toc[tocidx].type = MMV_TOC_STRINGS; toc[tocidx].count = nstrings; toc[tocidx].offset = strings_offset; tocidx++; } /* Indom section */ domlist = (mmv_disk_indom_t *)((char *)addr + indoms_offset); for (i = 0; i < nindoms; i++) { domlist[i].serial = in[i].serial; domlist[i].count = in[i].count; domlist[i].offset = 0; /* filled in below */ domlist[i].shorttext = 0; /* filled in later */ domlist[i].helptext = 0; /* filled in later */ } /* Instances section */ inlist = (mmv_disk_instance_t *)((char *)addr + instances_offset); for (i = 0; i < nindoms; i++) { mmv_instances_t *insts = in[i].instances; domlist[i].offset = ((char *)inlist - (char *)addr); for (j = 0; j < domlist[i].count; j++) { inlist->indom = indoms_offset + (i * sizeof(mmv_disk_indom_t)); inlist->padding = 0; inlist->internal = insts[j].internal; strncpy(inlist->external, insts[j].external, MMV_NAMEMAX); inlist->external[MMV_NAMEMAX-1] = '\0'; inlist++; } } /* Metrics section */ mlist = (mmv_disk_metric_t *)((char *)addr + metrics_offset); for (i = 0; i < nmetrics; i++) { strncpy(mlist[i].name, st[i].name, MMV_NAMEMAX); mlist[i].name[MMV_NAMEMAX-1] = '\0'; mlist[i].item = st[i].item; mlist[i].type = st[i].type; mlist[i].indom = st[i].indom; mlist[i].dimension = st[i].dimension; mlist[i].semantics = st[i].semantics; mlist[i].shorttext = 0; /* filled in later */ mlist[i].helptext = 0; /* filled in later */ mlist[i].padding = 0; } /* Values section */ vlist = (mmv_disk_value_t *)((char *)addr + values_offset); for (i = j = 0; i < nmetrics; i++) { __uint64_t off = metrics_offset + i * sizeof(mmv_disk_metric_t); if (mmv_singular(st[i].indom)) { memset(&vlist[j], 0, sizeof(mmv_disk_value_t)); vlist[j].metric = off; j++; } else { __uint64_t ioff; mmv_disk_indom_t *indom; indom = mmv_lookup_disk_indom(st[i].indom, domlist, nindoms); for (k = 0; k < indom->count; k++) { ioff = indom->offset + sizeof(mmv_disk_instance_t) * k; memset(&vlist[j], 0, sizeof(mmv_disk_value_t)); vlist[j].metric = off; vlist[j].instance = ioff; j++; } } } /* Strings section */ slist = (mmv_disk_string_t *)((char *)addr + strings_offset); stridx = 0; /* * 3 phases: all string values, any metric help, any indom help. */ for (i = 0; i < nvalues; i++) { mmv_disk_metric_t * metric = (mmv_disk_metric_t *) ((char *)(addr + vlist[i].metric)); if (metric->type == MMV_TYPE_STRING) { vlist[i].extra = strings_offset + (stridx * sizeof(mmv_disk_string_t)); stridx++; } } for (i = 0; i < nmetrics; i++) { if (st[i].shorttext) { mlist[i].shorttext = strings_offset + (stridx * sizeof(mmv_disk_string_t)); strncpy(slist[stridx].payload, st[i].shorttext, MMV_STRINGMAX); slist[stridx].payload[MMV_STRINGMAX-1] = '\0'; stridx++; } if (st[i].helptext) { mlist[i].helptext = strings_offset + (stridx * sizeof(mmv_disk_string_t)); strncpy(slist[stridx].payload, st[i].helptext, MMV_STRINGMAX); slist[stridx].payload[MMV_STRINGMAX-1] = '\0'; stridx++; } } for (i = 0; i < nindoms; i++) { if (in[i].shorttext) { domlist[i].shorttext = strings_offset + (stridx * sizeof(mmv_disk_string_t)); strncpy(slist[stridx].payload, in[i].shorttext, MMV_STRINGMAX); slist[stridx].payload[MMV_STRINGMAX-1] = '\0'; stridx++; } if (in[i].helptext) { domlist[i].helptext = strings_offset + (stridx * sizeof(mmv_disk_string_t)); strncpy(slist[stridx].payload, in[i].helptext, MMV_STRINGMAX); slist[stridx].payload[MMV_STRINGMAX-1] = '\0'; stridx++; } } /* Complete - unlock the header, PMDA can read now */ hdr->g2 = hdr->g1; return addr; } void mmv_stats_stop(const char *fname, void *addr) { mmv_disk_header_t *hdr = (mmv_disk_header_t *)addr; char path[MAXPATHLEN]; struct stat sbuf; mmv_stats_path(fname, path, sizeof(path)); if (stat(path, &sbuf) < 0) sbuf.st_size = (size_t)-1; else if (hdr->flags & MMV_FLAG_PROCESS) unlink(path); __pmMemoryUnmap(addr, sbuf.st_size); } pmAtomValue * mmv_lookup_value_desc(void *addr, const char *metric, const char *inst) { if (addr != NULL && metric != NULL) { int i; mmv_disk_header_t *hdr = (mmv_disk_header_t *)addr; mmv_disk_toc_t *toc = (mmv_disk_toc_t *) ((char *)addr + sizeof(mmv_disk_header_t)); for (i = 0; i < hdr->tocs; i++) { if (toc[i].type == MMV_TOC_VALUES) { int j; mmv_disk_value_t *v = (mmv_disk_value_t *) ((char *)addr + toc[i].offset); for (j = 0; j < toc[i].count; j++) { mmv_disk_metric_t *m = (mmv_disk_metric_t *) ((char *)addr + v[j].metric); if (strcmp(m->name, metric) == 0) { if (mmv_singular(m->indom)) { /* Singular metric */ return &v[j].value; } else { if (inst == NULL) { /* Metric has multiple instances, but * we don't know which one to return, * so return an error */ return NULL; } else { mmv_disk_instance_t * in = (mmv_disk_instance_t *) ((char *)addr + v[j].instance); if (strcmp(in->external, inst) == 0) return &v[j].value; } } } } } } } return NULL; } void mmv_inc_value(void *addr, pmAtomValue *av, double inc) { if (av != NULL && addr != NULL) { mmv_disk_value_t * v = (mmv_disk_value_t *) av; mmv_disk_metric_t * m = (mmv_disk_metric_t *) ((char *)addr + v->metric); switch (m->type) { case MMV_TYPE_I32: v->value.l += (__int32_t)inc; break; case MMV_TYPE_U32: v->value.ul += (__uint32_t)inc; break; case MMV_TYPE_I64: v->value.ll += (__int64_t)inc; break; case MMV_TYPE_U64: v->value.ull += (__uint64_t)inc; break; case MMV_TYPE_FLOAT: v->value.f += (float)inc; break; case MMV_TYPE_DOUBLE: v->value.d += inc; break; case MMV_TYPE_ELAPSED: if (inc < 0) v->extra = (__int64_t)inc; else { v->value.ll += v->extra + (__int64_t)inc; v->extra = 0; } break; default: break; } } } void mmv_set_value(void *addr, pmAtomValue *av, double val) { if (av != NULL && addr != NULL) { mmv_disk_value_t * v = (mmv_disk_value_t *) av; mmv_disk_metric_t * m = (mmv_disk_metric_t *) ((char *)addr + v->metric); switch (m->type) { case MMV_TYPE_I32: v->value.l = (__int32_t)val; break; case MMV_TYPE_U32: v->value.ul = (__uint32_t)val; break; case MMV_TYPE_I64: v->value.ll = (__int64_t)val; break; case MMV_TYPE_U64: v->value.ull = (__uint64_t)val; break; case MMV_TYPE_FLOAT: v->value.f = (float)val; break; case MMV_TYPE_DOUBLE: v->value.d = val; break; case MMV_TYPE_ELAPSED: v->value.ll = (__int64_t)val; v->extra = 0; break; default: break; } } } void mmv_set_string(void *addr, pmAtomValue *av, const char *string, int size) { if (av != NULL && addr != NULL && string != NULL) { mmv_disk_value_t * v = (mmv_disk_value_t *) av; mmv_disk_metric_t * m = (mmv_disk_metric_t *) ((char *)addr + v->metric); if (m->type == MMV_TYPE_STRING && (size >= 0 && size < MMV_STRINGMAX - 1)) { __uint64_t soffset = v->extra; mmv_disk_string_t * s; s = (mmv_disk_string_t *)((char *)addr + soffset); strncpy(s->payload, string, size); s->payload[size] = '\0'; v->value.l = size; } } } /* * Simple wrapper routines */ void mmv_stats_add(void *addr, const char *metric, const char *instance, double count) { if (addr) { pmAtomValue * mmv_metric; mmv_metric = mmv_lookup_value_desc(addr, metric, instance); if (mmv_metric) mmv_inc_value(addr, mmv_metric, count); } } void mmv_stats_inc(void *addr, const char *metric, const char *instance) { mmv_stats_add(addr, metric, instance, 1); } void mmv_stats_set(void *addr, const char *metric, const char *instance, double value) { if (addr) { pmAtomValue * mmv_metric; mmv_metric = mmv_lookup_value_desc(addr, metric, instance); if (mmv_metric) mmv_set_value(addr, mmv_metric, value); } } void mmv_stats_add_fallback(void *addr, const char *metric, const char *instance, const char *instance2, double count) { if (addr) { pmAtomValue * mmv_metric; mmv_metric = mmv_lookup_value_desc(addr, metric, instance); if (mmv_metric == NULL) mmv_metric = mmv_lookup_value_desc(addr,metric,instance2); if (mmv_metric) mmv_inc_value(addr, mmv_metric, count); } } void mmv_stats_inc_fallback(void *addr, const char *metric, const char *instance, const char *instance2) { mmv_stats_add_fallback(addr, metric, instance, instance2, 1); } pmAtomValue * mmv_stats_interval_start(void *addr, pmAtomValue *value, const char *metric, const char *instance) { if (addr) { if (value == NULL) value = mmv_lookup_value_desc(addr, metric, instance); if (value) { struct timeval tv; __pmtimevalNow(&tv); mmv_inc_value(addr, value, -(tv.tv_sec*1e6 + tv.tv_usec)); } } return value; } void mmv_stats_interval_end(void *addr, pmAtomValue *value) { if (value && addr) { struct timeval tv; __pmtimevalNow(&tv); mmv_inc_value(addr, value, (tv.tv_sec*1e6 + tv.tv_usec)); } } void mmv_stats_set_string(void *addr, const char *metric, const char *instance, const char *string) { if (addr) { size_t len = strlen(string); pmAtomValue *mmv_metric; mmv_metric = mmv_lookup_value_desc(addr, metric, instance); mmv_set_string(addr, mmv_metric, string, len); } } void mmv_stats_set_strlen(void *addr, const char *metric, const char *instance, const char *string, size_t len) { if (addr) { pmAtomValue *mmv_metric; mmv_metric = mmv_lookup_value_desc(addr, metric, instance); mmv_set_string(addr, mmv_metric, string, len); } } pcp-3.8.12ubuntu1/src/libpcp_mmv/src/exports0000664000000000000000000000061212272262501015736 0ustar PCP_MMV_1.0 { global: mmv_stats_init; mmv_stats_stop; mmv_inc_value; mmv_set_value; mmv_set_string; mmv_lookup_value_desc; mmv_stats_add; mmv_stats_add_fallback; mmv_stats_inc; mmv_stats_inc_fallback; mmv_stats_interval_end; mmv_stats_interval_start; mmv_stats_set; mmv_stats_set_string; mmv_stats_set_strlen; local: *; }; pcp-3.8.12ubuntu1/src/libpcp_mmv/src/GNUmakefile0000664000000000000000000000341012272262501016360 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2001,2009 Silicon Graphics, Inc. All Rights Reserved. # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs CFILES = mmv_stats.c VERSION_SCRIPT = exports LSRCFILES = $(VERSION_SCRIPT) STATICLIBTARGET = libpcp_mmv.a DSOVERSION = 1 LIBTARGET = libpcp_mmv.$(DSOSUFFIX).$(DSOVERSION) SYMTARGET = libpcp_mmv.$(DSOSUFFIX) ifeq "$(TARGET_OS)" "darwin" LIBTARGET = libpcp_mmv.$(DSOVERSION).$(DSOSUFFIX) endif ifeq "$(TARGET_OS)" "mingw" LIBTARGET = libpcp_mmv.$(DSOSUFFIX) SYMTARGET = STATICLIBTARGET = endif ifeq "$(ENABLE_SHARED)" "no" LIBTARGET = SYMTARGET = endif LCFLAGS = -I. LLDLIBS = -lpcp LDIRT = $(SYMTARGET) default: $(LIBTARGET) $(SYMTARGET) $(STATICLIBTARGET) include $(BUILDRULES) install: default ifneq ($(LIBTARGET),) $(INSTALL) -m 755 $(LIBTARGET) $(PCP_LIB_DIR)/$(LIBTARGET) endif ifneq ($(SYMTARGET),) for tt in $(SYMTARGET); do \ $(INSTALL) -S $(LIBTARGET) $(PCP_LIB_DIR)/$$tt || exit 1; \ done endif ifneq ($(STATICLIBTARGET),) $(INSTALL) -m 755 $(STATICLIBTARGET) $(PCP_LIB_DIR)/$(STATICLIBTARGET) endif default_pcp: default install_pcp: install ifneq ($(SYMTARGET),) $(SYMTARGET): $(LN_S) -f $(LIBTARGET) $@ endif ifneq ($(LIBTARGET),) $(LIBTARGET): $(VERSION_SCRIPT) endif pcp-3.8.12ubuntu1/src/libpcp_mmv/GNUmakefile0000664000000000000000000000161112272262501015572 0ustar # # Copyright (C) 2001,2009 Silicon Graphics, Inc. All Rights Reserved. # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # # libpcp_mmv.so - performance data export through shared memory # (used in conjunction with the mmv pmda) # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs BASE = libpcp_mmv.a SUBDIRS = src default install: $(SUBDIRS) $(SUBDIRS_MAKERULE) include $(BUILDRULES) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/libpcp/0000775000000000000000000000000012272262617012652 5ustar pcp-3.8.12ubuntu1/src/libpcp/GNUlocaldefs.320000664000000000000000000000014712272262501015320 0ustar LCFLAGS += -m32 -march=i386 LLDFLAGS += -m32 -march=i386 PCP_LIB_DIR=$(PCP_LIB32_DIR) LIBPCP_ABIDIR=32 pcp-3.8.12ubuntu1/src/libpcp/src/0000775000000000000000000000000012272262617013441 5ustar pcp-3.8.12ubuntu1/src/libpcp/src/p_fetch.c0000664000000000000000000000555312272262501015215 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "internal.h" /* * PDU for pmFetch request (PDU_FETCH) */ typedef struct { __pmPDUHdr hdr; int ctxnum; /* context no. */ __pmTimeval when; /* desired time */ int numpmid; /* no. PMIDs to follow */ pmID pmidlist[1]; /* one or more */ } fetch_t; int __pmSendFetch(int fd, int from, int ctxnum, __pmTimeval *when, int numpmid, pmID *pmidlist) { size_t need; fetch_t *pp; int j; int sts; need = sizeof(fetch_t) + (numpmid-1) * sizeof(pmID); if ((pp = (fetch_t *)__pmFindPDUBuf((int)need)) == NULL) return -oserror(); pp->hdr.len = (int)need; pp->hdr.type = PDU_FETCH; /* * note: context id may be sent twice due to protocol evolution and * backwards compatibility issues */ pp->hdr.from = from; pp->ctxnum = htonl(ctxnum); if (when == NULL) memset((void *)&pp->when, 0, sizeof(pp->when)); else { #if defined(HAVE_32BIT_LONG) pp->when.tv_sec = htonl(when->tv_sec); pp->when.tv_usec = htonl(when->tv_usec); #else pp->when.tv_sec = htonl((__int32_t)when->tv_sec); pp->when.tv_usec = htonl((__int32_t)when->tv_usec); #endif } pp->numpmid = htonl(numpmid); for (j = 0; j < numpmid; j++) pp->pmidlist[j] = __htonpmID(pmidlist[j]); sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmDecodeFetch(__pmPDU *pdubuf, int *ctxnum, __pmTimeval *when, int *numpmidp, pmID **pmidlist) { fetch_t *pp; char *pduend; int numpmid; int j; pp = (fetch_t *)pdubuf; pduend = (char *)pdubuf + pp->hdr.len; if (pduend - (char*)pp < sizeof(fetch_t)) return PM_ERR_IPC; numpmid = ntohl(pp->numpmid); if (numpmid <= 0 || numpmid > pp->hdr.len) return PM_ERR_IPC; if (numpmid >= (INT_MAX - sizeof(fetch_t)) / sizeof(pmID)) return PM_ERR_IPC; if ((pduend - (char*)pp) != sizeof(fetch_t) + ((sizeof(pmID)) * (numpmid-1))) return PM_ERR_IPC; for (j = 0; j < numpmid; j++) pp->pmidlist[j] = __ntohpmID(pp->pmidlist[j]); *ctxnum = ntohl(pp->ctxnum); when->tv_sec = ntohl(pp->when.tv_sec); when->tv_usec = ntohl(pp->when.tv_usec); *numpmidp = numpmid; *pmidlist = pp->pmidlist; __pmPinPDUBuf((void *)pdubuf); return 0; } pcp-3.8.12ubuntu1/src/libpcp/src/logconnect.c0000664000000000000000000001646212272262501015741 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe notes * * Do not need ctxp->c_pmcd->pc_lock lock around __pmSendCreds() call, * as the connection to pmlogger has not been created, so no-one else * could be using the fd. */ #include "pmapi.h" #include "impl.h" #include "internal.h" #include #include /* * Return timeout (in seconds) to be used when pmlc is communicating * with pmlogger ... used externally from pmlc and internally from * __pmConnectLogger() and __pmControlLogger() */ int __pmLoggerTimeout(void) { static int timeout = TIMEOUT_NEVER; static int done_default = 0; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (!done_default) { char *timeout_str; char *end_ptr; if ((timeout_str = getenv("PMLOGGER_REQUEST_TIMEOUT")) != NULL) { /* * Only a positive integer (the unit is seconds) is OK */ timeout = strtol(timeout_str, &end_ptr, 10); if (*end_ptr != '\0' || timeout < 0) { __pmNotifyErr(LOG_WARNING, "ignored bad PMLOGGER_REQUEST_TIMEOUT = '%s'\n", timeout_str); timeout = TIMEOUT_NEVER; } } done_default = 1; } PM_UNLOCK(__pmLock_libpcp); return timeout; } /* * expect one of pid or port to be 0 ... if port is 0, use * hostname+pid to find port, assuming pmcd is running there */ int __pmConnectLogger(const char *hostname, int *pid, int *port) { int n, sts; __pmLogPort *lpp; int fd; /* Fd for socket connection to pmcd */ __pmPDU *pb; __pmPDUHdr *php; int pinpdu; __pmHostEnt *servInfo; __pmSockAddr *myAddr; void *enumIx; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmConnectLogger(host=%s, pid=%d, port=%d)\n", hostname, *pid, *port); #endif /* * catch pid == PM_LOG_ALL_PIDS ... this tells __pmLogFindPort * to get all ports */ if (*pid == PM_LOG_ALL_PIDS) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmConnectLogger: pid == PM_LOG_ALL_PIDS makes no sense here\n"); #endif return -ECONNREFUSED; } if (*pid == PM_LOG_NO_PID && *port == PM_LOG_PRIMARY_PORT) { /* * __pmLogFindPort can only lookup based on pid, so xlate * the request */ *pid = PM_LOG_PRIMARY_PID; *port = PM_LOG_NO_PORT; } if (*port == PM_LOG_NO_PORT) { if ((n = __pmLogFindPort(hostname, *pid, &lpp)) < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmConnectLogger: __pmLogFindPort: %s\n", pmErrStr_r(n, errmsg, sizeof(errmsg))); } #endif return n; } else if (n != 1) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmConnectLogger: __pmLogFindPort -> 1, cannot contact pmcd\n"); #endif return -ECONNREFUSED; } *port = lpp->port; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmConnectLogger: __pmLogFindPort -> pid = %d\n", lpp->port); #endif } if ((servInfo = __pmGetAddrInfo(hostname)) == NULL) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmConnectLogger: gethostbyname: %s\n", hoststrerror()); #endif return -EHOSTUNREACH; } /* Loop over the addresses resolved for this host name until one of them connects. */ sts = -1; fd = -1; enumIx = NULL; for (myAddr = __pmHostEntGetSockAddr(servInfo, &enumIx); myAddr != NULL; myAddr = __pmHostEntGetSockAddr(servInfo, &enumIx)) { /* Create a socket */ if (__pmSockAddrIsInet(myAddr)) fd = __pmCreateSocket(); else if (__pmSockAddrIsIPv6(myAddr)) fd = __pmCreateIPv6Socket(); else { __pmNotifyErr(LOG_ERR, "__pmConnectLogger : invalid address family %d\n", __pmSockAddrGetFamily(myAddr)); fd = -1; } if (fd < 0) { __pmSockAddrFree(myAddr); continue; /* Try the next address */ } /* Attempt to connect */ __pmSockAddrSetPort(myAddr, *port); sts = __pmConnect(fd, myAddr, __pmSockAddrSize()); __pmSockAddrFree(myAddr); /* Successful connection? */ if (sts >= 0) break; sts = neterror(); if (sts == EINPROGRESS) { /* We're in progress - wait on select. */ struct timeval stv = { 0, 000000 }; struct timeval *pstv; __pmFdSet rfds; int rc; stv.tv_sec = __pmLoggerTimeout(); pstv = stv.tv_sec ? &stv : NULL; __pmFD_ZERO(&rfds); __pmFD_SET(fd, &rfds); sts = 0; if ((rc = __pmSelectRead(fd+1, &rfds, pstv)) == 1) { sts = __pmConnectCheckError(fd); } else if (rc == 0) { sts = ETIMEDOUT; } else { sts = (rc < 0) ? neterror() : EINVAL; } } sts = -sts; /* Successful connection? */ if (sts >= 0) break; /* Unsuccessful connection. */ __pmCloseSocket(fd); fd = -1; } __pmHostEntFree(servInfo); if (sts < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmConnectLogger: connect: %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } #endif return sts; } /* Expect an error PDU back: ACK/NACK for connection */ pinpdu = sts = __pmGetPDU(fd, ANY_SIZE, __pmLoggerTimeout(), &pb); if (sts == PDU_ERROR) { __pmOverrideLastFd(PDU_OVERRIDE2); /* don't dink with the value */ __pmDecodeError(pb, &sts); php = (__pmPDUHdr *)pb; if (*pid != PM_LOG_NO_PID && *pid != PM_LOG_PRIMARY_PID && php->from != *pid) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmConnectLogger: ACK response from pid %d, expected pid %d\n", php->from, *pid); #endif sts = -ECONNREFUSED; } *pid = php->from; } else if (sts < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { if (sts == PM_ERR_TIMEOUT) fprintf(stderr, "__pmConnectLogger: timeout (after %d secs)\n", __pmLoggerTimeout()); else { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmConnectLogger: Error: %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } } #endif ; /* fall through */ } else { /* wrong PDU type! */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmConnectLogger: ACK botch PDU type=%d not PDU_ERROR?\n", sts); #endif sts = PM_ERR_IPC; } if (pinpdu > 0) __pmUnpinPDUBuf(pb); if (sts >= 0) { if (sts == LOG_PDU_VERSION2) { __pmCred handshake[1]; __pmSetVersionIPC(fd, sts); handshake[0].c_type = CVERSION; handshake[0].c_vala = LOG_PDU_VERSION; handshake[0].c_valb = 0; handshake[0].c_valc = 0; sts = __pmSendCreds(fd, (int)getpid(), 1, handshake); } else sts = PM_ERR_IPC; if (sts >= 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmConnectLogger: PDU version=%d fd=%d\n", __pmVersionIPC(fd), fd); #endif return fd; } } /* error if we get here */ __pmCloseSocket(fd); return sts; } pcp-3.8.12ubuntu1/src/libpcp/src/lock.c0000664000000000000000000001710412272262501014530 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 2011 Ken McDonell. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "internal.h" #ifdef HAVE_EXECINFO_H #include #endif #ifdef PM_MULTI_THREAD typedef struct { void *lock; int count; } lockdbg_t; #define PM_LOCK_OP 1 #define PM_UNLOCK_OP 2 static int multi_init[PM_SCOPE_MAX+1]; static pthread_t multi_seen[PM_SCOPE_MAX+1]; /* the big libpcp lock */ #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP pthread_mutex_t __pmLock_libpcp = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; #else pthread_mutex_t __pmLock_libpcp = PTHREAD_MUTEX_INITIALIZER; #ifndef HAVE___THREAD pthread_key_t __pmTPDKey = 0; static void __pmTPD__destroy(void *addr) { free(addr); } #endif #endif void __pmInitLocks(void) { static pthread_mutex_t init = PTHREAD_MUTEX_INITIALIZER; static int done = 0; int psts; char errmsg[PM_MAXERRMSGLEN]; if ((psts = pthread_mutex_lock(&init)) != 0) { pmErrStr_r(-psts, errmsg, sizeof(errmsg)); fprintf(stderr, "__pmInitLocks: pthread_mutex_lock failed: %s", errmsg); exit(4); } if (!done) { #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP /* * Unable to initialize at compile time, need to do it here in * a one trip for all threads run-time initialization. */ pthread_mutexattr_t attr; if ((psts = pthread_mutexattr_init(&attr)) != 0) { pmErrStr_r(-psts, errmsg, sizeof(errmsg)); fprintf(stderr, "__pmInitLocks: pthread_mutexattr_init failed: %s", errmsg); exit(4); } if ((psts = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) != 0) { pmErrStr_r(-psts, errmsg, sizeof(errmsg)); fprintf(stderr, "__pmInitLocks: pthread_mutexattr_settype failed: %s", errmsg); exit(4); } if ((psts = pthread_mutex_init(&__pmLock_libpcp, &attr)) != 0) { pmErrStr_r(-psts, errmsg, sizeof(errmsg)); fprintf(stderr, "__pmInitLocks: pthread_mutex_init failed: %s", errmsg); exit(4); } #endif #ifndef HAVE___THREAD /* first thread here creates the thread private data key */ if ((psts = pthread_key_create(&__pmTPDKey, __pmTPD__destroy)) != 0) { pmErrStr_r(-psts, errmsg, sizeof(errmsg)); fprintf(stderr, "__pmInitLocks: pthread_key_create failed: %s", errmsg); exit(4); } #endif done = 1; } if ((psts = pthread_mutex_unlock(&init)) != 0) { pmErrStr_r(-psts, errmsg, sizeof(errmsg)); fprintf(stderr, "__pmInitLocks: pthread_mutex_unlock failed: %s", errmsg); exit(4); } #ifndef HAVE___THREAD if (pthread_getspecific(__pmTPDKey) == NULL) { __pmTPD *tpd = (__pmTPD *)malloc(sizeof(__pmTPD)); if (tpd == NULL) { __pmNoMem("__pmInitLocks: __pmTPD", sizeof(__pmTPD), PM_FATAL_ERR); /*NOTREACHED*/ } if ((psts = pthread_setspecific(__pmTPDKey, tpd)) != 0) { pmErrStr_r(-psts, errmsg, sizeof(errmsg)); fprintf(stderr, "__pmInitLocks: pthread_setspecific failed: %s", errmsg); exit(4); } tpd->curcontext = PM_CONTEXT_UNDEF; } #endif } int __pmMultiThreaded(int scope) { int sts = 0; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (!multi_init[scope]) { multi_init[scope] = 1; multi_seen[scope] = pthread_self(); } else { if (!pthread_equal(multi_seen[scope], pthread_self())) sts = 1; } PM_UNLOCK(__pmLock_libpcp); return sts; } #ifdef PM_MULTI_THREAD_DEBUG void __pmDebugLock(int op, void *lock, const char *file, int line) { int report = 0; int ctx; static __pmHashCtl hashctl = { 0, 0, NULL }; __pmHashNode *hp = NULL; lockdbg_t *ldp; int try; int sts; if (lock == (void *)&__pmLock_libpcp) { if ((pmDebug & DBG_TRACE_APPL0) | ((pmDebug & (DBG_TRACE_APPL0 | DBG_TRACE_APPL1 | DBG_TRACE_APPL2)) == 0)) report = DBG_TRACE_APPL0; } else if ((ctx = __pmIsContextLock(lock)) >= 0) { if ((pmDebug & DBG_TRACE_APPL1) | ((pmDebug & (DBG_TRACE_APPL0 | DBG_TRACE_APPL1 | DBG_TRACE_APPL2)) == 0)) report = DBG_TRACE_APPL1; } else { if ((pmDebug & DBG_TRACE_APPL2) | ((pmDebug & (DBG_TRACE_APPL0 | DBG_TRACE_APPL1 | DBG_TRACE_APPL2)) == 0)) report = DBG_TRACE_APPL2; } if (report) { __psint_t key = (__psint_t)lock; fprintf(stderr, "%s:%d %s", file, line, op == PM_LOCK_OP ? "lock" : "unlock"); try = 0; again: hp = __pmHashSearch((unsigned int)key, &hashctl); while (hp != NULL) { ldp = (lockdbg_t *)hp->data; if (ldp->lock == lock) break; hp = hp->next; } if (hp == NULL) { char errmsg[PM_MAXERRMSGLEN]; ldp = (lockdbg_t *)malloc(sizeof(lockdbg_t)); ldp->lock = lock; ldp->count = 0; sts = __pmHashAdd((unsigned int)key, (void *)ldp, &hashctl); if (sts == 1) { try++; if (try == 1) goto again; } hp = NULL; fprintf(stderr, " hash control failure: %s\n", pmErrStr_r(-sts, errmsg, sizeof(errmsg))); } } if (report == DBG_TRACE_APPL0) { fprintf(stderr, "(global_libpcp)"); } else if (report == DBG_TRACE_APPL1) { fprintf(stderr, "(ctx %d)", ctx); } else if (report == DBG_TRACE_APPL2) { if ((ctx = __pmIsChannelLock(lock)) >= 0) fprintf(stderr, "(ctx %d ipc channel)", ctx); else if (__pmIsDeriveLock(lock)) fprintf(stderr, "(derived_metric)"); else fprintf(stderr, "(" PRINTF_P_PFX "%p)", lock); } if (report) { if (hp != NULL) { ldp = (lockdbg_t *)hp->data; if (op == PM_LOCK_OP) { if (ldp->count != 0) fprintf(stderr, " [count=%d]", ldp->count); ldp->count++; } else { if (ldp->count != 1) fprintf(stderr, " [count=%d]", ldp->count); ldp->count--; } } fputc('\n', stderr); #ifdef HAVE_BACKTRACE #define MAX_TRACE_DEPTH 32 { void *backaddr[MAX_TRACE_DEPTH]; sts = backtrace(backaddr, MAX_TRACE_DEPTH); if (sts > 0) { char **symbols; symbols = backtrace_symbols(backaddr, MAX_TRACE_DEPTH); if (symbols != NULL) { int i; fprintf(stderr, "backtrace:\n"); for (i = 0; i < sts; i++) fprintf(stderr, " %s\n", symbols[i]); free(symbols); } } } #endif } } #else #define __pmDebugLock(op, lock, file, line) do { } while (0) #endif int __pmLock(void *lock, const char *file, int line) { int sts; if (pmDebug & DBG_TRACE_LOCK) __pmDebugLock(PM_LOCK_OP, lock, file, line); if ((sts = pthread_mutex_lock(lock)) != 0) { sts = -sts; if (pmDebug & DBG_TRACE_DESPERATE) fprintf(stderr, "%s:%d: lock failed: %s\n", file, line, pmErrStr(sts)); } return sts; } int __pmUnlock(void *lock, const char *file, int line) { int sts; if (pmDebug & DBG_TRACE_LOCK) __pmDebugLock(PM_UNLOCK_OP, lock, file, line); if ((sts = pthread_mutex_unlock(lock)) != 0) { sts = -sts; if (pmDebug & DBG_TRACE_DESPERATE) fprintf(stderr, "%s:%d: unlock failed: %s\n", file, line, pmErrStr(sts)); } return sts; } #else /* !PM_MULTI_THREAD - symbols exposed at the shlib ABI level */ void *__pmLock_libpcp; void __pmInitLocks(void) { } int __pmMultiThreaded(int scope) { (void)scope; return 0; } int __pmLock(void *l, const char *f, int n) { (void)l, (void)f, (void)n; return 0; } int __pmUnlock(void *l, const char *f, int n) { (void)l, (void)f, (void)n; return 0; } #endif pcp-3.8.12ubuntu1/src/libpcp/src/store.c0000664000000000000000000000540612272262501014736 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "internal.h" int pmStore(const pmResult *result) { int n; int sts; __pmContext *ctxp; __pmDSO *dp; if (result->numpmid < 1) return PM_ERR_TOOSMALL; for (n = 0; n < result->numpmid; n++) { if (result->vset[n]->numval < 1) { return PM_ERR_VALUE; } } if ((sts = pmWhichContext()) >= 0) { int ctx = sts; ctxp = __pmHandleToPtr(sts); if (ctxp == NULL) return PM_ERR_NOCONTEXT; if (ctxp->c_type == PM_CONTEXT_HOST) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); sts = __pmSendResult(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), result); if (sts < 0) sts = __pmMapErrno(sts); else { __pmPDU *pb; int pinpdu; pinpdu = sts = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, ctxp->c_pmcd->pc_tout_sec, &pb); if (sts == PDU_ERROR) __pmDecodeError(pb, &sts); else if (sts != PM_ERR_TIMEOUT) sts = PM_ERR_IPC; if (pinpdu > 0) __pmUnpinPDUBuf(pb); } PM_UNLOCK(__pmLock_libpcp); } else if (ctxp->c_type == PM_CONTEXT_LOCAL) { /* * have to do them one at a time in case different DSOs * involved ... need to copy each result->vset[n] */ pmResult tmp; pmValueSet tmpvset; if (PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) { /* Local context requires single-threaded applications */ sts = PM_ERR_THREAD; } else { sts = 0; for (n = 0; sts == 0 && n < result->numpmid; n++) { if ((dp = __pmLookupDSO(((__pmID_int *)&result->vset[n]->pmid)->domain)) == NULL) sts = PM_ERR_NOAGENT; else { tmp.numpmid = 1; tmp.vset[0] = &tmpvset; tmpvset.numval = 1; tmpvset.pmid = result->vset[n]->pmid; tmpvset.valfmt = result->vset[n]->valfmt; tmpvset.vlist[0] = result->vset[n]->vlist[0]; if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; sts = dp->dispatch.version.any.store(&tmp, dp->dispatch.version.any.ext); } } } } else { /* assume PM_CONTEXT_ARCHIVE -- this is an error */ sts = PM_ERR_NOTHOST; } PM_UNLOCK(ctxp->c_lock); } return sts; } pcp-3.8.12ubuntu1/src/libpcp/src/tv.c0000664000000000000000000000561312272262501014233 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include /* * real additive time, *ap plus *bp */ double __pmtimevalAdd(const struct timeval *ap, const struct timeval *bp) { return (double)(ap->tv_sec + bp->tv_sec) + (double)(ap->tv_usec + bp->tv_usec)/1000000.0; } /* * real time difference, *ap minus *bp */ double __pmtimevalSub(const struct timeval *ap, const struct timeval *bp) { return (double)(ap->tv_sec - bp->tv_sec) + (double)(ap->tv_usec - bp->tv_usec)/1000000.0; } /* * convert a timeval to a double (units = seconds) */ double __pmtimevalToReal(const struct timeval *val) { double dbl = (double)(val->tv_sec); dbl += (double)val->tv_usec / 1000000.0; return dbl; } /* * convert double to a timeval */ void __pmtimevalFromReal(double dbl, struct timeval *val) { val->tv_sec = (time_t)dbl; val->tv_usec = (long)(((dbl - (double)val->tv_sec) * 1000000.0)); } /* * Sleep for a specified amount of time */ void __pmtimevalSleep(struct timeval interval) { struct timespec delay; struct timespec left; int sts; delay.tv_sec = interval.tv_sec; delay.tv_nsec = interval.tv_usec * 1000; for (;;) { /* loop to catch early wakeup by nanosleep */ sts = nanosleep(&delay, &left); if (sts == 0 || (sts < 0 && oserror() != EINTR)) break; delay = left; } } /* subtract timevals */ static struct timeval tsub(struct timeval t1, struct timeval t2) { t1.tv_usec -= t2.tv_usec; if (t1.tv_usec < 0) { t1.tv_usec += 1000000; t1.tv_sec--; } t1.tv_sec -= t2.tv_sec; return t1; } /* convert timeval to timespec */ static struct timespec * tospec(struct timeval tv, struct timespec *ts) { ts->tv_nsec = tv.tv_usec * 1000; ts->tv_sec = tv.tv_sec; return ts; } #if !defined(IS_MINGW) void __pmtimevalNow(struct timeval *tv) { gettimeofday(tv, NULL); } #endif /* sleep until given timeval */ void __pmtimevalPause(struct timeval sched) { int sts; struct timeval curr; /* current time */ struct timespec delay; /* interval to sleep */ struct timespec left; /* remaining sleep time */ __pmtimevalNow(&curr); tospec(tsub(sched, curr), &delay); for (;;) { /* loop to catch early wakeup by nanosleep */ sts = nanosleep(&delay, &left); if (sts == 0 || (sts < 0 && oserror() != EINTR)) break; delay = left; } } pcp-3.8.12ubuntu1/src/libpcp/src/context.c0000664000000000000000000006610312272262501015267 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2007-2008 Aconex. All Rights Reserved. * Copyright (c) 1995-2002,2004,2006,2008 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe notes * * curcontext needs to be thread-private * * contexts[] et al and def_backoff[] et al are protected from changes * using the libpcp lock * * The actual contexts (__pmContext) are protected by the (recursive) * c_lock mutex which is intialized in pmNewContext() and pmDupContext(), * then locked in __pmHandleToPtr() ... it is the responsibility of all * __pmHandleToPtr() callers to call PM_UNLOCK(ctxp->c_lock) when they * are finished with the context. */ #include "pmapi.h" #include "impl.h" #include "internal.h" #include static __pmContext **contexts; /* array of context ptrs */ static int contexts_len; /* number of contexts */ #ifdef PM_MULTI_THREAD #ifdef HAVE___THREAD /* using a gcc construct here to make curcontext thread-private */ static __thread int curcontext = PM_CONTEXT_UNDEF; /* current context */ #endif #else static int curcontext = PM_CONTEXT_UNDEF; /* current context */ #endif static int n_backoff; static int def_backoff[] = {5, 10, 20, 40, 80}; static int *backoff; static void waitawhile(__pmPMCDCtl *ctl) { /* * after failure, compute delay before trying again ... */ PM_LOCK(__pmLock_libpcp); if (n_backoff == 0) { char *q; /* first time ... try for PMCD_RECONNECT_TIMEOUT from env */ if ((q = getenv("PMCD_RECONNECT_TIMEOUT")) != NULL) { char *pend; char *p; int val; for (p = q; *p != '\0'; ) { val = (int)strtol(p, &pend, 10); if (val <= 0 || (*pend != ',' && *pend != '\0')) { __pmNotifyErr(LOG_WARNING, "pmReconnectContext: ignored bad PMCD_RECONNECT_TIMEOUT = '%s'\n", q); n_backoff = 0; if (backoff != NULL) free(backoff); break; } if ((backoff = (int *)realloc(backoff, (n_backoff+1) * sizeof(backoff[0]))) == NULL) { __pmNoMem("pmReconnectContext", (n_backoff+1) * sizeof(backoff[0]), PM_FATAL_ERR); } backoff[n_backoff++] = val; if (*pend == '\0') break; p = &pend[1]; } } if (n_backoff == 0) { /* use default */ n_backoff = 5; backoff = def_backoff; } } PM_UNLOCK(__pmLock_libpcp); if (ctl->pc_timeout == 0) ctl->pc_timeout = 1; else if (ctl->pc_timeout < n_backoff) ctl->pc_timeout++; ctl->pc_again = time(NULL) + backoff[ctl->pc_timeout-1]; } /* * On success, context is locked and caller should unlock it */ __pmContext * __pmHandleToPtr(int handle) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (handle < 0 || handle >= contexts_len || contexts[handle]->c_type == PM_CONTEXT_FREE) { PM_UNLOCK(__pmLock_libpcp); return NULL; } else { __pmContext *sts; sts = contexts[handle]; PM_UNLOCK(__pmLock_libpcp); PM_LOCK(sts->c_lock); return sts; } } int __pmPtrToHandle(__pmContext *ctxp) { int i; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); for (i = 0; i < contexts_len; i++) { if (ctxp == contexts[i]) { PM_UNLOCK(__pmLock_libpcp); return i; } } PM_UNLOCK(__pmLock_libpcp); return PM_CONTEXT_UNDEF; } /* * Determine the hostname associated with the given context. */ const char * pmGetContextHostName (int ctxid) { __pmContext *ctxp; const char *sts; char *name; pmID pmid; pmResult *resp; int rc; static char hostbuf[MAXHOSTNAMELEN]; hostbuf[0]='\0'; if ((ctxp = __pmHandleToPtr(ctxid)) != NULL) { switch (ctxp->c_type) { case PM_CONTEXT_HOST: /* * Try and establish the hostname from the remote PMCD. * Do not nest the successive actions. That way, if any one of * them fails, we take the default. */ name = "pmcd.hostname"; rc = pmLookupName(1, &name, &pmid); if (rc >= 0) rc = pmFetch(1, &pmid, &resp); if (rc >= 0) { if (resp->vset[0]->numval > 0) { /* pmcd.hostname present */ strncpy(hostbuf, resp->vset[0]->vlist[0].value.pval->vbuf, sizeof(hostbuf)-1); pmFreeResult(resp); break; } pmFreeResult(resp); /* FALLTHROUGH */ } /* We could not get the hostname from the remote PMCD. If the * name in the context is a filesystem path (AF_UNIX address) * or is 'localhost', then use gethostname(). Otherwise, use the * name from the context. */ sts = ctxp->c_pmcd->pc_hosts[0].name; if (sts == NULL || /* no name ?! */ *sts == __pmPathSeparator() || /* AF_UNIX /path */ (strcmp(sts, "localhost") == 0)) /* localhost XXX: localhost6 etc.? */ gethostname(hostbuf, sizeof(hostbuf)); else strncpy(hostbuf, sts, sizeof(hostbuf)-1); break; case PM_CONTEXT_LOCAL: gethostname(hostbuf, sizeof(hostbuf)); break; case PM_CONTEXT_ARCHIVE: strncpy(hostbuf, ctxp->c_archctl->ac_log->l_label.ill_hostname, sizeof(hostbuf)-1); break; } hostbuf[sizeof(hostbuf)-1] = '\0'; PM_UNLOCK(ctxp->c_lock); } /* By using the static buffer, there exists a natural race * condition in multiple threads calling this function at the same * time. Still, it's better than passing back pointers directly * from ctxp->..., and slightly better than strdup()'ing results * thus leaking memory or mishandling OOM. */ return hostbuf; } int pmWhichContext(void) { /* * return curcontext, provided it is defined */ int sts; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (PM_TPD(curcontext) > PM_CONTEXT_UNDEF) sts = PM_TPD(curcontext); else sts = PM_ERR_NOCONTEXT; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmWhichContext() -> %d, cur=%d\n", sts, PM_TPD(curcontext)); #endif PM_UNLOCK(__pmLock_libpcp); return sts; } int __pmConvertTimeout(int timeo) { int tout_msec; const struct timeval *tv; switch (timeo) { case TIMEOUT_NEVER: tout_msec = -1; break; case TIMEOUT_DEFAULT: tv = __pmDefaultRequestTimeout(); tout_msec = tv->tv_sec *1000 + tv->tv_usec / 1000; break; case TIMEOUT_CONNECT: tv = __pmConnectTimeout(); tout_msec = tv->tv_sec *1000 + tv->tv_usec / 1000; break; default: tout_msec = timeo * 1000; break; } return tout_msec; } #ifdef PM_MULTI_THREAD static void __pmInitContextLock(pthread_mutex_t *lock) { pthread_mutexattr_t attr; int sts; char errmsg[PM_MAXERRMSGLEN]; /* * Need context lock to be recursive as we sometimes call * __pmHandleToPtr() while the current context is already * locked */ if ((sts = pthread_mutexattr_init(&attr)) != 0) { pmErrStr_r(-sts, errmsg, sizeof(errmsg)); fprintf(stderr, "pmNewContext: " "context=%d lock pthread_mutexattr_init failed: %s", contexts_len-1, errmsg); exit(4); } if ((sts = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) != 0) { pmErrStr_r(-sts, errmsg, sizeof(errmsg)); fprintf(stderr, "pmNewContext: " "context=%d lock pthread_mutexattr_settype failed: %s", contexts_len-1, errmsg); exit(4); } if ((sts = pthread_mutex_init(lock, &attr)) != 0) { pmErrStr_r(-sts, errmsg, sizeof(errmsg)); fprintf(stderr, "pmNewContext: " "context=%d lock pthread_mutex_init failed: %s", contexts_len-1, errmsg); exit(4); } } static void __pmInitChannelLock(pthread_mutex_t *lock) { int sts; char errmsg[PM_MAXERRMSGLEN]; if ((sts = pthread_mutex_init(lock, NULL)) != 0) { pmErrStr_r(-sts, errmsg, sizeof(errmsg)); fprintf(stderr, "pmNewContext: " "context=%d pmcd channel lock pthread_mutex_init failed: %s", contexts_len, errmsg); exit(4); } } #else #define __pmInitContextLock(x) do { } while (1) #define __pmInitChannelLock(x) do { } while (1) #endif static int ctxflags(__pmHashCtl *attrs) { int flags = 0; char *secure = NULL; __pmHashNode *node; if ((node = __pmHashSearch(PCP_ATTR_PROTOCOL, attrs)) != NULL) { if (strcmp((char *)node->data, "pcps") == 0) { if ((node = __pmHashSearch(PCP_ATTR_SECURE, attrs)) != NULL) secure = (char *)node->data; else secure = "enforce"; } } if (!secure) secure = getenv("PCP_SECURE_SOCKETS"); if (secure) { if (secure[0] == '\0' || (strcmp(secure, "1")) == 0 || (strcmp(secure, "enforce")) == 0) { flags |= PM_CTXFLAG_SECURE; } else if (strcmp(secure, "relaxed") == 0) { flags |= PM_CTXFLAG_RELAXED; } } if (__pmHashSearch(PCP_ATTR_COMPRESS, attrs) != NULL) flags |= PM_CTXFLAG_COMPRESS; if (__pmHashSearch(PCP_ATTR_USERAUTH, attrs) != NULL || __pmHashSearch(PCP_ATTR_USERNAME, attrs) != NULL || __pmHashSearch(PCP_ATTR_PASSWORD, attrs) != NULL || __pmHashSearch(PCP_ATTR_METHOD, attrs) != NULL || __pmHashSearch(PCP_ATTR_REALM, attrs) != NULL) flags |= PM_CTXFLAG_AUTH; return flags; } int pmNewContext(int type, const char *name) { __pmContext *new = NULL; __pmContext **list; int i; int sts; int old_curcontext; int old_contexts_len; PM_INIT_LOCKS(); if (PM_CONTEXT_LOCAL == (type & PM_CONTEXT_TYPEMASK) && PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) /* Local context requires single-threaded applications */ return PM_ERR_THREAD; PM_LOCK(__pmLock_libpcp); old_curcontext = PM_TPD(curcontext); old_contexts_len = contexts_len; /* See if we can reuse a free context */ for (i = 0; i < contexts_len; i++) { if (contexts[i]->c_type == PM_CONTEXT_FREE) { PM_TPD(curcontext) = i; new = contexts[i]; goto INIT_CONTEXT; } } /* Create a new one */ if (contexts == NULL) list = (__pmContext **)malloc(sizeof(__pmContext *)); else list = (__pmContext **)realloc((void *)contexts, (1+contexts_len) * sizeof(__pmContext *)); new = (__pmContext *)malloc(sizeof(__pmContext)); if (list == NULL || new == NULL) { /* fail : nothing changed, but new may have been allocated (in theory) */ if (new) memset(new, 0, sizeof(__pmContext)); sts = -oserror(); goto FAILED; } contexts = list; PM_TPD(curcontext) = contexts_len; contexts[contexts_len] = new; contexts_len++; INIT_CONTEXT: /* * Set up the default state */ memset(new, 0, sizeof(__pmContext)); __pmInitContextLock(&new->c_lock); new->c_type = (type & PM_CONTEXT_TYPEMASK); new->c_flags = (type & ~PM_CONTEXT_TYPEMASK); if ((new->c_instprof = (__pmProfile *)calloc(1, sizeof(__pmProfile))) == NULL) { /* * fail : nothing changed -- actually list is changed, but restoring * contexts_len should make it ok next time through */ sts = -oserror(); goto FAILED; } new->c_instprof->state = PM_PROFILE_INCLUDE; /* default global state */ if (new->c_type == PM_CONTEXT_HOST) { __pmHashCtl *attrs = &new->c_attrs; pmHostSpec *hosts; int nhosts; char *errmsg; /* break down a host[:port@proxy:port][?attributes] specification */ __pmHashInit(attrs); sts = __pmParseHostAttrsSpec(name, &hosts, &nhosts, attrs, &errmsg); if (sts < 0) { pmprintf("pmNewContext: bad host specification\n%s", errmsg); pmflush(); free(errmsg); goto FAILED; } else if (nhosts == 0) { sts = PM_ERR_NOTHOST; goto FAILED; } else { new->c_flags |= ctxflags(attrs); } /* As an optimization, if there is already a connection to the same PMCD, we try to reuse (share) it. */ if (nhosts == 1) { /* not proxied */ for (i = 0; i < contexts_len; i++) { if (i == PM_TPD(curcontext)) continue; if (contexts[i]->c_type == new->c_type && contexts[i]->c_flags == new->c_flags && strcmp(contexts[i]->c_pmcd->pc_hosts[0].name, hosts[0].name) == 0 && contexts[i]->c_pmcd->pc_hosts[0].nports == hosts[0].nports) { int j; int ports_same = 1; for (j=0; jc_pmcd->pc_hosts[0].ports[j] != hosts[0].ports[j]) ports_same = 0; if (ports_same) new->c_pmcd = contexts[i]->c_pmcd; } } } if (new->c_pmcd == NULL) { /* * Try to establish the connection. * If this fails, restore the original current context * and return an error. */ sts = __pmConnectPMCD(hosts, nhosts, new->c_flags, &new->c_attrs); if (sts < 0) { __pmFreeHostAttrsSpec(hosts, nhosts, attrs); __pmHashClear(attrs); goto FAILED; } new->c_pmcd = (__pmPMCDCtl *)calloc(1,sizeof(__pmPMCDCtl)); if (new->c_pmcd == NULL) { sts = -oserror(); __pmCloseSocket(sts); __pmFreeHostAttrsSpec(hosts, nhosts, attrs); __pmHashClear(attrs); goto FAILED; } new->c_pmcd->pc_fd = sts; new->c_pmcd->pc_hosts = hosts; new->c_pmcd->pc_nhosts = nhosts; new->c_pmcd->pc_tout_sec = __pmConvertTimeout(TIMEOUT_DEFAULT) / 1000; __pmInitChannelLock(&new->c_pmcd->pc_lock); } else { /* duplicate of an existing context, don't need the __pmHostSpec */ __pmFreeHostAttrsSpec(hosts, nhosts, attrs); __pmHashClear(attrs); } new->c_pmcd->pc_refcnt++; } else if (new->c_type == PM_CONTEXT_LOCAL) { if ((sts = __pmConnectLocal(&new->c_attrs)) != 0) goto FAILED; } else if (new->c_type == PM_CONTEXT_ARCHIVE) { if ((new->c_archctl = (__pmArchCtl *)malloc(sizeof(__pmArchCtl))) == NULL) { sts = -oserror(); goto FAILED; } new->c_archctl->ac_log = NULL; for (i = 0; i < contexts_len; i++) { if (i == PM_TPD(curcontext)) continue; if (contexts[i]->c_type == PM_CONTEXT_ARCHIVE && strcmp(name, contexts[i]->c_archctl->ac_log->l_name) == 0) { new->c_archctl->ac_log = contexts[i]->c_archctl->ac_log; } } if (new->c_archctl->ac_log == NULL) { if ((new->c_archctl->ac_log = (__pmLogCtl *)malloc(sizeof(__pmLogCtl))) == NULL) { free(new->c_archctl); sts = -oserror(); goto FAILED; } if ((sts = __pmLogOpen(name, new)) < 0) { free(new->c_archctl->ac_log); free(new->c_archctl); goto FAILED; } } else { /* archive already open, set default starting state as per __pmLogOpen */ new->c_origin.tv_sec = (__int32_t)new->c_archctl->ac_log->l_label.ill_start.tv_sec; new->c_origin.tv_usec = (__int32_t)new->c_archctl->ac_log->l_label.ill_start.tv_usec; new->c_mode = (new->c_mode & 0xffff0000) | PM_MODE_FORW; } /* start after header + label record + trailer */ new->c_archctl->ac_offset = sizeof(__pmLogLabel) + 2*sizeof(int); new->c_archctl->ac_vol = new->c_archctl->ac_log->l_curvol; new->c_archctl->ac_serial = 0; /* not serial access, yet */ new->c_archctl->ac_pmid_hc.nodes = 0; /* empty hash list */ new->c_archctl->ac_pmid_hc.hsize = 0; new->c_archctl->ac_end = 0.0; new->c_archctl->ac_want = NULL; new->c_archctl->ac_unbound = NULL; new->c_archctl->ac_log->l_refcnt++; } else { /* bad type */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { fprintf(stderr, "pmNewContext(%d, %s): illegal type\n", type, name); } #endif PM_UNLOCK(__pmLock_libpcp); return PM_ERR_NOCONTEXT; } /* bind defined metrics if any ... */ __dmopencontext(new); /* return the handle to the new (current) context */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { fprintf(stderr, "pmNewContext(%d, %s) -> %d\n", type, name, PM_TPD(curcontext)); __pmDumpContext(stderr, PM_TPD(curcontext), PM_INDOM_NULL); } #endif sts = PM_TPD(curcontext); PM_UNLOCK(__pmLock_libpcp); return sts; FAILED: if (new != NULL) { if (new->c_instprof != NULL) free(new->c_instprof); /* only free this pointer if it was not reclaimed from old contexts */ for (i = 0; i < old_contexts_len; i++) { if (contexts[i] != new) continue; new->c_type = PM_CONTEXT_FREE; break; } if (i == old_contexts_len) free(new); } PM_TPD(curcontext) = old_curcontext; contexts_len = old_contexts_len; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmNewContext(%d, %s) -> %d, curcontext=%d\n", type, name, sts, PM_TPD(curcontext)); #endif PM_UNLOCK(__pmLock_libpcp); return sts; } int pmReconnectContext(int handle) { __pmContext *ctxp; __pmPMCDCtl *ctl; int i, sts; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (handle < 0 || handle >= contexts_len || contexts[handle]->c_type == PM_CONTEXT_FREE) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmReconnectContext(%d) -> %d\n", handle, PM_ERR_NOCONTEXT); #endif PM_UNLOCK(__pmLock_libpcp); return PM_ERR_NOCONTEXT; } ctxp = contexts[handle]; ctl = ctxp->c_pmcd; if (ctxp->c_type == PM_CONTEXT_HOST) { if (ctl->pc_timeout && time(NULL) < ctl->pc_again) { /* too soon to try again */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmReconnectContext(%d) -> %d, too soon (need wait another %d secs)\n", handle, (int)-ETIMEDOUT, (int)(ctl->pc_again - time(NULL))); #endif PM_UNLOCK(__pmLock_libpcp); return -ETIMEDOUT; } if (ctl->pc_fd >= 0) { /* don't care if this fails */ __pmCloseSocket(ctl->pc_fd); ctl->pc_fd = -1; } if ((sts = __pmConnectPMCD(ctl->pc_hosts, ctl->pc_nhosts, ctxp->c_flags, &ctxp->c_attrs)) < 0) { waitawhile(ctl); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmReconnectContext(%d), failed (wait %d secs before next attempt)\n", handle, (int)(ctl->pc_again - time(NULL))); #endif PM_UNLOCK(__pmLock_libpcp); return -ETIMEDOUT; } else { ctl->pc_fd = sts; ctl->pc_timeout = 0; ctxp->c_sent = 0; /* mark profile as not sent for all contexts sharing this socket */ for (i = 0; i < contexts_len; i++) { if (contexts[i]->c_type != PM_CONTEXT_FREE && contexts[i]->c_pmcd == ctl) { contexts[i]->c_sent = 0; } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmReconnectContext(%d), done\n", handle); #endif } } /* clear any derived metrics and re-bind */ __dmclosecontext(ctxp); __dmopencontext(ctxp); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmReconnectContext(%d) -> %d\n", handle, handle); #endif PM_UNLOCK(__pmLock_libpcp); return handle; } int pmDupContext(void) { int sts, oldtype; int old, new = -1; char hostspec[4096]; __pmContext *newcon, *oldcon; __pmInDomProfile *q, *p, *p_end; __pmProfile *save; void *save_dm; #ifdef PM_MULTI_THREAD pthread_mutex_t save_lock; #endif PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if ((old = pmWhichContext()) < 0) { sts = old; goto done; } oldcon = contexts[old]; oldtype = oldcon->c_type | oldcon->c_flags; if (oldcon->c_type == PM_CONTEXT_HOST) { __pmUnparseHostSpec(oldcon->c_pmcd->pc_hosts, oldcon->c_pmcd->pc_nhosts, hostspec, sizeof(hostspec)); new = pmNewContext(oldtype, hostspec); } else if (oldcon->c_type == PM_CONTEXT_LOCAL) new = pmNewContext(oldtype, NULL); else /* assume PM_CONTEXT_ARCHIVE */ new = pmNewContext(oldtype, oldcon->c_archctl->ac_log->l_name); if (new < 0) { /* failed to connect or out of memory */ sts = new; goto done; } oldcon = contexts[old]; /* contexts[] may have been relocated */ newcon = contexts[new]; save = newcon->c_instprof; /* need this later */ save_dm = newcon->c_dm; /* need this later */ #ifdef PM_MULTI_THREAD save_lock = newcon->c_lock; /* need this later */ #endif if (newcon->c_archctl != NULL) free(newcon->c_archctl); /* will allocate a new one below */ *newcon = *oldcon; /* struct copy */ newcon->c_instprof = save; /* restore saved instprof from pmNewContext */ newcon->c_dm = save_dm; /* restore saved derived metrics control also */ #ifdef PM_MULTI_THREAD newcon->c_lock = save_lock; /* restore saved lock with initialized state also */ #endif /* clone the per-domain profiles (if any) */ if (oldcon->c_instprof->profile_len > 0) { newcon->c_instprof->profile = (__pmInDomProfile *)malloc( oldcon->c_instprof->profile_len * sizeof(__pmInDomProfile)); if (newcon->c_instprof->profile == NULL) { sts = -oserror(); goto done; } memcpy(newcon->c_instprof->profile, oldcon->c_instprof->profile, oldcon->c_instprof->profile_len * sizeof(__pmInDomProfile)); p = oldcon->c_instprof->profile; p_end = p + oldcon->c_instprof->profile_len; q = newcon->c_instprof->profile; for (; p < p_end; p++, q++) { if (p->instances) { q->instances = (int *)malloc(p->instances_len * sizeof(int)); if (q->instances == NULL) { sts = -oserror(); goto done; } memcpy(q->instances, p->instances, p->instances_len * sizeof(int)); } } } /* * The call to pmNewContext (above) should have connected to the pmcd. * Make sure the new profile will be sent before the next fetch. */ newcon->c_sent = 0; /* clone the archive control struct, if any */ if (oldcon->c_archctl != NULL) { if ((newcon->c_archctl = (__pmArchCtl *)malloc(sizeof(__pmArchCtl))) == NULL) { sts = -oserror(); goto done; } *newcon->c_archctl = *oldcon->c_archctl; /* struct assignment */ } sts = new; done: /* return an error code, or the handle for the new context */ if (sts < 0 && new >= 0) contexts[new]->c_type = PM_CONTEXT_FREE; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { fprintf(stderr, "pmDupContext() -> %d\n", sts); if (sts >= 0) __pmDumpContext(stderr, sts, PM_INDOM_NULL); } #endif PM_UNLOCK(__pmLock_libpcp); return sts; } int pmUseContext(int handle) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (handle < 0 || handle >= contexts_len || contexts[handle]->c_type == PM_CONTEXT_FREE) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmUseContext(%d) -> %d\n", handle, PM_ERR_NOCONTEXT); #endif PM_UNLOCK(__pmLock_libpcp); return PM_ERR_NOCONTEXT; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmUseContext(%d) -> 0\n", handle); #endif PM_TPD(curcontext) = handle; PM_UNLOCK(__pmLock_libpcp); return 0; } int pmDestroyContext(int handle) { __pmContext *ctxp; struct linger dolinger = {0, 1}; #ifdef PM_MULTI_THREAD int psts; char errmsg[PM_MAXERRMSGLEN]; #endif PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (handle < 0 || handle >= contexts_len || contexts[handle]->c_type == PM_CONTEXT_FREE) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmDestroyContext(%d) -> %d\n", handle, PM_ERR_NOCONTEXT); #endif PM_UNLOCK(__pmLock_libpcp); return PM_ERR_NOCONTEXT; } ctxp = contexts[handle]; PM_LOCK(ctxp->c_lock); if (ctxp->c_pmcd != NULL) { if (--ctxp->c_pmcd->pc_refcnt == 0) { if (ctxp->c_pmcd->pc_fd >= 0) { /* before close, unsent data should be flushed */ __pmSetSockOpt(ctxp->c_pmcd->pc_fd, SOL_SOCKET, SO_LINGER, (char *) &dolinger, (__pmSockLen)sizeof(dolinger)); __pmCloseSocket(ctxp->c_pmcd->pc_fd); } __pmFreeHostSpec(ctxp->c_pmcd->pc_hosts, ctxp->c_pmcd->pc_nhosts); free(ctxp->c_pmcd); } } if (ctxp->c_archctl != NULL) { if (--ctxp->c_archctl->ac_log->l_refcnt == 0) { __pmLogClose(ctxp->c_archctl->ac_log); free(ctxp->c_archctl->ac_log); } free(ctxp->c_archctl); } ctxp->c_type = PM_CONTEXT_FREE; if (handle == PM_TPD(curcontext)) /* we have no choice */ PM_TPD(curcontext) = PM_CONTEXT_UNDEF; __pmFreeProfile(ctxp->c_instprof); __dmclosecontext(ctxp); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmDestroyContext(%d) -> 0, curcontext=%d\n", handle, PM_TPD(curcontext)); #endif PM_UNLOCK(ctxp->c_lock); #ifdef PM_MULTI_THREAD if ((psts = pthread_mutex_destroy(&ctxp->c_lock)) != 0) { pmErrStr_r(-psts, errmsg, sizeof(errmsg)); fprintf(stderr, "pmDestroyContext: context=%d pthread_mutex_destroy failed: %s", handle, errmsg); exit(4); } #endif PM_UNLOCK(__pmLock_libpcp); return 0; } static const char *_mode[] = { "LIVE", "INTERP", "FORW", "BACK" }; /* * dump context(s); context == -1 for all contexts, indom == PM_INDOM_NULL * for all instance domains. */ void __pmDumpContext(FILE *f, int context, pmInDom indom) { int i; __pmContext *con; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); fprintf(f, "Dump Contexts: current context = %d\n", PM_TPD(curcontext)); if (PM_TPD(curcontext) < 0) { PM_UNLOCK(__pmLock_libpcp); return; } if (indom != PM_INDOM_NULL) { char strbuf[20]; fprintf(f, "Dump restricted to indom=%d [%s]\n", indom, pmInDomStr_r(indom, strbuf, sizeof(strbuf))); } for (i = 0; i < contexts_len; i++) { con = contexts[i]; if (context == -1 || context == i) { fprintf(f, "Context[%d]", i); if (con->c_type == PM_CONTEXT_HOST) { fprintf(f, " host %s:", con->c_pmcd->pc_hosts[0].name); fprintf(f, " pmcd=%s profile=%s fd=%d refcnt=%d", (con->c_pmcd->pc_fd < 0) ? "NOT CONNECTED" : "CONNECTED", con->c_sent ? "SENT" : "NOT_SENT", con->c_pmcd->pc_fd, con->c_pmcd->pc_refcnt); if (con->c_flags) fprintf(f, " flags=%x", con->c_flags); } else if (con->c_type == PM_CONTEXT_LOCAL) { fprintf(f, " standalone:"); fprintf(f, " profile=%s\n", con->c_sent ? "SENT" : "NOT_SENT"); } else { fprintf(f, " log %s:", con->c_archctl->ac_log->l_name); fprintf(f, " mode=%s", _mode[con->c_mode & __PM_MODE_MASK]); fprintf(f, " profile=%s tifd=%d mdfd=%d mfd=%d\nrefcnt=%d vol=%d", con->c_sent ? "SENT" : "NOT_SENT", con->c_archctl->ac_log->l_tifp == NULL ? -1 : fileno(con->c_archctl->ac_log->l_tifp), fileno(con->c_archctl->ac_log->l_mdfp), fileno(con->c_archctl->ac_log->l_mfp), con->c_archctl->ac_log->l_refcnt, con->c_archctl->ac_log->l_curvol); fprintf(f, " offset=%ld (vol=%d) serial=%d", (long)con->c_archctl->ac_offset, con->c_archctl->ac_vol, con->c_archctl->ac_serial); } if (con->c_type != PM_CONTEXT_LOCAL) { fprintf(f, " origin=%d.%06d", con->c_origin.tv_sec, con->c_origin.tv_usec); fprintf(f, " delta=%d\n", con->c_delta); } __pmDumpProfile(f, indom, con->c_instprof); } } PM_UNLOCK(__pmLock_libpcp); } #ifdef PM_MULTI_THREAD #ifdef PM_MULTI_THREAD_DEBUG /* * return context if lock == c_lock for a context ... no locking here * to avoid recursion ad nauseum */ int __pmIsContextLock(void *lock) { int i; for (i = 0; i < contexts_len; i++) { if ((void *)&contexts[i]->c_lock == lock) return i; } return -1; } /* * return context if lock == pc_lock for a context ... no locking here * to avoid recursion ad nauseum */ int __pmIsChannelLock(void *lock) { int i; for (i = 0; i < contexts_len; i++) { if ((void *)&contexts[i]->c_pmcd->pc_lock == lock) return i; } return -1; } #endif #endif pcp-3.8.12ubuntu1/src/libpcp/src/desc.c0000664000000000000000000000460512272262501014520 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "internal.h" int pmLookupDesc(pmID pmid, pmDesc *desc) { int n; __pmContext *ctxp; __pmPDU *pb; if ((n = pmWhichContext()) < 0) goto done; if ((ctxp = __pmHandleToPtr(n)) == NULL) { n = PM_ERR_NOCONTEXT; goto done; } if (ctxp->c_type == PM_CONTEXT_HOST) { PM_LOCK(ctxp->c_pmcd->pc_lock); if ((n = __pmSendDescReq(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), pmid)) < 0) n = __pmMapErrno(n); else { int pinpdu; pinpdu = n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, ctxp->c_pmcd->pc_tout_sec, &pb); if (n == PDU_DESC) n = __pmDecodeDesc(pb, desc); else if (n == PDU_ERROR) __pmDecodeError(pb, &n); else if (n != PM_ERR_TIMEOUT) n = PM_ERR_IPC; if (pinpdu > 0) __pmUnpinPDUBuf(pb); } PM_UNLOCK(ctxp->c_pmcd->pc_lock); } else if (ctxp->c_type == PM_CONTEXT_LOCAL) { int ctx = n; __pmDSO *dp; if (PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) /* Local context requires single-threaded applications */ n = PM_ERR_THREAD; else if ((dp = __pmLookupDSO(((__pmID_int *)&pmid)->domain)) == NULL) n = PM_ERR_NOAGENT; else { if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; n = dp->dispatch.version.any.desc(pmid, desc, dp->dispatch.version.any.ext); } } else { /* assume PM_CONTEXT_ARCHIVE */ n = __pmLogLookupDesc(ctxp->c_archctl->ac_log, pmid, desc); } if (n == PM_ERR_PMID || n == PM_ERR_PMID_LOG || n == PM_ERR_NOAGENT) { int sts; /* * check for derived metric ... keep error status from above * unless we have success with the derived metrics */ sts = __dmdesc(ctxp, pmid, desc); if (sts >= 0) n = sts; } PM_UNLOCK(ctxp->c_lock); done: return n; } pcp-3.8.12ubuntu1/src/libpcp/src/rtime.c0000664000000000000000000004310612272262501014721 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include #include "pmapi.h" #include "impl.h" /**************************************************************************** * macros ****************************************************************************/ #define CODE3(a,b,c) ((__uint32_t)(a)|((__uint32_t)(b)<<8)|((__uint32_t)(c)<<16)) /**************************************************************************** * constants ****************************************************************************/ #define whatmsg "unexpected value" #define moremsg "more information expected" #define alignmsg "alignment specified by -A switch could not be applied" #define N_WDAYS 7 static const __uint32_t wdays[N_WDAYS] = { CODE3('s', 'u', 'n'), CODE3('m', 'o', 'n'), CODE3('t', 'u', 'e'), CODE3('w', 'e', 'd'), CODE3('t', 'h', 'u'), CODE3('f', 'r', 'i'), CODE3('s', 'a', 't') }; #define N_MONTHS 12 static const __uint32_t months[N_MONTHS] = { CODE3('j', 'a', 'n'), CODE3('f', 'e', 'b'), CODE3('m', 'a', 'r'), CODE3('a', 'p', 'r'), CODE3('m', 'a', 'y'), CODE3('j', 'u', 'n'), CODE3('j', 'u', 'l'), CODE3('a', 'u', 'g'), CODE3('s', 'e', 'p'), CODE3('o', 'c', 't'), CODE3('n', 'o', 'v'), CODE3('d', 'e', 'c') }; #define N_AMPM 2 static const __uint32_t ampm[N_AMPM] = { CODE3('a', 'm', 0 ), CODE3('p', 'm', 0 ) }; static const struct { char *name; /* pmParseInterval scale name */ int len; /* length of scale name */ int scale; /* <0 -divisor, else multiplier */ } int_tab[] = { { "millisecond", 11, -1000 }, { "second", 6, 1 }, { "minute", 6, 60 }, { "hour", 4, 3600 }, { "day", 3, 86400 }, { "msec", 4, -1000 }, { "sec", 3, 1 }, { "min", 3, 60 }, { "hr", 2, 3600 }, { "s", 1, 1 }, { "m", 1, 60 }, { "h", 1, 3600 }, { "d", 1, 86400 }, }; static const int numint = sizeof(int_tab) / sizeof(int_tab[0]); #define NO_OFFSET 0 #define PLUS_OFFSET 1 #define NEG_OFFSET 2 /**************************************************************************** * local functions ****************************************************************************/ /* Compare struct timevals */ static int /* 0 -> equal, -1 -> tv1 < tv2, 1 -> tv1 > tv2 */ tvcmp(struct timeval tv1, struct timeval tv2) { if (tv1.tv_sec < tv2.tv_sec) return -1; if (tv1.tv_sec > tv2.tv_sec) return 1; if (tv1.tv_usec < tv2.tv_usec) return -1; if (tv1.tv_usec > tv2.tv_usec) return 1; return 0; } /* Recognise three character string as one of the given codes. return: 1 == ok, 0 <= *rslt <= ncodes-1, *spec points to following char 0 == not found, *spec updated to strip blanks */ static int parse3char(const char **spec, const __uint32_t *codes, int ncodes, int *rslt) { const char *scan = *spec; __uint32_t code = 0; int i; while (isspace((int)*scan)) scan++; *spec = scan; if (! isalpha((int)*scan)) return 0; for (i = 0; i <= 16; i += 8) { code |= (tolower((int)*scan) << i); scan++; if (! isalpha((int)*scan)) break; } for (i = 0; i < ncodes; i++) { if (code == codes[i]) { *spec = scan; *rslt = i; return 1; } } return 0; } /* Recognise single char (with optional leading space) */ static int parseChar(const char **spec, char this) { const char *scan = *spec; while (isspace((int)*scan)) scan++; *spec = scan; if (*scan != this) return 0; *spec = scan + 1; return 1; } /* Recognise integer in range min..max return: 1 == ok, min <= *rslt <= max, *spec points to following char 0 == not found, *spec updated to strip blanks */ static int parseInt(const char **spec, int min, int max, int *rslt) { const char *scan = *spec; char *tmp; long r; while (isspace((int)*scan)) scan++; tmp = (char *)scan; r = strtol(scan, &tmp, 10); *spec = tmp; if (scan == *spec || r < min || r > max) { *spec = scan; return 0; } *rslt = (int)r; return 1; } /* Recognise double precision float in the range min..max return: 1 == ok, min <= *rslt <= max, *spec points to following char 0 == not found, *spec updated to strip blanks */ static double parseDouble(const char **spec, double min, double max, double *rslt) { const char *scan = *spec; char *tmp; double r; while (isspace((int)*scan)) scan++; tmp = (char *)scan; r = strtod(scan, &tmp); *spec = tmp; if (scan == *spec || r < min || r > max) { *spec = scan; return 0; } *rslt = r; return 1; } /* Construct error message buffer for syntactic error */ static void parseError(const char *spec, const char *point, char *msg, char **rslt) { int need = 2 * (int)strlen(spec) + (int)strlen(msg) + 8; const char *p; char *q; if ((*rslt = malloc(need)) == NULL) __pmNoMem("__pmParseTime", need, PM_FATAL_ERR); q = *rslt; for (p = spec; *p != '\0'; p++) *q++ = *p; *q++ = '\n'; for (p = spec; p != point; p++) *q++ = isgraph((int)*p) ? ' ' : *p; sprintf(q, "^ -- "); q += 5; for (p = msg; *p != '\0'; p++) *q++ = *p; *q++ = '\n'; *q = '\0'; } /**************************************************************************** * exported functions ****************************************************************************/ int /* 0 -> ok, -1 -> error */ pmParseInterval( const char *spec, /* interval to parse */ struct timeval *rslt, /* result stored here */ char **errmsg) /* error message */ { const char *scan = spec; double d; double sec = 0.0; int i; const char *p; int len; if (scan == NULL || *scan == '\0') { char *empty = ""; parseError(empty, empty, "Null or empty specification", errmsg); return -1; } /* parse components of spec */ while (*scan != '\0') { if (! parseDouble(&scan, 0.0, (double)INT_MAX, &d)) break; while (*scan != '\0' && isspace((int)*scan)) scan++; if (*scan == '\0') { /* no scale, seconds is the default */ sec += d; break; } for (p = scan; *p && isalpha((int)*p); p++) ; len = (int)(p - scan); if (len == 0) /* no scale, seconds is the default */ sec += d; else { if (len > 1 && (p[-1] == 's' || p[-1] == 'S')) /* ignore any trailing 's' */ len--; for (i = 0; i < numint; i++) { if (len != int_tab[i].len) continue; if (strncasecmp(scan, int_tab[i].name, len) == 0) break; } if (i == numint) break; if (int_tab[i].scale < 0) sec += d / (-int_tab[i].scale); else sec += d * int_tab[i].scale; } scan = p; } /* error detection */ if (*scan != '\0') { parseError(spec, scan, whatmsg, errmsg); return -1; } /* convert into seconds and microseconds */ rslt->tv_sec = (time_t)sec; rslt->tv_usec = (int)(1000000.0 * (sec - (double)rslt->tv_sec)); return 0; } int /* 0 -> ok, -1 -> error */ __pmParseCtime( const char *spec, /* ctime string to parse */ struct tm *rslt, /* result stored here */ char **errmsg) /* error message */ { struct tm tm = {-1, -1, -1, -1, -1, -1, NO_OFFSET, -1, -1}; double d; const char *scan = spec; int pm = -1; int ignored = -1; int dflt; /* parse time spec */ parse3char(&scan, wdays, N_WDAYS, &ignored); parse3char(&scan, months, N_MONTHS, &tm.tm_mon); /* * (tes & nathans comment): * This used to look like this - * parseInt(&scan, 1, 31, &tm.tm_mday); * parseInt(&scan, 0, 23, &tm.tm_hour); * if (tm.tm_hour == -1 && tm.tm_mday > 0 && tm.tm_mday < 23 && * (tm.tm_mon == -1 || *scan == ':')) { * tm.tm_hour = tm.tm_mday; * tm.tm_mday = -1; * } * This is busted when the hour is past 11pm. */ parseInt(&scan, 0, 31, &tm.tm_mday); parseInt(&scan, 0, 23, &tm.tm_hour); if (tm.tm_mday == 0 && tm.tm_hour != -1) { tm.tm_mday = -1; } if (tm.tm_hour == -1 && tm.tm_mday >= 0 && tm.tm_mday <= 23 && (tm.tm_mon == -1 || *scan == ':')) { tm.tm_hour = tm.tm_mday; tm.tm_mday = -1; } if (parseChar(&scan, ':')) { if (tm.tm_hour == -1) tm.tm_hour = 0; tm.tm_min = 0; /* for moreError checking */ parseInt(&scan, 0, 59, &tm.tm_min); if (parseChar(&scan, ':')) { if (parseDouble(&scan, 0.0, 61.0, &d)) { tm.tm_sec = (time_t)d; tm.tm_yday = (int)(1000000.0 * (d - tm.tm_sec)); } } } if (parse3char(&scan, ampm, N_AMPM, &pm)) { if (tm.tm_hour > 12 || tm.tm_hour == -1) scan -= 2; else { if (pm) { if (tm.tm_hour < 12) tm.tm_hour += 12; } else { if (tm.tm_hour == 12) tm.tm_hour = 0; } } } /* * parse range forces tm_year to be >= 1900, so this is Y2K safe */ if (parseInt(&scan, 1900, 9999, &tm.tm_year)) tm.tm_year -= 1900; /* * error detection and reporting * * in the code below, tm_year is either years since 1900 or * -1 (a sentinel), so this is is Y2K safe */ while (isspace((int)*scan)) scan++; if (*scan != '\0') { parseError(spec, scan, whatmsg, errmsg); return -1; } if ((ignored != -1 && tm.tm_mon == -1 && tm.tm_mday == -1) || (tm.tm_hour != -1 && tm.tm_min == -1 && tm.tm_mday == -1 && tm.tm_mon == -1 && tm.tm_year == -1)) { parseError(spec, scan, moremsg, errmsg); return -1; } /* fill in elements of tm from spec */ dflt = (tm.tm_year != -1); if (tm.tm_mon != -1) dflt = 1; else if (dflt) tm.tm_mon = 0; if (tm.tm_mday != -1) dflt = 1; else if (dflt) tm.tm_mday = 1; if (tm.tm_hour != -1) dflt = 1; else if (dflt) tm.tm_hour = 0; if (tm.tm_min != -1) dflt = 1; else if (dflt) tm.tm_min = 0; if (tm.tm_sec == -1 && dflt) { tm.tm_sec = 0; tm.tm_yday = 0; } *rslt = tm; return 0; } int /* 0 ok, -1 error */ __pmConvertTime( struct tm *tmin, /* absolute or +ve or -ve offset time */ struct timeval *origin, /* defaults and origin for offset */ struct timeval *rslt) /* result stored here */ { time_t t; struct timeval tval = *origin; struct tm tm; /* positive offset interval */ if (tmin->tm_wday == PLUS_OFFSET) { tval.tv_usec += tmin->tm_yday; if (tval.tv_usec > 1000000) { tval.tv_usec -= 1000000; tval.tv_sec++; } tval.tv_sec += tmin->tm_sec; } /* negative offset interval */ else if (tmin->tm_wday == NEG_OFFSET) { if (tval.tv_usec < tmin->tm_yday) { tval.tv_usec += 1000000; tval.tv_sec--; } tval.tv_usec -= tmin->tm_yday; tval.tv_sec -= tmin->tm_sec; } /* absolute time */ else { /* tmin completely specified */ if (tmin->tm_year != -1) { tm = *tmin; tval.tv_usec = tmin->tm_yday; } /* tmin partially specified */ else { t = (time_t)tval.tv_sec; pmLocaltime(&t, &tm); tm.tm_isdst = -1; /* fill in elements of tm from spec */ if (tmin->tm_mon != -1) { if (tmin->tm_mon < tm.tm_mon) /* * tm_year is years since 1900 and the tm_year++ is * adjusting for the specified month being before the * current month, so this is Y2K safe */ tm.tm_year++; tm.tm_mon = tmin->tm_mon; tm.tm_mday = tmin->tm_mday; tm.tm_hour = tmin->tm_hour; tm.tm_min = tmin->tm_min; tm.tm_sec = tmin->tm_sec; tval.tv_usec = tmin->tm_yday; } else if (tmin->tm_mday != -1) { if (tmin->tm_mday < tm.tm_mday) tm.tm_mon++; tm.tm_mday = tmin->tm_mday; tm.tm_hour = tmin->tm_hour; tm.tm_min = tmin->tm_min; tm.tm_sec = tmin->tm_sec; tval.tv_usec = tmin->tm_yday; } else if (tmin->tm_hour != -1) { if (tmin->tm_hour < tm.tm_hour) tm.tm_mday++; tm.tm_hour = tmin->tm_hour; tm.tm_min = tmin->tm_min; tm.tm_sec = tmin->tm_sec; tval.tv_usec = tmin->tm_yday; } else if (tmin->tm_min != -1) { if (tmin->tm_min < tm.tm_min) tm.tm_hour++; tm.tm_min = tmin->tm_min; tm.tm_sec = tmin->tm_sec; tval.tv_usec = tmin->tm_yday; } else if (tmin->tm_sec != -1) { if (tmin->tm_sec < tm.tm_sec) tm.tm_min++; tm.tm_sec = tmin->tm_sec; tval.tv_usec = tmin->tm_yday; } } tval.tv_sec = __pmMktime(&tm); } *rslt = tval; return 0; } int /* 0 -> ok, -1 -> error */ __pmParseTime( const char *string, /* string to be parsed */ struct timeval *logStart, /* start of log or current time */ struct timeval *logEnd, /* end of log or tv_sec == INT_MAX */ /* assumes sizeof(t_time) == sizeof(int) */ struct timeval *rslt, /* if parsed ok, result filled in */ char **errMsg) /* error message, please free */ { struct tm tm; const char *scan; struct timeval start; struct timeval end; struct timeval tval; start = *logStart; end = *logEnd; if (end.tv_sec == INT_MAX) end.tv_usec = 999999; scan = string; /* ctime string */ if (parseChar(&scan, '@')) { if (__pmParseCtime(scan, &tm, errMsg) < 0) return -1; tm.tm_wday = NO_OFFSET; __pmConvertTime(&tm, &start, rslt); } /* relative to end of archive */ else if (end.tv_sec < INT_MAX && parseChar(&scan, '-')) { if (pmParseInterval(scan, &tval, errMsg) < 0) return -1; tm.tm_wday = NEG_OFFSET; tm.tm_sec = (int)tval.tv_sec; tm.tm_yday = (int)tval.tv_usec; __pmConvertTime(&tm, &end, rslt); } /* relative to start of archive or current time */ else { parseChar(&scan, '+'); if (pmParseInterval(scan, &tval, errMsg) < 0) return -1; tm.tm_wday = PLUS_OFFSET; tm.tm_sec = (int)tval.tv_sec; tm.tm_yday = (int)tval.tv_usec; __pmConvertTime(&tm, &start, rslt); } return 0; } /* This function is designed to encapsulate the interpretation of the -S, -T, -A and -O command line switches for use by the PCP client tools. */ int /* 1 -> ok, 0 -> warning, -1 -> error */ pmParseTimeWindow( const char *swStart, /* argument of -S switch, may be NULL */ const char *swEnd, /* argument of -T switch, may be NULL */ const char *swAlign, /* argument of -A switch, may be NULL */ const char *swOffset, /* argument of -O switch, may be NULL */ const struct timeval *logStart, /* start of log or current time */ const struct timeval *logEnd, /* end of log or tv_sec == INT_MAX */ struct timeval *rsltStart, /* start time returned here */ struct timeval *rsltEnd, /* end time returned here */ struct timeval *rsltOffset,/* offset time returned here */ char **errMsg) /* error message, please free */ { struct timeval astart; struct timeval start; struct timeval end; struct timeval offset; struct timeval aoffset; struct timeval tval; const char *scan; __int64_t delta = 0; /* initialize to pander to gcc */ __int64_t align; __int64_t blign; int sts = 1; /* default values for start and end */ start = *logStart; end = *logEnd; if (end.tv_sec == INT_MAX) end.tv_usec = 999999; /* parse -S argument and adjust start accordingly */ if (swStart) { if (__pmParseTime(swStart, &start, &end, &start, errMsg) < 0) return -1; } /* sanity check -S */ if (tvcmp(start, *logStart) < 0) /* move start forwards to the beginning of the archive */ start = *logStart; /* parse -A argument and adjust start accordingly */ if (swAlign) { scan = swAlign; if (pmParseInterval(scan, &tval, errMsg) < 0) return -1; delta = tval.tv_usec + 1000000 * (__int64_t)tval.tv_sec; align = start.tv_usec + 1000000 * (__int64_t)start.tv_sec; blign = (align / delta) * delta; if (blign < align) blign += delta; astart.tv_sec = (time_t)(blign / 1000000); astart.tv_usec = (int)(blign % 1000000); /* sanity check -S after alignment */ if (tvcmp(astart, *logStart) >= 0 && tvcmp(astart, *logEnd) <= 0) start = astart; else { parseError(swAlign, swAlign, alignmsg, errMsg); sts = 0; } } /* parse -T argument and adjust end accordingly */ if (swEnd) { if (__pmParseTime(swEnd, &start, &end, &end, errMsg) < 0) return -1; } /* sanity check -T */ if (tvcmp(end, *logEnd) > 0) /* move end backwards to the end of the archive */ end = *logEnd; /* parse -O argument and align if required */ offset = start; if (swOffset) { if (__pmParseTime(swOffset, &start, &end, &offset, errMsg) < 0) return -1; /* sanity check -O */ if (tvcmp(offset, start) < 0) offset = start; else if (tvcmp(offset, end) > 0) offset = end; if (swAlign) { align = offset.tv_usec + 1000000 * (__int64_t)offset.tv_sec; blign = (align / delta) * delta; if (blign < align) blign += delta; align = end.tv_usec + 1000000 * (__int64_t)end.tv_sec; if (blign > align) blign -= delta; aoffset.tv_sec = (time_t)(blign / 1000000); aoffset.tv_usec = (int)(blign % 1000000); /* sanity check -O after alignment */ if (tvcmp(aoffset, start) >= 0 && tvcmp(aoffset, end) <= 0) offset = aoffset; else { parseError(swAlign, swAlign, alignmsg, errMsg); sts = 0; } } } /* return results */ *rsltStart = start; *rsltEnd = end; *rsltOffset = offset; return sts; } pcp-3.8.12ubuntu1/src/libpcp/src/fault.c0000664000000000000000000001663612272262501014724 0ustar /* * Copyright (c) 2011 Ken McDonell. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "fault.h" /* need pmda.h and libpcp_pmda for the pmdaCache* routines */ #include "pmda.h" #include /* * Fault Injection - run-time control structure */ typedef struct { int ntrip; int op; int thres; int nfault; } control_t; #define PM_FAULT_LT 0 #define PM_FAULT_LE 1 #define PM_FAULT_EQ 2 #define PM_FAULT_GE 3 #define PM_FAULT_GT 4 #define PM_FAULT_NE 5 #define PM_FAULT_MOD 6 #ifdef PM_FAULT_INJECTION int __pmFault_arm; #define FAULT_INDOM pmInDom_build(DYNAMIC_PMID, 1024) static void __pmFaultAtExit(void) { __pmFaultSummary(stderr); } void __pmFaultInject(const char *ident, int class) { static int first = 1; int sts; control_t *cp; if (first) { char *fname = getenv("PM_FAULT_CONTROL"); if (fname != NULL) { FILE *f; if ((f = fopen(fname, "r")) == NULL) { char msgbuf[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmFaultInject: cannot open \"%s\": %s\n", fname, pmErrStr_r(-errno, msgbuf, sizeof(msgbuf))); } else { char line[128]; int lineno = 0; /* * control line format * ident - start of line to first white space * guard - optional, consists of and threshold * is one of <, <=, ==, >=, >=, != or % * threshold is an integer value ... * fault will be injected when * tripcount threshold == 1 * default guard is ">0", i.e. fault on every trip * leading # => comment */ pmdaCacheOp(FAULT_INDOM, PMDA_CACHE_CULL); while (fgets(line, sizeof(line), f) != NULL) { char *lp = line; char *sp; char *ep; int op; int thres; lineno++; while (*lp) { if (*lp == '\n') { *lp = '\0'; break; } lp++; } lp = line; while (*lp && isspace((int)*lp)) lp++; /* comment? */ if (*lp == '#') continue; sp = lp; while (*lp && !isspace((int)*lp)) lp++; /* empty line? */ if (lp == sp) continue; ep = lp; while (*lp && isspace((int)*lp)) lp++; if (*lp == '\0') { op = PM_FAULT_GT; thres = 0; } else { if (strncmp(lp, "<=", 2) == 0) { op = PM_FAULT_LE; lp +=2; } else if (strncmp(lp, ">=", 2) == 0) { op = PM_FAULT_GE; lp +=2; } else if (strncmp(lp, "!=", 2) == 0) { op = PM_FAULT_NE; lp +=2; } else if (strncmp(lp, "==", 2) == 0) { op = PM_FAULT_EQ; lp +=2; } else if (*lp == '<') { op = PM_FAULT_LT; lp++; } else if (*lp == '>') { op = PM_FAULT_GT; lp++; } else if (*lp == '%') { op = PM_FAULT_MOD; lp++; } else { fprintf(stderr, "Ignoring: %s[%d]: illegal operator: %s\n", fname, lineno, line); continue; } } while (*lp && isspace((int)*lp)) lp++; thres = (int)strtol(lp, &lp, 10); while (*lp && isspace((int)*lp)) lp++; if (*lp != '\0') { fprintf(stderr, "Ignoring: %s[%d]: non-numeric threshold: %s\n", fname, lineno, line); continue; } cp = (control_t *)malloc(sizeof(control_t)); if (cp == NULL) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmFaultInject: malloc failed: %s\n", pmErrStr_r(-errno, errmsg, sizeof(errmsg))); break; } *ep = '\0'; cp->ntrip = cp->nfault = 0; cp->op = op; cp->thres = thres; sts = pmdaCacheStore(FAULT_INDOM, PMDA_CACHE_ADD, sp, cp); if (sts < 0) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "%s[%d]: %s\n", fname, lineno, pmErrStr_r(sts, errmsg, sizeof(errmsg))); } } fclose(f); } } #ifdef HAVE_ATEXIT #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_FAULT) atexit(__pmFaultAtExit); #endif #endif first = 0; } sts = pmdaCacheLookupName(FAULT_INDOM, ident, NULL, (void **)&cp); if (sts == PMDA_CACHE_ACTIVE) { cp->ntrip++; __pmFault_arm = 0; switch (cp->op) { case PM_FAULT_LT: __pmFault_arm = (cp->ntrip < cp->thres) ? class : 0; break; case PM_FAULT_LE: __pmFault_arm = (cp->ntrip <= cp->thres) ? class : 0; break; case PM_FAULT_EQ: __pmFault_arm = (cp->ntrip == cp->thres) ? class : 0; break; case PM_FAULT_GE: __pmFault_arm = (cp->ntrip >= cp->thres) ? class : 0; break; case PM_FAULT_GT: __pmFault_arm = (cp->ntrip > cp->thres) ? class : 0; break; case PM_FAULT_NE: __pmFault_arm = (cp->ntrip != cp->thres) ? class : 0; break; case PM_FAULT_MOD: __pmFault_arm = ((cp->ntrip % cp->thres) == 1) ? class : 0; break; } if (__pmFault_arm != 0) cp->nfault++; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_FAULT) fprintf(stderr, "__pmFaultInject(%s) ntrip=%d %s\n", ident, cp->ntrip, __pmFault_arm == 0 ? "SKIP" : "INJECT"); #endif } else if (sts == PM_ERR_INST) { /* * expected for injection points that are compiled in the code * but not registered via the control file */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_FAULT) fprintf(stderr, "__pmFaultInject(%s) not registered\n", ident); #endif ; } else { /* oops, this is serious */ char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmFaultInject(%s): %s\n", ident, pmErrStr_r(sts, errmsg, sizeof(errmsg))); } } void __pmFaultSummary(FILE *f) { int inst; char *ident; control_t *cp; int sts; static char *opstr[] = { "<", "<=", "==", ">=", ">", "!=", "%" }; pmdaCacheOp(FAULT_INDOM, PMDA_CACHE_WALK_REWIND); fprintf(f, "=== Fault Injection Summary Report ===\n"); while ((inst = pmdaCacheOp(FAULT_INDOM, PMDA_CACHE_WALK_NEXT)) != -1) { sts = pmdaCacheLookup(FAULT_INDOM, inst, &ident, (void **)&cp); if (sts < 0) { char strbuf[20]; char errmsg[PM_MAXERRMSGLEN]; fprintf(f, "pmdaCacheLookup(%s, %d, %s, ..): %s\n", pmInDomStr_r(FAULT_INDOM, strbuf, sizeof(strbuf)), inst, ident, pmErrStr_r(sts, errmsg, sizeof(errmsg))); } else fprintf(f, "%s: guard trip%s%d, %d trips, %d faults\n", ident, opstr[cp->op], cp->thres, cp->ntrip, cp->nfault); } } void *__pmFault_malloc(size_t size) { if (__pmFault_arm == PM_FAULT_ALLOC) { __pmFault_arm = 0; errno = ENOMEM; return NULL; } else #undef malloc return malloc(size); } void *__pmFault_realloc(void *ptr, size_t size) { if (__pmFault_arm == PM_FAULT_ALLOC) { __pmFault_arm = 0; errno = ENOMEM; return NULL; } else #undef realloc return realloc(ptr, size); } char * __pmFault_strdup(const char *s) { if (__pmFault_arm == PM_FAULT_ALLOC) { __pmFault_arm = 0; errno = ENOMEM; return NULL; } else #undef strdup return strdup(s); } #else void __pmFaultInject(const char *ident, int class) { fprintf(stderr, "__pmFaultInject() called but library not compiled with -DPM_FAULT_INJECTION\n"); exit(1); } void __pmFaultSummary(FILE *f) { fprintf(f, "__pmFaultSummary() called but library not compiled with -DPM_FAULT_INJECTION\n"); exit(1); } #endif pcp-3.8.12ubuntu1/src/libpcp/src/win32.c0000664000000000000000000004432512272262501014547 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 2008-2010 Aconex. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ /* * For the MinGW headers and library to work correctly, we need * something newer than the default Windows 95 versions of the Win32 * APIs. 0x0500 is the magic sauce to select the Windows 2000 version * of the Win32 APIs, which is the minimal version needed for PCP. * * WINVER needs to be set before any of the MinGW headers are processed * and we include from pmapi.h via platform_defs.h. * * Thanks to "Earnie" on the mingw-users@lists.sourceforge.net mailing * list for this tip. */ #define WINVER 0x0500 #include "pmapi.h" #include "impl.h" #include #include #define FILETIME_1970 116444736000000000ull /* 1/1/1601-1/1/1970 */ #define HECTONANOSEC_PER_SEC 10000000ull #define MILLISEC_PER_SEC 1000 #define NANOSEC_PER_MILLISEC 1000000ull #define NANOSEC_BOUND (1000000000ull - 1) #define MAX_SIGNALS 3 /* HUP, USR1, TERM */ static struct { int signal; HANDLE eventhandle; HANDLE waithandle; __pmSignalHandler callback; } signals[MAX_SIGNALS]; VOID CALLBACK SignalCallback(PVOID param, BOOLEAN timerorwait) { int index = (int)param; if (index >= 0 && index < MAX_SIGNALS) signals[index].callback(signals[index].signal); else fprintf(stderr, "SignalCallback: bad signal index (%d)\n", index); } static char * MapSignals(int sig, int *index) { static char name[8]; switch (sig) { case SIGHUP: *index = 0; strcpy(name, "SIGHUP"); break; case SIGUSR1: *index = 1; strcpy(name, "SIGUSR1"); break; case SIGTERM: *index = 2; strcpy(name, "SIGTERM"); break; default: return NULL; } return name; } int __pmSetSignalHandler(int sig, __pmSignalHandler func) { int sts, index; char *signame, evname[64]; HANDLE eventhdl, waithdl; if ((signame = MapSignals(sig, &index)) < 0) return index; if (signals[index].callback) { /* remove old handler */ UnregisterWait(signals[index].waithandle); CloseHandle(signals[index].eventhandle); signals[index].callback = NULL; signals[index].signal = -1; } if (func == SIG_IGN) return 0; sts = 0; snprintf(evname, sizeof(evname), "PCP/%" FMT_PID "/%s", getpid(), signame); if (!(eventhdl = CreateEvent(NULL, FALSE, FALSE, TEXT(evname)))) { sts = GetLastError(); fprintf(stderr, "CreateEvent::%s failed (%d)\n", signame, sts); } else if (!RegisterWaitForSingleObject(&waithdl, eventhdl, SignalCallback, (PVOID)index, INFINITE, 0)) { sts = GetLastError(); fprintf(stderr, "RegisterWait::%s failed (%d)\n", signame, sts); } else { signals[index].eventhandle = eventhdl; signals[index].waithandle = waithdl; signals[index].callback = func; signals[index].signal = sig; } return sts; } static void sigterm_callback(int sig) { exit(0); /* give atexit(3) handlers a look-in */ } int __pmSetProcessIdentity(const char *username) { (void)username; return 0; /* Not Yet Implemented */ } int __pmSetProgname(const char *program) { int sts1, sts2; char *p, *suffix = NULL; WORD wVersionRequested = MAKEWORD(2, 2); WSADATA wsaData; /* Trim command name of leading directory components and ".exe" suffix */ if (program) pmProgname = (char *)program; for (p = pmProgname; pmProgname && *p; p++) { if (*p == '\\' || *p == '/') pmProgname = p + 1; if (*p == '.') suffix = p; } if (suffix && strcmp(suffix, ".exe") == 0) *suffix = '\0'; /* Deal with all files in binary mode - no EOL futzing */ _fmode = O_BINARY; /* * If Windows networking is not setup, all networking calls fail; * this even includes gethostname(2), if you can believe that. :[ */ sts1 = WSAStartup(wVersionRequested, &wsaData); /* * Here we are emulating POSIX signals using Event objects. * For all processes we want a SIGTERM handler, which allows * us an opportunity to cleanly shutdown: atexit(1) handlers * get a look-in, IOW. Other signals (HUP/USR1) are handled * in a similar way, but only by processes that need them. */ sts2 = __pmSetSignalHandler(SIGTERM, sigterm_callback); return sts1 | sts2; } void * __pmMemoryMap(int fd, size_t sz, int writable) { void *addr = NULL; int cflags = writable ? PAGE_READWRITE : PAGE_READONLY; HANDLE handle = CreateFileMapping((HANDLE)_get_osfhandle(fd), NULL, cflags, 0, sz, NULL); if (handle != NULL) { int mflags = writable ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ; addr = MapViewOfFile(handle, mflags, 0, 0, sz); CloseHandle(handle); if (addr == MAP_FAILED) return NULL; } return addr; } void __pmMemoryUnmap(void *addr, size_t sz) { (void)sz; UnmapViewOfFile(addr); } int __pmProcessExists(pid_t pid) { HANDLE ph = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid); if (ph == NULL) return 0; CloseHandle(ph); return 1; } int __pmProcessTerminate(pid_t pid, int force) { HANDLE ph = OpenProcess(PROCESS_TERMINATE, FALSE, pid); if (ph != NULL) { TerminateProcess(ph, 0); CloseHandle(ph); return 0; } return -ESRCH; } pid_t __pmProcessCreate(char **argv, int *infd, int *outfd) { HANDLE hChildStdinRd, hChildStdinWr, hChildStdoutRd, hChildStdoutWr; PROCESS_INFORMATION piProcInfo; SECURITY_ATTRIBUTES saAttr; STARTUPINFO siStartInfo; LPTSTR cmdline = NULL; char *command; int i, sz = 0; ZeroMemory(&saAttr, sizeof(SECURITY_ATTRIBUTES)); saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; /* pipe handles are inherited. */ saAttr.lpSecurityDescriptor = NULL; /* * Create a pipe for communication with the child process. * Ensure that the read handle to the child process's pipe for * STDOUT is not inherited. */ if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) return -1; SetHandleInformation(hChildStdoutRd, HANDLE_FLAG_INHERIT, 0); /* * Create a pipe for the child process's STDIN. * Ensure that the write handle to the child process's pipe for * STDIN is not inherited. */ if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) { CloseHandle(hChildStdoutRd); CloseHandle(hChildStdoutWr); return -1; } SetHandleInformation(hChildStdinWr, HANDLE_FLAG_INHERIT, 0); ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.hStdOutput = hChildStdoutWr; siStartInfo.hStdInput = hChildStdinRd; siStartInfo.dwFlags |= STARTF_USESTDHANDLES; /* Flatten the argv array for the Windows CreateProcess API */ for (command = argv[0], i = 0; command && *command; command = argv[++i]) { int length = strlen(command); cmdline = realloc(cmdline, sz + length + 1); /* 1space or 1null */ strcpy(&cmdline[sz], command); cmdline[sz + length] = ' '; sz += length + 1; } cmdline[sz - 1] = '\0'; if (0 == CreateProcess(NULL, cmdline, /* command line */ NULL, /* process security attributes */ NULL, /* primary thread security attributes */ TRUE, /* handles are inherited */ 0, /* creation flags */ NULL, /* use parent's environment */ NULL, /* use parent's current directory */ &siStartInfo, /* STARTUPINFO pointer */ &piProcInfo)) /* receives PROCESS_INFORMATION */ { CloseHandle(hChildStdinRd); CloseHandle(hChildStdinWr); CloseHandle(hChildStdoutRd); CloseHandle(hChildStdoutWr); return -1; } else { CloseHandle(piProcInfo.hProcess); CloseHandle(piProcInfo.hThread); } *infd = _open_osfhandle((intptr_t)hChildStdoutRd, _O_RDONLY); *outfd = _open_osfhandle((intptr_t)hChildStdinWr, _O_WRONLY); return piProcInfo.dwProcessId; } pid_t __pmProcessWait(pid_t pid, int nowait, int *code, int *signal) { HANDLE ph; DWORD status; if (pid == (pid_t)-1 || pid == (pid_t)-2) return -1; if ((ph = OpenProcess(SYNCHRONIZE, FALSE, pid)) == NULL) return -1; if (WaitForSingleObject(ph, (DWORD)(-1L)) == WAIT_FAILED) { CloseHandle(ph); return -1; } if (GetExitCodeProcess(ph, &status)) { CloseHandle(ph); return -1; } if (code) *code = status; CloseHandle(ph); *signal = -1; return pid; } int __pmProcessDataSize(unsigned long *datasize) { PROCESS_MEMORY_COUNTERS pmc; HANDLE ph; int sts = -1; if (!datasize) return 0; *datasize = 0UL; ph = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId()); if (ph == NULL) return sts; else if (GetProcessMemoryInfo(ph, &pmc, sizeof(pmc))) { *datasize = pmc.WorkingSetSize / 1024; sts = 0; } CloseHandle(ph); return sts; } int __pmProcessRunTimes(double *usr, double *sys) { ULARGE_INTEGER ul; FILETIME times[4]; HANDLE ph; int sts = -1; *usr = *sys = 0.0; ph = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId()); if (ph == NULL) return sts; else if (GetProcessTimes(ph, ×[0], ×[1], ×[2], ×[3])) { ul.LowPart = times[2].dwLowDateTime; ul.HighPart = times[2].dwHighDateTime; *sys = ul.QuadPart / 10000000.0; ul.LowPart = times[3].dwLowDateTime; ul.HighPart = times[3].dwHighDateTime; *usr = ul.QuadPart / 10000000.0; sts = 0; } CloseHandle(ph); return sts; } void __pmtimevalNow(struct timeval *tv) { struct timespec ts; union { unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */ FILETIME ft; } now; GetSystemTimeAsFileTime(&now.ft); now.ns100 -= FILETIME_1970; ts.tv_sec = now.ns100 / HECTONANOSEC_PER_SEC; ts.tv_nsec = (long)(now.ns100 % HECTONANOSEC_PER_SEC) * 100; tv->tv_sec = ts.tv_sec; tv->tv_usec = (ts.tv_nsec / 1000); } int nanosleep(const struct timespec *req, struct timespec *rem) { DWORD milliseconds; if (req->tv_sec < 0 || req->tv_nsec < 0 || req->tv_nsec > NANOSEC_BOUND) { SetLastError(EINVAL); return -1; } milliseconds = req->tv_sec * MILLISEC_PER_SEC + req->tv_nsec / NANOSEC_PER_MILLISEC; SleepEx(milliseconds, TRUE); if (rem) memset(rem, 0, sizeof(*rem)); return 0; } unsigned int sleep(unsigned int seconds) { SleepEx(seconds * 1000, TRUE); return 0; } void setlinebuf(FILE *stream) { setvbuf(stream, NULL, _IONBF, 0); /* no line buffering in Win32 */ } long int lrand48(void) { return rand(); } void srand48(long int seed) { srand(seed); } char * index(const char *string, int marker) { char *p; for (p = (char *)string; *p != '\0'; p++) if (*p == marker) return p; return NULL; } char * rindex(const char *string, int marker) { char *p; for (p = (char *)string; *p != '\0'; p++) ; if (p == string) return NULL; for (--p; p != string; p--) if (*p == marker) return p; return NULL; } void * dlopen(const char *filename, int flag) { return LoadLibrary(filename); } void * dlsym(void *handle, const char *symbol) { return GetProcAddress(handle, symbol); } int dlclose(void *handle) { return FreeLibrary(handle); } char * dlerror(void) { return strerror(GetLastError()); } static HANDLE eventlog; static char *eventlogPrefix; void openlog(const char *ident, int option, int facility) { if (eventlog) closelog(); eventlog = RegisterEventSource(NULL, "Application"); if (ident) eventlogPrefix = strdup(ident); } void syslog(int priority, const char *format, ...) { va_list arg; LPCSTR msgptr; char logmsg[2048]; char *p = logmsg; int offset = 0; DWORD eventlogPriority; va_start(arg, format); if (!eventlog) openlog(NULL, 0, 0); if (eventlogPrefix) offset = snprintf(p, sizeof(logmsg), "%s: ", eventlogPrefix); switch (priority) { case LOG_EMERG: case LOG_CRIT: case LOG_ERR: eventlogPriority = EVENTLOG_ERROR_TYPE; break; case LOG_WARNING: case LOG_ALERT: eventlogPriority = EVENTLOG_WARNING_TYPE; break; case LOG_NOTICE: case LOG_DEBUG: case LOG_INFO: default: eventlogPriority = EVENTLOG_INFORMATION_TYPE; break; } msgptr = logmsg; snprintf(p + offset, sizeof(logmsg) - offset, format, arg); ReportEvent(eventlog, eventlogPriority, 0, 0, NULL, 1, 0, &msgptr, NULL); va_end(arg); } void closelog(void) { if (eventlog) { DeregisterEventSource(eventlog); if (eventlogPrefix) free(eventlogPrefix); eventlogPrefix = NULL; } eventlog = NULL; } const char * strerror_r(int errnum, char *buf, size_t buflen) { /* strerror_s is missing from the MinGW string.h */ /* we need to wait for it until we can do this: */ /* return strerror_s(buf, buflen, errnum); */ return strerror(errnum); } /* Windows socket error codes - what a nightmare! */ static const struct { int err; char *errmess; } wsatab[] = { /*10004*/ { WSAEINTR, "Interrupted function call" }, /*10009*/ { WSAEBADF, "File handle is not valid" }, /*10013*/ { WSAEACCES, "Permission denied" }, /*10014*/ { WSAEFAULT, "Bad address" }, /*10022*/ { WSAEINVAL, "Invalid argument" }, /*10024*/ { WSAEMFILE, "Too many open files" }, /*10035*/ { WSAEWOULDBLOCK, "Resource temporarily unavailable" }, /*10036*/ { WSAEINPROGRESS, "Operation now in progress" }, /*10037*/ { WSAEALREADY, "Operation already in progress" }, /*10038*/ { WSAENOTSOCK, "Socket operation on nonsocket" }, /*10039*/ { WSAEDESTADDRREQ, "Destination address required" }, /*10040*/ { WSAEMSGSIZE, "Message too long" }, /*10041*/ { WSAEPROTOTYPE, "Protocol wrong type for socket" }, /*10042*/ { WSAENOPROTOOPT, "Bad protocol option" }, /*10043*/ { WSAEPROTONOSUPPORT, "Protocol not supported" }, /*10044*/ { WSAESOCKTNOSUPPORT, "Socket type not supported" }, /*10045*/ { WSAEOPNOTSUPP, "Operation not supported" }, /*10046*/ { WSAEPFNOSUPPORT, "Protocol family not supported" }, /*10047*/ { WSAEAFNOSUPPORT, "Address family not supported by protocol family"}, /*10048*/ { WSAEADDRINUSE, "Address already in use" }, /*10049*/ { WSAEADDRNOTAVAIL, "Cannot assign requested address" }, /*10050*/ { WSAENETDOWN, "Network is down" }, /*10051*/ { WSAENETUNREACH, "Network is unreachable" }, /*10052*/ { WSAENETRESET, "Network dropped connection on reset" }, /*10053*/ { WSAECONNABORTED, "Software caused connection abort" }, /*10054*/ { WSAECONNRESET, "Connection reset by peer" }, /*10055*/ { WSAENOBUFS, "No buffer space available" }, /*10056*/ { WSAEISCONN, "Socket is already connected" }, /*10057*/ { WSAENOTCONN, "Socket is not connected" }, /*10058*/ { WSAESHUTDOWN, "Cannot send after socket shutdown" }, /*10059*/ { WSAETOOMANYREFS, "Too many references" }, /*10060*/ { WSAETIMEDOUT, "Connection timed out" }, /*10061*/ { WSAECONNREFUSED, "Connection refused" }, /*10062*/ { WSAELOOP, "Cannot translate name" }, /*10063*/ { WSAENAMETOOLONG, "Name too long" }, /*10064*/ { WSAEHOSTDOWN, "Host is down" }, /*10065*/ { WSAEHOSTUNREACH, "No route to host" }, /*10066*/ { WSAENOTEMPTY, "Directory not empty" }, /*10067*/ { WSAEPROCLIM, "Too many processes" }, /*10070*/ { WSAESTALE, "Stale file handle reference" }, /*10091*/ { WSASYSNOTREADY, "Network subsystem is unavailable" }, /*10092*/ { WSAVERNOTSUPPORTED, "Winsock.dll version out of range" }, /*10093*/ { WSANOTINITIALISED, "Successful WSAStartup not yet performed" }, /*10101*/ { WSAEDISCON, "Graceful shutdown in progress" }, /*10102*/ { WSAENOMORE, "No more results" }, /*10103*/ { WSAECANCELLED, "Call has been canceled" }, /*10104*/ { WSAEINVALIDPROCTABLE, "Procedure call table is invalid" }, /*10105*/ { WSAEINVALIDPROVIDER, "Service provider is invalid" }, /*10106*/ { WSAEPROVIDERFAILEDINIT, "Service provider failed to initialize" }, /*10107*/ { WSASYSCALLFAILURE, "System call failure" }, /*10108*/ { WSASERVICE_NOT_FOUND, "Service not found" }, /*10109*/ { WSATYPE_NOT_FOUND, "Class type not found" }, /*10110*/ { WSA_E_NO_MORE, "No more results" }, /*10111*/ { WSA_E_CANCELLED, "Call was canceled" }, /*10112*/ { WSAEREFUSED, "Database query was refused" }, /*11001*/ { WSAHOST_NOT_FOUND, "Host not found" }, /*11002*/ { WSATRY_AGAIN, "Nonauthoritative host not found" }, /*11003*/ { WSANO_RECOVERY, "This is a nonrecoverable error" }, /*11004*/ { WSANO_DATA, "Valid name, no data record of requested type" }, { 0,"" } }; const char * wsastrerror(int code) { int i; for (i = 0; wsatab[i].err; i++) if (wsatab[i].err == code) return wsatab[i].errmess; return NULL; } /* * User and group account management using Security IDs (SIDs) */ int __pmValidUserID(__pmUserID sid) { return -ENOTSUP; /* NYI */ } int __pmValidGroupID(__pmGroupID sid) { return -ENOTSUP; /* NYI */ } int __pmEqualUserIDs(__pmUserID sid1, __pmUserID sid2) { return -ENOTSUP; /* NYI */ } int __pmEqualGroupIDs(__pmGroupID sid1, __pmGroupID sid2) { return -ENOTSUP; /* NYI */ } void __pmUserIDFromString(const char *username, __pmUserID *sid) { /* NYI */ } void __pmGroupIDFromString(const char *groupname, __pmGroupID *sid) { /* NYI */ } char * __pmUserIDToString(__pmUserID sid, char *buffer, size_t size) { return NULL; /* NYI */ } char * __pmGroupIDToString(__pmGroupID gid, char *buffer, size_t size) { return NULL; /* NYI */ } int __pmUsernameToID(const char *username, __pmUserID *uidp) { return -ENOTSUP; /* NYI */ } int __pmGroupnameToID(const char *groupname, __pmGroupID *gidp) { return -ENOTSUP; /* NYI */ } char * __pmGroupnameFromID(__pmGroupID gid, char *buf, size_t size) { return NULL; /* NYI */ } char * __pmUsernameFromID(__pmUserID uid, char *buf, size_t size) { return NULL; /* NYI */ } int __pmUsersGroupIDs(const char *username, __pmGroupID **groupids, unsigned int *ngroups) { return -ENOTSUP; /* NYI */ } int __pmGroupsUserIDs(const char *groupname, __pmUserID **userids, unsigned int *nusers) { return -ENOTSUP; /* NYI */ } int __pmGetUserIdentity(const char *username, __pmUserID *uid, __pmGroupID *gid, int mode) { return -ENOTSUP; /* NYI */ } pcp-3.8.12ubuntu1/src/libpcp/src/AF.c0000664000000000000000000002616712272262501014077 0ustar /* * Copyright (c) 1995-2001,2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2009 Aconex. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ /* * general purpose asynchronous event management */ #include "pmapi.h" #include "impl.h" #define MIN_ITIMER_USEC 100 typedef struct _qelt { struct _qelt *q_next; int q_afid; struct timeval q_when; struct timeval q_delta; void *q_data; void (*q_func)(int afid, void *data); } qelt; static qelt *root; static int afid = 0x8000; static int block; static void onalarm(int); /* * Platform dependent routines follow, Windows is very different * to POSIX platforms in terms of signals and timers. Note - we * attempted to use CreateTimerQueue API on Windows, but it does * not behave in the way we'd like unfortunately (QA slow_af.c - * shows quite different results & its un-debuggable cos its all * below the Win32 API). */ #ifdef IS_MINGW VOID CALLBACK ontimer(LPVOID arg, DWORD lo, DWORD hi) { onalarm(14); /* 14 == POSIX SIGALRM */ } static HANDLE afblock; /* mutex protecting callback */ static HANDLE aftimer; /* equivalent to ITIMER_REAL */ static int afsetup; /* one-time-setup: done flag */ static void AFsetup(void) { PM_LOCK(__pmLock_libpcp); if (afsetup) { PM_UNLOCK(__pmLock_libpcp); return; } afsetup = 1; afblock = CreateMutex(NULL, FALSE, NULL); aftimer = CreateWaitableTimer(NULL, TRUE, NULL); PM_UNLOCK(__pmLock_libpcp); } static void AFhold(void) { AFsetup(); WaitForSingleObject(afblock, INFINITE); } static void AFrelse(void) { if (afsetup) ReleaseMutex(afblock); } static void AFrearm(void) { /* do nothing, callback is always "armed" (except when not setup) */ } static void AFsetitimer(struct timeval *interval) { LARGE_INTEGER duetime; long long inc; AFsetup(); inc = interval->tv_sec * 10000000ULL; /* sec -> 100 nsecs */ inc += (interval->tv_usec * 10ULL); /* used -> 100 nsecs */ if (inc > 0) /* negative is relative, positive absolute */ inc = -inc; /* we will always want this to be relative */ duetime.QuadPart = inc; SetWaitableTimer(aftimer, &duetime, 0, ontimer, NULL, FALSE); } #else /* POSIX */ static void AFsetitimer(struct timeval *interval) { struct itimerval val; val.it_value = *interval; val.it_interval.tv_sec = val.it_interval.tv_usec = 0; setitimer(ITIMER_REAL, &val, NULL); } #if !defined(HAVE_SIGHOLD) static int sighold(int sig) { sigset_t s; sigemptyset(&s); sigaddset(&s, sig); sigprocmask(SIG_BLOCK, &s, NULL); return 0; } #else /* * for Linux the prototype is hidden, even though the function is in * libc */ extern int sighold(int); #endif #if !defined(HAVE_SIGRELSE) static int sigrelse(int sig) { sigset_t s; sigemptyset(&s); sigaddset(&s, sig); sigprocmask(SIG_UNBLOCK, &s, NULL); return 0; } #else /* * for Linux the prototype is hidden, even though the function is in * libc */ extern int sigrelse(int); #endif static void AFhold(void) { sighold(SIGALRM); } static void AFrelse(void) { sigrelse(SIGALRM); } static void AFrearm(void) { signal(SIGALRM, onalarm); } #endif /* POSIX */ /* * Platform independent code follows */ #ifdef PCP_DEBUG static void printdelta(FILE *f, struct timeval *tp) { struct tm *tmp; time_t tt = (time_t)tp->tv_sec; tmp = gmtime(&tt); fprintf(stderr, "%02d:%02d:%02d.%06ld", tmp->tm_hour, tmp->tm_min, tmp->tm_sec, (long)tp->tv_usec); } #endif /* * a := a + b for struct timevals */ static void tadd(struct timeval *a, struct timeval *b) { a->tv_usec += b->tv_usec; if (a->tv_usec > 1000000) { a->tv_usec -= 1000000; a->tv_sec++; } a->tv_sec += b->tv_sec; } /* * a := a - b for struct timevals */ static void tsub_real(struct timeval *a, struct timeval *b) { a->tv_usec -= b->tv_usec; if (a->tv_usec < 0) { a->tv_usec += 1000000; a->tv_sec--; } a->tv_sec -= b->tv_sec; } /* * a := a - b for struct timevals, but result is never less than zero */ static void tsub(struct timeval *a, struct timeval *b) { tsub_real(a, b); if (a->tv_sec < 0) { /* clip negative values at zero */ a->tv_sec = 0; a->tv_usec = 0; } } /* * a : b for struct timevals ... <0 for a0 for a>b */ static int tcmp(struct timeval *a, struct timeval *b) { int res; res = (int)(a->tv_sec - b->tv_sec); if (res == 0) res = (int)(a->tv_usec - b->tv_usec); return res; } static void enqueue(qelt *qp) { qelt *tqp; qelt *priorp; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { struct timeval now; __pmtimevalNow(&now); __pmPrintStamp(stderr, &now); fprintf(stderr, " AFenqueue " PRINTF_P_PFX "%p(%d, " PRINTF_P_PFX "%p) for ", qp->q_func, qp->q_afid, qp->q_data); __pmPrintStamp(stderr, &qp->q_when); fputc('\n', stderr); } #endif for (tqp = root, priorp = NULL; tqp != NULL && tcmp(&qp->q_when, &tqp->q_when) >= 0; tqp = tqp->q_next) priorp = tqp; if (priorp == NULL) { qp->q_next = root; root = qp; } else { qp->q_next = priorp->q_next; priorp->q_next = qp; } } static void onalarm(int dummy) { struct timeval now; struct timeval tmp; struct timeval interval; qelt *qp; if (!block) AFhold(); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmtimevalNow(&now); __pmPrintStamp(stderr, &now); fprintf(stderr, " AFonalarm(%d)\n", dummy); } #endif if (root != NULL) { /* something to do ... */ while (root != NULL) { /* compute difference between scheduled time and now */ __pmtimevalNow(&now); tmp = root->q_when; tsub(&tmp, &now); if (tmp.tv_sec == 0 && tmp.tv_usec <= 10000) { /* * within one 10msec tick, the time has passed for this one, * execute the callback and reschedule */ qp = root; root = root->q_next; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFcallback " PRINTF_P_PFX "%p(%d, " PRINTF_P_PFX "%p)\n", qp->q_func, qp->q_afid, qp->q_data); } #endif qp->q_func(qp->q_afid, qp->q_data); if (qp->q_delta.tv_sec == 0 && qp->q_delta.tv_usec == 0) { /* * if delta is zero, this is a single-shot event, * so do not reschedule it */ free(qp); } else { /* * avoid falling too far behind * if the scheduled time is more than q_delta in the * past we will never catch up ... better to skip some * events to catch up ... * * <------------ next q_when range -----------------> * * cannot catchup | may catchup | on schedule * | | * --------------------|---------------|------------> time * | | * | +-- now * +-- now - q_delta */ __pmtimevalNow(&now); for ( ; ; ) { tadd(&qp->q_when, &qp->q_delta); tmp = qp->q_when; tsub_real(&tmp, &now); tadd(&tmp, &qp->q_delta); if (tmp.tv_sec >= 0) break; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFcallback event %d too slow, skip callback for ", qp->q_afid); __pmPrintStamp(stderr, &qp->q_when); fputc('\n', stderr); } #endif } enqueue(qp); } } else /* * head of the queue (and hence all others) are too far in * the future ... done for this time */ break; } if (root == NULL) { pmprintf("Warning: AF event queue is empty, nothing more will be scheduled\n"); pmflush(); } else { /* set itimer for head of queue */ interval = root->q_when; __pmtimevalNow(&now); tsub(&interval, &now); if (interval.tv_sec == 0 && interval.tv_usec < MIN_ITIMER_USEC) /* use minimal delay (platform dependent) */ interval.tv_usec = MIN_ITIMER_USEC; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFsetitimer for delta "); printdelta(stderr, &interval); fputc('\n', stderr); } #endif AFsetitimer(&interval); } } if (!block) { AFrearm(); AFrelse(); } } int __pmAFregister(const struct timeval *delta, void *data, void (*func)(int, void *)) { qelt *qp; struct timeval now; struct timeval interval; if (PM_MULTIPLE_THREADS(PM_SCOPE_AF)) return PM_ERR_THREAD; if (!block) AFhold(); if (afid == 0x8000 && !block) /* first time */ AFrearm(); if ((qp = (qelt *)malloc(sizeof(qelt))) == NULL) { return -oserror(); } qp->q_afid = ++afid; qp->q_data = data; qp->q_delta = *delta; qp->q_func = func; __pmtimevalNow(&qp->q_when); tadd(&qp->q_when, &qp->q_delta); enqueue(qp); if (root == qp) { /* we ended up at the head of the list, set itimer */ interval = qp->q_when; __pmtimevalNow(&now); tsub(&interval, &now); if (interval.tv_sec == 0 && interval.tv_usec < MIN_ITIMER_USEC) /* use minimal delay (platform dependent) */ interval.tv_usec = MIN_ITIMER_USEC; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFsetitimer for delta "); printdelta(stderr, &interval); fputc('\n', stderr); } #endif AFsetitimer(&interval); } if (!block) AFrelse(); return qp->q_afid; } int __pmAFunregister(int afid) { qelt *qp; qelt *priorp; struct timeval now; struct timeval interval; if (PM_MULTIPLE_THREADS(PM_SCOPE_AF)) return PM_ERR_THREAD; if (!block) AFhold(); for (qp = root, priorp = NULL; qp != NULL && qp->q_afid != afid; qp = qp->q_next) priorp = qp; if (qp == NULL) { if (!block) AFrelse(); return -1; } if (priorp == NULL) { root = qp->q_next; if (root != NULL) { /* * we removed the head of the queue, set itimer for the * new head of queue */ interval = root->q_when; __pmtimevalNow(&now); tsub(&interval, &now); if (interval.tv_sec == 0 && interval.tv_usec < MIN_ITIMER_USEC) /* use minimal delay (platform dependent) */ interval.tv_usec = MIN_ITIMER_USEC; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_AF) { __pmPrintStamp(stderr, &now); fprintf(stderr, " AFsetitimer for delta "); printdelta(stderr, &interval); fputc('\n', stderr); } #endif AFsetitimer(&interval); } } else priorp->q_next = qp->q_next; free(qp); if (!block) AFrelse(); return 0; } void __pmAFblock(void) { if (PM_MULTIPLE_THREADS(PM_SCOPE_AF)) return; block = 1; AFhold(); } void __pmAFunblock(void) { if (PM_MULTIPLE_THREADS(PM_SCOPE_AF)) return; block = 0; AFrearm(); AFrelse(); } int __pmAFisempty(void) { return (root==NULL); } pcp-3.8.12ubuntu1/src/libpcp/src/connectlocal.c0000664000000000000000000004356112272262501016252 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 2010 Ken McDonell. All Rights Reserved. * Copyright (c) 1995-2002,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe notes * * atexit_installed is protected by the __pmLock_libpcp mutex. * * __pmSpecLocalPMDA() uses buffer[], but this routine is only called * from main() in single-threaded apps like pminfo, pmprobe, pmval * and pmevent ... so we can ignore any multi-threading issues, * especially as buffer[] is only used on an error handling code path. * * dsotab[] and numdso are obviously of interest via calls to * __pmLookupDSO(), EndLocalContext(), __pmConnectLocal() or * __pmLocalPMDA(). * * Within libpcp, __pmLookupDSO() is called _only_ for PM_CONTEXT_LOCAL * and it is not called from outside libpcp. Local contexts are only * supported for single-threaded applications in the scope * PM_SCOPE_DSO_PMDA that is enforced in pmNewContext. Multi-threaded * applications are not supported for local contexts, so we do not need * additional concurrency control for __pmLookupDSO(). * * The same arguments apply to EndLocalContext() and __pmConnectLocal(). * * __pmLocalPMDA() is a mixed bag, sharing some of the justification from * __pmSpecLocalPMDA() and some from __pmConnectLocal(). * * Because __pmConnectLocal() is not going to be used in a multi-threaded * environment, the call to the thread-unsafe dlerror() is OK. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include #include static __pmDSO *dsotab; static int numdso = -1; static int build_dsotab(void) { /* * parse pmcd's config file extracting details from dso lines * * very little syntactic checking here ... pmcd(1) does that job * nicely and even if we get confused, the worst thing that happens * is we don't include one or more of the DSO PMDAs in dsotab[] * * lines for DSO PMDAs generally look like this ... * Name Domain Type Init Routine Path * mmv 70 dso mmv_init /var/lib/pcp/pmdas/mmv/pmda_mmv.so * */ char configFileName[MAXPATHLEN]; FILE *configFile; char *config; char *p; char *q; struct stat sbuf; int lineno = 1; int domain; char *init; char *name; char peekc; numdso = 0; dsotab = NULL; strcpy(configFileName, pmGetConfig("PCP_PMCDCONF_PATH")); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { fprintf(stderr, "build_dsotab: parsing %s\n", configFileName); } #endif if (stat(configFileName, &sbuf) < 0) { return -oserror(); } configFile = fopen(configFileName, "r"); if (configFile == NULL) { return -oserror(); } if ((config = malloc(sbuf.st_size+1)) == NULL) { __pmNoMem("build_dsotbl:", sbuf.st_size+1, PM_RECOV_ERR); fclose(configFile); return -oserror(); } if (fread(config, 1, sbuf.st_size, configFile) != sbuf.st_size) { fclose(configFile); free(config); return -oserror(); } config[sbuf.st_size] = '\0'; p = config; while (*p != '\0') { /* each time through here we're at the start of a new line */ if (*p == '#') goto eatline; if (strncmp(p, "pmcd", 4) == 0) { /* * the pmcd PMDA is an exception ... it makes reference to * symbols in pmcd, and only makes sense when attached to the * pmcd process, so we skip this one */ goto eatline; } /* skip the PMDA's name */ while (*p != '\0' && *p != '\n' && !isspace((int)*p)) p++; while (*p != '\0' && *p != '\n' && isspace((int)*p)) p++; /* extract domain number */ domain = (int)strtol(p, &q, 10); p = q; while (*p != '\0' && *p != '\n' && isspace((int)*p)) p++; /* only interested if the type is "dso" */ if (strncmp(p, "dso", 3) != 0) goto eatline; p += 3; while (*p != '\0' && *p != '\n' && isspace((int)*p)) p++; /* up to the init routine name */ init = p; while (*p != '\0' && *p != '\n' && !isspace((int)*p)) p++; *p = '\0'; p++; while (*p != '\0' && *p != '\n' && isspace((int)*p)) p++; /* up to the dso pathname */ name = p; while (*p != '\0' && *p != '\n' && !isspace((int)*p)) p++; peekc = *p; *p = '\0'; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { fprintf(stderr, "[%d] domain=%d, name=%s, init=%s\n", lineno, domain, name, init); } #endif /* * a little bit recursive if we got here via __pmLocalPMDA(), * but numdso has been set correctly, so this is OK */ __pmLocalPMDA(PM_LOCAL_ADD, domain, name, init); *p = peekc; eatline: while (*p != '\0' && *p != '\n') p++; if (*p == '\n') { lineno++; p++; } } fclose(configFile); free(config); return 0; } static int build_dsoattrs(pmdaInterface *dispatch, __pmHashCtl *attrs) { __pmHashNode *node; char name[32]; char *namep; int sts = 0; snprintf(name, sizeof(name), "%u", getuid()); name[sizeof(name)-1] = '\0'; if ((namep = strdup(name)) != NULL) __pmHashAdd(PCP_ATTR_USERID, namep, attrs); snprintf(name, sizeof(name), "%u", getgid()); name[sizeof(name)-1] = '\0'; if ((namep = strdup(name)) != NULL) __pmHashAdd(PCP_ATTR_GROUPID, namep, attrs); snprintf(name, sizeof(name), "%u", getpid()); name[sizeof(name)-1] = '\0'; if ((namep = strdup(name)) != NULL) __pmHashAdd(PCP_ATTR_PROCESSID, namep, attrs); if (dispatch->version.six.attribute != NULL) { for (node = __pmHashWalk(attrs, PM_HASH_WALK_START); node != NULL; node = __pmHashWalk(attrs, PM_HASH_WALK_NEXT)) { if ((sts = dispatch->version.six.attribute( 0, node->key, node->data, node->data ? strlen(node->data)+1 : 0, dispatch->version.six.ext)) < 0) break; } } return sts; } #if defined(HAVE_DLFCN_H) #include #endif /* * As of PCP version 2.1, we're no longer searching for DSO's; * pmcd's config file should have full paths to each of 'em. */ const char * __pmFindPMDA(const char *name) { return (access(name, F_OK) == 0) ? name : NULL; } __pmDSO * __pmLookupDSO(int domain) { int i; for (i = 0; i < numdso; i++) { if (dsotab[i].domain == domain && dsotab[i].handle != NULL) return &dsotab[i]; } return NULL; } static void EndLocalContext(void) { int i; __pmDSO *dp; int ctx = pmWhichContext(); if (PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) /* * Local context requires single-threaded applications * ... should not really get here, so do nothing! */ return; for (i = 0; i < numdso; i++) { dp = &dsotab[i]; if (dp->domain != -1 && dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5 && dp->dispatch.version.four.ext->e_endCallBack != NULL) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { fprintf(stderr, "NotifyEndLocalContext: DSO PMDA %s (%d) notified of context %d close\n", dp->name, dp->domain, ctx); } #endif (*(dp->dispatch.version.four.ext->e_endCallBack))(ctx); } } } /* * Note order is significant here. Also EndLocalContext can be * called from atexit handler (if previously registered), but if * caller invokes shutdown beforehand, thats OK; EndLocalContext * will safely do nothing on the second call. */ int __pmShutdownLocal(void) { /* Call through to any PMDA termination callbacks */ EndLocalContext(); /* dso close and free up local memory allocations */ return __pmLocalPMDA(PM_LOCAL_CLEAR, 0, NULL, NULL); } int __pmConnectLocal(__pmHashCtl *attrs) { int i; __pmDSO *dp; char pathbuf[MAXPATHLEN]; const char *path; #if defined(HAVE_DLOPEN) unsigned int challenge; void (*initp)(pmdaInterface *); #ifdef HAVE_ATEXIT static int atexit_installed = 0; #endif #endif if (numdso == -1) { int sts; sts = build_dsotab(); if (sts < 0) return sts; } for (i = 0; i < numdso; i++) { dp = &dsotab[i]; if (dp->domain == -1 || dp->handle != NULL) continue; /* * __pmLocalPMDA() means the path to the DSO may be something * other than relative to $PCP_PMDAS_DIR ... need to try both * options and also with and without DSO_SUFFIX (so, dll, etc) */ snprintf(pathbuf, sizeof(pathbuf), "%s%c%s", pmGetConfig("PCP_PMDAS_DIR"), __pmPathSeparator(), dp->name); if ((path = __pmFindPMDA(pathbuf)) == NULL) { snprintf(pathbuf, sizeof(pathbuf), "%s%c%s.%s", pmGetConfig("PCP_PMDAS_DIR"), __pmPathSeparator(), dp->name, DSO_SUFFIX); if ((path = __pmFindPMDA(pathbuf)) == NULL) { if ((path = __pmFindPMDA(dp->name)) == NULL) { snprintf(pathbuf, sizeof(pathbuf), "%s.%s", dp->name, DSO_SUFFIX); if ((path = __pmFindPMDA(pathbuf)) == NULL) { pmprintf("__pmConnectLocal: Warning: cannot find DSO at \"%s\" or \"%s\"\n", pathbuf, dp->name); pmflush(); dp->domain = -1; dp->handle = NULL; continue; } } } } #if defined(HAVE_DLOPEN) dp->handle = dlopen(path, RTLD_NOW); if (dp->handle == NULL) { pmprintf("__pmConnectLocal: Warning: error attaching DSO " "\"%s\"\n%s\n\n", path, dlerror()); pmflush(); dp->domain = -1; } #else /* ! HAVE_DLOPEN */ dp->handle = NULL; pmprintf("__pmConnectLocal: Warning: error attaching DSO \"%s\"\n", path); pmprintf("No dynamic DSO/DLL support on this platform\n\n"); pmflush(); dp->domain = -1; #endif if (dp->handle == NULL) continue; #if defined(HAVE_DLOPEN) /* * rest of this only makes sense if the dlopen() worked */ if (dp->init == NULL) initp = NULL; else initp = (void (*)(pmdaInterface *))dlsym(dp->handle, dp->init); if (initp == NULL) { pmprintf("__pmConnectLocal: Warning: couldn't find init function " "\"%s\" in DSO \"%s\"\n", dp->init, path); pmflush(); dlclose(dp->handle); dp->domain = -1; continue; } /* * Pass in the expected domain id. * The PMDA initialization routine can (a) ignore it, (b) check it * is the expected value, or (c) self-adapt. */ dp->dispatch.domain = dp->domain; /* * the PMDA interface / PMAPI version discovery as a "challenge" ... * for pmda_interface it is all the bits being set, * for pmapi_version it is the complement of the one you are using now */ challenge = 0xff; dp->dispatch.comm.pmda_interface = challenge; dp->dispatch.comm.pmapi_version = ~PMAPI_VERSION; dp->dispatch.comm.flags = 0; dp->dispatch.status = 0; (*initp)(&dp->dispatch); if (dp->dispatch.status != 0) { /* initialization failed for some reason */ char errmsg[PM_MAXERRMSGLEN]; pmprintf("__pmConnectLocal: Warning: initialization " "routine \"%s\" failed in DSO \"%s\": %s\n", dp->init, path, pmErrStr_r(dp->dispatch.status, errmsg, sizeof(errmsg))); pmflush(); dlclose(dp->handle); dp->domain = -1; } else { if (dp->dispatch.comm.pmda_interface < PMDA_INTERFACE_2 || dp->dispatch.comm.pmda_interface > PMDA_INTERFACE_LATEST) { pmprintf("__pmConnectLocal: Error: Unknown PMDA interface " "version %d in \"%s\" DSO\n", dp->dispatch.comm.pmda_interface, path); pmflush(); dlclose(dp->handle); dp->domain = -1; } else if (dp->dispatch.comm.pmapi_version != PMAPI_VERSION_2) { pmprintf("__pmConnectLocal: Error: Unknown PMAPI version %d " "in \"%s\" DSO\n", dp->dispatch.comm.pmapi_version, path); pmflush(); dlclose(dp->handle); dp->domain = -1; } else if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_6 && (dp->dispatch.comm.flags & PDU_FLAG_AUTH) != 0) { /* Agent wants to know about connection attributes */ build_dsoattrs(&dp->dispatch, attrs); } } #ifdef HAVE_ATEXIT PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5 && atexit_installed == 0) { /* install end of local context handler */ atexit(EndLocalContext); atexit_installed = 1; } PM_UNLOCK(__pmLock_libpcp); #endif #endif /* HAVE_DLOPEN */ } return 0; } int __pmLocalPMDA(int op, int domain, const char *name, const char *init) { int sts = 0; int i; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { fprintf(stderr, "__pmLocalPMDA(op="); if (op == PM_LOCAL_ADD) fprintf(stderr, "ADD"); else if (op == PM_LOCAL_DEL) fprintf(stderr, "DEL"); else if (op == PM_LOCAL_CLEAR) fprintf(stderr, "CLEAR"); else fprintf(stderr, "%d ???", op); fprintf(stderr, ", domain=%d, name=%s, init=%s)\n", domain, name, init); } #endif if (numdso == -1) { if (op != PM_LOCAL_CLEAR) if ((sts = build_dsotab()) < 0) return sts; } switch (op) { case PM_LOCAL_ADD: if ((dsotab = (__pmDSO *)realloc(dsotab, (numdso+1)*sizeof(__pmDSO))) == NULL) { __pmNoMem("__pmLocalPMDA realloc", (numdso+1)*sizeof(__pmDSO), PM_FATAL_ERR); /*NOTREACHED*/ } dsotab[numdso].domain = domain; if (name == NULL) { /* odd, will fail later at dlopen */ dsotab[numdso].name = NULL; } else { if ((dsotab[numdso].name = strdup(name)) == NULL) { sts = -oserror(); __pmNoMem("__pmLocalPMDA name", strlen(name)+1, PM_RECOV_ERR); return sts; } } if (init == NULL) { /* odd, will fail later at initialization call */ dsotab[numdso].init = NULL; } else { if ((dsotab[numdso].init = strdup(init)) == NULL) { sts = -oserror(); __pmNoMem("__pmLocalPMDA init", strlen(init)+1, PM_RECOV_ERR); return sts; } } dsotab[numdso].handle = NULL; numdso++; break; case PM_LOCAL_DEL: sts = PM_ERR_INDOM; for (i = 0; i < numdso; i++) { if ((domain != -1 && dsotab[i].domain == domain) || (name != NULL && strcmp(dsotab[i].name, name) == 0)) { if (dsotab[i].handle) { dlclose(dsotab[i].handle); dsotab[i].handle = NULL; } dsotab[i].domain = -1; sts = 0; } } break; case PM_LOCAL_CLEAR: for (i = 0; i < numdso; i++) { free(dsotab[i].name); free(dsotab[i].init); if (dsotab[i].handle) dlclose(dsotab[i].handle); } free(dsotab); dsotab = NULL; numdso = 0; break; default: sts = PM_ERR_CONV; break; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { if (sts != 0) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmLocalPMDA -> %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } fprintf(stderr, "Local Context PMDA Table"); if (numdso == 0) fprintf(stderr, " ... empty"); fputc('\n', stderr); for (i = 0; i < numdso; i++) { fprintf(stderr, PRINTF_P_PFX "%p [%d] domain=%d name=%s init=%s handle=" PRINTF_P_PFX "%p\n", &dsotab[i], i, dsotab[i].domain, dsotab[i].name, dsotab[i].init, dsotab[i].handle); } } #endif return sts; } /* * Parse a command line string that encodes arguments to __pmLocalPMDA(), * then call __pmLocalPMDA(). * * The syntax for the string is 1 to 4 fields separated by colons: * - op ("add" for add, "del" for delete, "clear" for clear) * - domain (PMDA's PMD) * - path (path to DSO PMDA) * - init (name of DSO's initialization routine) */ char * __pmSpecLocalPMDA(const char *spec) { int op; int domain = -1; char *name = NULL; char *init = NULL; int sts; char *arg; char *sbuf; char *ap; if ((arg = sbuf = strdup(spec)) == NULL) { sts = -oserror(); __pmNoMem("__pmSpecLocalPMDA dup spec", strlen(spec)+1, PM_RECOV_ERR); return "strdup failed"; } if (strncmp(arg, "add", 3) == 0) { op = PM_LOCAL_ADD; ap = &arg[3]; } else if (strncmp(arg, "del", 3) == 0) { op = PM_LOCAL_DEL; ap = &arg[3]; } else if (strncmp(arg, "clear", 5) == 0) { op = PM_LOCAL_CLEAR; ap = &arg[5]; if (*ap == '\0') goto doit; else { free(sbuf); return "unexpected text after clear op in spec"; } } else { free(sbuf); return "bad op in spec"; } if (*ap != ',') { free(sbuf); return "expected , after op in spec"; } /* ap-> , after add or del */ arg = ++ap; if (*ap == '\0') { free(sbuf); return "missing domain in spec"; } else if (*ap != ',') { /* ap-> domain */ domain = (int)strtol(arg, &ap, 10); if ((*ap != ',' && *ap != '\0') || domain < 0 || domain > 510) { free(sbuf); return "bad domain in spec"; } if (*ap != '\0') /* skip , after domain */ ap++; } else { if (op != PM_LOCAL_DEL) { /* found ,, where ,domain, expected */ free(sbuf); return "missing domain in spec"; } ap++; } /* ap -> char after , following domain */ if (*ap == ',') { /* no path, could have init (not useful but possible!) */ ap++; if (*ap != '\0') init = ap; } else if (*ap != '\0') { /* have path and possibly init */ name = ap; while (*ap != ',' && *ap != '\0') ap++; if (*ap == ',') { *ap++ = '\0'; if (*ap != '\0') init = ap; else { if (op != PM_LOCAL_DEL) { /* found end of string where init-routine expected */ free(sbuf); return "missing init-routine in spec"; } } } else { if (op != PM_LOCAL_DEL) { /* found end of string where init-routine expected */ free(sbuf); return "missing init-routine in spec"; } } } else { if (op != PM_LOCAL_DEL) { /* found end of string where path expected */ free(sbuf); return "missing dso-path in spec"; } } if (domain == -1 && name == NULL) { free(sbuf); return "missing domain and dso-path in spec"; } doit: sts = __pmLocalPMDA(op, domain, name, init); if (sts < 0) { /* see thread-safe note at the head of this file */ static char buffer[256]; char errmsg[PM_MAXERRMSGLEN]; snprintf(buffer, sizeof(buffer), "__pmLocalPMDA: %s", pmErrStr_r(sts, errmsg, sizeof(errmsg))); free(sbuf); return buffer; } free(sbuf); return NULL; } pcp-3.8.12ubuntu1/src/libpcp/src/secureconnect.c0000664000000000000000000017116212272262501016445 0ustar /* * Copyright (c) 2012-2014 Red Hat. * Security and Authentication (NSS and SASL) support. Client side. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #define SOCKET_INTERNAL #include "internal.h" #include #include #include #include #include #include #include #ifdef HAVE_SYS_TERMIOS_H #include #endif void __pmHostEntFree(__pmHostEnt *hostent) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DESPERATE) fprintf(stderr, "%s:__pmHostEntFree(hostent=%p) name=%p (%s) addresses=%p\n", __FILE__, hostent, hostent->name, hostent->name, hostent-> addresses); #endif if (hostent->name != NULL) free(hostent->name); if (hostent->addresses != NULL) PR_FreeAddrInfo(hostent->addresses); free(hostent); } /* * We shift NSS/NSPR/SSL/SASL errors below the valid range for other * PCP error codes, in order to avoid conflicts. pmErrStr can then * detect and decode. PM_ERR_NYI is the PCP error code sentinel. */ int __pmSecureSocketsError(int code) { int sts = (PM_ERR_NYI + code); /* encode, negative value */ setoserror(-sts); return sts; } int __pmSocketClosed(void) { int error = oserror(); if (PM_ERR_NYI > -error) error = -(error + PM_ERR_NYI); switch (error) { /* * Treat this like end of file on input. * * failed as a result of pmcd exiting and the connection * being reset, or as a result of the kernel ripping * down the connection (most likely because the host at * the other end just took a dive) * * from IRIX BDS kernel sources, seems like all of the * following are peers here: * ECONNRESET (pmcd terminated?) * ETIMEDOUT ENETDOWN ENETUNREACH EHOSTDOWN EHOSTUNREACH * ECONNREFUSED * peers for BDS but not here: * ENETRESET ENONET ESHUTDOWN (cache_fs only?) * ECONNABORTED (accept, user req only?) * ENOTCONN (udp?) * EPIPE EAGAIN (nfs, bds & ..., but not ip or tcp?) */ case ECONNRESET: case EPIPE: case ETIMEDOUT: case ENETDOWN: case ENETUNREACH: case EHOSTDOWN: case EHOSTUNREACH: case ECONNREFUSED: case PR_IO_TIMEOUT_ERROR: case PR_NETWORK_UNREACHABLE_ERROR: case PR_CONNECT_TIMEOUT_ERROR: case PR_NOT_CONNECTED_ERROR: case PR_CONNECT_RESET_ERROR: case PR_PIPE_ERROR: case PR_NETWORK_DOWN_ERROR: case PR_SOCKET_SHUTDOWN_ERROR: case PR_HOST_UNREACHABLE_ERROR: return 1; } return 0; } /* * For every connection when operating under secure socket mode, we need * the following auxillary structure associated with the socket. It holds * critical information that each piece of the security pie can make use * of (NSS/SSL/NSPR/SASL). This is allocated once when initial connection * is being established. */ typedef struct { PRFileDesc *nsprFd; PRFileDesc *sslFd; sasl_conn_t *saslConn; sasl_callback_t *saslCB; } __pmSecureSocket; int __pmDataIPCSize(void) { return sizeof(__pmSecureSocket); } /* * NSS/NSPR file descriptors are not integers, however, integral file * descriptors are expected in many parts of pcp. In order to deal with * this assumption, when NSS/NSPR is available, we maintain a set of * available integral file descriptors. The file descriptor number * returned by __pmCreateSocket is a reference to this set and must be * used for all further I/O operations on that socket. * * Since some interfaces (e.g. the IPC table) will use a mix of native * file descriptors * and NSPR ones, we need a way to distinguish them. * Obtaining the hard max fd number using getrlimit() was considered, * but a sysadmin could change this limit arbitrarily while we are * running. We can't use negative values, since these indicate an error. * * There is a limit on the range of fd's which can be passed to the * fd_set API. It is FD_SETSIZE. So, consider all fd's >= FD_SETSIZE * to be ones which reference our set. Using this threshold will also * allow us to easily manage mixed sets of native and NSPR fds. * * NB: __pmLock_libpcp must be held when accessing this set, since * another thread could modify it at any time. */ static fd_set nsprFds; #define NSPR_HANDLE_BASE FD_SETSIZE static int newNSPRHandle(void) { int fd; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); for (fd = 0; fd < FD_SETSIZE; ++fd) { if (! FD_ISSET(fd, &nsprFds)) { FD_SET(fd, &nsprFds); PM_UNLOCK(__pmLock_libpcp); return NSPR_HANDLE_BASE + fd; } } PM_UNLOCK(__pmLock_libpcp); /* No free handles available */ return -1; } static void freeNSPRHandle(int fd) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); FD_CLR(fd - NSPR_HANDLE_BASE, &nsprFds); PM_UNLOCK(__pmLock_libpcp); } int __pmInitSecureSockets(void) { /* Make sure that NSPR has been initialized */ if (PR_Initialized() != PR_TRUE) PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); return 0; } int __pmShutdownSecureSockets(void) { if (PR_Initialized()) PR_Cleanup(); return 0; } static int __pmSetupSocket(PRFileDesc *fdp, int family) { __pmSecureSocket socket = { 0 }; int fd, sts; socket.nsprFd = fdp; if ((fd = newNSPRHandle()) < 0) { PR_Close(socket.nsprFd); return fd; } if ((sts = __pmSetDataIPC(fd, (void *)&socket)) < 0) { PR_Close(socket.nsprFd); freeNSPRHandle(fd); return sts; } (void)__pmInitSocket(fd, family); /* cannot fail after __pmSetDataIPC */ return fd; } int __pmCreateSocket(void) { PRFileDesc *fdp; __pmInitSecureSockets(); if ((fdp = PR_OpenTCPSocket(PR_AF_INET)) == NULL) return -neterror(); return __pmSetupSocket(fdp, AF_INET); } int __pmCreateIPv6Socket(void) { int fd, sts, on; __pmSockLen onlen = sizeof(on); PRFileDesc *fdp; __pmInitSecureSockets(); /* Open the socket */ if ((fdp = PR_OpenTCPSocket(PR_AF_INET6)) == NULL) return -neterror(); fd = PR_FileDesc2NativeHandle(fdp); /* * Disable IPv4-mapped connections. * Must explicitly check whether that worked, for ipv6.enabled=false * kernels. Setting then testing is the most reliable way we've found. */ on = 1; setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, onlen); on = 0; sts = getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, &onlen); if (sts < 0 || on != 1) { __pmNotifyErr(LOG_ERR, "%s:__pmCreateIPv6Socket: IPV6 is not supported\n", __FILE__); PR_Close(fdp); return -EOPNOTSUPP; } return __pmSetupSocket(fdp, AF_INET6); } int __pmCreateUnixSocket(void) { #if defined(HAVE_STRUCT_SOCKADDR_UN) PRFileDesc *fdp; __pmInitSecureSockets(); if ((fdp = PR_OpenTCPSocket(PR_AF_LOCAL)) == NULL) return -neterror(); return __pmSetupSocket(fdp, AF_UNIX); #else __pmNotifyErr(LOG_ERR, "%s:__pmCreateUnixSocket: AF_UNIX is not supported\n", __FILE__); return -EOPNOTSUPP; #endif } void __pmCloseSocket(int fd) { __pmSecureSocket socket; int sts; sts = __pmDataIPC(fd, (void *)&socket); __pmResetIPC(fd); if (sts == 0) { if (socket.saslConn) { sasl_dispose(&socket.saslConn); socket.saslConn = NULL; } if (socket.saslCB) { free(socket.saslCB); socket.saslCB = NULL; } if (socket.nsprFd) { freeNSPRHandle(fd); PR_Close(socket.nsprFd); socket.nsprFd = NULL; socket.sslFd = NULL; } } else { #if defined(IS_MINGW) closesocket(fd); #else close(fd); #endif } } static int mkpath(const char *dir, mode_t mode) { char path[MAXPATHLEN], *p; int sts; sts = access(dir, R_OK|W_OK|X_OK); if (sts == 0) return 0; if (sts < 0 && oserror() != ENOENT) return -1; strncpy(path, dir, sizeof(path)); path[sizeof(path)-1] = '\0'; for (p = path+1; *p != '\0'; p++) { if (*p == __pmPathSeparator()) { *p = '\0'; mkdir2(path, mode); *p = __pmPathSeparator(); } } return mkdir2(path, mode); } static char * dbpath(char *path, size_t size, char *db_method) { int sep = __pmPathSeparator(); const char *empty_homedir = ""; char *homedir = getenv("HOME"); char *nss_method = getenv("PCP_SECURE_DB_METHOD"); if (homedir == NULL) homedir = (char *)empty_homedir; if (nss_method == NULL) nss_method = db_method; /* * Fill in a buffer with the users NSS database specification. * Return a pointer to the filesystem path component - without * the :-prefix - for other routines to work with. */ snprintf(path, size, "%s%s" "%c" ".pki" "%c" "nssdb", nss_method, homedir, sep, sep); return path + strlen(nss_method); } static char * dbphrase(PK11SlotInfo *slot, PRBool retry, void *arg) { (void)arg; if (retry) return NULL; assert(PK11_IsInternal(slot)); return strdup(SECURE_USERDB_DEFAULT_KEY); } int __pmInitCertificates(void) { char nssdb[MAXPATHLEN]; PK11SlotInfo *slot; SECStatus secsts; PK11_SetPasswordFunc(dbphrase); /* * Check for client certificate databases. We enforce use * of the per-user shared NSS database at $HOME/.pki/nssdb * For simplicity, we create this directory if we need to. * If we cannot, we silently bail out so that users who're * not using secure connections (initially everyone) don't * have to diagnose / put up with spurious errors. */ if (mkpath(dbpath(nssdb, sizeof(nssdb), "sql:"), 0700) < 0) return 0; secsts = NSS_InitReadWrite(nssdb); if (secsts != SECSuccess) { /* fallback, older versions of NSS do not support sql: */ dbpath(nssdb, sizeof(nssdb), ""); secsts = NSS_InitReadWrite(nssdb); } if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); if ((slot = PK11_GetInternalKeySlot()) != NULL) { if (PK11_NeedUserInit(slot)) PK11_InitPin(slot, NULL, SECURE_USERDB_DEFAULT_KEY); else if (PK11_NeedLogin(slot)) PK11_Authenticate(slot, PR_FALSE, NULL); PK11_FreeSlot(slot); } /* Some NSS versions don't do this correctly in NSS_SetDomesticPolicy. */ do { const PRUint16 *cipher; for (cipher = SSL_ImplementedCiphers; *cipher != 0; ++cipher) SSL_CipherPolicySet(*cipher, SSL_ALLOWED); } while (0); SSL_ClearSessionCache(); return 0; } int __pmShutdownCertificates(void) { if (NSS_Shutdown() != SECSuccess) return __pmSecureSocketsError(PR_GetError()); return 0; } static void saveUserCertificate(CERTCertificate *cert) { SECStatus secsts; PK11SlotInfo *slot = PK11_GetInternalKeySlot(); CERTCertTrust *trust = NULL; secsts = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, SECURE_SERVER_CERTIFICATE, PR_FALSE); if (secsts != SECSuccess) goto done; secsts = SECFailure; trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust)); if (!trust) goto done; secsts = CERT_DecodeTrustString(trust, "P,P,P"); if (secsts != SECSuccess) goto done; secsts = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, trust); done: if (slot) PK11_FreeSlot(slot); if (trust) PORT_Free(trust); /* * Issue a warning only, but continue, if we fail to save certificate * (this is not a fatal condition on setting up the secure socket). */ if (secsts != SECSuccess) { char errmsg[PM_MAXERRMSGLEN]; pmprintf("WARNING: Failed to save certificate locally: %s\n", pmErrStr_r(__pmSecureSocketsError(PR_GetError()), errmsg, sizeof(errmsg))); pmflush(); } } static int rejectUserCertificate(const char *message) { pmprintf("%s? (no)\n", message); pmflush(); return 0; } #ifdef HAVE_SYS_TERMIOS_H static int queryCertificateOK(const char *message) { int c, fd, sts = 0, count = 0; fd = fileno(stdin); /* if we cannot interact, simply assume the answer to be "no". */ if (!isatty(fd)) return rejectUserCertificate(message); do { struct termios saved, raw; pmprintf("%s (y/n)? ", message); pmflush(); /* save terminal state and temporarily enter raw terminal mode */ if (tcgetattr(fd, &saved) < 0) return 0; cfmakeraw(&raw); if (tcsetattr(fd, TCSAFLUSH, &raw) < 0) return 0; c = getchar(); if (c == 'y' || c == 'Y') sts = 1; /* yes */ else if (c == 'n' || c == 'N') sts = 0; /* no */ else sts = -1; /* dunno, try again (3x) */ tcsetattr(fd, TCSAFLUSH, &saved); pmprintf("\n"); } while (sts == -1 && ++count < 3); pmflush(); return sts; } #else static int queryCertificateOK(const char *message) { /* no way implemented to interact to query the user, so decline */ return rejectUserCertificate(message); } #endif static void reportFingerprint(SECItem *item) { unsigned char fingerprint[SHA1_LENGTH] = { 0 }; SECItem fitem; char *fstring; PK11_HashBuf(SEC_OID_SHA1, fingerprint, item->data, item->len); fitem.data = fingerprint; fitem.len = SHA1_LENGTH; fstring = CERT_Hexify(&fitem, 1); pmprintf("SHA1 fingerprint is %s\n", fstring); PORT_Free(fstring); } static SECStatus queryCertificateAuthority(PRFileDesc *sslsocket) { int sts; int secsts = SECFailure; char *result; CERTCertificate *servercert; result = SSL_RevealURL(sslsocket); pmprintf("WARNING: " "issuer of certificate received from host %s is not trusted.\n", result); PORT_Free(result); servercert = SSL_PeerCertificate(sslsocket); if (servercert) { reportFingerprint(&servercert->derCert); sts = queryCertificateOK("Do you want to accept and save this certificate locally anyway"); if (sts == 1) { saveUserCertificate(servercert); secsts = SECSuccess; } CERT_DestroyCertificate(servercert); } else { pmflush(); } return secsts; } static SECStatus queryCertificateDomain(PRFileDesc *sslsocket) { int sts; char *result; SECItem secitem = { 0 }; SECStatus secstatus = SECFailure; PRArenaPool *arena = NULL; CERTCertificate *servercert = NULL; /* * Propagate a warning through to the client. Show the expected * host, then list the DNS names from the server certificate. */ result = SSL_RevealURL(sslsocket); pmprintf("WARNING: " "The domain name %s does not match the DNS name(s) on the server certificate:\n", result); PORT_Free(result); servercert = SSL_PeerCertificate(sslsocket); secstatus = CERT_FindCertExtension(servercert, SEC_OID_X509_SUBJECT_ALT_NAME, &secitem); if (secstatus != SECSuccess || !secitem.data) { pmprintf("Unable to find alt name extension on the server certificate\n"); } else if ((arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE)) == NULL) { pmprintf("Out of memory while generating name list\n"); SECITEM_FreeItem(&secitem, PR_FALSE); } else { CERTGeneralName *namelist, *n; namelist = n = CERT_DecodeAltNameExtension(arena, &secitem); SECITEM_FreeItem(&secitem, PR_FALSE); if (!namelist) { pmprintf("Unable to decode alt name extension on server certificate\n"); } else { do { if (n->type == certDNSName) pmprintf(" %.*s\n", (int)n->name.other.len, n->name.other.data); n = CERT_GetNextGeneralName(n); } while (n != namelist); } } if (arena) PORT_FreeArena(arena, PR_FALSE); if (servercert) CERT_DestroyCertificate(servercert); sts = queryCertificateOK("Do you want to accept this certificate anyway"); return (sts == 1) ? SECSuccess : SECFailure; } static SECStatus badCertificate(void *arg, PRFileDesc *sslsocket) { (void)arg; switch (PR_GetError()) { case SSL_ERROR_BAD_CERT_DOMAIN: return queryCertificateDomain(sslsocket); case SEC_ERROR_UNKNOWN_ISSUER: return queryCertificateAuthority(sslsocket); default: break; } return SECFailure; } static int __pmAuthLogCB(void *context, int priority, const char *message) { if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmAuthLogCB enter ctx=%p pri=%d\n", __FILE__, context, priority); if (!message) return SASL_BADPARAM; switch (priority) { case SASL_LOG_NONE: return SASL_OK; case SASL_LOG_ERR: priority = LOG_ERR; break; case SASL_LOG_FAIL: priority = LOG_ALERT; break; case SASL_LOG_WARN: priority = LOG_WARNING; break; case SASL_LOG_NOTE: priority = LOG_NOTICE; break; case SASL_LOG_DEBUG: case SASL_LOG_TRACE: case SASL_LOG_PASS: if (pmDebug & DBG_TRACE_AUTH) priority = LOG_DEBUG; else return SASL_OK; break; default: priority = LOG_INFO; break; } __pmNotifyErr(priority, "%s", message); return SASL_OK; } #if !defined(IS_MINGW) static void echoOff(int fd) { if (isatty(fd)) { struct termios tio; tcgetattr(fd, &tio); tio.c_lflag &= ~ECHO; tcsetattr(fd, TCSAFLUSH, &tio); } } static void echoOn(int fd) { if (isatty(fd)) { struct termios tio; tcgetattr(fd, &tio); tio.c_lflag |= ECHO; tcsetattr(fd, TCSAFLUSH, &tio); } } #define fgetsQuietly(buf,length,input) fgets(buf,length,input) #define consoleName "/dev/tty" #else #define echoOn(fd) do { } while (0) #define echoOff(fd) do { } while (0) #define consoleName "CON:" static char *fgetsQuietly(char *buf, int length, FILE *input) { int c; char *end = buf; if (!isatty(fileno(input))) return fgets(buf, length, input); do { c = getch(); if (c == '\b') { if (end > buf) end--; } else if (--length > 0) *end++ = c; if (!c || c == '\n' || c == '\r') break; } while (1); return buf; } #endif static char *fgetsPrompt(FILE *in, FILE *out, const char *prompt, int secret) { size_t length; int infd = fileno(in); int isTTY = isatty(infd); char *value, phrase[256]; if (isTTY) { fprintf(out, "%s", prompt); fflush(out); if (secret) echoOff(infd); } memset(phrase, 0, sizeof(phrase)); value = fgetsQuietly(phrase, sizeof(phrase)-1, in); if (!value) return strdup(""); length = strlen(value) - 1; while (length && (value[length] == '\n' || value[length] == '\r')) value[length] = '\0'; if (isTTY && secret) { fprintf(out, "\n"); echoOn(infd); } return strdup(value); } /* * SASL is calling us looking for the value for a specific attribute; * we must respond as best we can: * - if user specified it on the command line, its in the given hash * - if we can interact, we can ask the user for it (taking care for * sensitive info like passwords, not to echo back to the user) * Also take care to handle non-console interactive modes, like the * pmchart case. Further, we should consider a mode where we extract * these values from a per-user config file too (ala. libvirt). * * Return value is a dynamically allocated string, caller must free. */ static char * __pmGetAttrConsole(const char *prompt, int secret) { FILE *input, *output; char *value, *console; /* * Interactive mode: open terminal and discuss with user * For graphical tools, we do not want to ever be here. * For testing, we want to just error out of here ASAP. */ console = getenv("PCP_CONSOLE"); if (console) { if (strcmp(console, "none") == 0) return NULL; } else { console = consoleName; } input = fopen(console, "r"); if (input == NULL) { __pmNotifyErr(LOG_ERR, "opening input terminal for read\n"); return NULL; } output = fopen(console, "w"); if (output == NULL) { __pmNotifyErr(LOG_ERR, "opening output terminal for write\n"); fclose(input); return NULL; } value = fgetsPrompt(input, output, prompt, secret); fclose(input); fclose(output); return value; } static char * __pmGetAttrValue(__pmAttrKey key, __pmHashCtl *attrs, const char *prompt) { __pmHashNode *node; char *value; if ((node = __pmHashSearch(key, attrs)) != NULL) return (char *)node->data; value = __pmGetAttrConsole(prompt, key == PCP_ATTR_PASSWORD); if (value) /* must track all our own memory use in SASL */ __pmHashAdd(key, value, attrs); return value; } static int __pmAuthRealmCB(void *context, int id, const char **realms, const char **result) { __pmHashCtl *attrs = (__pmHashCtl *)context; char *value = NULL; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmAuthRealmCB enter ctx=%p id=%#x\n", __FILE__, context, id); if (id != SASL_CB_GETREALM) return SASL_FAIL; value = __pmGetAttrValue(PCP_ATTR_REALM, attrs, "Realm: "); *result = (const char *)value; if (pmDebug & DBG_TRACE_AUTH) { fprintf(stderr, "%s:__pmAuthRealmCB ctx=%p, id=%#x, realms=(", __FILE__, context, id); if (realms) { if (*realms) fprintf(stderr, "%s", *realms); for (value = (char *) *(realms + 1); value && *value; value++) fprintf(stderr, " %s", value); } fprintf(stderr, ") -> rslt=%s\n", *result ? *result : "(none)"); } return SASL_OK; } static int __pmAuthSimpleCB(void *context, int id, const char **result, unsigned *len) { __pmHashCtl *attrs = (__pmHashCtl *)context; char *value = NULL; int sts; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmAuthSimpleCB enter ctx=%p id=%#x\n", __FILE__, context, id); if (!result) return SASL_BADPARAM; sts = SASL_OK; switch (id) { case SASL_CB_USER: case SASL_CB_AUTHNAME: value = __pmGetAttrValue(PCP_ATTR_USERNAME, attrs, "Username: "); break; case SASL_CB_LANGUAGE: break; default: sts = SASL_BADPARAM; break; } if (len) *len = value ? strlen(value) : 0; *result = value; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmAuthSimpleCB ctx=%p id=%#x -> sts=%d rslt=%p len=%d\n", __FILE__, context, id, sts, *result, len ? *len : -1); return sts; } static int __pmAuthSecretCB(sasl_conn_t *saslconn, void *context, int id, sasl_secret_t **secret) { __pmHashCtl *attrs = (__pmHashCtl *)context; size_t length = 0; char *password; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmAuthSecretCB enter ctx=%p id=%#x\n", __FILE__, context, id); if (saslconn == NULL || secret == NULL || id != SASL_CB_PASS) return SASL_BADPARAM; password = __pmGetAttrValue(PCP_ATTR_PASSWORD, attrs, "Password: "); length = password ? strlen(password) : 0; *secret = (sasl_secret_t *) calloc(1, sizeof(sasl_secret_t) + length + 1); if (!*secret) { free(password); return SASL_NOMEM; } if (password) { (*secret)->len = length; strcpy((char *)(*secret)->data, password); } if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmAuthSecretCB ctx=%p id=%#x -> data=%s len=%u\n", __FILE__, context, id, password, (unsigned)length); free(password); return SASL_OK; } static int __pmAuthPromptCB(void *context, int id, const char *challenge, const char *prompt, const char *defaultresult, const char **result, unsigned *length) { char *value, message[512]; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmAuthPromptCB enter ctx=%p id=%#x\n", __FILE__, context, id); if (id != SASL_CB_ECHOPROMPT && id != SASL_CB_NOECHOPROMPT) return SASL_BADPARAM; if (!prompt || !result || !length) return SASL_BADPARAM; if (defaultresult == NULL) defaultresult = ""; if (!challenge) snprintf(message, sizeof(message), "%s [%s]: ", prompt, defaultresult); else snprintf(message, sizeof(message), "%s [challenge: %s] [%s]: ", prompt, challenge, defaultresult); message[sizeof(message)-1] = '\0'; if (id == SASL_CB_ECHOPROMPT) { value = __pmGetAttrConsole(message, 0); if (value && value[0] != '\0') { *result = value; } else { free(value); *result = defaultresult; } } else { if (fgets(message, sizeof(message), stdin) == NULL || message[0]) *result = strdup(message); else *result = defaultresult; } if (!*result) return SASL_NOMEM; *length = (unsigned) strlen(*result); return SASL_OK; } static int __pmSecureClientIPCFlags(int fd, int flags, const char *hostname, __pmHashCtl *attrs) { __pmSecureSocket socket; sasl_callback_t *cb; SECStatus secsts; int sts; if (__pmDataIPC(fd, &socket) < 0) return -EOPNOTSUPP; if (socket.nsprFd == NULL) return -EOPNOTSUPP; if ((flags & PDU_FLAG_SECURE) != 0) { if ((socket.sslFd = SSL_ImportFD(NULL, socket.nsprFd)) == NULL) { __pmNotifyErr(LOG_ERR, "SecureClientIPCFlags: importing socket into SSL"); return PM_ERR_IPC; } socket.nsprFd = socket.sslFd; secsts = SSL_OptionSet(socket.sslFd, SSL_SECURITY, PR_TRUE); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); secsts = SSL_OptionSet(socket.sslFd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); secsts = SSL_SetURL(socket.sslFd, hostname); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); secsts = SSL_BadCertHook(socket.sslFd, (SSLBadCertHandler)badCertificate, NULL); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); } if ((flags & PDU_FLAG_COMPRESS) != 0) { secsts = SSL_OptionSet(socket.sslFd, SSL_ENABLE_DEFLATE, PR_TRUE); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); } if ((flags & PDU_FLAG_AUTH) != 0) { socket.saslCB = calloc(LIMIT_CLIENT_CALLBACKS, sizeof(sasl_callback_t)); if ((cb = socket.saslCB) == NULL) return -ENOMEM; cb->id = SASL_CB_USER; cb->proc = (sasl_callback_func)&__pmAuthSimpleCB; cb->context = (void *)attrs; cb++; cb->id = SASL_CB_AUTHNAME; cb->proc = (sasl_callback_func)&__pmAuthSimpleCB; cb->context = (void *)attrs; cb++; cb->id = SASL_CB_LANGUAGE; cb->proc = (sasl_callback_func)&__pmAuthSimpleCB; cb++; cb->id = SASL_CB_GETREALM; cb->proc = (sasl_callback_func)&__pmAuthRealmCB; cb->context = (void *)attrs; cb++; cb->id = SASL_CB_PASS; cb->proc = (sasl_callback_func)&__pmAuthSecretCB; cb->context = (void *)attrs; cb++; cb->id = SASL_CB_ECHOPROMPT; cb->proc = (sasl_callback_func)&__pmAuthPromptCB; cb++; cb->id = SASL_CB_NOECHOPROMPT; cb->proc = (sasl_callback_func)&__pmAuthPromptCB; cb++; cb->id = SASL_CB_LIST_END; cb++; assert(cb - socket.saslCB <= LIMIT_CLIENT_CALLBACKS); sts = sasl_client_new(SECURE_SERVER_SASL_SERVICE, hostname, NULL, NULL, /*iplocal,ipremote*/ socket.saslCB, 0, &socket.saslConn); if (sts != SASL_OK && sts != SASL_CONTINUE) return __pmSecureSocketsError(sts); } /* save changes back into the IPC table (updates client sslFd) */ return __pmSetDataIPC(fd, (void *)&socket); } static int __pmSecureClientNegotiation(int fd, int *strength) { PRIntervalTime timer; PRFileDesc *sslsocket; SECStatus secsts; int enabled, keysize; int msec; sslsocket = (PRFileDesc *)__pmGetSecureSocket(fd); if (!sslsocket) return -EINVAL; secsts = SSL_ResetHandshake(sslsocket, PR_FALSE /*client*/); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); msec = __pmConvertTimeout(TIMEOUT_DEFAULT); timer = PR_MillisecondsToInterval(msec); secsts = SSL_ForceHandshakeWithTimeout(sslsocket, timer); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); secsts = SSL_SecurityStatus(sslsocket, &enabled, NULL, &keysize, NULL, NULL, NULL); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); *strength = (enabled > 0) ? keysize : DEFAULT_SECURITY_STRENGTH; return 0; } static void __pmInitAuthPaths(void) { char *path; if ((path = getenv("PCP_SASL2_PLUGIN_PATH")) != NULL) sasl_set_path(SASL_PATH_TYPE_PLUGIN, path); if ((path = getenv("PCP_SASL2_CONFIG_PATH")) != NULL) sasl_set_path(SASL_PATH_TYPE_CONFIG, path); } static sasl_callback_t common_callbacks[] = { \ { .id = SASL_CB_LOG, .proc = (sasl_callback_func)&__pmAuthLogCB }, { .id = SASL_CB_LIST_END }}; int __pmInitAuthClients(void) { __pmInitAuthPaths(); if (sasl_client_init(common_callbacks) != SASL_OK) return -EINVAL; return 0; } int __pmInitAuthServer(void) { __pmInitAuthPaths(); if (sasl_server_init(common_callbacks, pmProgname) != SASL_OK) return -EINVAL; return 0; } static int __pmAuthClientSetProperties(sasl_conn_t *saslconn, int ssf) { int sts; sasl_security_properties_t props; /* set external security strength factor */ if ((sts = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf)) != SASL_OK) return __pmSecureSocketsError(sts); /* set general security properties */ memset(&props, 0, sizeof(props)); props.maxbufsize = LIMIT_AUTH_PDU; props.max_ssf = UINT_MAX; if ((sts = sasl_setprop(saslconn, SASL_SEC_PROPS, &props)) != SASL_OK) return __pmSecureSocketsError(sts); return 0; } static int __pmAuthClientNegotiation(int fd, int ssf, const char *hostname, __pmHashCtl *attrs) { int sts, zero, saslsts = SASL_FAIL; int pinned, length, method_length; char *payload, buffer[LIMIT_AUTH_PDU]; const char *method = NULL; sasl_conn_t *saslconn; __pmHashNode *node; __pmPDU *pb; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmAuthClientNegotiation(fd=%d, ssf=%d, host=%s)\n", __FILE__, fd, ssf, hostname); if ((saslconn = (sasl_conn_t *)__pmGetUserAuthData(fd)) == NULL) return -EINVAL; /* setup all the security properties for this connection */ if ((sts = __pmAuthClientSetProperties(saslconn, ssf)) < 0) return sts; /* lookup users preferred connection method, if specified */ if ((node = __pmHashSearch(PCP_ATTR_METHOD, attrs)) != NULL) method = (const char *)node->data; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmAuthClientNegotiation requesting \"%s\" method\n", __FILE__, method ? method : "default"); /* get security mechanism list */ sts = pinned = __pmGetPDU(fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb); if (sts == PDU_AUTH) { sts = __pmDecodeAuth(pb, &zero, &payload, &length); if (sts >= 0) { strncpy(buffer, payload, length); buffer[length] = '\0'; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmAuthClientNegotiation got methods: " "\"%s\" (%d)\n", __FILE__, buffer, length); /* * buffer now contains the list of server mechanisms - * override using users preference (if any) and proceed. */ if (method) { strncpy(buffer, method, sizeof(buffer)); buffer[sizeof(buffer) - 1] = '\0'; length = strlen(buffer); } payload = NULL; saslsts = sasl_client_start(saslconn, buffer, NULL, (const char **)&payload, (unsigned int *)&length, &method); if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) { sts = __pmSecureSocketsError(saslsts); if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "sasl_client_start failed: %d (%s)\n", saslsts, pmErrStr(sts)); } } } else if (sts == PDU_ERROR) { __pmDecodeError(pb, &sts); } else if (sts != PM_ERR_TIMEOUT) { sts = PM_ERR_IPC; } if (pinned) __pmUnpinPDUBuf(pb); if (sts < 0) return sts; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "sasl_client_start chose \"%s\" method, saslsts=%s\n", method, saslsts == SASL_CONTINUE ? "continue" : "ok"); /* tell server we've made a decision and are ready to move on */ strncpy(buffer, method, sizeof(buffer)); buffer[sizeof(buffer) - 1] = '\0'; method_length = strlen(buffer); if (payload) { if (LIMIT_AUTH_PDU - method_length - 1 < length) return -E2BIG; memcpy(buffer + method_length + 1, payload, length); length += method_length + 1; } else { length = method_length + 1; } if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "sasl_client_start sending (%d bytes) \"%s\"\n", length, buffer); if ((sts = __pmSendAuth(fd, FROM_ANON, 0, buffer, length)) < 0) return sts; while (saslsts == SASL_CONTINUE) { if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmAuthClientNegotiation awaiting server reply\n", __FILE__); sts = pinned = __pmGetPDU(fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb); if (sts == PDU_AUTH) { sts = __pmDecodeAuth(pb, &zero, &payload, &length); if (sts >= 0) { saslsts = sasl_client_step(saslconn, payload, length, NULL, (const char **)&buffer, (unsigned int *)&length); if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) { sts = __pmSecureSocketsError(saslsts); if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "sasl_client_step failed: %d (%s)\n", saslsts, pmErrStr(sts)); break; } if (pmDebug & DBG_TRACE_AUTH) { fprintf(stderr, "%s:__pmAuthClientNegotiation" " step recv (%d bytes)", __FILE__, length); } } } else if (sts == PDU_ERROR) { __pmDecodeError(pb, &sts); } else if (sts != PM_ERR_TIMEOUT) { sts = PM_ERR_IPC; } if (pinned) __pmUnpinPDUBuf(pb); if (sts >= 0) sts = __pmSendAuth(fd, FROM_ANON, 0, length ? buffer : "", length); if (sts < 0) break; } if (pmDebug & DBG_TRACE_AUTH) { if (sts < 0) fprintf(stderr, "%s:__pmAuthClientNegotiation loop failed\n", __FILE__); else { saslsts = sasl_getprop(saslconn, SASL_USERNAME, (const void **)&payload); fprintf(stderr, "%s:__pmAuthClientNegotiation success, username=%s\n", __FILE__, saslsts != SASL_OK ? "?" : payload); } } return sts; } int __pmSecureClientHandshake(int fd, int flags, const char *hostname, __pmHashCtl *attrs) { int sts, ssf = DEFAULT_SECURITY_STRENGTH; if (flags & PDU_FLAG_CREDS_REQD) { if (__pmHashSearch(PCP_ATTR_UNIXSOCK, attrs) != NULL) return 0; flags |= PDU_FLAG_AUTH; /* force the use of SASL authentication */ } if ((sts = __pmSecureClientIPCFlags(fd, flags, hostname, attrs)) < 0) return sts; if (((flags & PDU_FLAG_SECURE) != 0) && ((sts = __pmSecureClientNegotiation(fd, &ssf)) < 0)) return sts; if (((flags & PDU_FLAG_AUTH) != 0) && ((sts = __pmAuthClientNegotiation(fd, ssf, hostname, attrs)) < 0)) return sts; return 0; } void * __pmGetSecureSocket(int fd) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) < 0) return NULL; return (void *)socket.sslFd; } void * __pmGetUserAuthData(int fd) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) < 0) return NULL; return (void *)socket.saslConn; } int __pmSecureServerIPCFlags(int fd, int flags) { __pmSecureSocket socket; SECStatus secsts; int saslsts; if (__pmDataIPC(fd, &socket) < 0) return -EOPNOTSUPP; if (socket.nsprFd == NULL) return -EOPNOTSUPP; if ((flags & PDU_FLAG_SECURE) != 0) { if ((socket.sslFd = SSL_ImportFD(NULL, socket.nsprFd)) == NULL) return __pmSecureSocketsError(PR_GetError()); socket.nsprFd = socket.sslFd; secsts = SSL_OptionSet(socket.sslFd, SSL_NO_LOCKS, PR_TRUE); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); secsts = SSL_OptionSet(socket.sslFd, SSL_SECURITY, PR_TRUE); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); secsts = SSL_OptionSet(socket.sslFd, SSL_HANDSHAKE_AS_SERVER, PR_TRUE); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); secsts = SSL_OptionSet(socket.sslFd, SSL_REQUEST_CERTIFICATE, PR_FALSE); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); secsts = SSL_OptionSet(socket.sslFd, SSL_REQUIRE_CERTIFICATE, PR_FALSE); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); } if ((flags & PDU_FLAG_COMPRESS) != 0) { secsts = SSL_OptionSet(socket.nsprFd, SSL_ENABLE_DEFLATE, PR_TRUE); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); } if ((flags & PDU_FLAG_AUTH) != 0) { saslsts = sasl_server_new(SECURE_SERVER_SASL_SERVICE, NULL, NULL, /*localdomain,userdomain*/ NULL, NULL, NULL, /*iplocal,ipremote,callbacks*/ 0, &socket.saslConn); if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "%s:__pmSecureServerIPCFlags SASL server: %d\n", __FILE__, saslsts); if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) return __pmSecureSocketsError(saslsts); } /* save changes back into the IPC table */ return __pmSetDataIPC(fd, (void *)&socket); } static int sockOptValue(const void *option_value, __pmSockLen option_len) { switch(option_len) { case sizeof(int): return *(int *)option_value; default: __pmNotifyErr(LOG_ERR, "sockOptValue: invalid option length: %d\n", option_len); break; } return 0; } int __pmSetSockOpt(int fd, int level, int option_name, const void *option_value, __pmSockLen option_len) { /* Map the request to the NSPR equivalent, if possible. */ PRSocketOptionData option_data; __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { switch(level) { case SOL_SOCKET: switch(option_name) { /* * These options are not related. They are just both options for which * NSPR has no direct mapping. */ #ifdef IS_MINGW case SO_EXCLUSIVEADDRUSE: /* Only exists on MINGW */ #endif { /* * There is no direct mapping of this option in NSPR. * The best we can do is to use the native handle and * call setsockopt on that handle. */ fd = PR_FileDesc2NativeHandle(socket.nsprFd); return setsockopt(fd, level, option_name, option_value, option_len); } case SO_KEEPALIVE: option_data.option = PR_SockOpt_Keepalive; option_data.value.keep_alive = sockOptValue(option_value, option_len); break; case SO_LINGER: { struct linger *linger = (struct linger *)option_value; option_data.option = PR_SockOpt_Linger; option_data.value.linger.polarity = linger->l_onoff; option_data.value.linger.linger = linger->l_linger; break; } case SO_REUSEADDR: option_data.option = PR_SockOpt_Reuseaddr; option_data.value.reuse_addr = sockOptValue(option_value, option_len); break; default: __pmNotifyErr(LOG_ERR, "%s:__pmSetSockOpt: unimplemented option_name for SOL_SOCKET: %d\n", __FILE__, option_name); return -1; } break; case IPPROTO_TCP: if (option_name == TCP_NODELAY) { option_data.option = PR_SockOpt_NoDelay; option_data.value.no_delay = sockOptValue(option_value, option_len); break; } __pmNotifyErr(LOG_ERR, "%s:__pmSetSockOpt: unimplemented option_name for IPPROTO_TCP: %d\n", __FILE__, option_name); return -1; case IPPROTO_IPV6: if (option_name == IPV6_V6ONLY) { /* * There is no direct mapping of this option in NSPR. * The best we can do is to use the native handle and * call setsockopt on that handle. */ fd = PR_FileDesc2NativeHandle(socket.nsprFd); return setsockopt(fd, level, option_name, option_value, option_len); } __pmNotifyErr(LOG_ERR, "%s:__pmSetSockOpt: unimplemented option_name for IPPROTO_IPV6: %d\n", __FILE__, option_name); return -1; default: __pmNotifyErr(LOG_ERR, "%s:__pmSetSockOpt: unimplemented level: %d\n", __FILE__, level); return -1; } return (PR_SetSocketOption(socket.nsprFd, &option_data) == PR_SUCCESS) ? 0 : -1; } /* We have a native socket. */ return setsockopt(fd, level, option_name, option_value, option_len); } int __pmGetSockOpt(int fd, int level, int option_name, void *option_value, __pmSockLen *option_len) { __pmSecureSocket socket; /* Map the request to the NSPR equivalent, if possible. */ if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { switch (level) { case SOL_SOCKET: switch(option_name) { #if defined(HAVE_STRUCT_UCRED) case SO_PEERCRED: #endif case SO_ERROR: { /* * There is no direct mapping of this option in NSPR. * Best we can do is call getsockopt on the native fd. */ fd = PR_FileDesc2NativeHandle(socket.nsprFd); return getsockopt(fd, level, option_name, option_value, option_len); } default: __pmNotifyErr(LOG_ERR, "%s:__pmGetSockOpt: unimplemented option_name for SOL_SOCKET: %d\n", __FILE__, option_name); return -1; } break; default: __pmNotifyErr(LOG_ERR, "%s:__pmGetSockOpt: unimplemented level: %d\n", __FILE__, level); break; } return -1; } /* We have a native socket. */ return getsockopt(fd, level, option_name, option_value, option_len); } /* * Initialize a socket address. The integral address must be INADDR_ANY or * INADDR_LOOPBACK in host byte order. */ void __pmSockAddrInit(__pmSockAddr *addr, int family, int address, int port) { PRStatus prStatus; switch(address) { case INADDR_ANY: prStatus = PR_SetNetAddr(PR_IpAddrAny, family, port, &addr->sockaddr); break; case INADDR_LOOPBACK: prStatus = PR_SetNetAddr(PR_IpAddrLoopback, family, port, &addr->sockaddr); break; default: __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrInit: Invalid address %d\n", __FILE__, address); return; } if (prStatus != PR_SUCCESS) __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrInit: PR_InitializeNetAddr failure: %d\n", __FILE__, PR_GetError()); } void __pmSockAddrSetFamily(__pmSockAddr *addr, int family) { if (family == AF_INET) addr->sockaddr.raw.family = PR_AF_INET; else if (family == AF_INET6) addr->sockaddr.raw.family = PR_AF_INET6; #if defined(HAVE_STRUCT_SOCKADDR_UN) else if (family == AF_UNIX) addr->sockaddr.raw.family = PR_AF_LOCAL; #endif else __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrSetFamily: Invalid address family: %d\n", __FILE__, family); } int __pmSockAddrGetFamily(const __pmSockAddr *addr) { if (addr->sockaddr.raw.family == PR_AF_INET) return AF_INET; if (addr->sockaddr.raw.family == PR_AF_INET6) return AF_INET6; #if defined(HAVE_STRUCT_SOCKADDR_UN) if (addr->sockaddr.raw.family == PR_AF_LOCAL) return AF_UNIX; #endif __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrGetFamily: Invalid address family: %d\n", __FILE__, addr->sockaddr.raw.family); return 0; /* not set */ } void __pmSockAddrSetPort(__pmSockAddr *addr, int port) { if (addr->sockaddr.raw.family == PR_AF_INET) addr->sockaddr.inet.port = htons(port); else if (addr->sockaddr.raw.family == PR_AF_INET6) addr->sockaddr.ipv6.port = htons(port); else __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrSetPort: Invalid address family: %d\n", __FILE__, addr->sockaddr.raw.family); } int __pmSockAddrGetPort(const __pmSockAddr *addr) { if (addr->sockaddr.raw.family == PR_AF_INET) return ntohs(addr->sockaddr.inet.port); if (addr->sockaddr.raw.family == PR_AF_INET6) return ntohs(addr->sockaddr.ipv6.port); __pmNotifyErr(LOG_ERR, "__pmSockAddrGetPort: Invalid address family: %d\n", addr->sockaddr.raw.family); return 0; /* not set */ } void __pmSockAddrSetScope(__pmSockAddr *addr, int scope) { if (addr->sockaddr.raw.family == PR_AF_INET6) addr->sockaddr.ipv6.scope_id = scope; } void __pmSockAddrSetPath(__pmSockAddr *addr, const char *path) { #if defined(HAVE_STRUCT_SOCKADDR_UN) if (addr->sockaddr.raw.family == PR_AF_LOCAL) { strncpy(addr->sockaddr.local.path, path, sizeof(addr->sockaddr.local.path)); addr->sockaddr.local.path[sizeof(addr->sockaddr.local.path)-1] = '\0'; } else { __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrSetPath: Invalid address family: %d\n", __FILE__, addr->sockaddr.raw.family); } #else __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrSetPath: AF_UNIX is not supported\n", __FILE__); #endif } int __pmListen(int fd, int backlog) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) return PR_Listen(socket.nsprFd, backlog) == PR_SUCCESS ? 0 : -1; return listen(fd, backlog); } int __pmAccept(int fd, void *addr, __pmSockLen *addrlen) { __pmSecureSocket socket; __pmSockAddr *sockAddr = (__pmSockAddr *)addr; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { PRIntervalTime timer; PRFileDesc *nsprFd; int msec; msec = __pmConvertTimeout(TIMEOUT_CONNECT); timer = PR_MillisecondsToInterval(msec); nsprFd = PR_Accept(socket.nsprFd, &sockAddr->sockaddr, timer); if (nsprFd == NULL) return -1; /* Add the accepted socket to the fd table. */ fd = newNSPRHandle(); socket.nsprFd = nsprFd; __pmSetDataIPC(fd, (void *)&socket); } else fd = accept(fd, (struct sockaddr *)sockAddr, addrlen); __pmCheckAcceptedAddress(sockAddr); return fd; } int __pmBind(int fd, void *addr, __pmSockLen addrlen) { __pmSecureSocket socket; int family; family = __pmSockAddrGetFamily((__pmSockAddr *)addr); if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { __pmSockAddr *nsprAddr = (__pmSockAddr *)addr; PRSocketOptionData socketOption; #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_CONTEXT) && (pmDebug & DBG_TRACE_DESPERATE)) { PRStatus prStatus; char buf[1024]; // at least PM_NET_ADDR_STRING_SIZE prStatus = PR_NetAddrToString((PRNetAddr *)addr, buf, sizeof(buf)); fprintf(stderr, "%s:__pmBind(fd=%d, family=%d, port=%d, addr=%s) using PR_Bind\n", __FILE__, fd, family, __pmSockAddrGetPort(nsprAddr), prStatus == PR_SUCCESS ? buf : ""); } #endif /* * Allow the socket address to be reused, in case we want the * same port across a service restart. */ socketOption.option = PR_SockOpt_Reuseaddr; socketOption.value.reuse_addr = PR_TRUE; PR_SetSocketOption(socket.nsprFd, &socketOption); return (PR_Bind(socket.nsprFd, &nsprAddr->sockaddr) == PR_SUCCESS) ? 0 : -1; } #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_CONTEXT) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "%s:__pmBind(fd=%d, family=%d, port=%d, addr=%s) using bind\n", __FILE__, fd, family, __pmSockAddrGetPort((__pmSockAddr *)addr), __pmSockAddrToString((__pmSockAddr *)addr)); } #endif return bind(fd, (struct sockaddr *)addr, addrlen); } int __pmConnect(int fd, void *addr, __pmSockLen addrlen) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { PRIntervalTime timer; int msec; PRStatus sts; msec = __pmConvertTimeout(TIMEOUT_CONNECT); timer = PR_MillisecondsToInterval(msec); sts = PR_Connect(socket.nsprFd, (PRNetAddr *)addr, timer); #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_CONTEXT) && (pmDebug & DBG_TRACE_DESPERATE)) { PRStatus prStatus; char buf[1024]; // at least PM_NET_ADDR_STRING_SIZE prStatus = PR_NetAddrToString((PRNetAddr *)addr, buf, sizeof(buf)); fprintf(stderr, "%s:__pmConnect(fd=%d(nsprFd=%p), %s) ->", __FILE__, fd, socket.nsprFd, prStatus == PR_SUCCESS ? buf : ""); if (sts == PR_SUCCESS) fprintf(stderr, " OK\n"); else { int code = __pmSecureSocketsError(PR_GetError()); pmErrStr_r(code, buf, sizeof(buf)); fprintf(stderr, " %s\n", buf); } } #endif return (sts == PR_SUCCESS) ? 0 : -1; } return connect(fd, (struct sockaddr *)addr, addrlen); } int __pmGetFileStatusFlags(int fd) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { /* * There is no direct mapping of this function in NSPR. * Best we can do is to call fcntl on the native fd. */ fd = PR_FileDesc2NativeHandle(socket.nsprFd); } return fcntl(fd, F_GETFL); } int __pmSetFileStatusFlags(int fd, int flags) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { /* * There is no direct mapping of this function in NSPR. * Best we can do is to call fcntl on the native fd. */ fd = PR_FileDesc2NativeHandle(socket.nsprFd); } return fcntl(fd, F_SETFL, flags); } int __pmGetFileDescriptorFlags(int fd) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { /* * There is no direct mapping of this function in NSPR. * Best we can do is to call fcntl on the native fd. */ fd = PR_FileDesc2NativeHandle(socket.nsprFd); } return fcntl(fd, F_GETFD); } int __pmSetFileDescriptorFlags(int fd, int flags) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { /* * There is no direct mapping of this function in NSPR. * Best we can do is to call fcntl on the native fd. */ fd = PR_FileDesc2NativeHandle(socket.nsprFd); } return fcntl(fd, F_SETFD, flags); } ssize_t __pmWrite(int fd, const void *buffer, size_t length) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { ssize_t size = PR_Write(socket.nsprFd, buffer, length); if (size < 0) __pmSecureSocketsError(PR_GetError()); return size; } return write(fd, buffer, length); } ssize_t __pmRead(int fd, void *buffer, size_t length) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { ssize_t size = PR_Read(socket.nsprFd, buffer, length); if (size < 0) __pmSecureSocketsError(PR_GetError()); return size; } return read(fd, buffer, length); } ssize_t __pmSend(int fd, const void *buffer, size_t length, int flags) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { ssize_t size = PR_Write(socket.nsprFd, buffer, length); if (size < 0) __pmSecureSocketsError(PR_GetError()); return size; } return send(fd, buffer, length, flags); } ssize_t __pmRecv(int fd, void *buffer, size_t length, int flags) { __pmSecureSocket socket; ssize_t size; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_PDU) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "%s:__pmRecv[secure](", __FILE__); } #endif size = PR_Read(socket.nsprFd, buffer, length); if (size < 0) __pmSecureSocketsError(PR_GetError()); } else { #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_PDU) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "%s:__pmRecv(", __FILE__); } #endif size = recv(fd, buffer, length, flags); } #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_PDU) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "%d, ..., %d, " PRINTF_P_PFX "%x) -> %d\n", fd, (int)length, flags, (int)size); } #endif return size; } int __pmFD(int fd) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) return PR_FileDesc2NativeHandle(socket.nsprFd); return fd; } void __pmFD_CLR(int fd, __pmFdSet *set) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { fd -= NSPR_HANDLE_BASE; FD_CLR(fd, &set->nspr_set); /* Reset the max fd, if necessary. */ if (fd + 1 >= set->num_nspr_fds) { for (--fd; fd >= 0; --fd) { if (FD_ISSET(fd, &set->nspr_set)) break; } set->num_nspr_fds = fd + 1; } } else { FD_CLR(fd, &set->native_set); /* Reset the max fd, if necessary. */ if (fd + 1 >= set->num_native_fds) { for (--fd; fd >= 0; --fd) { if (FD_ISSET(fd, &set->native_set)) break; } set->num_native_fds = fd + 1; } } } int __pmFD_ISSET(int fd, __pmFdSet *set) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { fd -= NSPR_HANDLE_BASE; return FD_ISSET(fd, &set->nspr_set); } return FD_ISSET(fd, &set->native_set); } void __pmFD_SET(int fd, __pmFdSet *set) { __pmSecureSocket socket; if (__pmDataIPC(fd, &socket) == 0 && socket.nsprFd) { fd -= NSPR_HANDLE_BASE; FD_SET(fd, &set->nspr_set); /* Reset the max fd, if necessary. */ if (fd >= set->num_nspr_fds) set->num_nspr_fds = fd + 1; } else { FD_SET(fd, &set->native_set); /* Reset the max fd, if necessary. */ if (fd >= set->num_native_fds) set->num_native_fds = fd + 1; } } void __pmFD_ZERO(__pmFdSet *set) { FD_ZERO(&set->nspr_set); FD_ZERO(&set->native_set); set->num_nspr_fds = 0; set->num_native_fds = 0; } void __pmFD_COPY(__pmFdSet *s1, const __pmFdSet *s2) { memcpy(s1, s2, sizeof(*s1)); } static int nsprSelect(int rwflag, __pmFdSet *fds, struct timeval *timeout) { __pmSecureSocket socket; fd_set combined; int numCombined; int fd; int ready; int nativeFD; char errmsg[PM_MAXERRMSGLEN]; /* * fds contains two sets; one of native file descriptors and one of * NSPR file descriptors. We can't poll them separately, since one * may block the other. We can either convert the native file * descriptors to NSPR or vice-versa. The NSPR function PR_Poll * does not seem to respond to SIGINT, so we will convert the NSPR * file descriptors to native ones and use select(2) to do the * polling. * First initialize our working set from the set of native file * descriptors in fds. */ combined = fds->native_set; numCombined = fds->num_native_fds; /* Now add the native fds associated with the NSPR fds in nspr_set, if any. */ for (fd = 0; fd < fds->num_nspr_fds; ++fd) { if (FD_ISSET(fd, &fds->nspr_set)) { __pmDataIPC(NSPR_HANDLE_BASE + fd, &socket); nativeFD = PR_FileDesc2NativeHandle(socket.nsprFd); FD_SET(nativeFD, &combined); if (nativeFD >= numCombined) numCombined = nativeFD + 1; } } /* Use the select(2) function to do the polling. Ignore the nfds passed to us and use the number that we have computed. */ if (rwflag == PR_POLL_READ) ready = select(numCombined, &combined, NULL, NULL, timeout); else ready = select(numCombined, NULL, &combined, NULL, timeout); if (ready < 0 && neterror() != EINTR) { __pmNotifyErr(LOG_ERR, "nsprSelect: error polling file descriptors: %s\n", netstrerror_r(errmsg, sizeof(errmsg))); return -1; } /* Separate the results into their corresponding sets again. */ for (fd = 0; fd < fds->num_nspr_fds; ++fd) { if (FD_ISSET(fd, &fds->nspr_set)) { __pmDataIPC(NSPR_HANDLE_BASE + fd, &socket); nativeFD = PR_FileDesc2NativeHandle(socket.nsprFd); /* As we copy the result to the nspr set, make sure the bit is cleared in the combined set. That way we can simply copy the resulting combined set to the native set when we're done. */ if (! FD_ISSET(nativeFD, &combined)) FD_CLR(fd, &fds->nspr_set); else FD_CLR(nativeFD, &combined); } } fds->native_set = combined; /* Reset the size of each set. */ while (fds->num_nspr_fds > 0 && ! FD_ISSET(fds->num_nspr_fds - 1, &fds->nspr_set)) --fds->num_nspr_fds; while (fds->num_native_fds > 0 && ! FD_ISSET(fds->num_native_fds - 1, &fds->native_set)) --fds->num_native_fds; /* Return the total number of ready fds. */ return ready; } int __pmSelectRead(int nfds, __pmFdSet *readfds, struct timeval *timeout) { return nsprSelect(PR_POLL_READ, readfds, timeout); } int __pmSelectWrite(int nfds, __pmFdSet *writefds, struct timeval *timeout) { return nsprSelect(PR_POLL_WRITE, writefds, timeout); } /* * In certain situations, we need to allow access to previously-read * data on a socket. This is because, for example, the SSL protocol * buffering may have already consumed data that we are now expecting * (in this case, its buffered internally and a socket read will give * up that data). * * PR_Poll does not seem to play well here and so we need to use the * native select-based mechanism to block and/or query the state of * pending data. */ int __pmSocketReady(int fd, struct timeval *timeout) { __pmSecureSocket socket; __pmFdSet onefd; if (__pmDataIPC(fd, &socket) == 0 && socket.sslFd) if (SSL_DataPending(socket.sslFd)) return 1; /* proceed without blocking */ __pmFD_ZERO(&onefd); __pmFD_SET(fd, &onefd); return nsprSelect(PR_POLL_READ, &onefd, timeout); } char * __pmGetNameInfo(__pmSockAddr *address) { char buffer[PR_NETDB_BUF_SIZE]; char *name; PRHostEnt he; PRStatus prStatus = PR_GetHostByAddr(&address->sockaddr, &buffer[0], sizeof(buffer), &he); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DESPERATE) { if (prStatus != PR_SUCCESS) { fprintf(stderr, "%s:PR_GetHostByAddr(%s) returns %d (%s)\n", __FILE__, __pmSockAddrToString(address), PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT)); } } #endif name = (prStatus == PR_SUCCESS ? strdup(he.h_name) : NULL); return name; } __pmHostEnt * __pmGetAddrInfo(const char *hostName) { __pmHostEnt *he = __pmHostEntAlloc(); if (he != NULL) { he->addresses = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC, PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME); if (he->addresses == NULL) { __pmHostEntFree(he); return NULL; } /* Leave the host name NULL. It will be looked up on demand in __pmHostEntGetName(). */ } return he; } __pmSockAddr * __pmHostEntGetSockAddr(const __pmHostEnt *he, void **ei) { __pmSockAddr* addr; addr = __pmSockAddrAlloc(); if (addr == NULL) { __pmNotifyErr(LOG_ERR, "%s:__pmHostEntGetSockAddr: out of memory\n", __FILE__); *ei = NULL; return NULL; } *ei = PR_EnumerateAddrInfo(*ei, he->addresses, 0, &addr->sockaddr); if (*ei == NULL) { /* End of the address chain or an error. No address to return. */ __pmSockAddrFree(addr); return NULL; } return addr; } __pmSockAddr * __pmSockAddrMask(__pmSockAddr *addr, const __pmSockAddr *mask) { int i; if (addr->sockaddr.raw.family != mask->sockaddr.raw.family) { __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrMask: Address family of the address (%d) must match that of the mask (%d)\n", __FILE__, addr->sockaddr.raw.family, mask->sockaddr.raw.family); } else if (addr->sockaddr.raw.family == PR_AF_INET) addr->sockaddr.inet.ip &= mask->sockaddr.inet.ip; else if (addr->sockaddr.raw.family == PR_AF_INET6) { /* IPv6: Mask it byte by byte */ char *addrBytes = (char *)&addr->sockaddr.ipv6.ip; const char *maskBytes = (const char *)&mask->sockaddr.ipv6.ip; for (i = 0; i < sizeof(addr->sockaddr.ipv6.ip); ++i) addrBytes[i] &= maskBytes[i]; } #if defined(HAVE_STRUCT_SOCKADDR_UN) else if (addr->sockaddr.raw.family == PR_AF_LOCAL) { /* Simply truncate the path in the address to the length of the mask. */ i = strlen(mask->sockaddr.local.path); addr->sockaddr.local.path[i] = '\0'; } #endif else /* not applicable to other address families, e.g. PR_AF_LOCAL. */ __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrMask: Invalid address family: %d\n", __FILE__, addr->sockaddr.raw.family); return addr; } int __pmSockAddrCompare(const __pmSockAddr *addr1, const __pmSockAddr *addr2) { if (addr1->sockaddr.raw.family != addr2->sockaddr.raw.family) return addr1->sockaddr.raw.family - addr2->sockaddr.raw.family; if (addr1->sockaddr.raw.family == PR_AF_INET) return addr1->sockaddr.inet.ip - addr2->sockaddr.inet.ip; if (addr1->sockaddr.raw.family == PR_AF_INET6) { /* IPv6: Compare it byte by byte */ return memcmp(&addr1->sockaddr.ipv6.ip, &addr2->sockaddr.ipv6.ip, sizeof(addr1->sockaddr.ipv6.ip)); } #if defined(HAVE_STRUCT_SOCKADDR_UN) if (addr1->sockaddr.raw.family == PR_AF_LOCAL) { /* Unix Domain: Compare the paths */ return strncmp(addr1->sockaddr.local.path, addr2->sockaddr.local.path, sizeof(addr1->sockaddr.local.path)); } #endif /* not applicable to other address families, e.g. PR_AF_LOCAL. */ __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrCompare: Invalid address family: %d\n", __FILE__, addr1->sockaddr.raw.family); return 1; /* not equal */ } int __pmSockAddrIsInet(const __pmSockAddr *addr) { return addr->sockaddr.raw.family == PR_AF_INET; } int __pmSockAddrIsIPv6(const __pmSockAddr *addr) { return addr->sockaddr.raw.family == PR_AF_INET6; } int __pmSockAddrIsUnix(const __pmSockAddr *addr) { return addr->sockaddr.raw.family == PR_AF_LOCAL; } __pmSockAddr * __pmStringToSockAddr(const char *cp) { PRStatus prStatus; __pmSockAddr *addr = __pmSockAddrAlloc(); if (addr) { if (cp == NULL || strcmp(cp, "INADDR_ANY") == 0) { prStatus = PR_InitializeNetAddr (PR_IpAddrAny, 0, &addr->sockaddr); /* Set the address family to 0, meaning "not set". */ addr->sockaddr.raw.family = 0; } #if defined(HAVE_STRUCT_SOCKADDR_UN) else if (*cp == __pmPathSeparator()) { if (strlen(cp) >= sizeof(addr->sockaddr.local.path)) prStatus = PR_FAILURE; /* too long */ else { addr->sockaddr.raw.family = PR_AF_LOCAL; strcpy(addr->sockaddr.local.path, cp); prStatus = PR_SUCCESS; } } #endif else prStatus = PR_StringToNetAddr(cp, &addr->sockaddr); if (prStatus != PR_SUCCESS) { __pmSockAddrFree(addr); addr = NULL; } } return addr; } /* * Convert an address to a string. * The caller must free the buffer. */ #define PM_NET_ADDR_STRING_SIZE 46 /* from the NSPR API reference */ char * __pmSockAddrToString(__pmSockAddr *addr) { PRStatus prStatus; char *buf; /* PR_NetAddrToString() does not handle PR_AF_LOCAL. Handle it ourselves. */ if (addr->sockaddr.raw.family == PR_AF_LOCAL) return strdup (addr->sockaddr.local.path); /* Otherwise, let NSPR construct the string. */ buf = malloc(PM_NET_ADDR_STRING_SIZE); if (buf) { prStatus = PR_NetAddrToString(&addr->sockaddr, buf, PM_NET_ADDR_STRING_SIZE); if (prStatus != PR_SUCCESS) { free(buf); return NULL; } } return buf; } pcp-3.8.12ubuntu1/src/libpcp/src/endian.c0000664000000000000000000001503012272262501015032 0ustar /* * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ /* * Bit field typedefs for endian translations to support little endian * hosts. * * For a typedef __X_foo, the big endian version will be "foo" or * The only structures that appear here are ones that * (a) may be encoded within a PDU, and/or * (b) may appear in a PCP archive */ #include "pmapi.h" #include "impl.h" #include "internal.h" #ifndef __htonpmUnits pmUnits __htonpmUnits(pmUnits units) { unsigned int x; x = htonl(*(unsigned int *)&units); units = *(pmUnits *)&x; return units; } #endif #ifndef __ntohpmUnits pmUnits __ntohpmUnits(pmUnits units) { unsigned int x; x = ntohl(*(unsigned int *)&units); units = *(pmUnits *)&x; return units; } #endif #ifndef __htonpmValueBlock static void htonEventArray(pmValueBlock * const vb) { pmEventArray *eap = (pmEventArray *)vb; pmEventRecord *erp; pmEventParameter *epp; char *base; int r; /* records */ int p; /* parameters in a record ... */ int nparams; int vtype; int vlen; __uint32_t *tp; /* points to int holding vtype/vlen */ /* ea_type and ea_len handled via *ip below */ base = (char *)&eap->ea_record[0]; /* walk packed event record array */ for (r = 0; r < eap->ea_nrecords; r++) { erp = (pmEventRecord *)base; base += sizeof(erp->er_timestamp) + sizeof(erp->er_flags) + sizeof(erp->er_nparams); erp->er_timestamp.tv_sec = htonl(erp->er_timestamp.tv_sec); erp->er_timestamp.tv_usec = htonl(erp->er_timestamp.tv_usec); if (erp->er_flags & PM_EVENT_FLAG_MISSED) nparams = 0; else nparams = erp->er_nparams; erp->er_flags = htonl(erp->er_flags); erp->er_nparams = htonl(erp->er_nparams); for (p = 0; p < nparams; p++) { epp = (pmEventParameter *)base; epp->ep_pmid = __htonpmID(epp->ep_pmid); vtype = epp->ep_type; vlen = epp->ep_len; tp = (__uint32_t *)&epp->ep_pmid; tp++; /* now points to ep_type/ep_len */ *tp = htonl(*tp); tp++; /* now points to vbuf */ /* convert the types we're able to ... */ switch (vtype) { case PM_TYPE_32: case PM_TYPE_U32: *tp = htonl(*tp); break; case PM_TYPE_64: case PM_TYPE_U64: __htonll((void *)tp); break; case PM_TYPE_DOUBLE: __htond((void *)tp); break; case PM_TYPE_FLOAT: __htonf((void *)tp); break; } base += sizeof(epp->ep_pmid) + PM_PDU_SIZE_BYTES(vlen); } } eap->ea_nrecords = htonl(eap->ea_nrecords); } void __htonpmValueBlock(pmValueBlock * const vb) { unsigned int *ip = (unsigned int *)vb; if (vb->vtype == PM_TYPE_U64 || vb->vtype == PM_TYPE_64) __htonll(vb->vbuf); else if (vb->vtype == PM_TYPE_DOUBLE) __htond(vb->vbuf); else if (vb->vtype == PM_TYPE_FLOAT) __htonf(vb->vbuf); else if (vb->vtype == PM_TYPE_EVENT) htonEventArray(vb); *ip = htonl(*ip); /* vtype/vlen */ } #endif #ifndef __ntohpmValueBlock static void ntohEventArray(pmValueBlock * const vb) { pmEventArray *eap = (pmEventArray *)vb; pmEventRecord *erp; pmEventParameter *epp; char *base; int r; /* records */ int p; /* parameters in a record ... */ int nparams; __uint32_t *tp; /* points to int holding vtype/vlen */ /* ea_type and ea_len handled via *ip above */ base = (char *)&eap->ea_record[0]; eap->ea_nrecords = ntohl(eap->ea_nrecords); /* walk packed event record array */ for (r = 0; r < eap->ea_nrecords; r++) { erp = (pmEventRecord *)base; base += sizeof(erp->er_timestamp) + sizeof(erp->er_flags) + sizeof(erp->er_nparams); erp->er_timestamp.tv_sec = ntohl(erp->er_timestamp.tv_sec); erp->er_timestamp.tv_usec = ntohl(erp->er_timestamp.tv_usec); erp->er_flags = ntohl(erp->er_flags); erp->er_nparams = ntohl(erp->er_nparams); if (erp->er_flags & PM_EVENT_FLAG_MISSED) nparams = 0; else nparams = erp->er_nparams; for (p = 0; p < nparams; p++) { epp = (pmEventParameter *)base; epp->ep_pmid = __ntohpmID(epp->ep_pmid); tp = (__uint32_t *)&epp->ep_pmid; tp++; /* now points to ep_type/ep_len */ *tp = ntohl(*tp); tp++; /* now points to vbuf */ /* convert the types we're able to ... */ switch (epp->ep_type) { case PM_TYPE_32: case PM_TYPE_U32: *tp = ntohl(*tp); break; case PM_TYPE_64: case PM_TYPE_U64: __ntohll((void *)tp); break; case PM_TYPE_DOUBLE: __ntohd((void *)tp); break; case PM_TYPE_FLOAT: __ntohf((void *)tp); break; } base += sizeof(epp->ep_pmid) + PM_PDU_SIZE_BYTES(epp->ep_len); } } } void __ntohpmValueBlock(pmValueBlock * const vb) { unsigned int *ip = (unsigned int *)vb; /* Swab the first word, which contain vtype and vlen */ *ip = ntohl(*ip); switch (vb->vtype) { case PM_TYPE_U64: case PM_TYPE_64: __ntohll(vb->vbuf); break; case PM_TYPE_DOUBLE: __ntohd(vb->vbuf); break; case PM_TYPE_FLOAT: __ntohf(vb->vbuf); break; case PM_TYPE_EVENT: ntohEventArray(vb); break; } } #endif #ifndef __htonpmPDUInfo __pmPDUInfo __htonpmPDUInfo(__pmPDUInfo info) { unsigned int x; x = htonl(*(unsigned int *)&info); info = *(__pmPDUInfo *)&x; return info; } #endif #ifndef __ntohpmPDUInfo __pmPDUInfo __ntohpmPDUInfo(__pmPDUInfo info) { unsigned int x; x = ntohl(*(unsigned int *)&info); info = *(__pmPDUInfo *)&x; return info; } #endif #ifndef __htonpmCred __pmCred __htonpmCred(__pmCred cred) { unsigned int x; x = htonl(*(unsigned int *)&cred); cred = *(__pmCred *)&x; return cred; } #endif #ifndef __ntohpmCred __pmCred __ntohpmCred(__pmCred cred) { unsigned int x; x = ntohl(*(unsigned int *)&cred); cred = *(__pmCred *)&x; return cred; } #endif #ifndef __htonf void __htonf(char *p) { char c; int i; for (i = 0; i < 2; i++) { c = p[i]; p[i] = p[3-i]; p[3-i] = c; } } #endif #ifndef __htonll void __htonll(char *p) { char c; int i; for (i = 0; i < 4; i++) { c = p[i]; p[i] = p[7-i]; p[7-i] = c; } } #endif pcp-3.8.12ubuntu1/src/libpcp/src/spec.c0000664000000000000000000006711212272262501014536 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 2007 Aconex. All Rights Reserved. * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ /* * Parse uniform metric and host specification syntax */ #include #include "pmapi.h" #include "impl.h" #include "internal.h" #ifdef HAVE_STRINGS_H #include #endif static void * parseAlloc(const char *func, size_t need) { void *tmp; if ((tmp = malloc(need)) == NULL) __pmNoMem(func, need, PM_FATAL_ERR); return tmp; } static void parseError(const char *func, const char *spec, const char *point, char *msg, char **rslt) { int need; const char *p; char *q; if (rslt == NULL) return; need = 2 * (int)strlen(spec) + 1 + 6 + (int)strlen(msg) + 2; *rslt = q = (char *)parseAlloc(func, need); for (p = spec; *p != '\0'; p++) *q++ = *p; *q++ = '\n'; for (p = spec; p != point; p++) *q++ = isgraph((int)*p) ? ' ' : *p; sprintf(q, "^ -- %s\n", msg); /* safe */ } static void * metricAlloc(size_t need) { return parseAlloc("pmParseMetricSpec", need); } static void metricError(const char *spec, const char *point, char *msg, char **rslt) { parseError("pmParseMetricSpec", spec, point, msg, rslt); } int /* 0 -> ok, PM_ERR_GENERIC -> error */ pmParseMetricSpec( const char *spec, /* parse this string */ int isarch, /* default source: 0 -> host, 1 -> archive */ char *source, /* name of default host or archive */ pmMetricSpec **rslt, /* result allocated and returned here */ char **errmsg) /* error message */ { pmMetricSpec *msp = NULL; const char *scan; const char *mark; const char *h_start = NULL; /* host name */ const char *h_end = NULL; const char *a_start = NULL; /* archive name */ const char *a_end = NULL; const char *m_start = NULL; /* metric name */ const char *m_end = NULL; const char *i_start = NULL; /* instance names */ const char *i_end = NULL; char *i_str = NULL; /* temporary instance names */ char *i_scan; int ninst; /* number of instance names */ char *push; const char *pull; int length; int i; int inquote = 0; /* true if within quotes */ scan = spec; while (isspace((int)*scan)) scan++; /* * Options here are ... * [host:]metric[[instance list]] * special case for PM_CONTEXT_LOCAL [@:]metric[[instance list]] * [archive/]metric[[instance list]] * * Find end of metric name first ([ or end of string) then scan * backwards for first ':' or '/' */ mark = index(scan, (int)'['); if (mark == NULL) mark = &scan[strlen(scan)-1]; while (mark >= scan) { if (*mark == ':') { h_start = scan; h_end = mark-1; while (h_end >= scan && isspace((int)*h_end)) h_end--; if (h_end < h_start) { metricError(spec, h_start, "host name expected", errmsg); return PM_ERR_GENERIC; } h_end++; scan = mark+1; break; } else if (*mark == '/') { a_start = scan; a_end = mark-1; while (a_end >= scan && isspace((int)*a_end)) a_end--; if (a_end < a_start) { metricError(spec, a_start, "archive name expected", errmsg); return PM_ERR_GENERIC; } a_end++; scan = mark+1; break; } mark--; } while (isspace((int)*scan)) scan++; mark = scan; /* delimit metric name */ m_start = scan; while (! isspace((int)*scan) && *scan != '\0' && *scan != '[') { if (*scan == ']' || *scan == ',') { metricError(spec, scan, "unexpected character in metric name", errmsg); return PM_ERR_GENERIC; } if (*scan == '\\' && *(scan+1) != '\0') scan++; scan++; } m_end = scan; if (m_start == m_end) { metricError(spec, m_start, "performance metric name expected", errmsg); return PM_ERR_GENERIC; } while (isspace((int)*scan)) scan++; /* delimit instance names */ if (*scan == '[') { scan++; while (isspace((int)*scan)) scan++; i_start = scan; for ( ; ; ) { if (*scan == '\0') { if (inquote) metricError(spec, scan, "closing \" and ] expected", errmsg); else metricError(spec, scan, "closing ] expected", errmsg); return PM_ERR_GENERIC; } if (*scan == '\\' && *(scan+1) != '\0') scan++; else if (*scan == '"') inquote = 1 - inquote; else if (!inquote && *scan == ']') break; scan++; } i_end = scan; scan++; } /* check for rubbish at end of string */ while (isspace((int)*scan)) scan++; if (*scan != '\0') { metricError(spec, scan, "unexpected extra characters", errmsg); return PM_ERR_GENERIC; } /* count instance names and make temporary copy */ ninst = 0; if (i_start != NULL) { i_str = (char *) metricAlloc(i_end - i_start + 1); /* count and copy instance names */ scan = i_start; i_scan = i_str; while (scan < i_end) { /* copy single instance name */ ninst++; if (*scan == '"') { scan++; for (;;) { if (scan >= i_end) { metricError(spec, scan, "closing \" expected (pmParseMetricSpec botch?)", errmsg); if (i_str) free(i_str); return PM_ERR_GENERIC; } if (*scan == '\\') scan++; else if (*scan == '"') break; *i_scan++ = *scan++; } scan++; } else { while (! isspace((int)*scan) && *scan != ',' && scan < i_end) { if (*scan == '\\') scan++; *i_scan++ = *scan++; } } *i_scan++ = '\0'; /* skip delimiters */ while ((isspace((int)*scan) || *scan == ',') && scan < i_end) scan++; } i_start = i_str; i_end = i_scan; } /* single memory allocation for result structure */ length = (int)(sizeof(pmMetricSpec) + ((ninst > 1) ? (ninst - 1) * sizeof(char *) : 0) + ((h_start) ? h_end - h_start + 1 : 0) + ((a_start) ? a_end - a_start + 1 : 0) + ((m_start) ? m_end - m_start + 1 : 0) + ((i_start) ? i_end - i_start + 1 : 0)); msp = (pmMetricSpec *)metricAlloc(length); /* strings follow pmMetricSpec proper */ push = ((char *) msp) + sizeof(pmMetricSpec) + ((ninst > 1) ? (ninst - 1) * sizeof(char *) : 0); /* copy metric name */ msp->metric = push; pull = m_start; while (pull < m_end) { if (*pull == '\\' && (pull+1) < m_end) pull++; *push++ = *pull++; } *push++ = '\0'; /* copy host name */ if (h_start != NULL) { if (h_end - h_start == 1 && *h_start == '@') { /* PM_CONTEXT_LOCAL special case */ msp->isarch = 2; } else { /* PM_CONTEXT_HOST */ msp->isarch = 0; } msp->source = push; pull = h_start; while (pull < h_end) { if (*pull == '\\' && (pull+1) < h_end) pull++; *push++ = *pull++; } *push++ = '\0'; } /* copy archive name */ else if (a_start != NULL) { msp->isarch = 1; msp->source = push; pull = a_start; while (pull < a_end) { if (*pull == '\\' && (pull+1) < a_end) pull++; *push++ = *pull++; } *push++ = '\0'; } /* take default host or archive */ else { msp->isarch = isarch; msp->source = source; } /* instance names */ msp->ninst = ninst; pull = i_start; for (i = 0; i < ninst; i++) { msp->inst[i] = push; do *push++ = *pull; while (*pull++ != '\0'); } if (i_str) free(i_str); *rslt = msp; return 0; } void pmFreeMetricSpec(pmMetricSpec *spec) { free(spec); } static void hostError(const char *spec, const char *point, char *msg, char **rslt) { parseError("pmParseHostSpec", spec, point, msg, rslt); } static char * hostStrndup(const char *name, int namelen) { char *s = malloc(namelen + 1); strncpy(s, name, namelen); s[namelen] = '\0'; return s; } static pmHostSpec * hostAdd(pmHostSpec *specp, int *count, const char *name, int namelen) { int n = *count; char *host; host = hostStrndup(name, namelen); if (!host || (specp = realloc(specp, sizeof(pmHostSpec) * (n+1))) == NULL) { if (host != NULL) free(host); *count = 0; return NULL; } specp[n].name = host; specp[n].ports = NULL; specp[n].nports = 0; *count = n + 1; return specp; } int __pmAddHostPorts(pmHostSpec *specp, int *ports, int nports) { int *portlist; if ((portlist = malloc(sizeof(int) * (specp->nports + nports))) == NULL) return -ENOMEM; if (specp->nports > 0) { memcpy(portlist, specp->ports, sizeof(int) * specp->nports); free(specp->ports); } memcpy(&portlist[specp->nports], ports, sizeof(int) * nports); specp->ports = portlist; specp->nports = specp->nports + nports; return 0; } void __pmDropHostPort(pmHostSpec *specp) { specp->nports--; memmove(&specp->ports[0], &specp->ports[1], specp->nports*sizeof(int)); } /* * Parse a host specification, with optional ports and proxy host(s). * Examples: * pcp -h app1.aconex.com:44321,4321@firewall.aconex.com:44322 * pcp -h app1.aconex.com:44321@firewall.aconex.com:44322 * pcp -h app1.aconex.com:44321@firewall.aconex.com * pcp -h app1.aconex.com@firewall.aconex.com * pcp -h app1.aconex.com:44321 * pcp -h 192.168.122.1:44321 * pcp -h [fe80::5eff:35ff:fe07:55ca]:44321,4321@[fe80::5eff:35ff:fe07:55cc]:44322 * pcp -h [fe80::5eff:35ff:fe07:55ca]:44321 * * Basic algorithm: * look for first colon, @ or null; preceding text is hostname * if colon, look for comma, @ or null, preceding text is port * while comma, look for comma, @ or null, preceding text is next port * if @, start following host specification at the following character, * by returning to the start and repeating the above for the next chunk. * Note: * IPv6 addresses contain colons and, so, must be separated from the * rest of the spec somehow. A common notation among ipv6-enabled * applications is to enclose the address within brackets, as in * [fe80::5eff:35ff:fe07:55ca]:44321. We keep it simple, however, * and allow any host spec to be enclosed in brackets. * Note: * Currently only two hosts are useful, but ability to handle more than * one optional proxy host is there (i.e. proxy ->proxy ->... ->pmcd), * in case someone implements the pmproxy->pmproxy protocol extension. */ static int /* 0 -> ok, PM_ERR_GENERIC -> error message is set */ parseHostSpec( const char *spec, char **position, /* parse this string, return end char */ pmHostSpec **rslt, /* result allocated and returned here */ int *count, char **errmsg) /* error message */ { pmHostSpec *hsp = NULL; const char *s, *start, *next; int nhosts = 0, sts = 0; for (s = start = *position; s != NULL; s++) { /* Allow the host spec to be enclosed in brackets. */ if (s == start && *s == '[') { for (s++; *s != ']' && *s != '\0'; s++) ; if (*s != ']') { hostError(spec, s, "missing closing ']' for host spec", errmsg); sts = PM_ERR_GENERIC; goto fail; } next = s + 1; /* past the trailing ']' */ if (*next != ':' && *next != '@' && *next != '\0' && *next != '/' && *next != '?') { hostError(spec, next, "extra characters after host spec", errmsg); sts = PM_ERR_GENERIC; goto fail; } start++; /* past the initial '[' */ } else next = s; if (*next == ':' || *next == '@' || *next == '\0' || *next == '/' || *next == '?') { if (s == *position) break; else if (s == start) continue; hsp = hostAdd(hsp, &nhosts, start, s - start); if (hsp == NULL) { sts = -ENOMEM; goto fail; } s = next; if (*s == ':') { for (++s, start = s; s != NULL; s++) { if (*s == ',' || *s == '@' || *s == '\0' || *s == '/' || *s == '?') { if (s - start < 1) { hostError(spec, s, "missing port", errmsg); sts = PM_ERR_GENERIC; goto fail; } int port = atoi(start); sts = __pmAddHostPorts(&hsp[nhosts-1], &port, 1); if (sts < 0) goto fail; start = s + 1; if (*s == '@' || *s == '\0' || *s == '/' || *s == '?') break; continue; } if (isdigit((int)*s)) continue; hostError(spec, s, "non-numeric port", errmsg); sts = PM_ERR_GENERIC; goto fail; } } if (*s == '@') { start = s+1; continue; } break; } } *position = (char *)s; *count = nhosts; *rslt = hsp; return 0; fail: __pmFreeHostSpec(hsp, nhosts); *rslt = NULL; *count = 0; return sts; } /* * Parse a socket path. * Accept anything up to, but not including the first ':', or the end of the spec. * We use ':' as the delimeter even though a '?' could be the start of the attibutes because * '?' is a valid character in a socket path. It is also consistent with things like $PATH. */ static int /* 0 -> ok, PM_ERR_GENERIC -> error message is set */ parseSocketPath( const char *spec, char **position, /* parse this string, return end char */ pmHostSpec **rslt) /* result allocated and returned here */ { pmHostSpec *hsp = NULL; const char *s, *start, *path; char absolute_path[MAXPATHLEN]; size_t len; int nhosts = 0; /* Scan to the end of the string or to the first ':'. */ for (s = start = *position; s != NULL; s++) { if (*s == '\0') break; if (*s == ':') { ++s; break; } } /* If the path is empty, then provide the default. */ if (s == start) { path = __pmPMCDLocalSocketDefault(); len = strlen(path); } else { path = start; len = s - start; } /* * Make sure that the path is absolute. parseProtocolSpec() removes the * (optional) "//" from "local://some/path". */ if (*path != __pmPathSeparator()) { len = snprintf (absolute_path, sizeof(absolute_path), "%c%s", __pmPathSeparator(), path); path = absolute_path; } /* Add the path as the only member of the host list. */ hsp = hostAdd(hsp, &nhosts, path, len); if (hsp == NULL) { __pmFreeHostSpec(hsp, nhosts); *rslt = NULL; return -ENOMEM; } *position = (char *)s; *rslt = hsp; return 0; } int __pmParseHostSpec( const char *spec, /* parse this string */ pmHostSpec **rslt, /* result allocated and returned here */ int *count, /* number of host specs returned here */ char **errmsg) /* error message */ { char *s = (char *)spec; int sts; if ((sts = parseHostSpec(spec, &s, rslt, count, errmsg)) < 0) return sts; if (*s == '\0') return 0; hostError(spec, s, "unexpected terminal character", errmsg); __pmFreeHostSpec(*rslt, *count); *rslt = NULL; *count = 0; return PM_ERR_GENERIC; } int __pmUnparseHostSpec(pmHostSpec *hostp, int count, char *string, size_t size) { int off = 0, len = size; /* offset in string and space remaining */ int i, j, sts; for (i = 0; i < count; i++) { if (i > 0) { if ((sts = snprintf(string + off, len, "@")) >= size) return -E2BIG; len -= sts; off += sts; } if (hostp[i].nports == PM_HOST_SPEC_NPORTS_LOCAL || hostp[i].nports == PM_HOST_SPEC_NPORTS_UNIX) { /* These host specs contain a leading path separator as part of the name which should not be printed. */ if ((sts = snprintf(string + off, len, "%s", hostp[i].name + 1)) >= size) return -E2BIG; } else { if ((sts = snprintf(string + off, len, "%s", hostp[i].name)) >= size) return -E2BIG; } len -= sts; off += sts; for (j = 0; j < hostp[i].nports; j++) { if ((sts = snprintf(string + off, len, "%c%u", (j == 0) ? ':' : ',', hostp[i].ports[j])) >= size) return -E2BIG; len -= sts; off += sts; } } return off; } void __pmFreeHostSpec(pmHostSpec *specp, int count) { int i; for (i = 0; i < count; i++) { free(specp[i].name); specp[i].name = NULL; if (specp[i].nports > 0) free(specp[i].ports); specp[i].ports = NULL; specp[i].nports = 0; } if (specp && count) free(specp); } static __pmHashWalkState attrHashNodeDel(const __pmHashNode *tp, void *cp) { (void)cp; if (tp->data) free(tp->data); return PM_HASH_WALK_DELETE_NEXT; } void __pmFreeAttrsSpec(__pmHashCtl *attrs) { __pmHashWalkCB(attrHashNodeDel, NULL, attrs); } void __pmFreeHostAttrsSpec(pmHostSpec *hosts, int count, __pmHashCtl *attrs) { __pmFreeHostSpec(hosts, count); __pmFreeAttrsSpec(attrs); } #define PCP_PROTOCOL_NAME "pcp" #define PCP_PROTOCOL_PREFIX PCP_PROTOCOL_NAME ":" #define PCP_PROTOCOL_SIZE (sizeof(PCP_PROTOCOL_NAME)-1) #define PCP_PROTOCOL_PREFIXSZ (sizeof(PCP_PROTOCOL_PREFIX)-1) #define PCPS_PROTOCOL_NAME "pcps" #define PCPS_PROTOCOL_PREFIX PCPS_PROTOCOL_NAME ":" #define PCPS_PROTOCOL_SIZE (sizeof(PCPS_PROTOCOL_NAME)-1) #define PCPS_PROTOCOL_PREFIXSZ (sizeof(PCPS_PROTOCOL_PREFIX)-1) #define LOCAL_PROTOCOL_NAME "local" #define LOCAL_PROTOCOL_PREFIX LOCAL_PROTOCOL_NAME ":" #define LOCAL_PROTOCOL_SIZE (sizeof(LOCAL_PROTOCOL_NAME)-1) #define LOCAL_PROTOCOL_PREFIXSZ (sizeof(LOCAL_PROTOCOL_PREFIX)-1) #define UNIX_PROTOCOL_NAME "unix" #define UNIX_PROTOCOL_PREFIX UNIX_PROTOCOL_NAME ":" #define UNIX_PROTOCOL_SIZE (sizeof(UNIX_PROTOCOL_NAME)-1) #define UNIX_PROTOCOL_PREFIXSZ (sizeof(UNIX_PROTOCOL_PREFIX)-1) static int parseProtocolSpec( const char *spec, /* the original, complete string to parse */ char **position, int *attribute, char **value, char **errmsg) { char *protocol = NULL; char *s = *position; /* optionally extract protocol specifier */ if (strncmp(s, PCP_PROTOCOL_PREFIX, PCP_PROTOCOL_PREFIXSZ) == 0) { protocol = PCP_PROTOCOL_NAME; s += PCP_PROTOCOL_PREFIXSZ; *attribute = PCP_ATTR_PROTOCOL; } else if (strncmp(s, PCPS_PROTOCOL_PREFIX, PCPS_PROTOCOL_PREFIXSZ) == 0) { protocol = PCPS_PROTOCOL_NAME; s += PCPS_PROTOCOL_PREFIXSZ; *attribute = PCP_ATTR_PROTOCOL; } else if (strncmp(s, LOCAL_PROTOCOL_PREFIX, LOCAL_PROTOCOL_PREFIXSZ) == 0) { protocol = LOCAL_PROTOCOL_NAME; s += LOCAL_PROTOCOL_PREFIXSZ; *attribute = PCP_ATTR_LOCAL; } else if (strncmp(s, UNIX_PROTOCOL_PREFIX, UNIX_PROTOCOL_PREFIXSZ) == 0) { protocol = UNIX_PROTOCOL_NAME; s += UNIX_PROTOCOL_PREFIXSZ; *attribute = PCP_ATTR_UNIXSOCK; } /* optionally skip over slash-delimiters */ if (protocol) { while (*s == '/') s++; if ((*value = strdup(protocol)) == NULL) return -ENOMEM; } else { *value = NULL; *attribute = PCP_ATTR_NONE; } *position = s; return 0; } __pmAttrKey __pmLookupAttrKey(const char *attribute, size_t size) { if (size == sizeof("compress") && strncmp(attribute, "compress", size) == 0) return PCP_ATTR_COMPRESS; if ((size == sizeof("userauth") && strncmp(attribute, "userauth", size) == 0) || (size == sizeof("authorise") && (strncmp(attribute, "authorise", size) == 0 || strncmp(attribute, "authorize", size) == 0))) return PCP_ATTR_USERAUTH; if ((size == sizeof("user") && strncmp(attribute, "user", size) == 0) || (size == sizeof("username") && strncmp(attribute, "username", size) == 0)) return PCP_ATTR_USERNAME; if (size == sizeof("realm") && strncmp(attribute, "realm", size) == 0) return PCP_ATTR_REALM; if ((size == sizeof("authmeth") && strncmp(attribute, "authmeth", size) == 0) || (size == sizeof("method") && strncmp(attribute, "method", size) == 0)) return PCP_ATTR_METHOD; if ((size == sizeof("pass") && strncmp(attribute, "pass", size) == 0) || (size == sizeof("password") && strncmp(attribute, "password", size) == 0)) return PCP_ATTR_PASSWORD; if ((size == sizeof("unix") && strncmp(attribute, "unix", size) == 0) || (size == sizeof("unixsock") && strncmp(attribute, "unixsock", size) == 0)) return PCP_ATTR_UNIXSOCK; if ((size == sizeof("local") && strncmp(attribute, "local", size) == 0)) return PCP_ATTR_LOCAL; if ((size == sizeof("uid") && strncmp(attribute, "uid", size) == 0) || (size == sizeof("userid") && strncmp(attribute, "userid", size) == 0)) return PCP_ATTR_USERID; if ((size == sizeof("gid") && strncmp(attribute, "gid", size) == 0) || (size == sizeof("groupid") && strncmp(attribute, "groupid", size) == 0)) return PCP_ATTR_GROUPID; if ((size == sizeof("pid") && strncmp(attribute, "pid", size) == 0) || (size == sizeof("processid") && strncmp(attribute, "processid", size) == 0)) return PCP_ATTR_PROCESSID; if (size == sizeof("secure") && strncmp(attribute, "secure", size) == 0) return PCP_ATTR_SECURE; return PCP_ATTR_NONE; } /* * Parse the attributes component of a PCP connection string. * Optionally, an initial attribute:value pair can be passed * in as well to add to the parsed set. */ static int parseAttributeSpec( const char *spec, /* the original, complete string to parse */ char **position, /* parse from here onward and update at end */ int attribute, char *value, __pmHashCtl *attributes, char **errmsg) { char *s, *start, *v = NULL; char buffer[32]; /* must be large enough to hold largest attr name */ int buflen, attr, len, sts; if (attribute != PCP_ATTR_NONE) if ((sts = __pmHashAdd(attribute, (void *)value, attributes)) < 0) return sts; for (s = start = *position; s != NULL; s++) { /* parse: foo=bar&moo&goo=blah ... go! */ if (*s == '\0' || *s == '/' || *s == '&') { if ((*s == '\0' || *s == '/') && s == start) break; len = v ? (v - start - 1) : (s - start); buflen = (len < sizeof(buffer)-1) ? len : sizeof(buffer)-1; strncpy(buffer, start, buflen); buffer[buflen] = '\0'; attr = __pmLookupAttrKey(buffer, buflen+1); if (attr != PCP_ATTR_NONE) { char *val = NULL; if (v && (val = strndup(v, s - v)) == NULL) { sts = -ENOMEM; goto fail; } if ((sts = __pmHashAdd(attr, (void *)val, attributes)) < 0) { free(val); goto fail; } } v = NULL; if (*s == '\0' || *s == '/') break; start = s + 1; /* start of attribute name */ continue; } if (*s == '=') { v = s + 1; /* start of attribute value */ } } *position = s; return 0; fail: if (attribute != PCP_ATTR_NONE) /* avoid double free in caller */ __pmHashDel(attribute, (void *)value, attributes); __pmFreeAttrsSpec(attributes); return sts; } /* * Finally, bring it all together to handle parsing full connection URLs: * * pcp://oss.sgi.com:45892?user=otto&pass=blotto&compress=true * pcps://oss.sgi.com@proxy.org:45893?user=jimbo&pass=jones&compress=true * local://path/to/socket:?user=jimbo&pass=jones * unix://path/to/socket */ int __pmParseHostAttrsSpec( const char *spec, /* the original, complete string to parse */ pmHostSpec **host, /* hosts result allocated and returned here */ int *count, __pmHashCtl *attributes, char **errmsg) /* error message */ { char *value = NULL, *s = (char *)spec; int sts, attr; *count = 0; /* ensure this initialised for fail: code */ /* parse optional protocol section */ if ((sts = parseProtocolSpec(spec, &s, &attr, &value, errmsg)) < 0) return sts; if (attr == PCP_ATTR_LOCAL || attr == PCP_ATTR_UNIXSOCK) { /* We are looking for a socket path. */ if ((sts = parseSocketPath(spec, &s, host)) < 0) goto fail; *count = 1; host[0]->nports = (attr == PCP_ATTR_LOCAL) ? PM_HOST_SPEC_NPORTS_LOCAL : PM_HOST_SPEC_NPORTS_UNIX; } else { /* We are looking for a host spec. */ if ((sts = parseHostSpec(spec, &s, host, count, errmsg)) < 0) goto fail; } /* skip over an attributes delimiter */ if (*s == '?') { s++; /* optionally skip over the question mark */ } else if (*s != '\0' && *s != '/') { hostError(spec, s, "unexpected terminal character", errmsg); sts = PM_ERR_GENERIC; goto fail; } /* parse optional attributes section */ if ((sts = parseAttributeSpec(spec, &s, attr, value, attributes, errmsg)) < 0) goto fail; return 0; fail: if (value) free(value); if (*count) __pmFreeHostSpec(*host, *count); *count = 0; *host = NULL; return sts; } static int unparseAttribute(__pmHashNode *node, char *string, size_t size) { return __pmAttrStr_r(node->key, node->data, string, size); } int __pmAttrKeyStr_r(__pmAttrKey key, char *string, size_t size) { switch (key) { case PCP_ATTR_PROTOCOL: return snprintf(string, size, "protocol"); case PCP_ATTR_COMPRESS: return snprintf(string, size, "compress"); case PCP_ATTR_USERAUTH: return snprintf(string, size, "userauth"); case PCP_ATTR_USERNAME: return snprintf(string, size, "username"); case PCP_ATTR_AUTHNAME: return snprintf(string, size, "authname"); case PCP_ATTR_PASSWORD: return snprintf(string, size, "password"); case PCP_ATTR_METHOD: return snprintf(string, size, "method"); case PCP_ATTR_REALM: return snprintf(string, size, "realm"); case PCP_ATTR_SECURE: return snprintf(string, size, "secure"); case PCP_ATTR_UNIXSOCK: return snprintf(string, size, "unixsock"); case PCP_ATTR_LOCAL: return snprintf(string, size, "local"); case PCP_ATTR_USERID: return snprintf(string, size, "userid"); case PCP_ATTR_GROUPID: return snprintf(string, size, "groupid"); case PCP_ATTR_PROCESSID: return snprintf(string, size, "processid"); case PCP_ATTR_NONE: default: break; } return 0; } int __pmAttrStr_r(__pmAttrKey key, const char *data, char *string, size_t size) { char name[16]; /* must be sufficient to hold any key name (above) */ int sts; if ((sts = __pmAttrKeyStr_r(key, name, sizeof(name))) <= 0) return sts; switch (key) { case PCP_ATTR_PROTOCOL: case PCP_ATTR_USERNAME: case PCP_ATTR_PASSWORD: case PCP_ATTR_METHOD: case PCP_ATTR_REALM: case PCP_ATTR_SECURE: case PCP_ATTR_USERID: case PCP_ATTR_GROUPID: case PCP_ATTR_PROCESSID: return snprintf(string, size, "%s=%s", name, data ? data : ""); case PCP_ATTR_UNIXSOCK: case PCP_ATTR_LOCAL: case PCP_ATTR_COMPRESS: case PCP_ATTR_USERAUTH: return snprintf(string, size, "%s", name); case PCP_ATTR_NONE: default: break; } return 0; } int __pmUnparseHostAttrsSpec( pmHostSpec *hosts, int count, __pmHashCtl *attrs, char *string, size_t size) { __pmHashNode *node; int off = 0, len = size; /* offset in string and space remaining */ int sts, first; if ((node = __pmHashSearch(PCP_ATTR_PROTOCOL, attrs)) != NULL) { if ((sts = snprintf(string, len, "%s://", (char *)node->data)) >= len) return -E2BIG; len -= sts; off += sts; } else if (__pmHashSearch(PCP_ATTR_UNIXSOCK, attrs) != NULL) { if ((sts = snprintf(string, len, "unix://")) >= len) return -E2BIG; len -= sts; off += sts; } else if (__pmHashSearch(PCP_ATTR_LOCAL, attrs) != NULL) { if ((sts = snprintf(string, len, "local://")) >= len) return -E2BIG; len -= sts; off += sts; } if ((sts = __pmUnparseHostSpec(hosts, count, string + off, len)) >= len) return sts; len -= sts; off += sts; first = 1; for (node = __pmHashWalk(attrs, PM_HASH_WALK_START); node != NULL; node = __pmHashWalk(attrs, PM_HASH_WALK_NEXT)) { if (node->key == PCP_ATTR_PROTOCOL || node->key == PCP_ATTR_UNIXSOCK || node->key == PCP_ATTR_LOCAL) continue; if ((sts = snprintf(string + off, len, "%c", first ? '?' : '&')) >= len) return -E2BIG; len -= sts; off += sts; first = 0; if ((sts = unparseAttribute(node, string + off, len)) >= len) return -E2BIG; len -= sts; off += sts; } return off; } pcp-3.8.12ubuntu1/src/libpcp/src/access.c0000664000000000000000000014633712272262501015054 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include #include "pmapi.h" #include "impl.h" #include "internal.h" /* Host access control list */ typedef struct { char *hostspec; /* Host specification */ __pmSockAddr *hostid; /* Partial host-id to match */ __pmSockAddr *hostmask; /* Mask for wildcarding */ int level; /* Level of wildcarding */ unsigned int specOps; /* Mask of specified operations */ unsigned int denyOps; /* Mask of disallowed operations */ int maxcons; /* Max connections permitted (0 => no limit) */ int curcons; /* Current # connections from matching clients */ } hostinfo; static hostinfo *hostlist; static int nhosts; static int szhostlist; /* User access control list */ typedef struct { char *username; /* User specification */ __pmUserID userid; /* User identifier to match */ unsigned int ngroups; /* Count of groups to which the user belongs */ __pmGroupID *groupids; /* Names of groups to which the user belongs */ unsigned int specOps; /* Mask of specified operations */ unsigned int denyOps; /* Mask of disallowed operations */ int maxcons; /* Max connections permitted (0 => no limit) */ int curcons; /* Current # connections from matching clients */ } userinfo; static userinfo *userlist; static int nusers; static int szuserlist; /* Group access control list */ typedef struct { char *groupname; /* Group specification */ __pmGroupID groupid; /* Group identifier to match */ unsigned int nusers; /* Count of users in this group */ __pmUserID *userids; /* Names of users in this group */ unsigned int specOps; /* Mask of specified operations */ unsigned int denyOps; /* Mask of disallowed operations */ int maxcons; /* Max connections permitted (0 => no limit) */ int curcons; /* Current # connections from matching clients */ } groupinfo; static groupinfo *grouplist; static int ngroups; static int szgrouplist; /* Mask of the operations defined by the user of the routines */ static unsigned int all_ops; /* mask of all operations specifiable */ /* This allows the set of valid operations to be specified. * Operations must be powers of 2. */ int __pmAccAddOp(unsigned int op) { unsigned int i, mask; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return PM_ERR_THREAD; /* op must not be zero or clash with existing ops */ if (op == 0 || (op & all_ops)) return -EINVAL; /* Find the lowest bit in op that is set (WORD_BIT from limits.h is the * number of bits in an unsigned int) */ for (i = 0; i < WORD_BIT; i++) if (op & (mask = 1 << i)) break; /* only one bit may be set in op */ if (op & ~mask) return -EINVAL; all_ops |= mask; return 0; } /* Get the host id for this host. The host id is used when translating * references to localhost into the host's real IP address during parsing of * the access control section of the config file. It may also used when * checking for incoming connections from localhost. */ static int gotmyhostid; static __pmHostEnt *myhostid; static char myhostname[MAXHOSTNAMELEN+1]; /* * Always called with __pmLock_libpcp already held, so accessing * gotmyhostid, myhostname, myhostid and gethostname() call are all * thread-safe. */ static int getmyhostid(void) { if (gethostname(myhostname, MAXHOSTNAMELEN) < 0) { __pmNotifyErr(LOG_ERR, "gethostname failure\n"); return -1; } myhostname[MAXHOSTNAMELEN-1] = '\0'; if ((myhostid = __pmGetAddrInfo(myhostname)) == NULL) { if ((myhostid = __pmGetAddrInfo("localhost")) == NULL) { __pmNotifyErr(LOG_ERR, "__pmGetAddrInfo failure for both %s and localhost\n", myhostname); return -1; } } gotmyhostid = 1; return 0; } /* Used for saving the current state of the access lists */ enum { HOSTS_SAVED = 0x1, USERS_SAVED = 0x2, GROUPS_SAVED = 0x4 }; static int saved; static hostinfo *oldhostlist; static int oldnhosts; static int oldszhostlist; static userinfo *olduserlist; static int oldnusers; static int oldszuserlist; static groupinfo *oldgrouplist; static int oldngroups; static int oldszgrouplist; /* Save the current access control lists. * Returns 0 for success or a negative error code on error. */ int __pmAccSaveLists(void) { int sts, code = 0; if ((sts = __pmAccSaveHosts()) < 0) code = sts; if ((sts = __pmAccSaveUsers()) < 0) code = sts; if ((sts = __pmAccSaveGroups()) < 0) code = sts; return code; } int __pmAccSaveHosts(void) { if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return PM_ERR_THREAD; if (saved & HOSTS_SAVED) return PM_ERR_TOOBIG; saved |= HOSTS_SAVED; oldhostlist = hostlist; oldnhosts = nhosts; oldszhostlist = szhostlist; hostlist = NULL; nhosts = 0; szhostlist = 0; return 0; } int __pmAccSaveUsers(void) { if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return PM_ERR_THREAD; if (saved & USERS_SAVED) return PM_ERR_TOOBIG; saved |= USERS_SAVED; olduserlist = userlist; oldnusers = nusers; oldszuserlist = szuserlist; userlist = NULL; nusers = 0; szuserlist = 0; return 0; } int __pmAccSaveGroups(void) { if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return PM_ERR_THREAD; if (saved & GROUPS_SAVED) return PM_ERR_TOOBIG; saved |= GROUPS_SAVED; oldgrouplist = grouplist; oldngroups = ngroups; oldszgrouplist = szgrouplist; grouplist = NULL; ngroups = 0; szgrouplist = 0; return 0; } /* Free the current access lists. These are done automatically by * __pmAccRestoreLists so there is no need for them to be globally visible. * A caller of these routines should never need to dispose of the access lists * once they has been built. */ static void accfreehosts(void) { int i; if (szhostlist) { for (i = 0; i < nhosts; i++) if (hostlist[i].hostspec != NULL) free(hostlist[i].hostspec); free(hostlist); } hostlist = NULL; nhosts = 0; szhostlist = 0; } static void accfreeusers(void) { int i; if (szuserlist) { for (i = 1; i < nusers; i++) { free(userlist[i].username); if (userlist[i].ngroups) free(userlist[i].groupids); } free(userlist); } userlist = NULL; nusers = 0; szuserlist = 0; } static void accfreegroups(void) { int i; if (szgrouplist) { for (i = 1; i < ngroups; i++) { free(grouplist[i].groupname); if (grouplist[i].nusers) free(grouplist[i].userids); } free(grouplist); } grouplist = NULL; ngroups = 0; szgrouplist = 0; } /* Restore the previously saved access lists. Any current list is freed. * Returns 0 for success or a negative error code on error. */ int __pmAccRestoreLists(void) { int sts, code = 0; if ((sts = __pmAccRestoreHosts()) < 0) code = sts; if ((sts = __pmAccRestoreUsers()) < 0 && !code) code = sts; if ((sts = __pmAccRestoreGroups()) < 0 && !code) code = sts; return code; } int __pmAccRestoreHosts(void) { if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return PM_ERR_THREAD; if (!(saved & HOSTS_SAVED)) return PM_ERR_TOOSMALL; accfreehosts(); saved &= ~HOSTS_SAVED; hostlist = oldhostlist; nhosts = oldnhosts; szhostlist = oldszhostlist; return 0; } int __pmAccRestoreUsers(void) { if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return PM_ERR_THREAD; if (!(saved & USERS_SAVED)) return PM_ERR_TOOSMALL; accfreeusers(); saved &= ~USERS_SAVED; userlist = olduserlist; nusers = oldnusers; szuserlist = oldszuserlist; return 0; } int __pmAccRestoreGroups(void) { if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return PM_ERR_THREAD; if (!(saved & GROUPS_SAVED)) return PM_ERR_TOOSMALL; accfreegroups(); saved &= ~GROUPS_SAVED; grouplist = oldgrouplist; ngroups = oldngroups; szgrouplist = oldszgrouplist; return 0; } /* Free the previously saved access lists. These should be called when the saved * access lists are no longer required (typically because the new ones supercede * the old, have been verified as valid and correct, etc). */ void __pmAccFreeSavedLists(void) { __pmAccFreeSavedHosts(); __pmAccFreeSavedUsers(); __pmAccFreeSavedGroups(); } void __pmAccFreeSavedHosts(void) { int i; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return; if (!(saved & HOSTS_SAVED)) return; if (oldszhostlist) { for (i = 0; i < oldnhosts; i++) if (oldhostlist[i].hostspec != NULL) free(oldhostlist[i].hostspec); free(oldhostlist); } saved &= ~HOSTS_SAVED; } void __pmAccFreeSavedUsers(void) { int i; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return; if (!(saved & USERS_SAVED)) return; if (oldszuserlist) { for (i = 1; i < oldnusers; i++) { free(olduserlist[i].username); if (olduserlist[i].ngroups) free(olduserlist[i].groupids); } free(olduserlist); } saved &= ~USERS_SAVED; } void __pmAccFreeSavedGroups(void) { int i; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return; if (!(saved & GROUPS_SAVED)) return; if (oldszgrouplist) { for (i = 1; i < oldngroups; i++) { free(oldgrouplist[i].groupname); if (oldgrouplist[i].nusers) free(oldgrouplist[i].userids); } free(oldgrouplist); } saved &= ~GROUPS_SAVED; } /* Build up strings representing the ip address and the mask. * Compute the wildcard level as we go. */ static int parseInetWildCard(const char *name, char *ip, char *mask) { int level; int ipIx, maskIx; int i, n; const char *p; /* Accept "*" or ".*" as the inet full wild card spec. */ level = 4; ipIx = maskIx = 0; p = name; if (*p == '.') { ++p; if (*p != '*') { __pmNotifyErr(LOG_ERR, "Bad IP address wildcard, %s\n", name); return -EINVAL; } } for (/**/; *p && *p != '*' ; p++) { n = (int)strtol(p, (char **)&p, 10); if ((*p != '.' && *p != '*') || n < 0 || n > 255) { __pmNotifyErr(LOG_ERR, "Bad IP address wildcard, %s\n", name); return -EINVAL; } if (ipIx != 0) { ipIx += sprintf(ip + ipIx, "."); maskIx += sprintf(mask + maskIx, "."); } ipIx += sprintf(ip + ipIx, "%d", n); maskIx += sprintf(mask + maskIx, "255"); --level; /* Check the wildcard level, 0 is exact match, 4 is most general */ if (level < 1) { __pmNotifyErr(LOG_ERR, "Too many dots in host pattern \"%s\"\n", name); return -EINVAL; } } /* Add zeroed components for the wildcarded levels. */ for (i = 0; i < level; ++i) { if (ipIx != 0) { ipIx += sprintf(ip + ipIx, "."); maskIx += sprintf(mask + maskIx, "."); } ipIx += sprintf(ip + ipIx, "0"); maskIx += sprintf(mask + maskIx, "0"); } return level; } static int parseIPv6WildCard(const char *name, char *ip, char *mask) { int level; int ipIx, maskIx; int emptyRegion; int n; const char *p; /* Accept ":*" as the IPv6 full wild card spec. Otherwise, if the string starts with ':', then the second character must also be a ':' which would form a region of zeroes of unspecified length. */ level = 8; emptyRegion = 0; ipIx = maskIx = 0; p = name; if (*p == ':') { ++p; if (*p != '*') { if (*p != ':') { __pmNotifyErr(LOG_ERR, "Bad IPv6 address wildcard, %s\n", name); return -EINVAL; } ipIx = sprintf(ip, ":"); maskIx = sprintf(mask, ":"); /* The second colon will be detected in the loop below. */ } } for (/**/; *p && *p != '*' ; p++) { /* Check for an empty region. There can only be one. */ if (*p == ':') { if (emptyRegion) { __pmNotifyErr(LOG_ERR, "Too many empty regions in host pattern \"%s\"\n", name); return -EINVAL; } emptyRegion = 1; ipIx += sprintf(ip + ipIx, ":"); maskIx += sprintf(mask + maskIx, ":"); } else { n = (int)strtol(p, (char **)&p, 16); if ((*p != ':' && *p != '*') || n < 0 || n > 0xffff) { __pmNotifyErr(LOG_ERR, "Bad IPv6 address wildcard, %s\n", name); return -EINVAL; } if (ipIx != 0) { ipIx += sprintf(ip + ipIx, ":"); maskIx += sprintf(mask + maskIx, ":"); } ipIx += sprintf(ip + ipIx, "%x", n); maskIx += sprintf(mask + maskIx, "ffff"); } --level; /* Check the wildcard level, 0 is exact match, 8 is most general */ if (level < 1) { __pmNotifyErr(LOG_ERR, "Too many colons in host pattern \"%s\"\n", name); return -EINVAL; } } /* Add zeroed components for the wildcarded levels. If the entire address is wildcarded then return the zero address. */ if (level == 8 || (level == 7 && emptyRegion)) { /* ":*" or "::*" */ strcpy(ip, "::"); strcpy(mask, "::"); level = 8; } else if (emptyRegion) { /* If there was an empty region, then we assume that the wildcard represents the final segment of the spec only. */ sprintf(ip + ipIx, ":0"); sprintf(mask + maskIx, ":0"); } else { /* no empty region, so use one to finish off the address and the mask */ sprintf(ip + ipIx, "::"); sprintf(mask + maskIx, "::"); } return level; } static int parseWildCard(const char *name, char *ip, char *mask) { /* We need only handle inet and IPv6 wildcards here. Unix * wildcards are handled separately. * * Names containing ':' are IPv6. The IPv6 full wildcard spec is ":*". */ if (strchr(name, ':') != NULL) return parseIPv6WildCard(name, ip, mask); /* Names containing '.' are inet. The inet full wildcard spec ".*". */ if (strchr(name, '.') != NULL) return parseInetWildCard(name, ip, mask); __pmNotifyErr(LOG_ERR, "Bad IP address wildcard, %s\n", name); return -EINVAL; } /* Information representing an access specification. */ struct accessSpec { char *name; __pmSockAddr *hostid; __pmSockAddr *hostmask; int level; }; static int setAccessSpecAddresses(struct accessSpec *spec, const char *addr, const char *mask) { /* Now create socket addresses for the address and mask. */ spec->hostid = __pmStringToSockAddr(addr); if (spec->hostid == NULL) { __pmNotifyErr(LOG_ERR, "__pmStringToSockAddr failure\n"); return -ENOMEM; } spec->hostmask = __pmStringToSockAddr(mask); if (spec->hostmask == NULL) { __pmNotifyErr(LOG_ERR, "__pmStringToSockAddr failure\n"); __pmSockAddrFree(spec->hostid); return -ENOMEM; } return 0; /* ok */ } #if defined(HAVE_STRUCT_SOCKADDR_UN) /* For the Unix spec: * - On input: * - We're expecting 'name' to be empty or an optional series of '/' followed by * and optional '*'. * - On output, within the 'spec' structure: * - The path of the 'hostid' will be '/'. * - The 'hostmask' will be a copy of the 'hostid'. * - The 'level' will be 1 * This sets up the spec to match the path of any unix domain socket. */ static int getUnixSpec(const char *name, struct accessSpec *spec) { const char *path; size_t addrSize; char rootPath[2]; int sts; /* Accept any number of '/', as is done by parseProtocolSpec(). */ for (path = name; *path == __pmPathSeparator(); ++path) ; /* Accept a final '*'. */ addrSize = strlen(path); if (addrSize >= 1 && path[addrSize - 1] == '*') --addrSize; /* If there is anything remaining, then it is a path, which we will ignore, with a * warning. */ if (addrSize) __pmNotifyErr(LOG_WARNING, "Ignoring the path in host pattern \"%s\"\n", name); /* Set the address and mask. */ rootPath[0] = __pmPathSeparator(); rootPath[1] = '\0'; sts = setAccessSpecAddresses(spec, rootPath, rootPath); if (sts < 0) return sts; /* Complete the rest of the spec. * Do this last since a valid name indicates a valid spec. */ spec->name = strdup("unix:"); if (spec->name == NULL) __pmNoMem("Unix host pattern name buffer", sizeof("unix:"), PM_FATAL_ERR); spec->level = 1; return 0; /* ok */ } #endif /* defined(HAVE_STRUCT_SOCKADDR_UN) */ /* Construct the proper spec for the given wildcard. */ static int getWildCardSpec(const char *name, struct accessSpec *spec) { char addr[INET6_ADDRSTRLEN]; char mask[INET6_ADDRSTRLEN]; int sts; /* Build up strings representing the ip address and the mask. Compute the wildcard level as we go. */ spec->level = parseWildCard(name, addr, mask); if (spec->level < 0) return spec->level; /* Set the address and mask. */ if ((sts = setAccessSpecAddresses(spec, addr, mask)) < 0) return sts; /* Do this last since a valid name indicates a valid spec. */ spec->name = strdup(name); return sts; /* ok */ } /* Determine all of the access specs which result from the given name. */ static struct accessSpec * getHostAccessSpecs(const char *name, int *sts) { struct accessSpec *specs; size_t specSize; size_t specIx; size_t ix; size_t need; __pmSockAddr *myAddr; __pmHostEnt *servInfo; void *enumIx; int family; int isWildCard; const char *realname; const char *p; /* If the general wildcard ("*") is specified, then generate individual * wildcards for inet, IPv6 (if supported) and unix domain sockets * (if supported). "localhost" is covered by the inet and IPv6 wildcards. */ if (strcmp(name, "*") == 0) { const char *ipv6 = __pmGetAPIConfig("ipv6"); /* Use calloc so that the final entries are zeroed, if not used. */ specs = calloc(4, sizeof(*specs)); if (specs == NULL) __pmNoMem("Access Spec List", 4 * sizeof(*specs), PM_FATAL_ERR); /* The inet general wildcard. */ specIx = 0; getWildCardSpec(".*", &specs[specIx]); /* Guaranteed to succeed. */ ++specIx; /* The IPv6 general wildcard. */ if (ipv6 != NULL && strcmp(ipv6, "true") == 0) { getWildCardSpec(":*", &specs[specIx]); /* Guaranteed to succeed. */ ++specIx; } #if defined(HAVE_STRUCT_SOCKADDR_UN) /* The unix domain socket general wildcard. */ getUnixSpec("*", &specs[specIx]); /* Guaranteed to succeed. */ #endif return specs; } /* If it is any other wildcard, make sure the '*' is at the end. */ if ((p = strchr(name, '*')) != NULL) { if (p[1] != '\0') { __pmNotifyErr(LOG_ERR, "Wildcard in host pattern \"%s\" is not at the end\n", name); *sts = -EINVAL; return NULL; } isWildCard = 1; } else isWildCard = 0; /* Initialize the specs array controls for general use. */ specs = NULL; specSize = 0; specIx = 0; /* If a name of the form "local:[xxx]" is specified, then expand it to be * "unix:[xxx]" + "localhost" in order to match the meaning of "local:[xxx]" * for pmcd clients. * If the spec is already "unix:[xxx] then leave it at that. * Note that the above includes wildcards. */ if (strncmp(name, "local:", 6) == 0 || strncmp(name, "unix:", 5) == 0) { #if defined(HAVE_STRUCT_SOCKADDR_UN) /* Use calloc so that the final entry is zeroed, if not used. */ specSize = 2; specs = calloc(specSize, sizeof(*specs)); if (specs == NULL) __pmNoMem("Access Spec List", specSize * sizeof(*specs), PM_FATAL_ERR); /* Process the equivalent unix domain socket spec. */ if ((*sts = getUnixSpec(strchr(name, ':') + 1, &specs[specIx])) >= 0) { /* If the spec was "unix:" then we're done. */ if (name[0] == 'u') return specs; ++specIx; } #else __pmNotifyErr(LOG_WARNING, "Host pattern \"%s\" is not supported. Using \"localhost\"\n", name); #endif /* Fall through to handle "localhost". */ name = "localhost"; } else if (isWildCard) { /* If any other wildcard is specified, then our list will contain that single item. * Use calloc so that the final entry is zeroed. */ specs = calloc(2, sizeof(*specs)); if (specs == NULL) __pmNoMem("Access Spec List", 2 * sizeof(*specs), PM_FATAL_ERR); *sts = getWildCardSpec(name, &specs[0]); return specs; } /* Assume we have a host name or address. Resolve it and contruct a list containing all of the resolved addresses. If the name is "localhost", then resolve using the actual host name. */ if (strcasecmp(name, "localhost") == 0) { if (!gotmyhostid) { if (getmyhostid() < 0) { __pmNotifyErr(LOG_ERR, "Can't get host name/IP address, giving up\n"); *sts = -EHOSTDOWN; if (specs) free(specs); return NULL; /* should never happen! */ } } realname = myhostname; } else realname = name; *sts = -EHOSTUNREACH; if ((servInfo = __pmGetAddrInfo(realname)) != NULL) { /* Collect all of the resolved addresses. Check for the end of the list within the loop since we need to add an empty entry and the code to grow the list is within the loop. */ enumIx = NULL; for (myAddr = __pmHostEntGetSockAddr(servInfo, &enumIx); /**/; myAddr = __pmHostEntGetSockAddr(servInfo, &enumIx)) { if (specIx == specSize) { specSize = specSize == 0 ? 4 : specSize * 2; need = specSize * sizeof(*specs); specs = realloc(specs, need); if (specs == NULL) { __pmNoMem("Access Spec List", need, PM_FATAL_ERR); } } /* No more addresses? */ if (myAddr == NULL) { specs[specIx].name = NULL; break; } /* Don't add any duplicate entries. It causes false permission clashes. */ for (ix = 0; ix < specIx; ++ix) { if (__pmSockAddrCompare(myAddr, specs[ix].hostid) == 0) break; } if (ix < specIx){ __pmSockAddrFree(myAddr); continue; } /* Add the new address and its corresponding mask. AF_UNIX socket addresses * will not appear here. */ family = __pmSockAddrGetFamily(myAddr); if (family == AF_INET) { specs[specIx].hostmask = __pmStringToSockAddr("255.255.255.255"); specs[specIx].level = 0; } else if (family == AF_INET6) { specs[specIx].hostmask = __pmStringToSockAddr("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); specs[specIx].level = 0; } else { __pmNotifyErr(LOG_ERR, "Unsupported socket address family: %d\n", family); __pmSockAddrFree(myAddr); continue; } specs[specIx].hostid = myAddr; specs[specIx].name = strdup(name); *sts = 0; ++specIx; } __pmHostEntFree(servInfo); } else { __pmNotifyErr(LOG_ERR, "__pmGetAddrInfo(%s), %s\n", realname, hoststrerror()); } /* Return NULL if nothing was discovered. *sts is already set. */ if (specIx == 0 && specs != NULL) { free(specs); specs = NULL; } return specs; } /* Routine to add a group to the group access list with a specified set of * permissions and a maximum connection limit. * specOps is a mask. Only bits corresponding to operations specified by * __pmAccAddOp have significance. A 1 bit indicates that the * corresponding bit in the denyOps mask is to be used. A zero bit in * specOps means the corresponding bit in denyOps should be ignored. * denyOps is a mask where a 1 bit indicates that permission to perform the * corresponding operation should be denied. * maxcons is a maximum connection limit for individial groups. Zero means * unspecified, which will allow unlimited connections or a subsequent * __pmAccAddUser call with the same group to override maxcons. * * Returns a negated system error code on failure. */ int __pmAccAddGroup(const char *name, unsigned int specOps, unsigned int denyOps, int maxcons) { size_t need; unsigned int nusers; int i = 0, sts, wildcard, found = 0; char errmsg[256]; char *groupname; __pmUserID *userids; __pmGroupID groupid; groupinfo *gp; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return PM_ERR_THREAD; if (specOps & ~all_ops) return -EINVAL; if (maxcons < 0) return -EINVAL; wildcard = (strcmp(name, "*") == 0); if (!wildcard) { if ((sts = __pmGroupnameToID(name, &groupid)) < 0) { __pmNotifyErr(LOG_ERR, "Failed to lookup group \"%s\": %s\n", name, pmErrStr_r(sts, errmsg, sizeof(errmsg))); return -EINVAL; } /* Search for a match to this group in the groups access table */ for (i = 1; i < ngroups; i++) { if (__pmEqualGroupIDs(groupid, grouplist[i].groupid)) { found = 1; break; } } } /* Check and augment existing group access list entry for this groupid * if a match was found, otherwise insert a new entry in list. */ if (found) { /* If the specified operations overlap, they must agree */ gp = &grouplist[i]; if ((gp->maxcons && maxcons && gp->maxcons != maxcons) || ((gp->specOps & specOps) && ((gp->specOps & gp->denyOps) ^ (specOps & denyOps)))) { __pmNotifyErr(LOG_ERR, "Permission clash for group %s with earlier statement\n", name); return -EINVAL; } gp->specOps |= specOps; gp->denyOps |= (specOps & denyOps); if (maxcons) gp->maxcons = maxcons; } else { /* Make the group access list larger if required */ if (ngroups == szgrouplist) { szgrouplist += 8; need = szgrouplist * sizeof(groupinfo); grouplist = (groupinfo *)realloc(grouplist, need); if (grouplist == NULL) __pmNoMem("AddGroup enlarge", need, PM_FATAL_ERR); } /* insert a permanent initial entry for '*' group wildcard */ if (ngroups == 0) { gp = &grouplist[0]; memset(gp, 0, sizeof(*gp)); gp->groupname = "*"; gp->denyOps = gp->specOps = all_ops; if (!wildcard) { /* if so, we're adding two entries */ i = ++ngroups; } } if (wildcard) { i = 0; /* always the first entry, setup constants */ gp = &grouplist[i]; /* for use when overwriting below */ groupname = gp->groupname; groupid = gp->groupid; userids = gp->userids; nusers = gp->nusers; } else if ((sts = __pmGroupsUserIDs(name, &userids, &nusers)) < 0) { __pmNotifyErr(LOG_ERR, "Failed to lookup users in group \"%s\": %s\n", name, pmErrStr_r(sts, errmsg, sizeof(errmsg))); return sts; } else if ((groupname = strdup(name)) == NULL) { __pmNoMem("AddGroup name", strlen(name)+1, PM_FATAL_ERR); } gp = &grouplist[i]; gp->groupname = groupname; gp->groupid = groupid; gp->userids = userids; gp->nusers = nusers; gp->specOps = specOps; gp->denyOps = specOps & denyOps; gp->maxcons = maxcons; gp->curcons = 0; ngroups++; } return 0; } /* Routine to add a user to the user access list with a specified set of * permissions and a maximum connection limit. * specOps is a mask. Only bits corresponding to operations specified by * __pmAccAddOp have significance. A 1 bit indicates that the * corresponding bit in the denyOps mask is to be used. A zero bit in * specOps means the corresponding bit in denyOps should be ignored. * denyOps is a mask where a 1 bit indicates that permission to perform the * corresponding operation should be denied. * maxcons is a maximum connection limit for individial users. Zero means * unspecified, which will allow unlimited connections or a subsequent * __pmAccAddUser call with the same user to override maxcons. * * Returns a negated system error code on failure. */ int __pmAccAddUser(const char *name, unsigned int specOps, unsigned int denyOps, int maxcons) { size_t need; unsigned int ngroups; int i = 0, sts, wildcard, found = 0; char errmsg[256]; char *username; __pmUserID userid; __pmGroupID *groupids; userinfo *up; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return PM_ERR_THREAD; if (specOps & ~all_ops) return -EINVAL; if (maxcons < 0) return -EINVAL; wildcard = (strcmp(name, "*") == 0); if (!wildcard) { if ((sts = __pmUsernameToID(name, &userid)) < 0) { __pmNotifyErr(LOG_ERR, "Failed to lookup user \"%s\": %s\n", name, pmErrStr_r(sts, errmsg, sizeof(errmsg))); return -EINVAL; } /* Search for a match to this user in the existing table of users. */ for (i = 1; i < nusers; i++) { if (__pmEqualUserIDs(userid, userlist[i].userid)) { found = 1; break; } } } /* Check and augment existing user access list entry for this userid if a * match was found otherwise insert a new entry in list. */ if (found) { /* If the specified operations overlap, they must agree */ up = &userlist[i]; if ((up->maxcons && maxcons && up->maxcons != maxcons) || ((up->specOps & specOps) && ((up->specOps & up->denyOps) ^ (specOps & denyOps)))) { __pmNotifyErr(LOG_ERR, "Permission clash for user %s with earlier statement\n", name); return -EINVAL; } up->specOps |= specOps; up->denyOps |= (specOps & denyOps); if (maxcons) up->maxcons = maxcons; } else { /* Make the user access list larger if required */ if (nusers == szuserlist) { szuserlist += 8; need = szuserlist * sizeof(userinfo); userlist = (userinfo *)realloc(userlist, need); if (userlist == NULL) { __pmNoMem("AddUser enlarge", need, PM_FATAL_ERR); } } /* insert a permanent initial entry for '*' user wildcard */ if (nusers == 0) { up = &userlist[0]; memset(up, 0, sizeof(*up)); up->username = "*"; up->denyOps = up->specOps = all_ops; if (!wildcard) /* if so, we're adding two entries */ i = ++nusers; } if (wildcard) { i = 0; /* always the first entry, setup constants */ up = &userlist[i]; /* for use when overwriting below */ username = up->username; userid = up->userid; ngroups = up->ngroups; groupids = up->groupids; } else if ((sts = __pmUsersGroupIDs(name, &groupids, &ngroups)) < 0) { __pmNotifyErr(LOG_ERR, "Failed to lookup groups for user \"%s\": %s\n", name, pmErrStr_r(sts, errmsg, sizeof(errmsg))); return sts; } else if ((username = strdup(name)) == NULL) { __pmNoMem("AddUser name", strlen(name)+1, PM_FATAL_ERR); } up = &userlist[i]; up->username = username; up->userid = userid; up->groupids = groupids; up->ngroups = ngroups; up->specOps = specOps; up->denyOps = specOps & denyOps; up->maxcons = maxcons; up->curcons = 0; nusers++; } return 0; } /* Routine to add a host to the host access list with a specified set of * permissions and a maximum connection limit. * specOps is a mask. Only bits corresponding to operations specified by * __pmAccAddOp have significance. A 1 bit indicates that the * corresponding bit in the denyOps mask is to be used. A zero bit in * specOps means the corresponding bit in denyOps should be ignored. * denyOps is a mask where a 1 bit indicates that permission to perform the * corresponding operation should be denied. * maxcons is a maximum connection limit for clients on hosts matching the host * id. Zero means unspecified, which will allow unlimited connections or * a subsequent __pmAccAddHost call with the same host to override maxcons. * * Returns a negated system error code on failure. */ int __pmAccAddHost(const char *name, unsigned int specOps, unsigned int denyOps, int maxcons) { size_t need; int i, sts = 0; struct accessSpec *specs; struct accessSpec *spec; hostinfo *hp; int found; char *prevHost; char *prevName; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return PM_ERR_THREAD; if (specOps & ~all_ops) return -EINVAL; if (maxcons < 0) return -EINVAL; /* The specified name may result in more than one access specification. */ specs = getHostAccessSpecs(name, &sts); if (specs == NULL) return sts; /* Search for a match to each spec in the existing table of hosts. We will either use or free the host id, mask and name of each spec as we go. */ prevHost = NULL; prevName = NULL; found = 0; for (spec = specs; spec->name != NULL; ++spec) { sts = 0; for (i = 0; i < nhosts; i++) { if (hostlist[i].level > spec->level) break; /* hostid AND level must match. Wildcarded IP addresses have zero in * the unspecified components. Distinguish between 155.23.6.0 and * 155.23.6.* or 155.23.0.0 and 155.23.* by wildcard level. IP * addresses shouldn't have zero in last position but to deal with * them just in case. * This test also works for Unix Domain addresses and wildcards. */ if (__pmSockAddrCompare(spec->hostid, hostlist[i].hostid) == 0 && spec->level == hostlist[i].level) { sts = 1; break; } } /* Check and augment existing host access list entry for this host id if a * match was found (sts == 1) otherwise insert a new entry in list. */ if (sts == 1) { __pmSockAddrFree(spec->hostid); __pmSockAddrFree(spec->hostmask); /* If the specified operations overlap, they must agree */ hp = &hostlist[i]; if ((hp->maxcons && maxcons && hp->maxcons != maxcons) || ((hp->specOps & specOps) && ((hp->specOps & hp->denyOps) ^ (specOps & denyOps)))) { /* Suppress duplicate messages. These can occur when a host resolves to more than one address. */ if (prevName == NULL || strcmp(prevName, spec->name) != 0 || strcmp(prevHost, hp->hostspec) != 0) { __pmNotifyErr(LOG_ERR, "Permission clash for %s with earlier statement for %s\n", spec->name, hp->hostspec); if (prevName != NULL) { free(prevName); free(prevHost); } prevName = strdup(spec->name); prevHost = strdup(hp->hostspec); } free(spec->name); continue; } free(spec->name); hp->specOps |= specOps; hp->denyOps |= (specOps & denyOps); if (maxcons) hp->maxcons = maxcons; } else { /* Make the host access list larger if required */ if (nhosts == szhostlist) { szhostlist += 8; need = szhostlist * sizeof(hostinfo); hostlist = (hostinfo *)realloc(hostlist, need); if (hostlist == NULL) { __pmNoMem("AddHost enlarge", need, PM_FATAL_ERR); } } /* Move any subsequent hosts down to make room for the new entry*/ hp = &hostlist[i]; if (i < nhosts) memmove(&hostlist[i+1], &hostlist[i], (nhosts - i) * sizeof(hostinfo)); hp->hostspec = spec->name; hp->hostid = spec->hostid; hp->hostmask = spec->hostmask; hp->level = spec->level; hp->specOps = specOps; hp->denyOps = specOps & denyOps; hp->maxcons = maxcons; hp->curcons = 0; nhosts++; } /* Count the found hosts. */ ++found; } /* loop over addresses */ if (prevName != NULL) { free(prevName); free(prevHost); } free(specs); return found != 0 ? 0 : -EINVAL; } static __pmSockAddr ** getClientIds(const __pmSockAddr *hostid, int *sts) { __pmSockAddr **clientIds; __pmSockAddr *myAddr; size_t clientIx; size_t clientSize; size_t need; void *enumIx; *sts = 0; /* If the address is not for "localhost", then return a list containing only the given address. */ if (! __pmSockAddrIsLoopBack(hostid)) { clientIds = calloc(2, sizeof(*clientIds)); if (clientIds == NULL) __pmNoMem("Client Ids", 2 * sizeof(*clientIds), PM_FATAL_ERR); clientIds[0] = __pmSockAddrDup(hostid); return clientIds; } /* Map "localhost" to the real IP addresses. Host access statements for * localhost are mapped to the "real" IP addresses so that wildcarding works * consistently. First get the real host address; */ PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (!gotmyhostid) getmyhostid(); *sts = PM_ERR_PERMISSION; if (gotmyhostid <= 0) { PM_UNLOCK(__pmLock_libpcp); return NULL; } PM_UNLOCK(__pmLock_libpcp); /* Now construct a list containing each address. Check for the end of the list within the loop since we need to add an empty entry and the code to grow the list is within the loop. */ clientIds = NULL; clientIx = 0; clientSize = 0; enumIx = NULL; for (myAddr = __pmHostEntGetSockAddr(myhostid, &enumIx); /**/; myAddr = __pmHostEntGetSockAddr(myhostid, &enumIx)) { if (clientIx == clientSize) { clientSize = clientSize == 0 ? 4 : clientSize * 2; need = clientSize * sizeof(*clientIds); clientIds = realloc(clientIds, need); if (clientIds == NULL) { PM_UNLOCK(__pmLock_libpcp); __pmNoMem("Client Ids", need, PM_FATAL_ERR); } } /* No more addresses? */ if (myAddr == NULL) { clientIds[clientIx] = NULL; break; } /* Add the new address and its corrsponding mask. */ clientIds[clientIx] = myAddr; ++clientIx; *sts = 0; } /* If no addresses were discovered, then return NULL. *sts is already set. */ if (clientIx == 0) { free(clientIds); clientIds = NULL; } return clientIds; } static void freeClientIds(__pmSockAddr **clientIds) { int i; for (i = 0; clientIds[i] != NULL; ++i) free(clientIds[i]); free(clientIds); } /* Called after accepting new client's connection to check that another * connection from its host is permitted and to find which operations the * client is permitted to perform. * hostid is the address of the host that the client is running on * denyOpsResult is a pointer to return the capability vector */ int __pmAccAddClient(__pmSockAddr *hostid, unsigned int *denyOpsResult) { int i; int sts; hostinfo *hp; hostinfo *lastmatch = NULL; int clientIx; __pmSockAddr **clientIds; __pmSockAddr *clientId; __pmSockAddr *matchId; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return PM_ERR_THREAD; *denyOpsResult = 0; /* deny nothing == allow all */ if (nhosts == 0) /* No access controls => allow all */ return 0; /* There could be more than one address associated with this host.*/ clientIds = getClientIds(hostid, &sts); if (clientIds == NULL) return sts; /* Accumulate permissions for each client address. */ for (clientIx = 0; clientIds[clientIx] != NULL; ++clientIx) { clientId = clientIds[clientIx]; for (i = nhosts - 1; i >= 0; i--) { hp = &hostlist[i]; /* At a minumum, the addresses must be from the same family. */ if (__pmSockAddrGetFamily(clientId) == __pmSockAddrGetFamily(hp->hostmask)) { matchId = __pmSockAddrDup(clientId); __pmSockAddrMask(matchId, hp->hostmask); if (__pmSockAddrCompare(matchId, hp->hostid) == 0) { /* Clobber specified ops then set. Leave unspecified ops alone. */ *denyOpsResult &= ~hp->specOps; *denyOpsResult |= hp->denyOps; lastmatch = hp; } __pmSockAddrFree(matchId); } } /* no matching entry in hostlist => allow all */ /* If no operations are allowed, disallow connection */ if (*denyOpsResult == all_ops) { freeClientIds(clientIds); return PM_ERR_PERMISSION; } /* Check for connection limit */ if (lastmatch != NULL && lastmatch->maxcons && lastmatch->curcons >= lastmatch->maxcons) { *denyOpsResult = all_ops; freeClientIds(clientIds); return PM_ERR_CONNLIMIT; } /* Increment the count of current connections for ALL host specs in the * host access list that match the client's IP address. A client may * contribute to several connection counts because of wildcarding. */ for (i = 0; i < nhosts; i++) { hp = &hostlist[i]; /* At a minumum, the addresses must be from the same family. */ if (__pmSockAddrGetFamily(clientId) == __pmSockAddrGetFamily(hp->hostmask)) { matchId = __pmSockAddrDup(clientId); __pmSockAddrMask(matchId, hp->hostmask); if (__pmSockAddrCompare(matchId, hp->hostid) == 0) { if (hp->maxcons) hp->curcons++; } __pmSockAddrFree(matchId); } } } freeClientIds(clientIds); return 0; } void __pmAccDelClient(__pmSockAddr *hostid) { int i; int sts; hostinfo *hp; int clientIx; __pmSockAddr **clientIds; __pmSockAddr *clientId; __pmSockAddr *matchId; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return; /* There could be more than one address associated with this host.*/ clientIds = getClientIds(hostid, &sts); if (clientIds == NULL) return; /* Decrement the count of current connections for ALL host specs in the * host access list that match the client's IP addresses. A client may * contribute to several connection counts because of wildcarding. */ for (clientIx = 0; clientIds[clientIx] != NULL; ++clientIx) { clientId = clientIds[clientIx]; for (i = 0; i < nhosts; i++) { hp = &hostlist[i]; /* At a minumum, the addresses must be from the same family. */ if (__pmSockAddrGetFamily(clientId) == __pmSockAddrGetFamily(hp->hostmask)) { matchId = __pmSockAddrDup(clientId); __pmSockAddrMask(matchId, hp->hostmask); if (__pmSockAddrCompare(matchId, hp->hostid) == 0) { if (hp->maxcons) hp->curcons--; } __pmSockAddrFree(matchId); } } } freeClientIds(clientIds); } static int findGidInUsersGroups(const userinfo *up, __pmGroupID gid) { int i; for (i = 0; i < up->ngroups; i++) if (__pmEqualGroupIDs(up->groupids[i], gid)) return 1; return 0; } static int accessCheckUsers(__pmUserID uid, __pmGroupID gid, unsigned int *denyOpsResult) { userinfo *up; int matched = 0; int i; for (i = 1; i < nusers; i++) { up = &userlist[i]; if ((__pmValidUserID(uid) && __pmEqualUserIDs(up->userid, uid)) || (__pmValidGroupID(gid) && findGidInUsersGroups(up, gid))) { if (up->maxcons && up->curcons >= up->maxcons) { *denyOpsResult = all_ops; return PM_ERR_CONNLIMIT; } *denyOpsResult |= up->denyOps; matched = 1; } } if (nusers && !matched) { up = &userlist[0]; /* global wildcard */ if (up->maxcons && up->curcons >= up->maxcons) { *denyOpsResult = all_ops; return PM_ERR_CONNLIMIT; } *denyOpsResult |= up->denyOps; } return 0; } static int findUidInGroupsUsers(const groupinfo *gp, __pmUserID uid) { int i; for (i = 0; i < gp->nusers; i++) if (__pmEqualUserIDs(gp->userids[i], uid)) return 1; return 0; } static int accessCheckGroups(__pmUserID uid, __pmGroupID gid, unsigned int *denyOpsResult) { groupinfo *gp; int matched = 0; int i; for (i = 1; i < ngroups; i++) { gp = &grouplist[i]; if ((__pmValidGroupID(gid) && __pmEqualGroupIDs(gp->groupid, gid)) || (__pmValidUserID(uid) && findUidInGroupsUsers(gp, uid))) { if (gp->maxcons && gp->curcons >= gp->maxcons) { *denyOpsResult = all_ops; return PM_ERR_CONNLIMIT; } *denyOpsResult |= gp->denyOps; matched = 1; } } if (ngroups && !matched) { gp = &grouplist[0]; /* global wildcard */ if (gp->maxcons && gp->curcons >= gp->maxcons) { *denyOpsResult = all_ops; return PM_ERR_CONNLIMIT; } *denyOpsResult |= gp->denyOps; } return 0; } static void updateGroupAccountConnections(__pmGroupID, int, int); static void updateUserAccountConnections(__pmUserID uid, int descend, int direction) { int i, j; userinfo *up; for (i = 1; i < nusers; i++) { up = &userlist[i]; if (!__pmEqualUserIDs(up->userid, uid)) continue; if (up->maxcons) up->curcons += direction; /* might be negative */ assert(up->curcons >= 0); if (!descend) continue; for (j = 0; j < up->ngroups; j++) updateGroupAccountConnections(up->groupids[j], 0, direction); } } static void updateGroupAccountConnections(__pmGroupID gid, int descend, int direction) { int i, j; groupinfo *gp; for (i = 1; i < ngroups; i++) { gp = &grouplist[i]; if (!__pmEqualGroupIDs(gp->groupid, gid)) continue; if (gp->maxcons) gp->curcons += direction; /* might be negative */ assert(gp->curcons >= 0); if (!descend) continue; for (j = 0; j < gp->nusers; j++) updateUserAccountConnections(gp->userids[j], 0, direction); } } /* Called after authenticating a new connection to check that another * connection from this account is permitted and to find which operations * the account is permitted to perform. * uid and gid identify the account, if not authenticated these will be * negative. denyOpsResult is a pointer to return the capability vector * and note that it is both input (host access) and output (merged host * and account access). So, do not blindly zero or overwrite existing. */ int __pmAccAddAccount(const char *userid, const char *groupid, unsigned int *denyOpsResult) { int sts; __pmUserID uid; __pmGroupID gid; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return PM_ERR_THREAD; if (nusers == 0 && ngroups == 0) /* No access controls => allow all */ return (userid || groupid); /* Inform caller of credentials */ /* Access controls present, but no authentication information - denied */ if (!userid || !groupid) { *denyOpsResult = all_ops; return PM_ERR_PERMISSION; } __pmUserIDFromString(userid, &uid); __pmGroupIDFromString(groupid, &gid); /* Access controls present, but invalid user/group information - denied */ if (!__pmValidUserID(uid) && !__pmValidGroupID(gid)) { *denyOpsResult = all_ops; return PM_ERR_PERMISSION; } if ((sts = accessCheckUsers(uid, gid, denyOpsResult)) < 0) return sts; if ((sts = accessCheckGroups(uid, gid, denyOpsResult)) < 0) return sts; /* If no operations are allowed, disallow connection */ if (*denyOpsResult == all_ops) return PM_ERR_PERMISSION; /* Increment the count of current connections for this user and group * in the user and groups access lists. Must walk the supplementary * ID lists as well as the primary ID ACLs. */ updateUserAccountConnections(uid, 1, +1); updateGroupAccountConnections(gid, 1, +1); /* Return code indicates access controls OK and have credentials */ return 1; } void __pmAccDelAccount(const char *userid, const char *groupid) { __pmUserID uid; __pmGroupID gid; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return; __pmUserIDFromString(userid, &uid); __pmGroupIDFromString(groupid, &gid); /* Decrement the count of current connections for this user and group * in the user and groups access lists. Must walk the supplementary * ID lists as well as the primary ID ACLs. */ updateUserAccountConnections(uid, 1, -1); updateGroupAccountConnections(gid, 1, -1); } static void getAccMinMaxBits(int *minbitp, int *maxbitp) { unsigned int mask = all_ops; int i, minbit = -1; for (i = 0; mask; i++) { if (mask % 2) if (minbit < 0) minbit = i; mask = mask >> 1; } *minbitp = minbit; *maxbitp = i - 1; } #define NAME_WIDTH 39 /* sufficient for a full IPv6 address */ #define ID_WIDTH 7 /* sufficient for large group/user ID */ void __pmAccDumpHosts(FILE *stream) { int h, i; int minbit, maxbit; char *addrid, *addrmask; unsigned int mask; hostinfo *hp; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return; if (nhosts == 0) { fprintf(stream, "Host access list empty: host-based access control turned off\n"); return; } getAccMinMaxBits(&minbit, &maxbit); fprintf(stream, "Host access list:\n"); for (i = minbit; i <= maxbit; i++) if (all_ops & (1 << i)) fprintf(stream, "%02d ", i); fprintf(stream, "Cur/MaxCons %-*s %-*s lvl host-name\n", NAME_WIDTH, "host-spec", NAME_WIDTH, "host-mask"); for (i = minbit; i <= maxbit; i++) if (all_ops & (1 << i)) fputs("== ", stream); fprintf(stream, "=========== "); for (i = 0; i < 2; i++) { for (h = 0; h < NAME_WIDTH; h++) fprintf(stream, "="); fprintf(stream, " "); } fprintf(stream, "=== ==============\n"); for (h = 0; h < nhosts; h++) { hp = &hostlist[h]; for (i = minbit; i <= maxbit; i++) { mask = 1 << i; if (all_ops & mask) { if (hp->specOps & mask) fputs((hp->denyOps & mask) ? " n " : " y ", stream); else fputs(" ", stream); } } addrid = __pmSockAddrToString(hp->hostid); addrmask = __pmSockAddrToString(hp->hostmask); fprintf(stream, "%5d %5d %-*s %-*s %3d %s\n", hp->curcons, hp->maxcons, NAME_WIDTH, addrid, NAME_WIDTH, addrmask, hp->level, hp->hostspec); free(addrmask); free(addrid); } } void __pmAccDumpUsers(FILE *stream) { int u, i; int minbit, maxbit; char buf[128]; unsigned int mask; userinfo *up; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return; if (nusers == 0) { fprintf(stream, "User access list empty: user-based access control turned off\n"); return; } getAccMinMaxBits(&minbit, &maxbit); fprintf(stream, "User access list:\n"); for (i = minbit; i <= maxbit; i++) if (all_ops & (1 << i)) fprintf(stream, "%02d ", i); fprintf(stream, "Cur/MaxCons %*s %-*s %s\n", ID_WIDTH, "uid", NAME_WIDTH-ID_WIDTH-1, "user-name", "group-list"); for (i = minbit; i <= maxbit; i++) if (all_ops & (1 << i)) fputs("== ", stream); fprintf(stream, "=========== "); for (i = 0; i < ID_WIDTH; i++) /* user-id */ fprintf(stream, "="); fprintf(stream, " "); for (i = 0; i < NAME_WIDTH-ID_WIDTH-1; i++) /* user-name */ fprintf(stream, "="); fprintf(stream, " "); for (i = 0; i < NAME_WIDTH + 19; i++) /* group-list */ fprintf(stream, "="); fprintf(stream, "\n"); for (u = nusers-1; u >= 0; u--) { up = &userlist[u]; for (i = minbit; i <= maxbit; i++) { mask = 1 << i; if (all_ops & mask) { if (up->specOps & mask) fputs((up->denyOps & mask) ? " n " : " y ", stream); else fputs(" ", stream); } } fprintf(stream, "%5d %5d %*s %-*s", up->curcons, up->maxcons, ID_WIDTH, u == 0 ? "*" : __pmUserIDToString(up->userid, buf, sizeof(buf)), NAME_WIDTH-ID_WIDTH-1, up->username); for (i = 0; i < up->ngroups; i++) fprintf(stream, "%c%u(%s)", i ? ',' : ' ', up->groupids[i], __pmGroupnameFromID(up->groupids[i], buf, sizeof(buf))); fprintf(stream, "\n"); } } void __pmAccDumpGroups(FILE *stream) { int g, i; int minbit, maxbit; char buf[128]; unsigned int mask; groupinfo *gp; if (PM_MULTIPLE_THREADS(PM_SCOPE_ACL)) return; if (ngroups == 0) { fprintf(stream, "Group access list empty: group-based access control turned off\n"); return; } getAccMinMaxBits(&minbit, &maxbit); fprintf(stream, "Group access list:\n"); for (i = minbit; i <= maxbit; i++) if (all_ops & (1 << i)) fprintf(stream, "%02d ", i); fprintf(stream, "Cur/MaxCons %*s %-*s %s\n", ID_WIDTH, "gid", NAME_WIDTH-ID_WIDTH-1, "group-name", "user-list"); for (i = minbit; i <= maxbit; i++) if (all_ops & (1 << i)) fputs("== ", stream); fprintf(stream, "=========== "); for (i = 0; i < ID_WIDTH; i++) /* group-id */ fprintf(stream, "="); fprintf(stream, " "); for (i = 0; i < NAME_WIDTH-ID_WIDTH-1; i++) /* group-name */ fprintf(stream, "="); fprintf(stream, " "); for (i = 0; i < NAME_WIDTH + 19; i++) /* user-list */ fprintf(stream, "="); fprintf(stream, "\n"); for (g = ngroups-1; g >= 0; g--) { gp = &grouplist[g]; for (i = minbit; i <= maxbit; i++) { mask = 1 << i; if (all_ops & mask) { if (gp->specOps & mask) fputs((gp->denyOps & mask) ? " n " : " y ", stream); else fputs(" ", stream); } } snprintf(buf, sizeof(buf), g ? "%6d" : " *", gp->groupid); fprintf(stream, "%5d %5d %*s %-*s", gp->curcons, gp->maxcons, ID_WIDTH, g == 0 ? "*" : __pmGroupIDToString(gp->groupid, buf, sizeof(buf)), NAME_WIDTH-ID_WIDTH-1, gp->groupname); for (i = 0; i < gp->nusers; i++) fprintf(stream, "%c%u(%s)", i ? ',' : ' ', gp->userids[i], __pmUsernameFromID(gp->userids[i], buf, sizeof(buf))); fprintf(stream, "\n"); } } void __pmAccDumpLists(FILE *stream) { putc('\n', stream); __pmAccDumpHosts(stream); __pmAccDumpUsers(stream); __pmAccDumpGroups(stream); putc('\n', stream); } pcp-3.8.12ubuntu1/src/libpcp/src/util.c0000664000000000000000000014271212272262501014561 0ustar /* * General Utility Routines * * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2009 Aconex. All Rights Reserved. * Copyright (c) 1995-2002,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe notes * * pmState - no side-effects, don't bother locking * * pmProgname - most likely set in main(), not worth protecting here * and impossible to capture all the read uses in other places * * base (in __pmProcessDataSize) - no real side-effects, don't bother * locking */ #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "pmdbg.h" #include "internal.h" #if defined(HAVE_SYS_TIMES_H) #include #endif #if defined(HAVE_SYS_MMAN_H) #include #endif #if defined(HAVE_IEEEFP_H) #include #endif #if defined(HAVE_MATH_H) #include #endif static FILE **filelog; static int nfilelog; static int dosyslog; static int pmState = PM_STATE_APPL; static int done_exit; INTERN char *pmProgname = "pcp"; /* the real McCoy */ static int vpmprintf(const char *, va_list); /* * if onoff == 1, logging is to syslog and stderr, else logging is * just to stderr (this is the default) */ void __pmSyslog(int onoff) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); dosyslog = onoff; if (dosyslog) openlog("pcp", LOG_PID, LOG_DAEMON); else closelog(); PM_UNLOCK(__pmLock_libpcp); } /* * This is a wrapper around syslog(3C) that writes similar messages to stderr, * but if __pmSyslog(1) is called, the messages will really go to syslog */ void __pmNotifyErr(int priority, const char *message, ...) { va_list arg; char *p; char *level; time_t now; va_start(arg, message); time(&now); PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (dosyslog) { char syslogmsg[2048]; vsnprintf(syslogmsg, sizeof(syslogmsg), message, arg); va_end(arg); va_start(arg, message); syslog(priority, "%s", syslogmsg); } PM_UNLOCK(__pmLock_libpcp); /* * do the stderr equivalent */ switch (priority) { case LOG_EMERG : level = "Emergency"; break; case LOG_ALERT : level = "Alert"; break; case LOG_CRIT : level = "Critical"; break; case LOG_ERR : level = "Error"; break; case LOG_WARNING : level = "Warning"; break; case LOG_NOTICE : level = "Notice"; break; case LOG_INFO : level = "Info"; break; case LOG_DEBUG : level = "Debug"; break; default: level = "???"; break; } PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); pmprintf("[%.19s] %s(%" FMT_PID ") %s: ", ctime(&now), pmProgname, getpid(), level); PM_UNLOCK(__pmLock_libpcp); vpmprintf(message, arg); va_end(arg); /* trailing \n if needed */ for (p = (char *)message; *p; p++) ; if (p == message || p[-1] != '\n') pmprintf("\n"); pmflush(); } static void logheader(const char *progname, FILE *log, const char *act) { time_t now; char host[MAXHOSTNAMELEN]; setlinebuf(log); /* line buffering for log files */ gethostname(host, MAXHOSTNAMELEN); host[MAXHOSTNAMELEN-1] = '\0'; time(&now); PM_LOCK(__pmLock_libpcp); fprintf(log, "Log for %s on %s %s %s\n", progname, host, act, ctime(&now)); PM_UNLOCK(__pmLock_libpcp); } static void logfooter(FILE *log, const char *act) { time_t now; time(&now); PM_LOCK(__pmLock_libpcp); fprintf(log, "\nLog %s %s", act, ctime(&now)); PM_UNLOCK(__pmLock_libpcp); } static void logonexit(void) { int i; PM_LOCK(__pmLock_libpcp); if (++done_exit != 1) { PM_UNLOCK(__pmLock_libpcp); return; } for (i = 0; i < nfilelog; i++) logfooter(filelog[i], "finished"); PM_UNLOCK(__pmLock_libpcp); } /* common code shared by __pmRotateLog and __pmOpenLog */ static FILE * logreopen(const char *progname, const char *logname, FILE *oldstream, int *status) { int oldfd; int dupoldfd; FILE *dupoldstream = oldstream; /* * Do our own version of freopen() because the standard one closes the * original stream BEFORE trying to open the new one. Once it's gone, * there's no way to get the closed stream back if the open fails. */ fflush(oldstream); *status = 0; /* set to one if all this works ... */ oldfd = fileno(oldstream); if ((dupoldfd = dup(oldfd)) >= 0) { /* * try to remove the file first ... don't bother if this fails, * but if it succeeds, we at least get a chance to define the * owner and mode, rather than inheriting this from an existing * writeable file ... really only a problem when called as with * uid == 0, e.g. from pmcd(1). */ unlink(logname); oldstream = freopen(logname, "w", oldstream); if (oldstream == NULL) { int save_error = oserror(); /* need for error message */ close(oldfd); if (dup(dupoldfd) != oldfd) { /* fd juggling failed! */ oldstream = NULL; } else { /* oldfd now re-instated as at entry */ oldstream = fdopen(oldfd, "w"); } if (oldstream == NULL) { /* serious trouble ... choose least obnoxious alternative */ if (dupoldstream == stderr) oldstream = fdopen(fileno(stdout), "w"); else oldstream = fdopen(fileno(stderr), "w"); } if (oldstream != NULL) { /* * oldstream was NULL, but recovered so now fixup * input oldstream ... this is potentially dangerous, * but we're relying on * (a) fflush(oldstream) on entry flushes buffers * (b) fdopen() leaves new oldstream initialized * (c) caller knows nothing about "new" oldstream * and is never going to fclose() it, so only * fclose() will come at exit() and should be * benign (except possibly for a free() of an * already free()'d buffer) */ *dupoldstream = *oldstream; /* struct copy */ /* put oldstream back for return value */ oldstream = dupoldstream; } pmprintf("%s: cannot open log \"%s\" for writing : %s\n", progname, logname, strerror(save_error)); pmflush(); } else { /* yippee */ *status = 1; } close(dupoldfd); } else { pmprintf("%s: cannot redirect log output to \"%s\": %s\n", progname, logname, strerror(errno)); pmflush(); } return oldstream; } FILE * __pmOpenLog(const char *progname, const char *logname, FILE *oldstream, int *status) { oldstream = logreopen(progname, logname, oldstream, status); PM_INIT_LOCKS(); logheader(progname, oldstream, "started"); PM_LOCK(__pmLock_libpcp); nfilelog++; if (nfilelog == 1) atexit(logonexit); filelog = (FILE **)realloc(filelog, nfilelog * sizeof(FILE *)); if (filelog == NULL) { __pmNoMem("__pmOpenLog", nfilelog * sizeof(FILE *), PM_FATAL_ERR); } filelog[nfilelog-1] = oldstream; PM_UNLOCK(__pmLock_libpcp); return oldstream; } FILE * __pmRotateLog(const char *progname, const char *logname, FILE *oldstream, int *status) { int i; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); for (i = 0; i < nfilelog; i++) { if (oldstream == filelog[i]) { logfooter(oldstream, "rotated"); /* old */ oldstream = logreopen(progname, logname, oldstream, status); logheader(progname, oldstream, "rotated"); /* new */ filelog[i] = oldstream; break; } } PM_UNLOCK(__pmLock_libpcp); return oldstream; } /* pmID -> string, max length is 20 bytes */ char * pmIDStr_r(pmID pmid, char *buf, int buflen) { __pmID_int* p = (__pmID_int*)&pmid; if (pmid == PM_ID_NULL) snprintf(buf, buflen, "%s", "PM_ID_NULL"); else if (p->domain == DYNAMIC_PMID && p->item == 0) /* * this PMID represents the base of a dynamic subtree in the PMNS * ... identified by setting the domain field to the reserved * value DYNAMIC_PMID and storing the real domain of the PMDA * that can enumerate the subtree in the cluster field, while * the item field is not used */ snprintf(buf, buflen, "%d.*.*", p->cluster); else snprintf(buf, buflen, "%d.%d.%d", p->domain, p->cluster, p->item); return buf; } const char * pmIDStr(pmID pmid) { static char idbuf[20]; pmIDStr_r(pmid, idbuf, sizeof(idbuf)); return idbuf; } /* pmInDom -> string, max length is 20 bytes */ char * pmInDomStr_r(pmInDom indom, char *buf, int buflen) { __pmInDom_int* p = (__pmInDom_int*)&indom; if (indom == PM_INDOM_NULL) snprintf(buf, buflen, "%s", "PM_INDOM_NULL"); else snprintf(buf, buflen, "%d.%d", p->domain, p->serial); return buf; } const char * pmInDomStr(pmInDom indom) { static char indombuf[20]; pmInDomStr_r(indom, indombuf, sizeof(indombuf)); return indombuf; } /* double -> string, max length is 8 bytes */ char * pmNumberStr_r(double value, char *buf, int buflen) { if (value >= 0.0) { if (value >= 999995000000000.0) snprintf(buf, buflen, " inf? "); else if (value >= 999995000000.0) snprintf(buf, buflen, "%6.2fT", value / 1000000000000.0); else if (value >= 999995000.0) snprintf(buf, buflen, "%6.2fG", value / 1000000000.0); else if (value >= 999995.0) snprintf(buf, buflen, "%6.2fM", value / 1000000.0); else if (value >= 999.995) snprintf(buf, buflen, "%6.2fK", value / 1000.0); else if (value >= 0.005) snprintf(buf, buflen, "%6.2f ", value); else snprintf(buf, buflen, "%6.2f ", 0.0); } else { if (value <= -99995000000000.0) snprintf(buf, buflen, "-inf? "); else if (value <= -99995000000.0) snprintf(buf, buflen, "%6.2fT", value / 1000000000000.0); else if (value <= -99995000.0) snprintf(buf, buflen, "%6.2fG", value / 1000000000.0); else if (value <= -99995.0) snprintf(buf, buflen, "%6.2fM", value / 1000000.0); else if (value <= -99.995) snprintf(buf, buflen, "%6.2fK", value / 1000.0); else if (value <= -0.005) snprintf(buf, buflen, "%6.2f ", value); else snprintf(buf, buflen, "%6.2f ", 0.0); } return buf; } const char * pmNumberStr(double value) { static char nbuf[8]; pmNumberStr_r(value, nbuf, sizeof(nbuf)); return nbuf; } /* flags -> string, max length is 64 bytes */ char * pmEventFlagsStr_r(int flags, char *buf, int buflen) { /* * buffer needs to be long enough to hold each flag name * (excluding missed) plus the separation commas, so * point,start,end,id,parent (even though it is unlikely that * both start and end would be set for the one event record) */ int started = 0; if (flags & PM_EVENT_FLAG_MISSED) return strcpy(buf, "missed"); buf[0] = '\0'; if (flags & PM_EVENT_FLAG_POINT) { if (started++) strcat(buf, ","); strcat(buf, "point"); } if (flags & PM_EVENT_FLAG_START) { if (started++) strcat(buf, ","); strcat(buf, "start"); } if (flags & PM_EVENT_FLAG_END) { if (started++) strcat(buf, ","); strcat(buf, "end"); } if (flags & PM_EVENT_FLAG_ID) { if (started++) strcat(buf, ","); strcat(buf, "id"); } if (flags & PM_EVENT_FLAG_PARENT) { if (started++) strcat(buf, ","); strcat(buf, "parent"); } return buf; } const char * pmEventFlagsStr(int flags) { static char ebuf[64]; pmEventFlagsStr_r(flags, ebuf, sizeof(ebuf)); return ebuf; } /* * Several PMAPI interfaces allocate a list of strings into a buffer * pointed to by (char **) which can be safely freed simply by * freeing the pointer to the buffer. * * Here we provide some functions for manipulating these lists. */ /* Add the given item to the list, which may be empty. */ int __pmStringListAdd(char *item, int numElements, char ***list) { size_t ptrSize; size_t dataSize; size_t newSize; char *initialString; char *finalString; char **newList; int i; /* Compute the sizes of the pointers and data for the current list. */ if (*list != NULL) { ptrSize = numElements * sizeof(**list); initialString = **list; finalString = (*list)[numElements - 1]; dataSize = (finalString + strlen(finalString) + 1) - initialString; } else { ptrSize = 0; dataSize = 0; } /* * Now allocate a new buffer for the expanded list. * We need room for a new pointer and for the new item. */ newSize = ptrSize + sizeof(**list) + dataSize + strlen(item) + 1; newList = realloc(*list, newSize); if (newList == NULL) { __pmNoMem("__pmStringListAdd", newSize, PM_FATAL_ERR); } /* * Shift the existing data to make room for the new pointer and * recompute each existing pointer. */ finalString = (char *)(newList + numElements + 1); if (dataSize != 0) { initialString = (char *)(newList + numElements); memmove(finalString, initialString, dataSize); for (i = 0; i < numElements; ++i) { newList[i] = finalString; finalString += strlen(finalString) + 1; } } /* Now add the new item. */ newList[numElements] = finalString; strcpy(finalString, item); *list = newList; return numElements + 1; } /* Search for the given string in the given string list. */ char * __pmStringListFind(const char *item, int numElements, char **list) { int e; if (list == NULL) return NULL; /* no list to search */ for (e = 0; e < numElements; ++e) { if (strcmp(item, list[e]) == 0) return list[e]; } /* Not found. */ return NULL; } void __pmDumpResult(FILE *f, const pmResult *resp) { int i; int j; int n; int saveDebug; char *p; pmDesc desc; int have_desc; /* tracing PDUs really messes this up when pmNameInDom is called below */ saveDebug = pmDebug; pmDebug = 0; fprintf(f,"pmResult dump from " PRINTF_P_PFX "%p timestamp: %d.%06d ", resp, (int)resp->timestamp.tv_sec, (int)resp->timestamp.tv_usec); __pmPrintStamp(f, &resp->timestamp); fprintf(f, " numpmid: %d\n", resp->numpmid); for (i = 0; i < resp->numpmid; i++) { pmValueSet *vsp = resp->vset[i]; char strbuf[20]; n = pmNameID(vsp->pmid, &p); if (n < 0) fprintf(f," %s (%s):", pmIDStr_r(vsp->pmid, strbuf, sizeof(strbuf)), ""); else { fprintf(f," %s (%s):", pmIDStr_r(vsp->pmid, strbuf, sizeof(strbuf)), p); free(p); } if (vsp->numval == 0) { fprintf(f, " No values returned!\n"); continue; } else if (vsp->numval < 0) { char errmsg[PM_MAXERRMSGLEN]; fprintf(f, " %s\n", pmErrStr_r(vsp->numval, errmsg, sizeof(errmsg))); continue; } if (__pmGetInternalState() == PM_STATE_PMCS || pmLookupDesc(vsp->pmid, &desc) < 0) { /* don't know, so punt on the most common cases */ desc.indom = PM_INDOM_NULL; have_desc = 0; } else have_desc = 1; fprintf(f, " numval: %d", vsp->numval); fprintf(f, " valfmt: %d vlist[]:\n", vsp->valfmt); for (j = 0; j < vsp->numval; j++) { pmValue *vp = &vsp->vlist[j]; if (vsp->numval > 1 || vp->inst != PM_INDOM_NULL) { fprintf(f," inst [%d", vp->inst); if (have_desc && pmNameInDom(desc.indom, vp->inst, &p) >= 0) { fprintf(f, " or \"%s\"]", p); free(p); } else { fprintf(f, " or ???]"); } fputc(' ', f); } else fprintf(f, " "); fprintf(f, "value "); if (have_desc) pmPrintValue(f, vsp->valfmt, desc.type, vp, 1); else { if (vsp->valfmt == PM_VAL_INSITU) pmPrintValue(f, vsp->valfmt, PM_TYPE_UNKNOWN, vp, 1); else pmPrintValue(f, vsp->valfmt, (int)vp->value.pval->vtype, vp, 1); } fputc('\n', f); } } pmDebug = saveDebug; } static void print_event_summary(FILE *f, const pmValue *val) { pmEventArray *eap = (pmEventArray *)val->value.pval; char *base; struct timeval stamp; __pmTimeval *tvp; int nrecords; int nmissed = 0; int r; /* records */ int p; /* parameters in a record ... */ pmEventRecord *erp; pmEventParameter *epp; nrecords = eap->ea_nrecords; base = (char *)&eap->ea_record[0]; tvp = (__pmTimeval *)base; stamp.tv_sec = tvp->tv_sec; stamp.tv_usec = tvp->tv_usec; /* walk packed event record array */ for (r = 0; r < eap->ea_nrecords-1; r++) { erp = (pmEventRecord *)base; base += sizeof(erp->er_timestamp) + sizeof(erp->er_flags) + sizeof(erp->er_nparams); if (erp->er_flags & PM_EVENT_FLAG_MISSED) { nmissed += erp->er_nparams; continue; } for (p = 0; p < erp->er_nparams; p++) { epp = (pmEventParameter *)base; base += sizeof(epp->ep_pmid) + PM_PDU_SIZE_BYTES(epp->ep_len); } } fprintf(f, "[%d event record", nrecords); if (nrecords != 1) fputc('s', f); if (nmissed > 0) fprintf(f, " (%d missed)", nmissed); if (nrecords > 0) { fprintf(f, " timestamp"); if (nrecords > 1) fputc('s', f); fputc(' ', f); __pmPrintStamp(f, &stamp); if (eap->ea_nrecords > 1) { fprintf(f, "..."); tvp = (__pmTimeval *)base; stamp.tv_sec = tvp->tv_sec; stamp.tv_usec = tvp->tv_usec; __pmPrintStamp(f, &stamp); } } fputc(']', f); } /* Print single pmValue. */ void pmPrintValue(FILE *f, /* output stream */ int valfmt, /* from pmValueSet */ int type, /* from pmDesc */ const pmValue *val, /* value to print */ int minwidth) /* output is at least this wide */ { pmAtomValue a; int i; int n; char *p; int sts; if (type != PM_TYPE_UNKNOWN && type != PM_TYPE_EVENT) { sts = pmExtractValue(valfmt, val, type, &a, type); if (sts < 0) type = PM_TYPE_UNKNOWN; } switch (type) { case PM_TYPE_32: fprintf(f, "%*i", minwidth, a.l); break; case PM_TYPE_U32: fprintf(f, "%*u", minwidth, a.ul); break; case PM_TYPE_64: fprintf(f, "%*"PRIi64, minwidth, a.ll); break; case PM_TYPE_U64: fprintf(f, "%*"PRIu64, minwidth, a.ull); break; case PM_TYPE_FLOAT: fprintf(f, "%*.8g", minwidth, (double)a.f); break; case PM_TYPE_DOUBLE: fprintf(f, "%*.16g", minwidth, a.d); break; case PM_TYPE_STRING: n = (int)strlen(a.cp) + 2; while (n < minwidth) { fputc(' ', f); n++; } fprintf(f, "\"%s\"", a.cp); free(a.cp); break; case PM_TYPE_AGGREGATE: case PM_TYPE_UNKNOWN: if (valfmt == PM_VAL_INSITU) { float *fp = (float *)&val->value.lval; __uint32_t *ip = (__uint32_t *)&val->value.lval; int fp_bad = 0; fprintf(f, "%*u", minwidth, *ip); #ifdef HAVE_FPCLASSIFY fp_bad = fpclassify(*fp) == FP_NAN; #else #ifdef HAVE_ISNANF fp_bad = isnanf(*fp); #endif #endif if (!fp_bad) fprintf(f, " %*.8g", minwidth, (double)*fp); if (minwidth > 2) minwidth -= 2; fprintf(f, " 0x%*x", minwidth, val->value.lval); } else { int string; int done = 0; if (val->value.pval->vlen == PM_VAL_HDR_SIZE + sizeof(__uint64_t)) { __uint64_t tmp; memcpy((void *)&tmp, (void *)val->value.pval->vbuf, sizeof(tmp)); fprintf(f, "%*"PRIu64, minwidth, tmp); done = 1; } if (val->value.pval->vlen == PM_VAL_HDR_SIZE + sizeof(double)) { double tmp; int fp_bad = 0; memcpy((void *)&tmp, (void *)val->value.pval->vbuf, sizeof(tmp)); #ifdef HAVE_FPCLASSIFY fp_bad = fpclassify(tmp) == FP_NAN; #else #ifdef HAVE_ISNAN fp_bad = isnan(tmp); #endif #endif if (!fp_bad) { if (done) fputc(' ', f); fprintf(f, "%*.16g", minwidth, tmp); done = 1; } } if (val->value.pval->vlen == PM_VAL_HDR_SIZE + sizeof(float)) { float tmp; int fp_bad = 0; memcpy((void *)&tmp, (void *)val->value.pval->vbuf, sizeof(tmp)); #ifdef HAVE_FPCLASSIFY fp_bad = fpclassify(tmp) == FP_NAN; #else #ifdef HAVE_ISNANF fp_bad = isnanf(tmp); #endif #endif if (!fp_bad) { if (done) fputc(' ', f); fprintf(f, "%*.8g", minwidth, (double)tmp); done = 1; } } if (val->value.pval->vlen < PM_VAL_HDR_SIZE) fprintf(f, "pmPrintValue: negative length (%d) for aggregate value?", (int)val->value.pval->vlen - PM_VAL_HDR_SIZE); else { string = 1; for (n = 0; n < val->value.pval->vlen - PM_VAL_HDR_SIZE; n++) { if (!isprint((int)val->value.pval->vbuf[n])) { string = 0; break; } } if (string) { if (done) fputc(' ', f); n = (int)val->value.pval->vlen - PM_VAL_HDR_SIZE + 2; while (n < minwidth) { fputc(' ', f); n++; } n = (int)val->value.pval->vlen - PM_VAL_HDR_SIZE; fprintf(f, "\"%*.*s\"", n, n, val->value.pval->vbuf); done = 1; } n = 2 * (val->value.pval->vlen - PM_VAL_HDR_SIZE) + 2; while (n < minwidth) { fputc(' ', f); n++; } if (done) fputc(' ', f); fputc('[', f); p = &val->value.pval->vbuf[0]; for (i = 0; i < val->value.pval->vlen - PM_VAL_HDR_SIZE; i++) { fprintf(f, "%02x", *p & 0xff); p++; } fputc(']', f); } } if (type != PM_TYPE_UNKNOWN) free(a.vbp); break; case PM_TYPE_EVENT: /* not much we can do about minwidth */ if (valfmt == PM_VAL_INSITU) { /* * Special case for pmlc/pmlogger where PMLC_SET_*() macros * used to set control requests / state in the lval field * and the pval does not really contain a valid event record * Code here comes from PrintState() in actions.c from pmlc. */ fputs("[pmlc control ", f); fputs(PMLC_GET_MAND(val->value.lval) ? "mand " : "adv ", f); fputs(PMLC_GET_ON(val->value.lval) ? "on " : "off ", f); if (PMLC_GET_INLOG(val->value.lval)) fputs(PMLC_GET_AVAIL(val->value.lval) ? " " : "na ", f); else fputs("nl ", f); fprintf(f, "%d]", PMLC_GET_DELTA(val->value.lval)); } else print_event_summary(f, val); break; case PM_TYPE_NOSUPPORT: fprintf(f, "pmPrintValue: bogus value, metric Not Supported\n"); break; default: fprintf(f, "pmPrintValue: unknown value type=%d\n", type); } } void __pmNoMem(const char *where, size_t size, int fatal) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(fatal ? LOG_ERR : LOG_WARNING, "%s: malloc(%d) failed: %s", where, (int)size, osstrerror_r(errmsg, sizeof(errmsg))); if (fatal) exit(1); } /* * this one is used just below the PMAPI to convert platform errors * into more appropriate PMAPI error codes */ int __pmMapErrno(int sts) { if (sts == -EBADF || sts == -EPIPE) sts = PM_ERR_IPC; #ifdef IS_MINGW else if (sts == -EINVAL) sts = PM_ERR_IPC; #endif return sts; } /* * difference for two on the internal timestamps */ double __pmTimevalSub(const __pmTimeval *ap, const __pmTimeval *bp) { return ap->tv_sec - bp->tv_sec + (double)(ap->tv_usec - bp->tv_usec)/1000000.0; } /* * print timeval timestamp in HH:MM:SS.XXX format */ void __pmPrintStamp(FILE *f, const struct timeval *tp) { struct tm tmp; time_t now; now = (time_t)tp->tv_sec; pmLocaltime(&now, &tmp); fprintf(f, "%02d:%02d:%02d.%03d", tmp.tm_hour, tmp.tm_min, tmp.tm_sec, (int)(tp->tv_usec/1000)); } /* * print __pmTimeval timestamp in HH:MM:SS.XXX format * (__pmTimeval variant used in PDUs, archives and internally) */ void __pmPrintTimeval(FILE *f, const __pmTimeval *tp) { struct tm tmp; time_t now; now = (time_t)tp->tv_sec; pmLocaltime(&now, &tmp); fprintf(f, "%02d:%02d:%02d.%03d", tmp.tm_hour, tmp.tm_min, tmp.tm_sec, tp->tv_usec/1000); } /* * descriptor */ void __pmPrintDesc(FILE *f, const pmDesc *desc) { const char *type; const char *sem; static const char *unknownVal = "???"; const char *units; char strbuf[60]; if (desc->type == PM_TYPE_NOSUPPORT) { fprintf(f, " Data Type: Not Supported\n"); return; } switch (desc->type) { case PM_TYPE_32: type = "32-bit int"; break; case PM_TYPE_U32: type = "32-bit unsigned int"; break; case PM_TYPE_64: type = "64-bit int"; break; case PM_TYPE_U64: type = "64-bit unsigned int"; break; case PM_TYPE_FLOAT: type = "float"; break; case PM_TYPE_DOUBLE: type = "double"; break; case PM_TYPE_STRING: type = "string"; break; case PM_TYPE_AGGREGATE: type = "aggregate"; break; case PM_TYPE_AGGREGATE_STATIC: type = "static aggregate"; break; case PM_TYPE_EVENT: type = "event record array"; break; default: type = unknownVal; break; } fprintf(f, " Data Type: %s", type); if (type == unknownVal) fprintf(f, " (%d)", desc->type); fprintf(f," InDom: %s 0x%x\n", pmInDomStr_r(desc->indom, strbuf, sizeof(strbuf)), desc->indom); switch (desc->sem) { case PM_SEM_COUNTER: sem = "counter"; break; case PM_SEM_INSTANT: sem = "instant"; break; case PM_SEM_DISCRETE: sem = "discrete"; break; default: sem = unknownVal; break; } fprintf(f, " Semantics: %s", sem); if (sem == unknownVal) fprintf(f, " (%d)", desc->sem); fprintf(f, " Units: "); units = pmUnitsStr_r(&desc->units, strbuf, sizeof(strbuf)); if (*units == '\0') fprintf(f, "none\n"); else fprintf(f, "%s\n", units); } /* * print times between events */ void __pmEventTrace_r(const char *event, int *first, double *sum, double *last) { #ifdef PCP_DEBUG struct timeval tv; double now; __pmtimevalNow(&tv); now = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0; if (*first) { *first = 0; *sum = 0; *last = now; } *sum += now - *last; fprintf(stderr, "%s: +%4.2f = %4.2f -> %s\n", pmProgname, now-*last, *sum, event); *last = now; #endif } void __pmEventTrace(const char *event) { #ifdef PCP_DEBUG static double last; static double sum; static int first = 1; __pmEventTrace_r(event, &first, &sum, &last); #endif } int __pmParseDebug(const char *spec) { #ifdef PCP_DEBUG int val = 0; int tmp; const char *p; char *pend; int i; for (p = spec; *p; ) { tmp = (int)strtol(p, &pend, 10); if (tmp == -1) /* special case ... -1 really means set all the bits! */ tmp = INT_MAX; if (*pend == '\0') { val |= tmp; break; } else if (*pend == ',') { val |= tmp; p = pend + 1; } else { pend = strchr(p, ','); if (pend != NULL) *pend = '\0'; if (strcasecmp(p, "ALL") == 0) { val |= INT_MAX; if (pend != NULL) { *pend = ','; p = pend + 1; } else p = ""; /* force termination of outer loop */ break; } for (i = 0; i < num_debug; i++) { if (strcasecmp(p, debug_map[i].name) == 0) { val |= debug_map[i].bit; if (pend != NULL) { *pend = ','; p = pend + 1; } else p = ""; /* force termination of outer loop */ break; } } if (i == num_debug) { if (pend != NULL) *pend = ','; return PM_ERR_CONV; } } } return val; #else return PM_ERR_NYI; #endif } int __pmGetInternalState(void) { return pmState; } void __pmSetInternalState(int state) { pmState = state; } /* * GUI output option */ #define MSGBUFLEN 256 static FILE *fptr = NULL; static int msgsize = 0; static char *fname; /* temporary file name for buffering errors */ static char *ferr; /* error output filename from PCP_STDERR */ #define PM_QUERYERR -1 #define PM_USEDIALOG 0 #define PM_USESTDERR 1 #define PM_USEFILE 2 static int pmfstate(int state) { static int errtype = -1; if (state > PM_QUERYERR) errtype = state; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (errtype == PM_QUERYERR) { errtype = PM_USESTDERR; if ((ferr = getenv("PCP_STDERR")) != NULL) { if (strcasecmp(ferr, "DISPLAY") == 0) { char * xconfirm = pmGetConfig("PCP_XCONFIRM_PROG"); if (access(__pmNativePath(xconfirm), X_OK) < 0) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "%s: using stderr - cannot access %s: %s\n", pmProgname, xconfirm, osstrerror_r(errmsg, sizeof(errmsg))); } else errtype = PM_USEDIALOG; } else if (strcmp(ferr, "") != 0) errtype = PM_USEFILE; } } PM_UNLOCK(__pmLock_libpcp); return errtype; } static int vpmprintf(const char *msg, va_list arg) { int lsize = 0; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (fptr == NULL && msgsize == 0) { /* create scratch file */ int fd = -1; char *tmpdir = pmGetConfig("PCP_TMPFILE_DIR"); if (tmpdir[0] != '\0') { mode_t cur_umask; /* * PCP_TMPFILE_DIR found in the configuration/environment, * otherwise fall through to the stderr case */ #if HAVE_MKSTEMP fname = (char *)malloc(MAXPATHLEN+1); if (fname == NULL) goto fail; snprintf(fname, MAXPATHLEN, "%s/pcp-XXXXXX", tmpdir); cur_umask = umask(S_IXUSR | S_IRWXG | S_IRWXO); fd = mkstemp(fname); umask(cur_umask); #else fname = tempnam(tmpdir, "pcp-"); if (fname == NULL) goto fail; cur_umask = umask(S_IXUSR | S_IRWXG | S_IRWXO); fd = open(fname, O_RDWR|O_APPEND|O_CREAT|O_EXCL, 0600); umask(cur_umask); #endif /* HAVE_MKSTEMP */ if (fd < 0) goto fail; if ((fptr = fdopen(fd, "a")) == NULL) { char errmsg[PM_MAXERRMSGLEN]; fail: if (fname != NULL) { fprintf(stderr, "%s: vpmprintf: failed to create \"%s\": %s\n", pmProgname, fname, osstrerror_r(errmsg, sizeof(errmsg))); unlink(fname); free(fname); } else { fprintf(stderr, "%s: vpmprintf: failed to create temporary file: %s\n", pmProgname, osstrerror_r(errmsg, sizeof(errmsg))); } fprintf(stderr, "vpmprintf msg:\n"); if (fd >= 0) close(fd); msgsize = -1; fptr = NULL; } } else msgsize = -1; } if (msgsize < 0) { vfprintf(stderr, msg, arg); fflush(stderr); lsize = 0; } else msgsize += (lsize = vfprintf(fptr, msg, arg)); PM_UNLOCK(__pmLock_libpcp); return lsize; } int pmprintf(const char *msg, ...) { va_list arg; int lsize; va_start(arg, msg); lsize = vpmprintf(msg, arg); va_end(arg); return lsize; } int pmflush(void) { int sts = 0; int len; int state; FILE *eptr = NULL; char outbuf[MSGBUFLEN]; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (fptr != NULL && msgsize > 0) { fflush(fptr); state = pmfstate(PM_QUERYERR); if (state == PM_USEFILE) { if ((eptr = fopen(ferr, "a")) == NULL) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "pmflush: cannot append to file '%s' (from " "$PCP_STDERR): %s\n", ferr, osstrerror_r(errmsg, sizeof(errmsg))); state = PM_USESTDERR; } } switch (state) { case PM_USESTDERR: rewind(fptr); while ((len = (int)read(fileno(fptr), outbuf, MSGBUFLEN)) > 0) { sts = write(fileno(stderr), outbuf, len); if (sts != len) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "pmflush: write() failed: %s\n", osstrerror_r(errmsg, sizeof(errmsg))); } sts = 0; } break; case PM_USEDIALOG: /* If we're here, it means xconfirm has passed access test */ snprintf(outbuf, sizeof(outbuf), "%s -file %s -c -B OK -icon info" " %s -header 'PCP Information' >/dev/null", __pmNativePath(pmGetConfig("PCP_XCONFIRM_PROG")), fname, (msgsize > 80 ? "-useslider" : "")); if (system(outbuf) < 0) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "%s: system failed: %s\n", pmProgname, osstrerror_r(errmsg, sizeof(errmsg))); sts = -oserror(); } break; case PM_USEFILE: rewind(fptr); while ((len = (int)read(fileno(fptr), outbuf, MSGBUFLEN)) > 0) { sts = write(fileno(eptr), outbuf, len); if (sts != len) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "pmflush: write() failed: %s\n", osstrerror_r(errmsg, sizeof(errmsg))); } sts = 0; } fclose(eptr); break; } fclose(fptr); fptr = NULL; unlink(fname); free(fname); if (sts >= 0) sts = msgsize; } msgsize = 0; PM_UNLOCK(__pmLock_libpcp); return sts; } /* * Set the pmcd client identity as exported by pmcd.client.whoami * * Identity is of the form * hostname (ipaddr) * * Assumes you already have a current host context. */ int __pmSetClientId(const char *id) { char *name = "pmcd.client.whoami"; pmID pmid; int sts; pmResult store = { .numpmid = 1 }; pmValueSet pmvs; pmValueBlock *pmvb; char host[MAXHOSTNAMELEN]; char ipaddr[16] = ""; /* IPv4 xxx.xxx.xxx.xxx */ struct hostent *hep = NULL; int vblen; if ((sts = pmLookupName(1, &name, &pmid)) < 0) return sts; (void)gethostname(host, MAXHOSTNAMELEN); PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); hep = gethostbyname(host); if (hep != NULL) { strcpy(host, hep->h_name); if (hep->h_addrtype == AF_INET) { strcpy(ipaddr, inet_ntoa(*((struct in_addr *)hep->h_addr_list[0]))); } vblen = strlen(host) + strlen(ipaddr) + strlen(id) + 5; } else vblen = strlen(host) + strlen(id) + 2; PM_UNLOCK(__pmLock_libpcp); /* build pmResult for pmStore() */ pmvb = (pmValueBlock *)malloc(PM_VAL_HDR_SIZE+vblen); if (pmvb == NULL) { __pmNoMem("__pmSetClientId", PM_VAL_HDR_SIZE+vblen, PM_RECOV_ERR); return -ENOMEM; } pmvb->vtype = PM_TYPE_STRING; pmvb->vlen = PM_VAL_HDR_SIZE+vblen; strcpy(pmvb->vbuf, host); strcat(pmvb->vbuf, " "); if (ipaddr[0] != '\0') { strcat(pmvb->vbuf, "("); strcat(pmvb->vbuf, ipaddr); strcat(pmvb->vbuf, ") "); } strcat(pmvb->vbuf, id); pmvs.pmid = pmid; pmvs.numval = 1; pmvs.valfmt = PM_VAL_SPTR; pmvs.vlist[0].value.pval = pmvb; pmvs.vlist[0].inst = PM_IN_NULL; store.vset[0] = &pmvs; sts = pmStore(&store); free(pmvb); return sts; } char * __pmGetClientId(int argc, char **argv) { char *clientID; int a, need = 0; for (a = 0; a < argc; a++) need += strlen(argv[a]) + 1; clientID = (char *)malloc(need); if (clientID) { clientID[0] = '\0'; for (a = 0; a < argc; a++) { strcat(clientID, argv[a]); if (a < argc - 1) strcat(clientID, " "); } } return clientID; } int __pmSetClientIdArgv(int argc, char **argv) { char *id = __pmGetClientId(argc, argv); int sts; if (id) { sts = __pmSetClientId(id); free(id); return sts; } return -ENOMEM; } /* * Support for C environments that have lame libc implementations. * All of these developed from first principles, so no 3rd party * copyright or licensing issues, else used under a licence that * is compatible with the PCP licence. */ #ifndef HAVE_BASENAME char * basename(char *name) { char *p = strrchr(name, '/'); if (p == NULL) return(name); else return(p+1); } #endif /* HAVE_BASENAME */ #ifndef HAVE_DIRNAME char * dirname(char *name) { char *p = strrchr(name, '/'); if (p == NULL) return("."); else { *p = '\0'; return(name); } } #endif /* HAVE_DIRNAME */ #ifndef HAVE_STRNDUP char * strndup(const char *s, size_t n) { char *buf; if ((buf = malloc(n + 1)) != NULL) { strncpy(buf, s, n); buf[n] = '\0'; } return buf; } #endif /* HAVE_STRNDUP */ #ifndef HAVE_SCANDIR /* * Scan the directory dirname, building an array of pointers to * dirent entries using malloc(3C). select() and compare() are * used to optionally filter and sort directory entries. */ int scandir(const char *dirname, struct dirent ***namelist, int(*select)(const_dirent *), int(*compare)(const_dirent **, const_dirent **)) { DIR *dirp; int n = 0; struct dirent **names = NULL; struct dirent *dp; struct dirent *tp; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if ((dirp = opendir(dirname)) == NULL) return -1; while ((dp = readdir(dirp)) != NULL) { if (select && (*select)(dp) == 0) continue; n++; if ((names = (struct dirent **)realloc(names, n * sizeof(dp))) == NULL) { PM_UNLOCK(__pmLock_libpcp); closedir(dirp); return -1; } if ((names[n-1] = tp = (struct dirent *)malloc( sizeof(*dp)-sizeof(dp->d_name)+strlen(dp->d_name)+1)) == NULL) { PM_UNLOCK(__pmLock_libpcp); closedir(dirp); return -1; } tp->d_ino = dp->d_ino; #if defined(HAVE_DIRENT_D_OFF) tp->d_off = dp->d_off; #else tp->d_reclen = dp->d_reclen; #endif memcpy(tp->d_name, dp->d_name, strlen(dp->d_name)+1); } closedir(dirp); PM_UNLOCK(__pmLock_libpcp); *namelist = names; if (n && compare) qsort(names, n, sizeof(names[0]), (int(*)(const void *, const void *))compare); return n; } /* * Alphabetical sort for default use */ int alphasort(const_dirent **p, const_dirent **q) { return strcmp((*p)->d_name, (*q)->d_name); } #endif /* HAVE_SCANDIR */ #ifndef HAVE_POW /* * For PCP we have not found a platform yet that needs this, but just * in case, this implementation comes from * http://www.netlib.org/fdlibm/e_pow.c * * ==================================================== * Copyright (C) 2003 by Sun Microsystems, Inc. All rights reserved. * * Permission to use, copy, modify, and distribute this * software is freely granted, provided that this notice * is preserved. * ==================================================== */ #ifdef HAVE_ENDIAN_H #include #else #ifdef HAVE_SYS_ENDIAN_H #include #else bozo! #endif #endif #if __BYTE_ORDER == __LITTLE_ENDIAN #define __HI(x) *(1+(int*)&x) #define __LO(x) *(int*)&x #define __HIp(x) *(1+(int*)x) #define __LOp(x) *(int*)x #else #define __HI(x) *(int*)&x #define __LO(x) *(1+(int*)&x) #define __HIp(x) *(int*)x #define __LOp(x) *(1+(int*)x) #endif /* _pow(x,y) return x**y * * n * Method: Let x = 2 * (1+f) * 1. Compute and return log2(x) in two pieces: * log2(x) = w1 + w2, * where w1 has 53-24 = 29 bit trailing zeros. * 2. Perform y*log2(x) = n+y' by simulating muti-precision * arithmetic, where |y'|<=0.5. * 3. Return x**y = 2**n*exp(y'*log2) * * Special cases: * 1. (anything) ** 0 is 1 * 2. (anything) ** 1 is itself * 3. (anything) ** NAN is NAN * 4. NAN ** (anything except 0) is NAN * 5. +-(|x| > 1) ** +INF is +INF * 6. +-(|x| > 1) ** -INF is +0 * 7. +-(|x| < 1) ** +INF is +0 * 8. +-(|x| < 1) ** -INF is +INF * 9. +-1 ** +-INF is NAN * 10. +0 ** (+anything except 0, NAN) is +0 * 11. -0 ** (+anything except 0, NAN, odd integer) is +0 * 12. +0 ** (-anything except 0, NAN) is +INF * 13. -0 ** (-anything except 0, NAN, odd integer) is +INF * 14. -0 ** (odd integer) = -( +0 ** (odd integer) ) * 15. +INF ** (+anything except 0,NAN) is +INF * 16. +INF ** (-anything except 0,NAN) is +0 * 17. -INF ** (anything) = -0 ** (-anything) * 18. (-anything) ** (integer) is (-1)**(integer)*(+anything**integer) * 19. (-anything except 0 and inf) ** (non-integer) is NAN * * Accuracy: * pow(x,y) returns x**y nearly rounded. In particular * pow(integer,integer) * always returns the correct integer provided it is * representable. * * Constants : * The hexadecimal values are the intended ones for the following * constants. The decimal values may be used, provided that the * compiler will convert from decimal to binary accurately enough * to produce the hexadecimal values shown. */ static const double bp[] = {1.0, 1.5,}, dp_h[] = { 0.0, 5.84962487220764160156e-01,}, /* 0x3FE2B803, 0x40000000 */ dp_l[] = { 0.0, 1.35003920212974897128e-08,}, /* 0x3E4CFDEB, 0x43CFD006 */ zero = 0.0, one = 1.0, two = 2.0, two53 = 9007199254740992.0, /* 0x43400000, 0x00000000 */ huge = 1.0e300, tiny = 1.0e-300, /* poly coefs for (3/2)*(log(x)-2s-2/3*s**3 */ L1 = 5.99999999999994648725e-01, /* 0x3FE33333, 0x33333303 */ L2 = 4.28571428578550184252e-01, /* 0x3FDB6DB6, 0xDB6FABFF */ L3 = 3.33333329818377432918e-01, /* 0x3FD55555, 0x518F264D */ L4 = 2.72728123808534006489e-01, /* 0x3FD17460, 0xA91D4101 */ L5 = 2.30660745775561754067e-01, /* 0x3FCD864A, 0x93C9DB65 */ L6 = 2.06975017800338417784e-01, /* 0x3FCA7E28, 0x4A454EEF */ P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */ P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */ P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */ P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */ P5 = 4.13813679705723846039e-08, /* 0x3E663769, 0x72BEA4D0 */ lg2 = 6.93147180559945286227e-01, /* 0x3FE62E42, 0xFEFA39EF */ lg2_h = 6.93147182464599609375e-01, /* 0x3FE62E43, 0x00000000 */ lg2_l = -1.90465429995776804525e-09, /* 0xBE205C61, 0x0CA86C39 */ ovt = 8.0085662595372944372e-0017, /* -(1024-log2(ovfl+.5ulp)) */ cp = 9.61796693925975554329e-01, /* 0x3FEEC709, 0xDC3A03FD =2/(3ln2) */ cp_h = 9.61796700954437255859e-01, /* 0x3FEEC709, 0xE0000000 =(float)cp */ cp_l = -7.02846165095275826516e-09, /* 0xBE3E2FE0, 0x145B01F5 =tail of cp_h*/ ivln2 = 1.44269504088896338700e+00, /* 0x3FF71547, 0x652B82FE =1/ln2 */ ivln2_h = 1.44269502162933349609e+00, /* 0x3FF71547, 0x60000000 =24b 1/ln2*/ ivln2_l = 1.92596299112661746887e-08; /* 0x3E54AE0B, 0xF85DDF44 =1/ln2 tail*/ double pow(double x, double y) { double z,ax,z_h,z_l,p_h,p_l; double y1,t1,t2,r,s,t,u,v,w; int i,j,k,yisint,n; int hx,hy,ix,iy; unsigned lx,ly; hx = __HI(x); lx = __LO(x); hy = __HI(y); ly = __LO(y); ix = hx&0x7fffffff; iy = hy&0x7fffffff; /* y==zero: x**0 = 1 */ if((iy|ly)==0) return one; /* +-NaN return x+y */ if(ix > 0x7ff00000 || ((ix==0x7ff00000)&&(lx!=0)) || iy > 0x7ff00000 || ((iy==0x7ff00000)&&(ly!=0))) return x+y; /* determine if y is an odd int when x < 0 * yisint = 0 ... y is not an integer * yisint = 1 ... y is an odd int * yisint = 2 ... y is an even int */ yisint = 0; if(hx<0) { if(iy>=0x43400000) yisint = 2; /* even integer y */ else if(iy>=0x3ff00000) { k = (iy>>20)-0x3ff; /* exponent */ if(k>20) { j = ly>>(52-k); if((j<<(52-k))==ly) yisint = 2-(j&1); } else if(ly==0) { j = iy>>(20-k); if((j<<(20-k))==iy) yisint = 2-(j&1); } } } /* special value of y */ if(ly==0) { if (iy==0x7ff00000) { /* y is +-inf */ if(((ix-0x3ff00000)|lx)==0) return y - y; /* inf**+-1 is NaN */ else if (ix >= 0x3ff00000)/* (|x|>1)**+-inf = inf,0 */ return (hy>=0)? y: zero; else /* (|x|<1)**-,+inf = inf,0 */ return (hy<0)?-y: zero; } if(iy==0x3ff00000) { /* y is +-1 */ if(hy<0) return one/x; else return x; } if(hy==0x40000000) return x*x; /* y is 2 */ if(hy==0x3fe00000) { /* y is 0.5 */ if(hx>=0) /* x >= +0 */ return sqrt(x); } } ax = fabs(x); /* special value of x */ if(lx==0) { if(ix==0x7ff00000||ix==0||ix==0x3ff00000){ z = ax; /*x is +-0,+-inf,+-1*/ if(hy<0) z = one/z; /* z = (1/|x|) */ if(hx<0) { if(((ix-0x3ff00000)|yisint)==0) { z = (z-z)/(z-z); /* (-1)**non-int is NaN */ } else if(yisint==1) z = -z; /* (x<0)**odd = -(|x|**odd) */ } return z; } } n = (hx>>31)+1; /* (x<0)**(non-int) is NaN */ if((n|yisint)==0) return (x-x)/(x-x); s = one; /* s (sign of result -ve**odd) = -1 else = 1 */ if((n|(yisint-1))==0) s = -one;/* (-ve)**(odd int) */ /* |y| is huge */ if(iy>0x41e00000) { /* if |y| > 2**31 */ if(iy>0x43f00000){ /* if |y| > 2**64, must o/uflow */ if(ix<=0x3fefffff) return (hy<0)? huge*huge:tiny*tiny; if(ix>=0x3ff00000) return (hy>0)? huge*huge:tiny*tiny; } /* over/underflow if x is not close to one */ if(ix<0x3fefffff) return (hy<0)? s*huge*huge:s*tiny*tiny; if(ix>0x3ff00000) return (hy>0)? s*huge*huge:s*tiny*tiny; /* now |1-x| is tiny <= 2**-20, suffice to compute log(x) by x-x^2/2+x^3/3-x^4/4 */ t = ax-one; /* t has 20 trailing zeros */ w = (t*t)*(0.5-t*(0.3333333333333333333333-t*0.25)); u = ivln2_h*t; /* ivln2_h has 21 sig. bits */ v = t*ivln2_l-w*ivln2; t1 = u+v; __LO(t1) = 0; t2 = v-(t1-u); } else { double ss,s2,s_h,s_l,t_h,t_l; n = 0; /* take care subnormal number */ if(ix<0x00100000) {ax *= two53; n -= 53; ix = __HI(ax); } n += ((ix)>>20)-0x3ff; j = ix&0x000fffff; /* determine interval */ ix = j|0x3ff00000; /* normalize ix */ if(j<=0x3988E) k=0; /* |x|>1)|0x20000000)+0x00080000+(k<<18); t_l = ax - (t_h-bp[k]); s_l = v*((u-s_h*t_h)-s_h*t_l); /* compute log(ax) */ s2 = ss*ss; r = s2*s2*(L1+s2*(L2+s2*(L3+s2*(L4+s2*(L5+s2*L6))))); r += s_l*(s_h+ss); s2 = s_h*s_h; t_h = 3.0+s2+r; __LO(t_h) = 0; t_l = r-((t_h-3.0)-s2); /* u+v = ss*(1+...) */ u = s_h*t_h; v = s_l*t_h+t_l*ss; /* 2/(3log2)*(ss+...) */ p_h = u+v; __LO(p_h) = 0; p_l = v-(p_h-u); z_h = cp_h*p_h; /* cp_h+cp_l = 2/(3*log2) */ z_l = cp_l*p_h+p_l*cp+dp_l[k]; /* log2(ax) = (ss+..)*2/(3*log2) = n + dp_h + z_h + z_l */ t = (double)n; t1 = (((z_h+z_l)+dp_h[k])+t); __LO(t1) = 0; t2 = z_l-(((t1-t)-dp_h[k])-z_h); } /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ y1 = y; __LO(y1) = 0; p_l = (y-y1)*t1+y*t2; p_h = y1*t1; z = p_l+p_h; j = __HI(z); i = __LO(z); if (j>=0x40900000) { /* z >= 1024 */ if(((j-0x40900000)|i)!=0) /* if z > 1024 */ return s*huge*huge; /* overflow */ else { if(p_l+ovt>z-p_h) return s*huge*huge; /* overflow */ } } else if((j&0x7fffffff)>=0x4090cc00 ) { /* z <= -1075 */ if(((j-0xc090cc00)|i)!=0) /* z < -1075 */ return s*tiny*tiny; /* underflow */ else { if(p_l<=z-p_h) return s*tiny*tiny; /* underflow */ } } /* * compute 2**(p_h+p_l) */ i = j&0x7fffffff; k = (i>>20)-0x3ff; n = 0; if(i>0x3fe00000) { /* if |z| > 0.5, set n = [z+0.5] */ n = j+(0x00100000>>(k+1)); k = ((n&0x7fffffff)>>20)-0x3ff; /* new k for n */ t = zero; __HI(t) = (n&~(0x000fffff>>k)); n = ((n&0x000fffff)|0x00100000)>>(20-k); if(j<0) n = -n; p_h -= t; } t = p_l+p_h; __LO(t) = 0; u = t*lg2_h; v = (p_l-(t-p_h))*lg2+t*lg2_l; z = u+v; w = v-(z-u); t = z*z; t1 = z - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); r = (z*t1)/(t1-two)-(w+z*w); z = one-(r-z); j = __HI(z); j += (n<<20); if((j>>20)<=0) z = scalbn(z,n); /* subnormal output */ else __HI(z) += (n<<20); return s*z; } #endif /* HAVE_POW */ #define PROCFS_ENTRY_SIZE 40 /* encompass any size of entry for pid */ #if defined(IS_DARWIN) /* No procfs on Mac OS X */ #include int __pmProcessExists(pid_t pid) { struct kinfo_proc kp; size_t len = sizeof(kp); int mib[4]; mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = pid; if (sysctl(mib, 4, &kp, &len, NULL, 0) == -1) return 0; return (len > 0); } #elif defined(HAVE_PROCFS) #define PROCFS "/proc" #define PROCFS_PATH_SIZE (sizeof(PROCFS)+PROCFS_ENTRY_SIZE) int __pmProcessExists(pid_t pid) { char proc_buf[PROCFS_PATH_SIZE]; snprintf(proc_buf, sizeof(proc_buf), "%s/%" FMT_PID, PROCFS, pid); return (access(proc_buf, F_OK) == 0); } #elif !defined(IS_MINGW) !bozo! #endif #if defined(HAVE_KILL) int __pmProcessTerminate(pid_t pid, int force) { return kill(pid, force ? SIGKILL : SIGTERM); } #elif !defined(IS_MINGW) !bozo! #endif #if defined(HAVE_SBRK) int __pmProcessDataSize(unsigned long *size) { static void *base; if (size && base) *size = (sbrk(0) - base) / 1024; else { base = sbrk(0); if (size) *size = 0; } return 0; } #elif !defined(IS_MINGW) #warning "Platform does not define a process datasize interface?" int __pmProcessDataSize(unsigned long *) { return -1; } #endif #if !defined(IS_MINGW) int __pmProcessRunTimes(double *usr, double *sys) { struct tms tms; double ticks = (double)sysconf(_SC_CLK_TCK); if (times(&tms) == (clock_t)-1) { *usr = *sys = 0.0; return -1; } *usr = (double)tms.tms_utime / ticks; *sys = (double)tms.tms_stime / ticks; return 0; } #endif #if !defined(IS_MINGW) pid_t __pmProcessCreate(char **argv, int *infd, int *outfd) { int in[2]; int out[2]; pid_t pid; if (pipe1(in) < 0) return -oserror(); if (pipe1(out) < 0) return -oserror(); pid = fork(); if (pid < 0) { return -1; } else if (pid) { /* parent */ close(in[0]); close(out[1]); *infd = out[0]; *outfd = in[1]; } else { /* child */ char errmsg[PM_MAXERRMSGLEN]; close(in[1]); close(out[0]); if (in[0] != 0) { close(0); dup2(in[0], 0); close(in[0]); } if (out[1] != 1) { close(1); dup2(out[1], 1); close(out[1]); } execvp(argv[0], argv); fprintf(stderr, "execvp: %s\n", osstrerror_r(errmsg, sizeof(errmsg))); exit(1); } return pid; } int __pmSetSignalHandler(int sig, __pmSignalHandler func) { signal(sig, func); return 0; } int __pmSetProgname(const char *program) { char *p; /* Trim command name of leading directory components */ if (program) pmProgname = (char *)program; for (p = pmProgname; pmProgname && *p; p++) { if (*p == '/') pmProgname = p+1; } return 0; } int __pmShutdown(void) { int code = 0, sts; if ((sts = __pmShutdownLocal()) < 0 && !code) code = sts; if ((sts = __pmShutdownCertificates()) < 0 && !code) code = sts; if ((sts = __pmShutdownSecureSockets()) < 0 && !code) code = sts; return code; } void * __pmMemoryMap(int fd, size_t sz, int writable) { int mflags = writable ? (PROT_READ | PROT_WRITE) : PROT_READ; void *addr = mmap(NULL, sz, mflags, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) return NULL; return addr; } void __pmMemoryUnmap(void *addr, size_t sz) { munmap(addr, sz); } #endif pcp-3.8.12ubuntu1/src/libpcp/src/stuffvalue.c0000664000000000000000000000451112272262501015762 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" int __pmStuffValue(const pmAtomValue *avp, pmValue *vp, int type) { void *src; size_t need, body; switch (type) { case PM_TYPE_32: case PM_TYPE_U32: vp->value.lval = avp->ul; return PM_VAL_INSITU; case PM_TYPE_FLOAT: body = sizeof(float); src = (void *)&avp->f; break; case PM_TYPE_64: case PM_TYPE_U64: case PM_TYPE_DOUBLE: body = sizeof(__int64_t); src = (void *)&avp->ull; break; case PM_TYPE_AGGREGATE: /* * vbp field of pmAtomValue points to a dynamically allocated * pmValueBlock ... the vlen and vtype fields MUST have been * already set up. * A new pmValueBlock header will be allocated below, so adjust * the length here (PM_VAL_HDR_SIZE will be added back later). */ body = avp->vbp->vlen - PM_VAL_HDR_SIZE; src = avp->vbp->vbuf; break; case PM_TYPE_STRING: body = strlen(avp->cp) + 1; src = (void *)avp->cp; break; case PM_TYPE_AGGREGATE_STATIC: case PM_TYPE_EVENT: /* * vbp field of pmAtomValue points to a statically allocated * pmValueBlock ... the vlen and vtype fields MUST have been * already set up and are not modified here * * DO NOT make a copy of the value in this case */ vp->value.pval = avp->vbp; return PM_VAL_SPTR; default: return PM_ERR_TYPE; } need = body + PM_VAL_HDR_SIZE; vp->value.pval = (pmValueBlock *)malloc( (need < sizeof(pmValueBlock)) ? sizeof(pmValueBlock) : need); if (vp->value.pval == NULL) return -oserror(); vp->value.pval->vlen = (int)need; vp->value.pval->vtype = type; memcpy((void *)vp->value.pval->vbuf, (void *)src, body); return PM_VAL_DPTR; } pcp-3.8.12ubuntu1/src/libpcp/src/err.c0000664000000000000000000002151112272262501014365 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1995-2001,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "fault.h" #include #ifdef HAVE_SECURE_SOCKETS #include #include #include #include #endif #ifdef IS_MINGW extern const char *strerror_r(int, char *, size_t); #endif /* * if you modify this table at all, be sure to remake qa/006 */ static const struct { int err; char *symb; char *errmess; } errtab[] = { { PM_ERR_GENERIC, "PM_ERR_GENERIC", "Generic error, already reported above" }, { PM_ERR_PMNS, "PM_ERR_PMNS", "Problems parsing PMNS definitions" }, { PM_ERR_NOPMNS, "PM_ERR_NOPMNS", "PMNS not accessible" }, { PM_ERR_DUPPMNS, "PM_ERR_DUPPMNS", "Attempt to reload the PMNS" }, { PM_ERR_TEXT, "PM_ERR_TEXT", "One-line or help text is not available" }, { PM_ERR_APPVERSION, "PM_ERR_APPVERSION", "Metric not supported by this version of monitored application" }, { PM_ERR_VALUE, "PM_ERR_VALUE", "Missing metric value(s)" }, { PM_ERR_TIMEOUT, "PM_ERR_TIMEOUT", "Timeout waiting for a response from PMCD" }, { PM_ERR_NODATA, "PM_ERR_NODATA", "Empty archive log file" }, { PM_ERR_RESET, "PM_ERR_RESET", "PMCD reset or configuration change" }, { PM_ERR_NAME, "PM_ERR_NAME", "Unknown metric name" }, { PM_ERR_PMID, "PM_ERR_PMID", "Unknown or illegal metric identifier" }, { PM_ERR_INDOM, "PM_ERR_INDOM", "Unknown or illegal instance domain identifier" }, { PM_ERR_INST, "PM_ERR_INST", "Unknown or illegal instance identifier" }, { PM_ERR_TYPE, "PM_ERR_TYPE", "Unknown or illegal metric type" }, { PM_ERR_UNIT, "PM_ERR_UNIT", "Illegal pmUnits specification" }, { PM_ERR_CONV, "PM_ERR_CONV", "Impossible value or scale conversion" }, { PM_ERR_TRUNC, "PM_ERR_TRUNC", "Truncation in value conversion" }, { PM_ERR_SIGN, "PM_ERR_SIGN", "Negative value in conversion to unsigned" }, { PM_ERR_PROFILE, "PM_ERR_PROFILE", "Explicit instance identifier(s) required" }, { PM_ERR_IPC, "PM_ERR_IPC", "IPC protocol failure" }, { PM_ERR_EOF, "PM_ERR_EOF", "IPC channel closed" }, { PM_ERR_NOTHOST, "PM_ERR_NOTHOST", "Operation requires context with host source of metrics" }, { PM_ERR_EOL, "PM_ERR_EOL", "End of PCP archive log" }, { PM_ERR_MODE, "PM_ERR_MODE", "Illegal mode specification" }, { PM_ERR_LABEL, "PM_ERR_LABEL", "Illegal label record at start of a PCP archive log file" }, { PM_ERR_LOGREC, "PM_ERR_LOGREC", "Corrupted record in a PCP archive log" }, { PM_ERR_LOGFILE, "PM_ERR_LOGFILE", "Missing PCP archive log file" }, { PM_ERR_NOTARCHIVE, "PM_ERR_NOTARCHIVE", "Operation requires context with archive source of metrics" }, { PM_ERR_NOCONTEXT, "PM_ERR_NOCONTEXT", "Attempt to use an illegal context" }, { PM_ERR_PROFILESPEC, "PM_ERR_PROFILESPEC", "NULL pmInDom with non-NULL instlist" }, { PM_ERR_PMID_LOG, "PM_ERR_PMID_LOG", "Metric not defined in the PCP archive log" }, { PM_ERR_INDOM_LOG, "PM_ERR_INDOM_LOG", "Instance domain identifier not defined in the PCP archive log" }, { PM_ERR_INST_LOG, "PM_ERR_INST_LOG", "Instance identifier not defined in the PCP archive log" }, { PM_ERR_NOPROFILE, "PM_ERR_NOPROFILE", "Missing profile - protocol botch" }, { PM_ERR_NOAGENT, "PM_ERR_NOAGENT", "No PMCD agent for domain of request" }, { PM_ERR_PERMISSION, "PM_ERR_PERMISSION", "No permission to perform requested operation" }, { PM_ERR_CONNLIMIT, "PM_ERR_CONNLIMIT", "PMCD connection limit for this host exceeded" }, { PM_ERR_AGAIN, "PM_ERR_AGAIN", "Try again. Information not currently available" }, { PM_ERR_ISCONN, "PM_ERR_ISCONN", "Already Connected" }, { PM_ERR_NOTCONN, "PM_ERR_NOTCONN", "Not Connected" }, { PM_ERR_NEEDPORT, "PM_ERR_NEEDPORT", "A non-null port name is required" }, { PM_ERR_NONLEAF, "PM_ERR_NONLEAF", "Metric name is not a leaf in PMNS" }, { PM_ERR_PMDANOTREADY, "PM_ERR_PMDANOTREADY", "PMDA is not yet ready to respond to requests" }, { PM_ERR_PMDAREADY, "PM_ERR_PMDAREADY", "PMDA is now responsive to requests" }, { PM_ERR_TOOSMALL, "PM_ERR_TOOSMALL", "Insufficient elements in list" }, { PM_ERR_TOOBIG, "PM_ERR_TOOBIG", "Result size exceeded" }, { PM_ERR_FAULT, "PM_ERR_FAULT", "QA fault injected" }, { PM_ERR_THREAD, "PM_ERR_THREAD", "Operation not supported for multi-threaded applications" }, /* insert new libpcp error codes here */ { PM_ERR_NYI, "PM_ERR_NYI", "Functionality not yet implemented" }, /* do not use values smaller than NYI */ { 0, "", "" } }; #define BADCODE "No such PMAPI error code (%d)" #ifndef IS_MINGW /* * handle non-determinism in the GNU implementation of strerror_r() */ static void strerror_x(int code, char *buf, int buflen) { #ifdef HAVE_STRERROR_R_PTR char *p; p = strerror_r(code, buf, buflen); if (p != buf) strncpy(buf, p, buflen); #else /* * the more normal POSIX and XSI compliant variants always fill buf[] */ strerror_r(code, buf, buflen); #endif } #endif char * pmErrStr_r(int code, char *buf, int buflen) { int i; #ifndef IS_MINGW static int first = 1; static char *unknown = NULL; #else static char unknown[] = "Unknown error"; #endif if (code == 0) { strncpy(buf, "No error", buflen); return buf; } /* * Is the code from a library wrapped by libpcp? (e.g. NSS/SSL/SASL) * By good fortune, these libraries are using error codes that do not * overlap - by design for NSS/SSL/NSPR, and by sheer luck with SASL. */ if (code < PM_ERR_NYI) { #ifdef HAVE_SECURE_SOCKETS #define DECODE_SECURE_SOCKETS_ERROR(c) ((c) - PM_ERR_NYI) /* negative */ #define DECODE_SASL_SPECIFIC_ERROR(c) ((c) < -1000 ? 0 : (c)) int error = DECODE_SECURE_SOCKETS_ERROR(code); if (DECODE_SASL_SPECIFIC_ERROR(error)) snprintf(buf, buflen, "Authentication - %s", sasl_errstring(error, NULL, NULL)); else strncpy(buf, PR_ErrorToString(error, PR_LANGUAGE_EN), buflen); buf[buflen-1] = '\0'; return buf; #endif } #ifndef IS_MINGW if (first) { /* * reference message for an unrecognized error code. * For IRIX, strerror() returns NULL in this case. */ strerror_x(-1, buf, buflen); if (buf[0] != '\0') { /* * For Linux et al, strip the last word, expected to be the * error number as in ... * Unknown error -1 * or * Unknown error 4294967295 */ char *sp = strrchr(buf, ' '); char *p; if (sp != NULL) { sp++; if (*sp == '-') sp++; for (p = sp; *p != '\0'; p++) { if (!isdigit((int)*p)) break; } if (*p == '\0') { PM_FAULT_POINT("libpcp/" __FILE__ ":1", PM_FAULT_ALLOC); *sp = '\0'; if ((unknown = strdup(buf)) != NULL) unknown[sp - buf] = '\0'; } } } first = 0; } if (code < 0 && code > -PM_ERR_BASE) { /* intro(2) / errno(3) errors, maybe */ strerror_x(-code, buf, buflen); if (unknown == NULL) { if (buf[0] != '\0') return buf; } else { /* The intention here is to catch variants of "Unknown * error XXX" - in this case we're going to fail the * stncmp() below, fall through and return a pcp error * message, otherwise return the system error message */ if (strncmp(buf, unknown, strlen(unknown)) != 0) return buf; } } #else /* WIN32 */ if (code > -PM_ERR_BASE || code < -PM_ERR_NYI) { const char *bp; if ((bp = wsastrerror(-code)) != NULL) strncpy(buf, bp, buflen); else { /* No strerror_r in MinGW, so need to lock */ char *tbp; PM_LOCK(__pmLock_libpcp); tbp = strerror(-code); strncpy(buf, tbp, buflen); PM_UNLOCK(__pmLock_libpcp); } if (strncmp(buf, unknown, strlen(unknown)) != 0) return buf; } #endif for (i = 0; errtab[i].err; i++) { if (errtab[i].err == code) { strncpy(buf, errtab[i].errmess, buflen); return buf; } } /* failure */ snprintf(buf, buflen, BADCODE, code); return buf; } char * pmErrStr(int code) { static char errmsg[PM_MAXERRMSGLEN]; pmErrStr_r(code, errmsg, sizeof(errmsg)); return errmsg; } void __pmDumpErrTab(FILE *f) { int i; fprintf(f, " Code Symbolic Name Message\n"); for (i = 0; errtab[i].err; i++) fprintf(f, "%6d %-20s %s\n", errtab[i].err, errtab[i].symb, errtab[i].errmess); } pcp-3.8.12ubuntu1/src/libpcp/src/hash.c0000664000000000000000000001130412272262501014517 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2013 Red Hat, Inc. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include void __pmHashInit(__pmHashCtl *hcp) { memset(hcp, 0, sizeof(*hcp)); } __pmHashNode * __pmHashSearch(unsigned int key, __pmHashCtl *hcp) { __pmHashNode *hp; if (hcp->hsize == 0) return NULL; for (hp = hcp->hash[key % hcp->hsize]; hp != NULL; hp = hp->next) { if (hp->key == key) return hp; } return NULL; } int __pmHashAdd(unsigned int key, void *data, __pmHashCtl *hcp) { __pmHashNode *hp; int k; hcp->nodes++; if (hcp->hsize == 0) { hcp->hsize = 1; /* arbitrary number */ if ((hcp->hash = (__pmHashNode **)calloc(hcp->hsize, sizeof(__pmHashNode *))) == NULL) { hcp->hsize = 0; return -oserror(); } } else if (hcp->nodes / 4 > hcp->hsize) { __pmHashNode *tp; __pmHashNode **old = hcp->hash; int oldsize = hcp->hsize; hcp->hsize *= 2; if (hcp->hsize % 2) hcp->hsize++; if (hcp->hsize % 3) hcp->hsize += 2; if (hcp->hsize % 5) hcp->hsize += 2; if ((hcp->hash = (__pmHashNode **)calloc(hcp->hsize, sizeof(__pmHashNode *))) == NULL) { hcp->hsize = oldsize; hcp->hash = old; return -oserror(); } /* * re-link chains */ while (oldsize) { for (hp = old[--oldsize]; hp != NULL; ) { tp = hp; hp = hp->next; k = tp->key % hcp->hsize; tp->next = hcp->hash[k]; hcp->hash[k] = tp; } } free(old); } if ((hp = (__pmHashNode *)malloc(sizeof(__pmHashNode))) == NULL) return -oserror(); k = key % hcp->hsize; hp->key = key; hp->data = data; hp->next = hcp->hash[k]; hcp->hash[k] = hp; return 1; } int __pmHashDel(unsigned int key, void *data, __pmHashCtl *hcp) { __pmHashNode *hp; __pmHashNode *lhp = NULL; if (hcp->hsize == 0) return 0; for (hp = hcp->hash[key % hcp->hsize]; hp != NULL; hp = hp->next) { if (hp->key == key && hp->data == data) { if (lhp == NULL) hcp->hash[key % hcp->hsize] = hp->next; else lhp->next = hp->next; free(hp); return 1; } lhp = hp; } return 0; } void __pmHashClear(__pmHashCtl *hcp) { if (hcp->hsize != 0) { free(hcp->hash); hcp->hsize = 0; } } /* * Iterate over the entire hash table. For each entry, call *cb, * passing *cdata and the current key/value pair. The function's * return value decides how to continue or abort iteration. The * callback function must not modify the hash table. */ void __pmHashWalkCB(__pmHashWalkCallback cb, void *cdata, const __pmHashCtl *hcp) { int n; for (n = 0; n < hcp->hsize; n++) { __pmHashNode *tp = hcp->hash[n]; __pmHashNode **tpp = & hcp->hash[n]; while (tp != NULL) { __pmHashWalkState state = (*cb)(tp, cdata); switch (state) { case PM_HASH_WALK_DELETE_STOP: *tpp = tp->next; /* unlink */ free(tp); /* delete */ return; /* & stop */ case PM_HASH_WALK_NEXT: tpp = &tp->next; tp = *tpp; break; case PM_HASH_WALK_DELETE_NEXT: *tpp = tp->next; /* unlink */ /* NB: do not change tpp. It will still point at the previous * node's "next" pointer. Consider consecutive CONTINUE_DELETEs. */ free(tp); /* delete */ tp = *tpp; /* == tp->next, except that tp is already freed. */ break; /* & next */ case PM_HASH_WALK_STOP: default: return; } } } } /* * Walk a hash table; state flow is START ... NEXT ... NEXT ... */ __pmHashNode * __pmHashWalk(__pmHashCtl *hcp, __pmHashWalkState state) { __pmHashNode *node; if (hcp->hsize == 0) return NULL; if (state == PM_HASH_WALK_START) { hcp->index = 0; hcp->next = hcp->hash[0]; } while (hcp->next == NULL) { hcp->index++; if (hcp->index >= hcp->hsize) return NULL; hcp->next = hcp->hash[hcp->index]; } node = hcp->next; hcp->next = node->next; return node; } pcp-3.8.12ubuntu1/src/libpcp/src/fetch.c0000664000000000000000000001530012272262501014665 0ustar /* * Copyright (c) 1995-2006,2008 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "internal.h" static int request_fetch(int ctxid, __pmContext *ctxp, int numpmid, pmID pmidlist[]) { int n; if (ctxp->c_sent == 0) { /* * current profile is _not_ already cached at other end of * IPC, so send get current profile */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PROFILE) { fprintf(stderr, "pmFetch: calling __pmSendProfile, context: %d\n", ctxid); __pmDumpProfile(stderr, PM_INDOM_NULL, ctxp->c_instprof); } #endif if ((n = __pmSendProfile(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), ctxid, ctxp->c_instprof)) < 0) return (__pmMapErrno(n)); else ctxp->c_sent = 1; } n = __pmSendFetch(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), ctxid, &ctxp->c_origin, numpmid, pmidlist); if (n < 0) { n = __pmMapErrno(n); } return n; } int __pmPrepareFetch(__pmContext *ctxp, int numpmid, const pmID *ids, pmID **newids) { return __dmprefetch(ctxp, numpmid, ids, newids); } int __pmFinishResult(__pmContext *ctxp, int count, pmResult **resultp) { if (count >= 0) __dmpostfetch(ctxp, resultp); return count; } int pmFetch(int numpmid, pmID pmidlist[], pmResult **result) { int n; if (numpmid < 1) { n = PM_ERR_TOOSMALL; goto done; } if ((n = pmWhichContext()) >= 0) { __pmContext *ctxp = __pmHandleToPtr(n); int newcnt; pmID *newlist = NULL; int have_dm; if (ctxp == NULL) { n = PM_ERR_NOCONTEXT; goto done; } if (ctxp->c_type == PM_CONTEXT_LOCAL && PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) { /* Local context requires single-threaded applications */ n = PM_ERR_THREAD; PM_UNLOCK(ctxp->c_lock); goto done; } /* for derived metrics, may need to rewrite the pmidlist */ have_dm = newcnt = __pmPrepareFetch(ctxp, numpmid, pmidlist, &newlist); if (newcnt > numpmid) { /* replace args passed into pmFetch */ numpmid = newcnt; pmidlist = newlist; } if (ctxp->c_type == PM_CONTEXT_HOST) { /* * Thread-safe note * * Need to be careful here, because the PMCD changed protocol * may mean several PDUs are returned, but __pmDecodeResult() * may request more info from PMCD if pmDebug is set. * * So unlock ctxp->c_pmcd->pc_lock as soon as possible. */ PM_LOCK(ctxp->c_pmcd->pc_lock); if ((n = request_fetch(n, ctxp, numpmid, pmidlist)) >= 0) { int changed = 0; do { __pmPDU *pb; int pinpdu; pinpdu = n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, ctxp->c_pmcd->pc_tout_sec, &pb); if (n == PDU_RESULT) { PM_UNLOCK(ctxp->c_pmcd->pc_lock); n = __pmDecodeResult(pb, result); } else if (n == PDU_ERROR) { __pmDecodeError(pb, &n); if (n > 0) /* PMCD state change protocol */ changed = n; else PM_UNLOCK(ctxp->c_pmcd->pc_lock); } else { PM_UNLOCK(ctxp->c_pmcd->pc_lock); if (n != PM_ERR_TIMEOUT) n = PM_ERR_IPC; } if (pinpdu > 0) __pmUnpinPDUBuf(pb); } while (n > 0); if (n == 0) n |= changed; } else PM_UNLOCK(ctxp->c_pmcd->pc_lock); } else if (ctxp->c_type == PM_CONTEXT_LOCAL) { n = __pmFetchLocal(ctxp, numpmid, pmidlist, result); } else { /* assume PM_CONTEXT_ARCHIVE */ n = __pmLogFetch(ctxp, numpmid, pmidlist, result); if (n >= 0 && (ctxp->c_mode & __PM_MODE_MASK) != PM_MODE_INTERP) { ctxp->c_origin.tv_sec = (__int32_t)(*result)->timestamp.tv_sec; ctxp->c_origin.tv_usec = (__int32_t)(*result)->timestamp.tv_usec; } } /* process derived metrics, if any */ if (have_dm) { __pmFinishResult(ctxp, n, result); if (newlist != NULL) free(newlist); } PM_UNLOCK(ctxp->c_lock); } done: #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_FETCH) { fprintf(stderr, "pmFetch returns ...\n"); if (n > 0) { fprintf(stderr, "PMCD state changes: agent(s)"); if (n & PMCD_ADD_AGENT) fprintf(stderr, " added"); if (n & PMCD_RESTART_AGENT) fprintf(stderr, " restarted"); if (n & PMCD_DROP_AGENT) fprintf(stderr, " dropped"); fputc('\n', stderr); } if (n >= 0) __pmDumpResult(stderr, *result); else { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "Error: %s\n", pmErrStr_r(n, errmsg, sizeof(errmsg))); } } #endif return n; } int pmFetchArchive(pmResult **result) { int n; __pmContext *ctxp; int ctxp_mode; if ((n = pmWhichContext()) >= 0) { ctxp = __pmHandleToPtr(n); if (ctxp == NULL) n = PM_ERR_NOCONTEXT; else { ctxp_mode = (ctxp->c_mode & __PM_MODE_MASK); if (ctxp->c_type != PM_CONTEXT_ARCHIVE) n = PM_ERR_NOTARCHIVE; else if (ctxp_mode == PM_MODE_INTERP) /* makes no sense! */ n = PM_ERR_MODE; else { /* assume PM_CONTEXT_ARCHIVE and BACK or FORW */ n = __pmLogFetch(ctxp, 0, NULL, result); if (n >= 0) { ctxp->c_origin.tv_sec = (__int32_t)(*result)->timestamp.tv_sec; ctxp->c_origin.tv_usec = (__int32_t)(*result)->timestamp.tv_usec; } } PM_UNLOCK(ctxp->c_lock); } } return n; } int pmSetMode(int mode, const struct timeval *when, int delta) { int n; __pmContext *ctxp; int l_mode = (mode & __PM_MODE_MASK); if ((n = pmWhichContext()) >= 0) { ctxp = __pmHandleToPtr(n); if (ctxp == NULL) return PM_ERR_NOCONTEXT; if (ctxp->c_type == PM_CONTEXT_HOST) { if (l_mode != PM_MODE_LIVE) n = PM_ERR_MODE; else { ctxp->c_origin.tv_sec = ctxp->c_origin.tv_usec = 0; ctxp->c_mode = mode; ctxp->c_delta = delta; n = 0; } } else if (ctxp->c_type == PM_CONTEXT_LOCAL) { n = PM_ERR_MODE; } else { /* assume PM_CONTEXT_ARCHIVE */ if (l_mode == PM_MODE_INTERP || l_mode == PM_MODE_FORW || l_mode == PM_MODE_BACK) { if (when != NULL) { /* * special case of NULL for timestamp * => do not update notion of "current" time */ ctxp->c_origin.tv_sec = (__int32_t)when->tv_sec; ctxp->c_origin.tv_usec = (__int32_t)when->tv_usec; } ctxp->c_mode = mode; ctxp->c_delta = delta; __pmLogSetTime(ctxp); __pmLogResetInterp(ctxp); n = 0; } else n = PM_ERR_MODE; } PM_UNLOCK(ctxp->c_lock); } return n; } pcp-3.8.12ubuntu1/src/libpcp/src/exports0000664000000000000000000002057012272262501015064 0ustar PCP_3.0 { global: pmAddProfile; pmAtomStr; pmAtomStr_r; pmConvScale; pmCtime; pmDebug; pmDelProfile; pmDerivedErrStr; pmDestroyContext; pmDupContext; pmErrStr; pmErrStr_r; pmEventFlagsStr; pmEventFlagsStr_r; pmExtractValue; pmFetch; pmFetchArchive; pmflush; pmFreeEventResult; pmFreeMetricSpec; pmFreeResult; pmGetArchiveEnd; pmGetArchiveLabel; pmGetChildren; pmGetChildrenStatus; pmGetConfig; pmGetContextHostName; pmGetInDom; pmGetInDomArchive; pmGetPMNSLocation; pmIDStr; pmIDStr_r; pmInDomStr; pmInDomStr_r; pmLoadASCIINameSpace; pmLoadDerivedConfig; pmLoadNameSpace; pmLocaltime; pmLookupDesc; pmLookupInDom; pmLookupInDomArchive; pmLookupInDomText; pmLookupName; pmLookupText; pmNameAll; pmNameID; pmNameInDom; pmNameInDomArchive; pmNewContext; pmNewContextZone; pmNewZone; pmNumberStr; pmNumberStr_r; pmParseInterval; pmParseMetricSpec; pmParseTimeWindow; pmprintf; pmPrintValue; pmProgname; pmReconnectContext; pmRegisterDerived; pmSetMode; pmSortInstances; pmStore; pmTraversePMNS; pmTraversePMNS_r; pmTrimNameSpace; pmTypeStr; pmTypeStr_r; pmUnitsStr; pmUnitsStr_r; pmUnloadNameSpace; pmUnpackEventRecords; pmUseContext; pmUseZone; pmWhichContext; pmWhichZone; __pmAbsolutePath; __pmAccAddAccount; __pmAccAddClient; __pmAccAddGroup; __pmAccAddHost; __pmAccAddOp; __pmAccAddUser; __pmAccDelAccount; __pmAccDelClient; __pmAccDumpGroups; __pmAccDumpHosts; __pmAccDumpLists; __pmAccDumpUsers; __pmAccept; __pmAccFreeSavedGroups; __pmAccFreeSavedHosts; __pmAccFreeSavedLists; __pmAccFreeSavedUsers; __pmAccRestoreGroups; __pmAccRestoreHosts; __pmAccRestoreLists; __pmAccRestoreUsers; __pmAccSaveGroups; __pmAccSaveHosts; __pmAccSaveLists; __pmAccSaveUsers; __pmAddHostPorts; __pmAddPMNSNode; __pmAFblock; __pmAFisempty; __pmAFregister; __pmAFunblock; __pmAFunregister; __pmAPIConfig; __pmAttrKeyStr_r; __pmAttrStr_r; __pmAuxConnectPMCD; __pmAuxConnectPMCDPort; __pmAuxConnectPMCDUnixSocket; __pmBind; __pmCheckEventRecords; __pmCheckSum; __pmCloseSocket; __pmConfig; __pmConnect; __pmConnectGetPorts; __pmConnectLocal; __pmConnectLogger; __pmConnectPMCD; __pmConnectTo; __pmControlLog; __pmConvertTime; __pmCountPDUBuf; __pmCreateIPv6Socket; __pmCreateSocket; __pmCreateUnixSocket; __pmDataIPC; __pmDataIPCSize; __pmDecodeAuth; __pmDecodeChildReq; __pmDecodeCreds; __pmDecodeDesc; __pmDecodeDescReq; __pmDecodeError; __pmDecodeFetch; __pmDecodeIDList; __pmDecodeInstance; __pmDecodeInstanceReq; __pmDecodeLogControl; __pmDecodeLogRequest; __pmDecodeLogStatus; __pmDecodeNameList; __pmDecodeProfile; __pmDecodeResult; __pmDecodeText; __pmDecodeTextReq; __pmDecodeTraversePMNSReq; __pmDecodeXtendError; __pmDropHostPort; __pmDumpContext; __pmDumpErrTab; __pmDumpEventRecords; __pmDumpIDList; __pmDumpInResult; __pmDumpNameAndStatusList; __pmDumpNameList; __pmDumpNameSpace; __pmDumpProfile; __pmDumpResult; __pmDumpStatusList; __pmEncodeResult; __pmEventTrace; __pmEventTrace_r; __pmExportPMNS; __pmFaultInject; __pmFaultSummary; __pmFD; __pmFD_CLR; __pmFD_COPY; __pmFD_ISSET; __pmFD_SET; __pmFD_ZERO; __pmFindPDUBuf; __pmFindPMDA; __pmFindProfile; __pmFinishResult; __pmFixPMNSHashTab; __pmFreeAttrsSpec; __pmFreeHostAttrsSpec; __pmFreeHostSpec; __pmFreeInResult; __pmFreePMNS; __pmFreeProfile; __pmFreeResultValues; __pmGetAddrInfo; __pmGetAPIConfig; __pmGetArchiveEnd; __pmGetClientId; __pmGetInternalState; __pmGetNameInfo; __pmGetPDU; __pmGetPDUCeiling; __pmGetSockOpt; __pmGetUsername; __pmHandleToPtr; __pmHashAdd; __pmHashClear; __pmHashDel; __pmHashInit; __pmHashSearch; __pmHashWalk; __pmHashWalkCB; __pmHasPMNSFileChanged; __pmHostEntAlloc; __pmHostEntFree; __pmHostEntGetName; __pmHostEntGetSockAddr; __pmInitLocks; __pmInProfile; __pmIsLocalhost; __pmLastVersionIPC; __pmListen; __pmLocalPMDA; __pmLock; __pmLock_libpcp; __pmLogCacheClear; __pmLogChangeVol; __pmLogChkLabel; __pmLogClose; __pmLogCreate; __pmLogFetch; __pmLogFetchInterp; __pmLogFindLocalPorts; __pmLogFindPort; __pmLoggerTimeout; __pmLogGetInDom; __pmLogLoadIndex; __pmLogLoadLabel; __pmLogLoadMeta; __pmLogLookupDesc; __pmLogLookupInDom; __pmLogName; __pmLogNameInDom; __pmLogName_r; __pmLogNewFile; __pmLogOpen; __pmLogPutDesc; __pmLogPutIndex; __pmLogPutInDom; __pmLogPutResult; __pmLogRead; __pmLogReads; __pmLogResetInterp; __pmLogSetTime; __pmLogWriteLabel; __pmLookupAttrKey; __pmLookupDSO; __pmLoopBackAddress; __pmMapErrno; __pmMemoryMap; __pmMemoryUnmap; __pmMktime; __pmMultiThreaded; __pmNativeConfig; __pmNativePath; __pmNewPMNS; __pmNoMem; __pmNotifyErr; __pmOpenLog; __pmOptFetchAdd; __pmOptFetchDel; __pmOptFetchDump; __pmOptFetchGetParams; __pmOptFetchPutParams; __pmOptFetchRedo; __pmOverrideLastFd; __pmParseCtime; __pmParseDebug; __pmParseHostAttrsSpec; __pmParseHostSpec; __pmParseTime; __pmPathSeparator; __pmPDUCntIn; __pmPDUCntOut; __pmPDUTypeStr; __pmPDUTypeStr_r; __pmPinPDUBuf; __pmPrepareFetch; __pmPrintDesc; __pmPrintIPC; __pmPrintStamp; __pmPrintTimeval; __pmProcessCreate; __pmProcessDataSize; __pmProcessExists; __pmProcessRunTimes; __pmProcessTerminate; __pmRead; __pmRecv; __pmRegisterAnon; __pmResetIPC; __pmRotateLog; __pmSecureClientHandshake; __pmSecureServerHandshake; __pmSecureServerSetup; __pmSecureServerShutdown; __pmSelectRead; __pmSelectWrite; __pmSend; __pmSendAuth; __pmSendChildReq; __pmSendCreds; __pmSendDesc; __pmSendDescReq; __pmSendError; __pmSendFetch; __pmSendIDList; __pmSendInstance; __pmSendInstanceReq; __pmSendLogControl; __pmSendLogRequest; __pmSendLogStatus; __pmSendNameList; __pmSendProfile; __pmSendResult; __pmSendText; __pmSendTextReq; __pmSendTraversePMNSReq; __pmSendXtendError; __pmServerAddInterface; __pmServerAddNewClients; __pmServerAddPorts; __pmServerAdvertisePresence; __pmServerClearFeature; __pmServerCloseRequestPorts; __pmServerDumpRequestPorts; __pmServerHasFeature; __pmServerOpenRequestPorts; __pmServerRequestPortString; __pmServerSetFeature; __pmServerSetLocalCreds; __pmServerSetLocalSocket; __pmServerSetServiceSpec; __pmServerUnadvertisePresence; __pmSetClientId; __pmSetClientIdArgv; __pmSetDataIPC; __pmSetInternalState; __pmSetPDUCeiling; __pmSetPDUCntBuf; __pmSetProcessIdentity; __pmSetProgname; __pmSetSignalHandler; __pmSetSocketIPC; __pmSetSockOpt; __pmSetVersionIPC; __pmShutdown; __pmSockAddrAlloc; __pmSockAddrCompare; __pmSockAddrDup; __pmSockAddrFree; __pmSockAddrGetFamily; __pmSockAddrGetPort; __pmSockAddrInit; __pmSockAddrIsInet; __pmSockAddrIsIPv6; __pmSockAddrIsLoopBack; __pmSockAddrIsUnix; __pmSockAddrMask; __pmSockAddrSetFamily; __pmSockAddrSetPath; __pmSockAddrSetPort; __pmSockAddrSetScope; __pmSockAddrSize; __pmSockAddrToString; __pmSocketIPC; __pmSpecLocalPMDA; __pmStringToSockAddr; __pmStuffValue; __pmSyslog; __pmtimevalAdd; __pmtimevalFromReal; __pmtimevalNow; __pmtimevalPause; __pmtimevalSleep; __pmtimevalSub; __pmTimevalSub; __pmtimevalToReal; __pmTimezone; __pmTimezone_r; __pmUnlock; __pmUnparseHostAttrsSpec; __pmUnparseHostSpec; __pmUnpinPDUBuf; __pmUsePMNS; __pmVersionIPC; __pmWrite; __pmXmitPDU; local: *; }; PCP_3.1 { global: pmDiscoverServices; } PCP_3.0; pcp-3.8.12ubuntu1/src/libpcp/src/p_profile.c0000664000000000000000000001416212272262501015560 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "internal.h" #define LIMIT_CTXNUM 2048 /* * PDU used to transmit __pmProfile prior to pmFetch (PDU_PROFILE) */ typedef struct { pmInDom indom; int state; /* include/exclude */ int numinst; /* no. of instances to follow */ int pad; /* protocol backward compatibility */ } instprof_t; typedef struct { __pmPDUHdr hdr; int ctxnum; int g_state; /* global include/exclude */ int numprof; /* no. of elts to follow */ int pad; /* protocol backward compatibility */ } profile_t; int __pmSendProfile(int fd, int from, int ctxnum, __pmProfile *instprof) { __pmInDomProfile *prof, *p_end; profile_t *pduProfile; instprof_t *pduInstProf; __pmPDU *p; size_t need; __pmPDU *pdubuf; int sts; /* work out how much space we need and then alloc a pdu buf */ need = sizeof(profile_t) + instprof->profile_len * sizeof(instprof_t); for (prof = instprof->profile, p_end = prof + instprof->profile_len; prof < p_end; prof++) need += prof->instances_len * sizeof(int); if ((pdubuf = __pmFindPDUBuf((int)need)) == NULL) return -oserror(); p = (__pmPDU *)pdubuf; /* First the profile itself */ pduProfile = (profile_t *)p; pduProfile->hdr.len = (int)need; pduProfile->hdr.type = PDU_PROFILE; /* * note: context id may be sent twice due to protocol evolution and * backwards compatibility issues */ pduProfile->hdr.from = from; pduProfile->ctxnum = htonl(ctxnum); pduProfile->g_state = htonl(instprof->state); pduProfile->numprof = htonl(instprof->profile_len); pduProfile->pad = 0; p += sizeof(profile_t) / sizeof(__pmPDU); if (instprof->profile_len) { /* Next all the profile entries (if any) in one block */ for (prof = instprof->profile, p_end = prof + instprof->profile_len; prof < p_end; prof++) { pduInstProf = (instprof_t *)p; pduInstProf->indom = __htonpmInDom(prof->indom); pduInstProf->state = htonl(prof->state); pduInstProf->numinst = htonl(prof->instances_len); pduInstProf->pad = 0; p += sizeof(instprof_t) / sizeof(__pmPDU); } /* and then all the instances */ for (prof = instprof->profile, p_end = prof+instprof->profile_len; prof < p_end; prof++) { int j; /* and then the instances themselves (if any) */ for (j = 0; j < prof->instances_len; j++, p++) *p = htonl(prof->instances[j]); } } sts = __pmXmitPDU(fd, pdubuf); __pmUnpinPDUBuf(pdubuf); return sts; } int __pmDecodeProfile(__pmPDU *pdubuf, int *ctxnump, __pmProfile **resultp) { __pmProfile *instprof; __pmInDomProfile *prof, *p_end; profile_t *pduProfile; instprof_t *pduInstProf; __pmPDU *p = (__pmPDU *)pdubuf; char *pdu_end; int ctxnum; int sts = 0; /* First the profile */ pduProfile = (profile_t *)pdubuf; pdu_end = (char*)pdubuf + pduProfile->hdr.len; if (pdu_end - (char*)pdubuf < sizeof(profile_t)) return PM_ERR_IPC; ctxnum = ntohl(pduProfile->ctxnum); if (ctxnum < 0 || ctxnum > LIMIT_CTXNUM) return PM_ERR_IPC; if ((instprof = (__pmProfile *)malloc(sizeof(__pmProfile))) == NULL) return -oserror(); instprof->state = ntohl(pduProfile->g_state); instprof->profile = NULL; instprof->profile_len = ntohl(pduProfile->numprof); if (instprof->profile_len < 0) { sts = PM_ERR_IPC; goto fail; } p += sizeof(profile_t) / sizeof(__pmPDU); if (instprof->profile_len > 0) { if (instprof->profile_len >= INT_MAX / sizeof(__pmInDomProfile) || instprof->profile_len >= pduProfile->hdr.len) { sts = PM_ERR_IPC; goto fail; } if ((instprof->profile = (__pmInDomProfile *)calloc( instprof->profile_len, sizeof(__pmInDomProfile))) == NULL) { sts = -oserror(); goto fail; } /* Next the profiles (if any) all together */ for (prof = instprof->profile, p_end = prof + instprof->profile_len; prof < p_end; prof++) { if ((char *)p >= pdu_end) { sts = PM_ERR_IPC; goto fail; } pduInstProf = (instprof_t *)p; prof->indom = __ntohpmInDom(pduInstProf->indom); prof->state = ntohl(pduInstProf->state); prof->instances = NULL; prof->instances_len = ntohl(pduInstProf->numinst); p += sizeof(instprof_t) / sizeof(__pmPDU); } /* Finally, all the instances for all profiles (if any) together */ for (prof = instprof->profile, p_end = prof+instprof->profile_len; prof < p_end; prof++) { int j; if (prof->instances_len > 0) { if (prof->instances_len >= INT_MAX / sizeof(int) || prof->instances_len >= pduProfile->hdr.len) { sts = PM_ERR_IPC; goto fail; } prof->instances = (int *)calloc(prof->instances_len, sizeof(int)); if (prof->instances == NULL) { sts = -oserror(); goto fail; } for (j = 0; j < prof->instances_len; j++, p++) { if ((char *)p >= pdu_end) { sts = PM_ERR_IPC; goto fail; } prof->instances[j] = ntohl(*p); } } else if (prof->instances_len < 0) { sts = PM_ERR_IPC; goto fail; } else { prof->instances = NULL; } } } else { instprof->profile = NULL; } *resultp = instprof; *ctxnump = ctxnum; return 0; fail: if (instprof != NULL) { if (instprof->profile != NULL) { for (prof = instprof->profile, p_end = prof+instprof->profile_len; prof < p_end; prof++) { if (prof->instances != NULL) free(prof->instances); } free(instprof->profile); } free(instprof); } return sts; } pcp-3.8.12ubuntu1/src/libpcp/src/p_error.c0000664000000000000000000001070712272262501015252 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "internal.h" #include /* * Old V1 error codes are only used in 2 places now: * 1) embedded in pmResults of V1 archives, and * 2) as part of the client/pmcd connection challenge where all versions * if pmcd return the status as a V1 error code as a legacy of * migration from V1 to V2 protocols that we're stuck with (not * really an issue, as the error code is normally 0) * * These macros were removed from the more public pmapi.h and impl.h * headers in PCP 3.6 */ #define PM_ERR_BASE1 1000 #define PM_ERR_V1(e) (e)+PM_ERR_BASE2-PM_ERR_BASE1 #define XLATE_ERR_1TO2(e) \ ((e) <= -PM_ERR_BASE1 ? (e)+PM_ERR_BASE1-PM_ERR_BASE2 : (e)) #define XLATE_ERR_2TO1(e) \ ((e) <= -PM_ERR_BASE2 ? PM_ERR_V1(e) : (e)) /* * PDU for general error reporting (PDU_ERROR) */ typedef struct { __pmPDUHdr hdr; int code; /* error code */ } p_error_t; /* * and the extended variant, with a second datum word */ typedef struct { __pmPDUHdr hdr; int code; /* error code */ int datum; /* additional information */ } x_error_t; int __pmSendError(int fd, int from, int code) { p_error_t *pp; int sts; if ((pp = (p_error_t *)__pmFindPDUBuf(sizeof(p_error_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(p_error_t); pp->hdr.type = PDU_ERROR; pp->hdr.from = from; pp->code = code; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmSendError: sending error PDU (code=%d, toversion=%d)\n", pp->code, __pmVersionIPC(fd)); #endif pp->code = htonl(pp->code); sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmSendXtendError(int fd, int from, int code, int datum) { x_error_t *pp; int sts; if ((pp = (x_error_t *)__pmFindPDUBuf(sizeof(x_error_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(x_error_t); pp->hdr.type = PDU_ERROR; pp->hdr.from = from; /* * It is ALWAYS a PCP 1.x error code here ... this was required * to support migration from the V1 to V2 protocols when a V2 pmcd * (who is the sole user of this routine) supported connections * from both V1 and V2 PMAPI clients ... for the same reason we * cannot retire this translation, even when the V1 protocols are * no longer supported in all other IPC cases. * * For most common cases, code is 0 so it makes no difference. */ pp->code = htonl(XLATE_ERR_2TO1(code)); pp->datum = datum; /* NOTE: caller must swab this */ sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmDecodeError(__pmPDU *pdubuf, int *code) { p_error_t *pp; int sts; pp = (p_error_t *)pdubuf; if (pp->hdr.len != sizeof(p_error_t) && pp->hdr.len != sizeof(x_error_t)) { sts = *code = PM_ERR_IPC; } else { *code = ntohl(pp->code); sts = 0; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmDecodeError: got error PDU (code=%d, fromversion=%d)\n", *code, __pmLastVersionIPC()); #endif return sts; } int __pmDecodeXtendError(__pmPDU *pdubuf, int *code, int *datum) { x_error_t *pp = (x_error_t *)pdubuf; int sts; if (pp->hdr.len != sizeof(p_error_t) && pp->hdr.len != sizeof(x_error_t)) { *code = PM_ERR_IPC; } else { /* * It is ALWAYS a PCP 1.x error code here ... see note above * in __pmSendXtendError() */ *code = XLATE_ERR_1TO2((int)ntohl(pp->code)); } if (pp->hdr.len == sizeof(x_error_t)) { /* really version 2 extended error PDU */ sts = PDU_VERSION2; *datum = pp->datum; /* NOTE: caller must swab this */ } else { sts = PM_ERR_IPC; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmDecodeXtendError: " "got error PDU (code=%d, datum=%d, version=%d)\n", *code, *datum, sts); #endif return sts; } pcp-3.8.12ubuntu1/src/libpcp/src/p_auth.c0000664000000000000000000000532212272262501015057 0ustar /* * Copyright (c) 2013 Red Hat. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "internal.h" #include /* * PDU for per-user authentication (PDU_AUTH) */ typedef struct { __pmPDUHdr hdr; int attr; /* PCP_ATTR code (optional, can be zero) */ char value[sizeof(int)]; } auth_t; int __pmSendAuth(int fd, int from, int attr, const char *value, int length) { size_t need; auth_t *pp; int i; int sts; if (length < 0 || length >= LIMIT_AUTH_PDU) return PM_ERR_IPC; need = (sizeof(*pp) - sizeof(pp->value)) + length; if ((pp = (auth_t *)__pmFindPDUBuf((int)need)) == NULL) return -oserror(); pp->hdr.len = (int)need; pp->hdr.type = PDU_AUTH; pp->hdr.from = from; pp->attr = htonl(attr); memcpy(&pp->value, value, length); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char buffer[LIMIT_AUTH_PDU]; for (i = 0; i < length; i++) buffer[i] = isprint(value[i]) ? value[i] : '.'; buffer[length] = buffer[LIMIT_AUTH_PDU-1] = '\0'; if (attr) fprintf(stderr, "__pmSendAuth [len=%d]: attr=%x value=\"%s\"\n", length, attr, buffer); else fprintf(stderr, "__pmSendAuth [len=%d]: payload=\"%s\"\n", length, buffer); } #endif sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmDecodeAuth(__pmPDU *pdubuf, int *attr, char **value, int *vlen) { auth_t *pp; int i; int pdulen; int length; pp = (auth_t *)pdubuf; pdulen = pp->hdr.len; /* ntohl() converted already in __pmGetPDU() */ length = pdulen - (sizeof(*pp) - sizeof(pp->value)); if (length < 0 || length >= LIMIT_AUTH_PDU) return PM_ERR_IPC; *attr = ntohl(pp->attr); *value = length ? pp->value : NULL; *vlen = length; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char buffer[LIMIT_AUTH_PDU]; for (i = 0; i < length; i++) buffer[i] = isprint(pp->value[i]) ? pp->value[i] : '.'; buffer[length] = buffer[LIMIT_AUTH_PDU-1] = '\0'; if (*attr) fprintf(stderr, "__pmDecodeAuth [len=%d]: attr=%x value=\"%s\"\n", length, *attr, buffer); else fprintf(stderr, "__pmDecodeAuth [len=%d]: payload=\"%s\"\n", length, buffer); } #endif return 0; } pcp-3.8.12ubuntu1/src/libpcp/src/connect.c0000664000000000000000000003242712272262501015236 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2002,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe notes * * Do not need ctxp->c_pmcd->pc_lock lock around __pmSendCreds() call, * as the context has not been created, so no-one else could be using * the context's fd. */ #include "pmapi.h" #include "impl.h" #include "internal.h" /* MY_BUFLEN needs to big enough to hold "hostname port" */ #define MY_BUFLEN (MAXHOSTNAMELEN+10) #define MY_VERSION "pmproxy-client 1\n" static int negotiate_proxy(int fd, const char *hostname, int port) { char buf[MY_BUFLEN]; char *bp; int ok = 0; /* * version negotiation (converse to pmproxy logic) * __pmSend my client version message * __pmRecv server version message * __pmSend hostname and port */ if (__pmSend(fd, MY_VERSION, strlen(MY_VERSION), 0) != strlen(MY_VERSION)) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: send version string to pmproxy failed: %s\n", pmErrStr_r(-neterror(), errmsg, sizeof(errmsg))); return PM_ERR_IPC; } for (bp = buf; bp < &buf[MY_BUFLEN]; bp++) { if (__pmRecv(fd, bp, 1, 0) != 1) { *bp = '\0'; bp = &buf[MY_BUFLEN]; break; } if (*bp == '\n' || *bp == '\r') { *bp = '\0'; break; } } if (bp < &buf[MY_BUFLEN]) { if (strcmp(buf, "pmproxy-server 1") == 0) ok = 1; } if (!ok) { __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: bad version string from pmproxy: \"%s\"\n", buf); return PM_ERR_IPC; } snprintf(buf, sizeof(buf), "%s %d\n", hostname, port); if (__pmSend(fd, buf, strlen(buf), 0) != strlen(buf)) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: send hostname+port string to pmproxy failed: %s'\n", pmErrStr_r(-neterror(), errmsg, sizeof(errmsg))); return PM_ERR_IPC; } return ok; } /* * client connects to pmcd handshake */ static int __pmConnectHandshake(int fd, const char *hostname, int ctxflags, __pmHashCtl *attrs) { __pmPDU *pb; int ok; int version; int challenge; int sts; int pinpdu; /* Expect an error PDU back from PMCD: ACK/NACK for connection */ pinpdu = sts = __pmGetPDU(fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb); if (sts == PDU_ERROR) { /* * See comments in pmcd ... we actually get an extended error PDU * from pmcd, of the form * * :----------:-----------: * | status | challenge | * :----------:-----------: * * For a good connection, status is 0, else a PCP error code; * challenge contains server-side info (e.g. enabled features) */ version = __pmDecodeXtendError(pb, &sts, &challenge); if (version < 0) { __pmUnpinPDUBuf(pb); return version; } if (sts < 0) { __pmUnpinPDUBuf(pb); return sts; } if (version == PDU_VERSION2) { __pmPDUInfo pduinfo; __pmVersionCred handshake; int pduflags = 0; pduinfo = __ntohpmPDUInfo(*(__pmPDUInfo *)&challenge); if (pduinfo.features & PDU_FLAG_CREDS_REQD) /* * This is a mandatory connection feature - pmcd must be * sent user credential information one way or another - * i.e. via SASL2 authentication, or AF_UNIX peer creds. */ pduflags |= PDU_FLAG_CREDS_REQD; if (ctxflags) { /* * If an optional connection feature (e.g. encryption) is * desired, the pmcd that we're talking to must advertise * support for the feature. And if it did, the client in * turn must request it be enabled (now, via pduflags). */ if (ctxflags & (PM_CTXFLAG_SECURE|PM_CTXFLAG_RELAXED)) { if (pduinfo.features & PDU_FLAG_SECURE) { pduflags |= PDU_FLAG_SECURE; } else if (ctxflags & PM_CTXFLAG_SECURE) { __pmUnpinPDUBuf(pb); return -EOPNOTSUPP; } } if (ctxflags & PM_CTXFLAG_COMPRESS) { if (pduinfo.features & PDU_FLAG_COMPRESS) pduflags |= PDU_FLAG_COMPRESS; else { __pmUnpinPDUBuf(pb); return -EOPNOTSUPP; } } if (ctxflags & PM_CTXFLAG_AUTH) { if (pduinfo.features & PDU_FLAG_AUTH) pduflags |= PDU_FLAG_AUTH; else { __pmUnpinPDUBuf(pb); return -EOPNOTSUPP; } } } /* * Negotiate connection version and features (via creds PDU) */ if ((ok = __pmSetVersionIPC(fd, version)) < 0) { __pmUnpinPDUBuf(pb); return ok; } memset(&handshake, 0, sizeof(handshake)); handshake.c_type = CVERSION; handshake.c_version = PDU_VERSION; handshake.c_flags = pduflags; sts = __pmSendCreds(fd, (int)getpid(), 1, (__pmCred *)&handshake); /* * At this point we know caller wants to set channel options and * pmcd supports them so go ahead and update the socket now (this * completes the SSL handshake in encrypting mode, authentication * via SASL, and/or enabling compression in NSS). */ if (sts >= 0 && pduflags) sts = __pmSecureClientHandshake(fd, pduflags, hostname, attrs); } else sts = PM_ERR_IPC; } else if (sts != PM_ERR_TIMEOUT) sts = PM_ERR_IPC; if (pinpdu > 0) __pmUnpinPDUBuf(pb); return sts; } static int global_nports; static int *global_portlist; static int default_portlist[] = { SERVER_PORT }; static void load_pmcd_ports(void) { static int first_time = 1; if (first_time) { char *envstr; char *endptr; first_time = 0; if ((envstr = getenv("PMCD_PORT")) != NULL) { char *p = envstr; for ( ; ; ) { int size, port = (int)strtol(p, &endptr, 0); if ((*endptr != '\0' && *endptr != ',') || port < 0) { __pmNotifyErr(LOG_WARNING, "ignored bad PMCD_PORT = '%s'", p); } else { size = ++global_nports * sizeof(int); global_portlist = (int *)realloc(global_portlist, size); if (global_portlist == NULL) { __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: portlist alloc failed (%d bytes), using default PMCD_PORT (%d)\n", size, SERVER_PORT); global_nports = 0; break; } global_portlist[global_nports-1] = port; } if (*endptr == '\0') break; p = &endptr[1]; } } if (global_nports == 0) { global_portlist = default_portlist; global_nports = sizeof(default_portlist) / sizeof(default_portlist[0]); } } } static void load_proxy_hostspec(pmHostSpec *proxy) { static int proxy_port; char errmsg[PM_MAXERRMSGLEN]; char *envstr; char *endptr; if ((envstr = getenv("PMPROXY_HOST")) != NULL) { proxy->name = strdup(envstr); if (proxy->name == NULL) { __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: cannot save PMPROXY_HOST: %s\n", pmErrStr_r(-oserror(), errmsg, sizeof(errmsg))); } else { if ((envstr = getenv("PMPROXY_PORT")) != NULL) { proxy_port = (int)strtol(envstr, &endptr, 0); if (*endptr != '\0' || proxy_port < 0) { __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: ignored bad PMPROXY_PORT = '%s'\n", envstr); proxy_port = PROXY_PORT; } } else { proxy_port = PROXY_PORT; } proxy->ports = &proxy_port; proxy->nports = 1; } } } static void load_secure_runtime(void) { /* Ensure correct security lib initialisation order */ __pmInitAuthClients(); __pmInitSecureSockets(); /* * If secure sockets functionality available, iterate over the set of * known locations for certificate databases and attempt to initialise * one of them for our use. */ if (__pmInitCertificates() < 0) __pmNotifyErr(LOG_WARNING, "__pmConnectPMCD: " "certificate database exists, but failed initialization"); } void __pmConnectGetPorts(pmHostSpec *host) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); load_pmcd_ports(); if (__pmAddHostPorts(host, global_portlist, global_nports) < 0) { __pmNotifyErr(LOG_WARNING, "__pmConnectGetPorts: portlist dup failed, " "using default PMCD_PORT (%d)\n", SERVER_PORT); host->ports[0] = SERVER_PORT; host->nports = 1; } PM_UNLOCK(__pmLock_libpcp); } int __pmConnectPMCD(pmHostSpec *hosts, int nhosts, int ctxflags, __pmHashCtl *attrs) { int sts = -1; int fd = -1; /* Fd for socket connection to pmcd */ int *ports; int nports; int portIx; int version = -1; int proxyport; pmHostSpec *proxyhost; static int first_time = 1; static pmHostSpec proxy; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (first_time) { /* * One-trip check for use of pmproxy(1) in lieu of pmcd(1), * and to extract the optional environment variables ... * PMCD_PORT, PMPROXY_HOST and PMPROXY_PORT. * We also check for the presense of a certificate database * and load it up if either a user or system (global) DB is * found. */ first_time = 0; load_pmcd_ports(); load_proxy_hostspec(&proxy); load_secure_runtime(); } if (hosts[0].nports == 0) { nports = global_nports; ports = global_portlist; } else { nports = hosts[0].nports; ports = hosts[0].ports; } if (proxy.name == NULL && nhosts == 1) { const char *name = (const char *)hosts[0].name; /* * no proxy, connecting directly to pmcd */ PM_UNLOCK(__pmLock_libpcp); sts = -1; /* Try connecting via the local unix domain socket, if requested and supported. */ if (nports == PM_HOST_SPEC_NPORTS_LOCAL || nports == PM_HOST_SPEC_NPORTS_UNIX) { #if defined(HAVE_STRUCT_SOCKADDR_UN) if ((fd = __pmAuxConnectPMCDUnixSocket(name)) >= 0) { if ((sts = __pmConnectHandshake(fd, name, ctxflags, attrs)) < 0) { __pmCloseSocket(fd); } else sts = fd; portIx = -1; /* no port */ } #endif /* * If the connection failed, or is not supported, and the protocol was 'local:', * then try connecting to localhost via the default port(s). */ if (sts < 0) { if (nports == PM_HOST_SPEC_NPORTS_LOCAL) { name = "localhost"; nports = global_nports; ports = global_portlist; sts = -1; /* keep trying */ } else sts = -2; /* no more connection attempts. */ } } /* If still not connected, try via the given host name and ports, if requested. */ if (sts == -1) { for (portIx = 0; portIx < nports; portIx++) { if ((fd = __pmAuxConnectPMCDPort(name, ports[portIx])) >= 0) { if ((sts = __pmConnectHandshake(fd, name, ctxflags, attrs)) < 0) { __pmCloseSocket(fd); } else /* success */ break; } else sts = fd; } } if (sts < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection port=", hosts[0].name); for (portIx = 0; portIx < nports; portIx++) { if (portIx == 0) fprintf(stderr, "%d", ports[portIx]); else fprintf(stderr, ",%d", ports[portIx]); } fprintf(stderr, " failed: %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } #endif return sts; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { if (portIx >= 0) { fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection port=%d fd=%d PDU version=%u\n", hosts[0].name, ports[portIx], fd, __pmVersionIPC(fd)); } else { fprintf(stderr, "__pmConnectPMCD(%s): pmcd connection path=%s fd=%d PDU version=%u\n", hosts[0].name, name, fd, __pmVersionIPC(fd)); } __pmPrintIPC(); } #endif return fd; } /* * connecting to pmproxy, and then to pmcd ... not a direct * connection to pmcd */ proxyhost = (nhosts > 1) ? &hosts[1] : &proxy; proxyport = (proxyhost->nports > 0) ? proxyhost->ports[0] : PROXY_PORT; for (portIx = 0; portIx < nports; portIx++) { fd = __pmAuxConnectPMCDPort(proxyhost->name, proxyport); if (fd < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmConnectPMCD(%s): proxy to %s port=%d failed: %s \n", hosts[0].name, proxyhost->name, proxyport, pmErrStr_r(-neterror(), errmsg, sizeof(errmsg))); } #endif PM_UNLOCK(__pmLock_libpcp); return fd; } if ((sts = version = negotiate_proxy(fd, hosts[0].name, ports[portIx])) < 0) __pmCloseSocket(fd); else if ((sts = __pmConnectHandshake(fd, proxyhost->name, ctxflags, attrs)) < 0) __pmCloseSocket(fd); else /* success */ break; } if (sts < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmConnectPMCD(%s): proxy connection to %s port=", hosts[0].name, proxyhost->name); for (portIx = 0; portIx < nports; portIx++) { if (portIx == 0) fprintf(stderr, "%d", ports[portIx]); else fprintf(stderr, ",%d", ports[portIx]); } fprintf(stderr, " failed: %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } #endif PM_UNLOCK(__pmLock_libpcp); return sts; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { fprintf(stderr, "__pmConnectPMCD(%s): proxy connection host=%s port=%d fd=%d version=%d\n", hosts[0].name, proxyhost->name, ports[portIx], fd, version); } #endif PM_UNLOCK(__pmLock_libpcp); return fd; } pcp-3.8.12ubuntu1/src/libpcp/src/p_text.c0000664000000000000000000000777612272262501015121 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "internal.h" /* * PDU for pmLookupText request (PDU_TEXT_REQ) */ typedef struct { __pmPDUHdr hdr; int ident; int type; /* one line or help, PMID or InDom */ } text_req_t; int __pmSendTextReq(int fd, int from, int ident, int type) { text_req_t *pp; int sts; if ((pp = (text_req_t *)__pmFindPDUBuf(sizeof(text_req_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(text_req_t); pp->hdr.type = PDU_TEXT_REQ; pp->hdr.from = from; if (type & PM_TEXT_PMID) pp->ident = __htonpmID((pmID)ident); else if (type & PM_TEXT_INDOM) pp->ident = __htonpmInDom((pmInDom)ident); else pp->ident = __htonpmInDom((pmInDom)ident); pp->type = htonl(type); sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmDecodeTextReq(__pmPDU *pdubuf, int *ident, int *type) { text_req_t *pp; char *pduend; pp = (text_req_t *)pdubuf; pduend = (char *)pdubuf + pp->hdr.len; if (pduend - (char*)pp < sizeof(text_req_t)) return PM_ERR_IPC; *type = ntohl(pp->type); if ((*type) & PM_TEXT_PMID) *ident = __ntohpmID(pp->ident); else if ((*type) & PM_TEXT_INDOM) *ident = __ntohpmInDom(pp->ident); else *ident = PM_INDOM_NULL; return 0; } /* * PDU for pmLookupText result (PDU_TEXT) */ typedef struct { __pmPDUHdr hdr; int ident; int buflen; /* no. of chars following */ char buffer[sizeof(int)]; /* desired text */ } text_t; int __pmSendText(int fd, int ctx, int ident, const char *buffer) { text_t *pp; size_t need; int sts; need = sizeof(text_t) - sizeof(pp->buffer) + PM_PDU_SIZE_BYTES(strlen(buffer)); if ((pp = (text_t *)__pmFindPDUBuf((int)need)) == NULL) return -oserror(); pp->hdr.len = (int)need; pp->hdr.type = PDU_TEXT; pp->hdr.from = ctx; /* * Note: ident argument must already be in network byte order. * The caller has to do this because the type of ident is not * part of the transmitted PDU_TEXT pdu; ident may be either * a pmID or pmInDom, and so the caller must use either * __htonpmID or __htonpmInDom (respectfully). */ pp->ident = ident; pp->buflen = (int)strlen(buffer); memcpy((void *)pp->buffer, (void *)buffer, pp->buflen); pp->buflen = htonl(pp->buflen); sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmDecodeText(__pmPDU *pdubuf, int *ident, char **buffer) { text_t *pp; char *pduend; int buflen; pp = (text_t *)pdubuf; pduend = (char *)pdubuf + pp->hdr.len; if (pduend - (char*)pp < sizeof(text_t) - sizeof(int)) return PM_ERR_IPC; /* * Note: ident argument is returned in network byte order. * The caller has to convert it to host byte order because * the type of ident is not part of the transmitted PDU_TEXT * pdu (ident may be either a pmID or a pmInDom. The caller * must use either __ntohpmID() or __ntohpmInDom(), respectfully. */ *ident = pp->ident; buflen = ntohl(pp->buflen); if (buflen < 0 || buflen >= INT_MAX - 1 || buflen > pp->hdr.len) return PM_ERR_IPC; if (pduend - (char *)pp < sizeof(text_t) - sizeof(pp->buffer) + buflen) return PM_ERR_IPC; if ((*buffer = (char *)malloc(buflen+1)) == NULL) return -oserror(); strncpy(*buffer, pp->buffer, buflen); (*buffer)[buflen] = '\0'; return 0; } pcp-3.8.12ubuntu1/src/libpcp/src/fetchlocal.c0000664000000000000000000001161512272262501015705 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "internal.h" /* * Called with valid context locked ... */ int __pmFetchLocal(__pmContext *ctxp, int numpmid, pmID pmidlist[], pmResult **result) { int sts; int ctx; int j; int k; int n; pmResult *ans; pmResult *tmp_ans; __pmDSO *dp; int need; static pmID * splitlist=NULL; static int splitmax=0; if (PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) /* Local context requires single-threaded applications */ return PM_ERR_THREAD; if (numpmid < 1) return PM_ERR_TOOSMALL; ctx = __pmPtrToHandle(ctxp); /* * this is very ugly ... the DSOs have a high-water mark * allocation algorithm for the result skeleton, but the * code that calls us assumes it has freedom to retain * this result structure for as long as it wishes, and * then to call pmFreeResult * * we make another skeleton, selectively copy and return that * * (numpmid - 1) because there's room for one valueSet * in a pmResult */ need = (int)sizeof(pmResult) + (numpmid - 1) * (int)sizeof(pmValueSet *); if ((ans = (pmResult *)malloc(need)) == NULL) return -oserror(); /* * Check if we have enough space to accomodate "best" case scenario - * all pmids are from the same domain */ if (splitmax < numpmid) { splitmax = numpmid; pmID *tmp_list = (pmID *)realloc(splitlist, sizeof(pmID)*splitmax); if (tmp_list == NULL) { free(splitlist); splitmax = 0; free(ans); return -oserror(); } splitlist = tmp_list; } ans->numpmid = numpmid; __pmtimevalNow(&ans->timestamp); for (j = 0; j < numpmid; j++) ans->vset[j] = NULL; for (j = 0; j < numpmid; j++) { int cnt; if (ans->vset[j] != NULL) /* picked up in a previous fetch */ continue; sts = 0; if ((dp = __pmLookupDSO(((__pmID_int *)&pmidlist[j])->domain)) == NULL) /* based on domain, unknown PMDA */ sts = PM_ERR_NOAGENT; else { if (ctxp->c_sent != dp->domain) { /* * current profile is _not_ already cached at other end of * IPC, so send get current profile ... * Note: trickier than the non-local case, as no per-PMDA * caching at the PMCD end, so need to remember the * last domain to receive a profile */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_FETCH) fprintf(stderr, "__pmFetchLocal: calling ???_profile(domain: %d), " "context: %d\n", dp->domain, ctx); #endif if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; sts = dp->dispatch.version.any.profile(ctxp->c_instprof, dp->dispatch.version.any.ext); if (sts >= 0) ctxp->c_sent = dp->domain; } } /* Copy all pmID for the current domain into the temp. list */ for (cnt=0, k=j; k < numpmid; k++ ) { if (((__pmID_int*)(pmidlist+k))->domain == ((__pmID_int*)(pmidlist+j))->domain) splitlist[cnt++] = pmidlist[k]; } if (sts >= 0) { if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; sts = dp->dispatch.version.any.fetch(cnt, splitlist, &tmp_ans, dp->dispatch.version.any.ext); } /* Copy results back * * Note: We DO NOT have to free tmp_ans since DSO PMDA would * ALWAYS return a pointer to the static area. */ for (n = 0, k = j; k < numpmid && n < cnt; k++) { if (pmidlist[k] == splitlist[n]) { if (sts < 0) { ans->vset[k] = (pmValueSet *)malloc(sizeof(pmValueSet)); if (ans->vset[k] == NULL) { /* cleanup all partial allocations for ans->vset[] */ for (k--; k >=0; k--) free(ans->vset[k]); free(ans); return -oserror(); } ans->vset[k]->numval = sts; ans->vset[k]->pmid = pmidlist[k]; } else { ans->vset[k] = tmp_ans->vset[n]; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_FETCH) { char strbuf[20]; char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmFetchLocal: [%d] PMID=%s nval=", k, pmIDStr_r(pmidlist[k], strbuf, sizeof(strbuf))); if (ans->vset[k]->numval < 0) fprintf(stderr, "%s\n", pmErrStr_r(ans->vset[k]->numval, errmsg, sizeof(errmsg))); else fprintf(stderr, "%d\n", ans->vset[k]->numval); } #endif n++; } } } *result = ans; return 0; } pcp-3.8.12ubuntu1/src/libpcp/src/p_desc.c0000664000000000000000000000540212272262501015033 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "internal.h" /* * PDU for pmLookupDesc request (PDU_DESC_REQ) */ typedef struct { __pmPDUHdr hdr; pmID pmid; } desc_req_t; int __pmSendDescReq(int fd, int from, pmID pmid) { desc_req_t *pp; int sts; if ((pp = (desc_req_t *)__pmFindPDUBuf(sizeof(desc_req_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(desc_req_t); pp->hdr.type = PDU_DESC_REQ; pp->hdr.from = from; pp->pmid = __htonpmID(pmid); #ifdef DESPERATE { char strbuf[20]; fprintf(stderr, "__pmSendDescReq: converted 0x%08x (%s) to 0x%08x\n", pmid, pmIDStr_r(pmid, strbuf, sizeof(strbuf)), pp->pmid); } #endif sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmDecodeDescReq(__pmPDU *pdubuf, pmID *pmid) { desc_req_t *pp; char *pduend; pp = (desc_req_t *)pdubuf; pduend = (char *)pdubuf + pp->hdr.len; if (pduend - (char*)pp != sizeof(desc_req_t)) return PM_ERR_IPC; *pmid = __ntohpmID(pp->pmid); return 0; } /* * PDU for pmLookupDesc result (PDU_DESC) */ typedef struct { __pmPDUHdr hdr; pmDesc desc; } desc_t; int __pmSendDesc(int fd, int ctx, pmDesc *desc) { desc_t *pp; int sts; if ((pp = (desc_t *)__pmFindPDUBuf(sizeof(desc_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(desc_t); pp->hdr.type = PDU_DESC; pp->hdr.from = ctx; pp->desc.type = htonl(desc->type); pp->desc.sem = htonl(desc->sem); pp->desc.indom = __htonpmInDom(desc->indom); pp->desc.units = __htonpmUnits(desc->units); pp->desc.pmid = __htonpmID(desc->pmid); sts =__pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmDecodeDesc(__pmPDU *pdubuf, pmDesc *desc) { desc_t *pp; char *pduend; pp = (desc_t *)pdubuf; pduend = (char *)pdubuf + pp->hdr.len; if (pduend - (char*)pp != sizeof(desc_t)) return PM_ERR_IPC; desc->type = ntohl(pp->desc.type); desc->sem = ntohl(pp->desc.sem); desc->indom = __ntohpmInDom(pp->desc.indom); desc->units = __ntohpmUnits(pp->desc.units); desc->pmid = __ntohpmID(pp->desc.pmid); return 0; } pcp-3.8.12ubuntu1/src/libpcp/src/p_pmns.c0000664000000000000000000003537012272262501015101 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include "pmapi.h" #include "impl.h" #include "internal.h" /* * PDU for id list (PDU_PMNS_IDS) */ typedef struct { __pmPDUHdr hdr; int sts; /* to encode status of pmns op */ int numids; pmID idlist[1]; } idlist_t; #ifdef PCP_DEBUG void __pmDumpIDList(FILE *f, int numids, const pmID idlist[]) { int i; char strbuf[20]; fprintf(f, "IDlist dump: numids = %d\n", numids); for (i = 0; i < numids; i++) fprintf(f, " PMID[%d]: 0x%08x %s\n", i, idlist[i], pmIDStr_r(idlist[i], strbuf, sizeof(strbuf))); } #endif /* * Send a PDU_PMNS_IDS across socket. */ int __pmSendIDList(int fd, int from, int numids, const pmID idlist[], int sts) { idlist_t *ip; int need; int j; int lsts; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "__pmSendIDList\n"); __pmDumpIDList(stderr, numids, idlist); } #endif need = (int)(sizeof(idlist_t) + (numids-1) * sizeof(idlist[0])); if ((ip = (idlist_t *)__pmFindPDUBuf(need)) == NULL) return -oserror(); ip->hdr.len = need; ip->hdr.type = PDU_PMNS_IDS; ip->hdr.from = from; ip->sts = htonl(sts); ip->numids = htonl(numids); for (j = 0; j < numids; j++) { ip->idlist[j] = __htonpmID(idlist[j]); } lsts = __pmXmitPDU(fd, (__pmPDU *)ip); __pmUnpinPDUBuf(ip); return lsts; } /* * Decode a PDU_PMNS_IDS * Assumes that we have preallocated idlist prior to this call * (i.e. we know how many should definitely be coming over) * Returns 0 on success. */ int __pmDecodeIDList(__pmPDU *pdubuf, int numids, pmID idlist[], int *sts) { idlist_t *idlist_pdu; char *pdu_end; int nids; int j; idlist_pdu = (idlist_t *)pdubuf; pdu_end = (char *)pdubuf + idlist_pdu->hdr.len; if (pdu_end - (char *)pdubuf < sizeof(idlist_t) - sizeof(pmID)) return PM_ERR_IPC; *sts = ntohl(idlist_pdu->sts); nids = ntohl(idlist_pdu->numids); if (nids <= 0 || nids != numids || nids > idlist_pdu->hdr.len) return PM_ERR_IPC; if (nids >= (INT_MAX - sizeof(idlist_t)) / sizeof(pmID)) return PM_ERR_IPC; if (sizeof(idlist_t) + (sizeof(pmID) * (nids-1)) > (size_t)(pdu_end - (char *)pdubuf)) return PM_ERR_IPC; for (j = 0; j < numids; j++) idlist[j] = __ntohpmID(idlist_pdu->idlist[j]); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "__pmDecodeIDList\n"); __pmDumpIDList(stderr, numids, idlist); } #endif return 0; } /*********************************************************************/ /* * PDU for name list (PDU_PMNS_NAMES) */ typedef struct { int namelen; char name[sizeof(__pmPDU)]; /* variable length */ } name_t; typedef struct { int status; int namelen; char name[sizeof(__pmPDU)]; /* variable length */ } name_status_t; typedef struct { __pmPDUHdr hdr; int nstrbytes; /* number of str bytes including null terminators */ int numstatus; /* = 0 if there is no status to be encoded */ int numnames; __pmPDU names[1]; /* list of variable length name_t or name_status_t */ } namelist_t; /* * NOTES: * * 1. * name_t's are padded to a __pmPDU boundary (if needed) * so that direct accesses of a following record * can be made on a word boundary. * i.e. the following "namelen" field will be accessible. * * 2. * Names are sent length prefixed as opposed to null terminated. * This can make copying at the decoding end simpler * (and possibly more efficient using memcpy). * * 3. * nstrbytes is used by the decoding function to know how many * bytes to allocate. * * 4. * name_status_t was added for pmGetChildrenStatus. * It is a variant of the names pdu which encompasses status * data as well. */ #ifdef PCP_DEBUG void __pmDumpNameList(FILE *f, int numnames, char *namelist[]) { int i; fprintf(f, "namelist dump: numnames = %d\n", numnames); for (i = 0; i < numnames; i++) fprintf(f, " name[%d]: \"%s\"\n", i, namelist[i]); } void __pmDumpStatusList(FILE *f, int numstatus, const int statuslist[]) { int i; fprintf(f, "statuslist dump: numstatus = %d\n", numstatus); for (i = 0; i < numstatus; i++) fprintf(f, " status[%d]: %d\n", i, statuslist[i]); } void __pmDumpNameAndStatusList(FILE *f, int numnames, char *namelist[], int statuslist[]) { int i; fprintf(f, "namelist & statuslist dump: numnames = %d\n", numnames); for (i = 0; i < numnames; i++) fprintf(f, " name[%d]: \"%s\" (%s)\n", i, namelist[i], statuslist[i] == PMNS_LEAF_STATUS ? "leaf" : "non-leaf"); } #endif /* * Send a PDU_PMNS_NAMES across socket. */ int __pmSendNameList(int fd, int from, int numnames, char *namelist[], const int statuslist[]) { namelist_t *nlistp; int need; int nstrbytes=0; int i; name_t *nt; name_status_t *nst; int sts; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "__pmSendNameList\n"); __pmDumpNameList(stderr, numnames, namelist); if (statuslist != NULL) __pmDumpStatusList(stderr, numnames, statuslist); } #endif /* namelist_t + names rounded up to a __pmPDU boundary */ need = sizeof(*nlistp) - sizeof(nlistp->names); for (i = 0; i < numnames; i++) { int len = (int)strlen(namelist[i]); nstrbytes += len+1; need += PM_PDU_SIZE_BYTES(len); if (statuslist == NULL) need += sizeof(*nt) - sizeof(nt->name); else need += sizeof(*nst) - sizeof(nst->name); } if ((nlistp = (namelist_t *)__pmFindPDUBuf(need)) == NULL) return -oserror(); nlistp->hdr.len = need; nlistp->hdr.type = PDU_PMNS_NAMES; nlistp->hdr.from = from; nlistp->nstrbytes = htonl(nstrbytes); nlistp->numnames = htonl(numnames); if (statuslist == NULL) { int i, j = 0, namelen; nlistp->numstatus = htonl(0); for(i=0; inames[j/sizeof(__pmPDU)]; namelen = (int)strlen(namelist[i]); memcpy(nt->name, namelist[i], namelen); #ifdef PCP_DEBUG if ((namelen % sizeof(__pmPDU)) != 0) { /* for Purify */ int pad; char *padp = nt->name + namelen; for (pad = sizeof(__pmPDU) - 1; pad >= (namelen % sizeof(__pmPDU)); pad--) *padp++ = '~'; /* buffer end */ } #endif j += sizeof(namelen) + PM_PDU_SIZE_BYTES(namelen); nt->namelen = htonl(namelen); } } else { /* include the status fields */ int i, j = 0, namelen; nlistp->numstatus = htonl(numnames); for(i=0; inames[j/sizeof(__pmPDU)]; nst->status = htonl(statuslist[i]); namelen = (int)strlen(namelist[i]); memcpy(nst->name, namelist[i], namelen); #ifdef PCP_DEBUG if ((namelen % sizeof(__pmPDU)) != 0) { /* for Purify */ int pad; char *padp = nst->name + namelen; for (pad = sizeof(__pmPDU) - 1; pad >= (namelen % sizeof(__pmPDU)); pad--) *padp++ = '~'; /* buffer end */ } #endif j += sizeof(nst->status) + sizeof(namelen) + PM_PDU_SIZE_BYTES(namelen); nst->namelen = htonl(namelen); } } sts = __pmXmitPDU(fd, (__pmPDU *)nlistp); __pmUnpinPDUBuf(nlistp); return sts; } /* * Decode a PDU_PMNS_NAMES * * statuslist is optional ... if NULL, no status values will be returned */ int __pmDecodeNameList(__pmPDU *pdubuf, int *numnamesp, char*** namelist, int** statuslist) { namelist_t *namelist_pdu; char *pdu_end; char **names; char *dest, *dest_end; int *status = NULL; int namesize, numnames; int statussize, numstatus; int nstrbytes; int namelen; int i, j; namelist_pdu = (namelist_t *)pdubuf; pdu_end = (char *)pdubuf + namelist_pdu->hdr.len; *namelist = NULL; if (statuslist != NULL) *statuslist = NULL; if (pdu_end - (char*)namelist_pdu < sizeof(namelist_t) - sizeof(__pmPDU)) return PM_ERR_IPC; numnames = ntohl(namelist_pdu->numnames); numstatus = ntohl(namelist_pdu->numstatus); nstrbytes = ntohl(namelist_pdu->nstrbytes); if (numnames == 0) { *numnamesp = 0; return 0; } /* validity checks - none of these conditions should happen */ if (numnames < 0 || nstrbytes < 0) return PM_ERR_IPC; /* anti-DOS measure - limiting allowable memory allocations */ if (numnames > namelist_pdu->hdr.len || nstrbytes > namelist_pdu->hdr.len) return PM_ERR_IPC; /* numstatus must be one (and only one) of zero or numnames */ if (numstatus != 0 && numstatus != numnames) return PM_ERR_IPC; /* need space for name ptrs and the name characters */ if (numnames >= (INT_MAX - nstrbytes) / (int)sizeof(char *)) return PM_ERR_IPC; namesize = numnames * ((int)sizeof(char*)) + nstrbytes; if ((names = (char**)malloc(namesize)) == NULL) return -oserror(); /* need space for status values */ if (statuslist != NULL && numstatus > 0) { if (numstatus >= INT_MAX / (int)sizeof(int)) goto corrupt; statussize = numstatus * (int)sizeof(int); if ((status = (int*)malloc(statussize)) == NULL) { free(names); return -oserror(); } } dest = (char*)&names[numnames]; dest_end = (char*)names + namesize; /* copy over ptrs and characters */ if (numstatus == 0) { name_t *np; for (i = j = 0; i < numnames; i++) { np = (name_t*)&namelist_pdu->names[j/sizeof(__pmPDU)]; names[i] = dest; if (sizeof(name_t) > (size_t)(pdu_end - (char *)np)) goto corrupt; namelen = ntohl(np->namelen); /* ensure source buffer contains everything that we copy over */ if (sizeof(np->namelen) + namelen > (size_t)(pdu_end - (char *)np)) goto corrupt; /* ensure space in destination; note null-terminator is added */ if (namelen < 0 || (namelen + 1) > (dest_end - dest)) goto corrupt; memcpy(dest, np->name, namelen); *(dest + namelen) = '\0'; dest += namelen + 1; j += sizeof(namelen) + PM_PDU_SIZE_BYTES(namelen); } } else { /* status fields included in the PDU */ name_status_t *np; for (i = j = 0; i < numnames; i++) { np = (name_status_t*)&namelist_pdu->names[j/sizeof(__pmPDU)]; names[i] = dest; if (sizeof(name_status_t) > (size_t)(pdu_end - (char *)np)) goto corrupt; namelen = ntohl(np->namelen); /* ensure source buffer contains everything that we copy over */ if (sizeof(np->namelen) + sizeof(np->status) + namelen > (size_t)(pdu_end - (char *)np)) goto corrupt; /* ensure space for null-terminated name in destination buffer */ if (namelen < 0 || (namelen + 1) > (dest_end - dest)) goto corrupt; if (status != NULL) status[i] = ntohl(np->status); memcpy(dest, np->name, namelen); *(dest + namelen) = '\0'; dest += namelen + 1; j += sizeof(np->status) + sizeof(namelen) + PM_PDU_SIZE_BYTES(namelen); } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "__pmDecodeNameList\n"); __pmDumpNameList(stderr, numnames, names); if (status != NULL) __pmDumpStatusList(stderr, numstatus, status); } #endif *namelist = names; if (statuslist != NULL) *statuslist = status; *numnamesp = numnames; return numnames; corrupt: if (status != NULL) free(status); free(names); return PM_ERR_IPC; } /*********************************************************************/ /* * name request */ typedef struct { __pmPDUHdr hdr; int subtype; int namelen; char name[sizeof(int)]; } namereq_t; /* * Send a PDU_PMNS_CHILD_REQ across socket. */ static int SendNameReq(int fd, int from, const char *name, int pdu_type, int subtype) { namereq_t *nreq; int need; int namelen; int alloc_len; /* length allocated for name */ int sts; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { char strbuf[20]; fprintf(stderr, "SendNameReq: from=%d name=\"%s\" pdu=%s subtype=%d\n", from, name, __pmPDUTypeStr_r(pdu_type, strbuf, sizeof(strbuf)), subtype); } #endif namelen = (int)strlen(name); alloc_len = (int)(sizeof(int)*((namelen-1 + sizeof(int))/sizeof(int))); need = (int)(sizeof(*nreq) - sizeof(nreq->name) + alloc_len); if ((nreq = (namereq_t *)__pmFindPDUBuf(need)) == NULL) return -oserror(); nreq->hdr.len = need; nreq->hdr.type = pdu_type; nreq->hdr.from = from; nreq->subtype = htonl(subtype); nreq->namelen = htonl(namelen); memcpy(&nreq->name[0], name, namelen); sts = __pmXmitPDU(fd, (__pmPDU *)nreq); __pmUnpinPDUBuf(nreq); return sts; } /* * Decode a name request */ static int DecodeNameReq(__pmPDU *pdubuf, char **name_p, int *subtype) { namereq_t *namereq_pdu; char *pdu_end; char *name; int namelen; namereq_pdu = (namereq_t *)pdubuf; pdu_end = (char *)pdubuf + namereq_pdu->hdr.len; if (pdu_end - (char *)namereq_pdu < sizeof(namereq_t) - sizeof(int)) return PM_ERR_IPC; /* only set it if you want it */ if (subtype != NULL) *subtype = ntohl(namereq_pdu->subtype); namelen = ntohl(namereq_pdu->namelen); if (namelen < 0 || namelen > namereq_pdu->hdr.len) return PM_ERR_IPC; if (sizeof(namereq_t) - sizeof(int) + namelen > (size_t)(pdu_end - (char *)namereq_pdu)) return PM_ERR_IPC; name = malloc(namelen+1); if (name == NULL) return -oserror(); memcpy(name, namereq_pdu->name, namelen); name[namelen] = '\0'; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) fprintf(stderr, "DecodeNameReq: name=\"%s\"\n", name); #endif *name_p = name; return 0; } /*********************************************************************/ /* * Send a PDU_PMNS_CHILD */ int __pmSendChildReq(int fd, int from, const char *name, int subtype) { return SendNameReq(fd, from, name, PDU_PMNS_CHILD, subtype); } /* * Decode a PDU_PMNS_CHILD */ int __pmDecodeChildReq(__pmPDU *pdubuf, char **name_p, int *subtype) { return DecodeNameReq(pdubuf, name_p, subtype); } /*********************************************************************/ /* * Send a PDU_PMNS_TRAVERSE */ int __pmSendTraversePMNSReq(int fd, int from, const char *name) { return SendNameReq(fd, from, name, PDU_PMNS_TRAVERSE, 0); } /* * Decode a PDU_PMNS_TRAVERSE */ int __pmDecodeTraversePMNSReq(__pmPDU *pdubuf, char **name_p) { return DecodeNameReq(pdubuf, name_p, 0); } /*********************************************************************/ pcp-3.8.12ubuntu1/src/libpcp/src/logportmap.c0000664000000000000000000002632712272262501015773 0ustar /* * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include static __pmLogPort *logport; /* array of all known pmlogger ports */ static int nlogports; /* no. of elements used in logports array */ static int szlogport; /* size of logport array */ /* Make sure the logports array is large enough to hold newsize entries. Free * any currently allocated names and zero the first newsize entries. */ static int resize_logports(int newsize) { int i; int need; if (nlogports) { for (i = 0; i < nlogports; i++) { if (logport[i].pmcd_host != NULL) free(logport[i].pmcd_host); if (logport[i].archive != NULL) free(logport[i].archive); if (logport[i].name != NULL) free(logport[i].name); } memset(logport, 0, nlogports * sizeof(__pmLogPort)); } nlogports = 0; if (szlogport >= newsize) return 0; free(logport); need = newsize * (int)sizeof(__pmLogPort); if ((logport = (__pmLogPort *)malloc(need)) == NULL) { szlogport = 0; return -1; } memset(logport, 0, need); szlogport = newsize; return 0; } /* Used by scandir to determine which files are pmlogger port files. The valid * files are numbers (pids) or PM_LOG_PRIMARY_LINK for the primary logger. */ static int is_portfile(const_dirent *dep) { char *endp; pid_t pid; pid = (pid_t)strtol(dep->d_name, &endp, 10); if (pid > (pid_t)1) return __pmProcessExists(pid); return strcmp(dep->d_name, "primary") == 0; } /* The following function is used for selecting particular port files rather * than all valid files. snprintf the pid of the pmlogger process or the * special constant PM_LOG_PRIMARY_LINK into the match array first. */ #define PROCFS_ENTRY_SIZE 40 /* encompass any size of entry for pid */ static char match[PROCFS_ENTRY_SIZE]; static int is_match(const_dirent *dep) { return strcmp(match, dep->d_name) == 0; } /* Return (in result) a list of active pmlogger ports on the local machine. * The return value of the function is the number of elements in the array. * The caller must NOT free any part of the result stucture, it's storage is * managed here. Subsequent calls will overwrite the data so the caller should * copy it if persistence is required. */ int __pmLogFindLocalPorts(int pid, __pmLogPort **result) { char dir[MAXPATHLEN]; int lendir; int i, j, n; int nf; /* number of port files found */ struct dirent **files = NULL; /* array of port file dirents */ char *p; int len; char namebuf[MAXPATHLEN]; int (*scanfn)(const_dirent *dep); FILE *pfile; char buf[MAXPATHLEN]; if (PM_MULTIPLE_THREADS(PM_SCOPE_LOGPORT)) return PM_ERR_THREAD; if (result == NULL) return -EINVAL; lendir = snprintf(dir, sizeof(dir), "%s%cpmlogger", pmGetConfig("PCP_TMP_DIR"), __pmPathSeparator()); /* Set up the appropriate function to select files from the control port * directory. Anticipate that this will usually be an exact match for * the primary logger control port. */ scanfn = is_match; switch (pid) { case PM_LOG_PRIMARY_PID: /* primary logger control (single) */ strcpy(match, "primary"); break; case PM_LOG_ALL_PIDS: /* find all ports */ scanfn = is_portfile; break; default: /* a specific pid (single) */ if (!__pmProcessExists((pid_t)pid)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "__pmLogFindLocalPorts() -> 0, " "pid(%d) doesn't exist\n", pid); } #endif *result = NULL; return 0; } snprintf(match, sizeof(match), "%d", pid); break; } nf = scandir(dir, &files, scanfn, alphasort); if (nf == -1 && oserror() == ENOENT) nf = 0; else if (nf == -1) { char errmsg[PM_MAXERRMSGLEN]; pmprintf("__pmLogFindLocalPorts: scandir: %s\n", osstrerror_r(errmsg, sizeof(errmsg))); pmflush(); return -oserror(); } if (resize_logports(nf) < 0) { for (i=0; i < nf; i++) free(files[i]); free(files); return -oserror(); } if (nf == 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "__pmLogFindLocalPorts() -> 0, " "num files = 0\n"); } #endif *result = NULL; free(files); return 0; } /* make a buffer for the longest complete pathname found */ len = (int)strlen(files[0]->d_name); for (i = 1; i < nf; i++) if ((j = (int)strlen(files[i]->d_name)) > len) len = j; /* +1 for trailing path separator, +1 for null termination */ len += lendir + 2; /* namebuf is the complete pathname, p points to the trailing filename * within namebuf. */ strcpy(namebuf, dir); p = namebuf + lendir; *p++ = __pmPathSeparator(); /* open the file, try to read the port number and add the port to the * logport array if successful. */ for (i = 0; i < nf; i++) { char *fname = files[i]->d_name; int err = 0; __pmLogPort *lpp = &logport[nlogports]; strcpy(p, fname); if ((pfile = fopen(namebuf, "r")) == NULL) { char errmsg[PM_MAXERRMSGLEN]; pmprintf("__pmLogFindLocalPorts: pmlogger port file %s: %s\n", namebuf, osstrerror_r(errmsg, sizeof(errmsg))); free(files[i]); pmflush(); continue; } if (!err && fgets(buf, MAXPATHLEN, pfile) == NULL) { if (feof(pfile)) { clearerr(pfile); pmprintf("__pmLogFindLocalPorts: pmlogger port file %s empty!\n", namebuf); } else { char errmsg[PM_MAXERRMSGLEN]; pmprintf("__pmLogFindLocalPorts: pmlogger port file %s: %s\n", namebuf, osstrerror_r(errmsg, sizeof(errmsg))); } err = 1; } else { char *endp; lpp->port = (int)strtol(buf, &endp, 10); if (*endp != '\n') { pmprintf("__pmLogFindLocalPorts: pmlogger port file %s: no port number\n", namebuf); err = 1; } else { lpp->pid = (int)strtol(fname, &endp, 10); if (*endp != '\0') { if (strcmp(fname, "primary") == 0) lpp->pid = PM_LOG_PRIMARY_PORT; else { pmprintf("__pmLogFindLocalPorts: unrecognised pmlogger port file %s\n", namebuf); err = 1; } } } } if (err) { pmflush(); fclose(pfile); } else { if (fgets(buf, MAXPATHLEN, pfile) == NULL) { pmprintf("__pmLogFindLocalPorts: pmlogger port file %s: no PMCD host name\n", namebuf); pmflush(); } else { char *q = strchr(buf, '\n'); if (q != NULL) *q = '\0'; lpp->pmcd_host = strdup(buf); if (fgets(buf, MAXPATHLEN, pfile) == NULL) { pmprintf("__pmLogFindLocalPorts: pmlogger port file %s: no archive base pathname\n", namebuf); pmflush(); } else { char *q = strchr(buf, '\n'); if (q != NULL) *q = '\0'; lpp->archive = strdup(buf); } } fclose(pfile); if ((lpp->name = strdup(fname)) != NULL) nlogports++; else { if (lpp->pmcd_host != NULL) { free(lpp->pmcd_host); lpp->pmcd_host = NULL; } if (lpp->archive != NULL) { free(lpp->archive); lpp->archive = NULL; } break; } } free(files[i]); } if (i == nf) { /* all went well */ n = nlogports; *result = logport; } else { /* strdup error on fname, clean up */ *result = NULL; for (j = i; j < nf; j++) free(files[j]); n = -oserror(); } free(files); return n; } /* * Return 1 if hostname corresponds to the current host, 0 if not and < 0 for * an error. */ int __pmIsLocalhost(const char *hostname) { int sts = 0; if (strcasecmp(hostname, "localhost") == 0 || strncmp(hostname, "local:", 6) == 0 || strncmp(hostname, "unix:", 5) == 0) return 1; else { char lhost[MAXHOSTNAMELEN+1]; struct hostent *he; if (gethostname(lhost, MAXHOSTNAMELEN) < 0) return -oserror(); PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if ((he = gethostbyname(lhost)) != NULL ) { int i; unsigned int * laddrs; for (i=0; he->h_addr_list[i] != NULL; i++) ; laddrs = (unsigned int *)calloc(i, sizeof (unsigned int)); if (laddrs != NULL) { int k; for (k=0; k < i; k++) { laddrs[k] = ((struct in_addr *)he->h_addr_list[k])->s_addr; } if ((he = gethostbyname(hostname)) == NULL) { free(laddrs); PM_UNLOCK(__pmLock_libpcp); return -EHOSTUNREACH; } for (i--; i >= 0; i--) { for (k = 0; he->h_addr_list[k] != NULL; k++) { struct in_addr *s=(struct in_addr *)he->h_addr_list[k]; if (s->s_addr == laddrs[i]) { free(laddrs); PM_UNLOCK(__pmLock_libpcp); return 1; } } } free(laddrs); } } PM_UNLOCK(__pmLock_libpcp); } return sts; } /* Return (in result) a list of active pmlogger ports on the specified machine. * The return value of the function is the number of elements in the array. * The caller must NOT free any part of the result stucture, it's storage is * managed here. Subsequent calls will overwrite the data so the caller should * copy it if persistence is required. */ int __pmLogFindPort(const char *host, int pid, __pmLogPort **lpp) { int ctx, oldctx; int sts, numval; int i, j; int findone = pid != PM_LOG_ALL_PIDS; int localcon = 0; /* > 0 for local connection */ pmDesc desc; pmResult *res; char *namelist[] = {"pmcd.pmlogger.port"}; pmID pmid; if (PM_MULTIPLE_THREADS(PM_SCOPE_LOGPORT)) return PM_ERR_THREAD; *lpp = NULL; /* pass null back in event of error */ localcon = __pmIsLocalhost(host); if (localcon > 0) /* do the work here instead of making PMCD do it */ return __pmLogFindLocalPorts(pid, lpp); else if (localcon < 0) return localcon; /* note: there may not be a current context */ oldctx = pmWhichContext(); if ((ctx = pmNewContext(PM_CONTEXT_HOST, host)) < 0) return ctx; if ((sts = pmLookupName(1, namelist, &pmid)) < 0) goto ctxErr; if ((sts = pmLookupDesc(pmid, &desc)) < 0) goto ctxErr; if ((sts = pmFetch(1, &pmid, &res) < 0)) goto ctxErr; if ((sts = numval = res->vset[0]->numval) < 0) goto resErr; j = 0; if (numval) { if (resize_logports(findone ? 1 : numval) < 0) { sts = -oserror(); goto resErr; } /* scan the pmResult, copying matching pid(s) to logport */ for (i = j = 0; i < numval; i++) { __pmLogPort *p = &logport[j]; pmValue *vp = &res->vset[0]->vlist[i]; if (vp->inst == 1) /* old vcr instance (pseudo-init) */ continue; if (findone && vp->inst != pid) continue; p->pid = vp->inst; p->port = vp->value.lval; sts = pmNameInDom(desc.indom, p->pid, &p->name); if (sts < 0) { p->name = NULL; goto resErr; } j++; if (findone) /* found one, stop searching */ break; } *lpp = logport; } sts = j; /* the number actually added */ resErr: pmFreeResult(res); ctxErr: if (oldctx >= 0) pmUseContext(oldctx); pmDestroyContext(ctx); return sts; } pcp-3.8.12ubuntu1/src/libpcp/src/pdubuf.c0000664000000000000000000001320612272262501015064 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe notes * * To avoid buffer trampling, on success __pmFindPDUBuf() now returns * a pinned PDU buffer. It is the caller's responsibility to unpin the * PDU buffer when safe to do so. * * TODO now that buffers always pinned on return, we can do away * with buf_pin and buf_pin_tail and maintain one list? */ #include "pmapi.h" #include "impl.h" #include #define PDU_CHUNK 1024 /* unit of space allocation for PDU buffer */ typedef struct bufctl { struct bufctl *bc_next; int bc_size; int bc_pincnt; char *bc_buf; char *bc_bufend; } bufctl_t; static bufctl_t *buf_free; static bufctl_t *buf_pin; static bufctl_t *buf_pin_tail; #ifdef PCP_DEBUG static void pdubufdump(void) { bufctl_t *pcp; PM_LOCK(__pmLock_libpcp); if (buf_free != NULL) { fprintf(stderr, " free pdubuf[size]:"); for (pcp = buf_free; pcp != NULL; pcp = pcp->bc_next) fprintf(stderr, " " PRINTF_P_PFX "%p[%d]", pcp->bc_buf, pcp->bc_size); fputc('\n', stderr); } if (buf_pin != NULL) { fprintf(stderr, " pinned pdubuf[pincnt]:"); for (pcp = buf_pin; pcp != NULL; pcp = pcp->bc_next) fprintf(stderr, " " PRINTF_P_PFX "%p[%d]", pcp->bc_buf, pcp->bc_pincnt); fputc('\n', stderr); } PM_UNLOCK(__pmLock_libpcp); } #endif __pmPDU * __pmFindPDUBuf(int need) { bufctl_t *pcp; __pmPDU *sts; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); for (pcp = buf_free; pcp != NULL; pcp = pcp->bc_next) { if (pcp->bc_size >= need) break; } if (pcp == NULL) { if ((pcp = (bufctl_t *)malloc(sizeof(*pcp))) == NULL) { PM_UNLOCK(__pmLock_libpcp); return NULL; } pcp->bc_pincnt = 0; pcp->bc_size = PDU_CHUNK * (1 + need/PDU_CHUNK); if ((pcp->bc_buf = (char *)valloc(pcp->bc_size)) == NULL) { free(pcp); PM_UNLOCK(__pmLock_libpcp); return NULL; } pcp->bc_next = buf_free; pcp->bc_bufend = &pcp->bc_buf[pcp->bc_size]; buf_free = pcp; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDUBUF) { fprintf(stderr, "__pmFindPDUBuf(%d) -> " PRINTF_P_PFX "%p\n", need, pcp->bc_buf); pdubufdump(); } #endif __pmPinPDUBuf(pcp->bc_buf); sts = (__pmPDU *)pcp->bc_buf; PM_UNLOCK(__pmLock_libpcp); return sts; } void __pmPinPDUBuf(void *handle) { bufctl_t *pcp; bufctl_t *prior = NULL; assert(((__psint_t)handle % sizeof(int)) == 0); PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); for (pcp = buf_free; pcp != NULL; pcp = pcp->bc_next) { if (pcp->bc_buf <= (char *)handle && (char *)handle < pcp->bc_bufend) break; prior = pcp; } if (pcp != NULL) { /* first pin for this buffer, move between lists */ if (prior == NULL) buf_free = pcp->bc_next; else prior->bc_next = pcp->bc_next; pcp->bc_next = NULL; if (buf_pin_tail != NULL) buf_pin_tail->bc_next = pcp; buf_pin_tail = pcp; if (buf_pin == NULL) buf_pin = pcp; pcp->bc_pincnt = 1; } else { for (pcp = buf_pin; pcp != NULL; pcp = pcp->bc_next) { if (pcp->bc_buf <= (char *)handle && (char *)handle < pcp->bc_bufend) break; } if (pcp != NULL) pcp->bc_pincnt++; else { __pmNotifyErr(LOG_WARNING, "__pmPinPDUBuf: 0x%lx not in pool!", (unsigned long)handle); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDUBUF) pdubufdump(); #endif PM_UNLOCK(__pmLock_libpcp); return; } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDUBUF) fprintf(stderr, "__pmPinPDUBuf(" PRINTF_P_PFX "%p) -> pdubuf=" PRINTF_P_PFX "%p, cnt=%d\n", handle, pcp->bc_buf, pcp->bc_pincnt); #endif PM_UNLOCK(__pmLock_libpcp); return; } int __pmUnpinPDUBuf(void *handle) { bufctl_t *pcp; bufctl_t *prior = NULL; assert(((__psint_t)handle % sizeof(int)) == 0); PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); for (pcp = buf_pin; pcp != NULL; pcp = pcp->bc_next) { if (pcp->bc_buf <= (char *)handle && (char *)handle < &pcp->bc_buf[pcp->bc_size]) break; prior = pcp; } if (pcp == NULL) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDUBUF) { fprintf(stderr, "__pmUnpinPDUBuf(" PRINTF_P_PFX "%p) -> fails\n", handle); pdubufdump(); } #endif PM_UNLOCK(__pmLock_libpcp); return 0; } if (--pcp->bc_pincnt == 0) { if (prior == NULL) buf_pin = pcp->bc_next; else prior->bc_next = pcp->bc_next; if (buf_pin_tail == pcp) buf_pin_tail = prior; pcp->bc_next = buf_free; buf_free = pcp; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDUBUF) fprintf(stderr, "__pmUnpinPDUBuf(" PRINTF_P_PFX "%p) -> pdubuf=" PRINTF_P_PFX "%p, pincnt=%d\n", handle, pcp->bc_buf, pcp->bc_pincnt); #endif PM_UNLOCK(__pmLock_libpcp); return 1; } void __pmCountPDUBuf(int need, int *alloc, int *free) { bufctl_t *pcp; int count; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); count = 0; for (pcp = buf_pin; pcp != NULL; pcp = pcp->bc_next) { if (pcp->bc_size >= need) count++; } *alloc = count; count = 0; for (pcp = buf_free; pcp != NULL; pcp = pcp->bc_next) { if (pcp->bc_size >= need) count++; } *free = count; *alloc += count; PM_UNLOCK(__pmLock_libpcp); return; } pcp-3.8.12ubuntu1/src/libpcp/src/interp.c0000664000000000000000000013753612272262501015115 0ustar /* * Copyright (c) 1995,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe notes: * * nr[] and nr_cache[] are diagnostic counters that are maintained with * non-atomic updates ... we've decided that it is acceptable for their * values to be subject to possible (but unlikely) missed updates */ /* * Note: _FORTIFY_SOURCE cannot be set here because the calls to memcpy() * with vp->vbuf as the destination raise a warning that is not * correct as the allocation for a pmValueBlock always extends * vbuf[] to be the correct size, not the [1] as per the declaration * in pmapi.h */ #ifdef _FORTIFY_SOURCE #undef _FORTIFY_SOURCE #define _FORTIFY_SOURCE 0 #endif #include #include #include #include "pmapi.h" #include "impl.h" #define UPD_MARK_NONE 0 #define UPD_MARK_FORW 1 #define UPD_MARK_BACK 2 #if defined(HAVE_CONST_LONGLONG) #define SIGN_64_MASK 0x8000000000000000LL #else #define SIGN_64_MASK 0x8000000000000000 #endif typedef union { /* value from pmResult */ pmValueBlock *pval; int lval; } value; typedef struct instcntl { /* metric-instance control */ struct instcntl *next; /* next for this metric control */ struct instcntl *want; /* ones of interest */ struct instcntl *unbound; /* not yet bound above [or below] */ int search; /* looking for found this one? */ int inst; /* instance identifier */ int inresult; /* will be in this result */ double t_prior; int m_prior; /* mark, not value at t_prior */ value v_prior; double t_next; int m_next; /* mark, not value at t_next */ value v_next; double t_first; /* no records before this */ double t_last; /* no records after this */ struct pmidcntl *metric; /* back to metric control */ } instcntl_t; typedef struct pmidcntl { /* metric control */ pmDesc desc; int valfmt; /* used to build result */ int numval; /* number of instances in this result */ struct instcntl *first; /* first metric-instace control */ } pmidcntl_t; typedef struct { pmResult *rp; /* cached pmResult from __pmLogRead */ int sts; /* from __pmLogRead */ FILE *mfp; /* log stream */ int vol; /* log volume */ long head_posn; /* posn in file before forwards __pmLogRead */ long tail_posn; /* posn in file after forwards __pmLogRead */ int mode; /* PM_MODE_FORW or PM_MODE_BACK */ int used; /* used count for LFU replacement */ } cache_t; #define NUMCACHE 4 static cache_t cache[NUMCACHE]; /* * diagnostic counters ... indexed by PM_MODE_FORW (2) and * PM_MODE_BACK (3), hence 4 elts for cached and non-cached reads */ static long nr_cache[PM_MODE_BACK+1]; static long nr[PM_MODE_BACK+1]; static int cache_read(__pmArchCtl *acp, int mode, pmResult **rp) { long posn; cache_t *cp; cache_t *lfup; int save_curvol; static int round_robin = -1; PM_LOCK(__pmLock_libpcp); if (acp->ac_vol == acp->ac_log->l_curvol) { posn = ftell(acp->ac_log->l_mfp); assert(posn >= 0); } else posn = 0; if (round_robin == -1) { /* cache initialization */ for (cp = cache; cp < &cache[NUMCACHE]; cp++) { cp->rp = NULL; cp->mfp = NULL; } round_robin = 0; } #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_LOG) && (pmDebug & DBG_TRACE_INTERP)) { fprintf(stderr, "cache_read: fd=%d mode=%s vol=%d (curvol=%d) %s_posn=%ld ", fileno(acp->ac_log->l_mfp), mode == PM_MODE_FORW ? "forw" : "back", acp->ac_vol, acp->ac_log->l_curvol, mode == PM_MODE_FORW ? "head" : "tail", (long)posn); } #endif round_robin = (round_robin + 1) % NUMCACHE; lfup = &cache[round_robin]; for (cp = cache; cp < &cache[NUMCACHE]; cp++) { if (cp->mfp == acp->ac_log->l_mfp && cp->vol == acp->ac_vol && ((mode == PM_MODE_FORW && cp->head_posn == posn) || (mode == PM_MODE_BACK && cp->tail_posn == posn)) && cp->rp != NULL) { int sts; *rp = cp->rp; cp->used++; if (mode == PM_MODE_FORW) fseek(acp->ac_log->l_mfp, cp->tail_posn, SEEK_SET); else fseek(acp->ac_log->l_mfp, cp->head_posn, SEEK_SET); #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_LOG) && (pmDebug & DBG_TRACE_INTERP)) { __pmTimeval tmp; double t_this; tmp.tv_sec = (__int32_t)cp->rp->timestamp.tv_sec; tmp.tv_usec = (__int32_t)cp->rp->timestamp.tv_usec; t_this = __pmTimevalSub(&tmp, &acp->ac_log->l_label.ill_start); fprintf(stderr, "hit cache[%d] t=%.6f\n", (int)(cp - cache), t_this); nr_cache[mode]++; } #endif sts = cp->sts; PM_UNLOCK(__pmLock_libpcp); return sts; } } #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_LOG) && (pmDebug & DBG_TRACE_INTERP)) fprintf(stderr, "miss\n"); nr[mode]++; #endif if (lfup->rp != NULL) pmFreeResult(lfup->rp); save_curvol = acp->ac_log->l_curvol; lfup->sts = __pmLogRead(acp->ac_log, mode, NULL, &lfup->rp, PMLOGREAD_NEXT); if (lfup->sts < 0) lfup->rp = NULL; *rp = lfup->rp; if (posn == 0 || save_curvol != acp->ac_log->l_curvol) { /* * vol switch since last time, or vol switch in __pmLogRead() ... * new vol, stdio stream and we don't know where we started from * ... don't cache */ lfup->mfp = NULL; #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_LOG) && (pmDebug & DBG_TRACE_INTERP)) fprintf(stderr, "cache_read: reload vol switch, mark cache[%d] unused\n", (int)(lfup - cache)); #endif } else { lfup->mode = mode; lfup->vol = acp->ac_vol; lfup->mfp = acp->ac_log->l_mfp; lfup->used = 1; if (mode == PM_MODE_FORW) { lfup->head_posn = posn; lfup->tail_posn = ftell(acp->ac_log->l_mfp); assert(lfup->tail_posn >= 0); } else { lfup->tail_posn = posn; lfup->head_posn = ftell(acp->ac_log->l_mfp); assert(lfup->head_posn >= 0); } #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_LOG) && (pmDebug & DBG_TRACE_INTERP)) { fprintf(stderr, "cache_read: reload cache[%d] vol=%d (curvol=%d) head=%ld tail=%ld ", (int)(lfup - cache), lfup->vol, acp->ac_log->l_curvol, (long)lfup->head_posn, (long)lfup->tail_posn); if (lfup->sts == 0) fprintf(stderr, "sts=%d\n", lfup->sts); else { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "sts=%s\n", pmErrStr_r(lfup->sts, errmsg, sizeof(errmsg))); } } #endif } PM_UNLOCK(__pmLock_libpcp); return lfup->sts; } void __pmLogCacheClear(FILE *mfp) { cache_t *cp; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); for (cp = cache; cp < &cache[NUMCACHE]; cp++) { if (cp->mfp == mfp) { if (cp->rp != NULL) pmFreeResult(cp->rp); cp->rp = NULL; cp->mfp = NULL; cp->used = 0; } } PM_UNLOCK(__pmLock_libpcp); } #ifdef PCP_DEBUG /* * prior == 1 for ?_prior fields, else use ?_next fields */ static void dumpval(FILE *f, int type, int valfmt, int prior, instcntl_t *icp) { int mark; value *vp; if (prior) { if (icp->t_prior == -1) { fprintf(stderr, " "); return; } mark = icp->m_prior; vp = &icp->v_prior; } else { if (icp->t_next == -1) { fprintf(stderr, " "); return; } mark = icp->m_next; vp = &icp->v_next; } if (mark) { fprintf(f, " "); return; } if (type == PM_TYPE_32 || type == PM_TYPE_U32) fprintf(f, " v=%d", vp->lval); else if (type == PM_TYPE_FLOAT && valfmt == PM_VAL_INSITU) { float tmp; memcpy((void *)&tmp, (void *)&vp->lval, sizeof(tmp)); fprintf(f, " v=%f", (double)tmp); } else if (type == PM_TYPE_64) { __int64_t tmp; memcpy((void *)&tmp, (void *)vp->pval->vbuf, sizeof(tmp)); fprintf(f, " v=%"PRIi64, tmp); } else if (type == PM_TYPE_U64) { __uint64_t tmp; memcpy((void *)&tmp, (void *)vp->pval->vbuf, sizeof(tmp)); fprintf(f, " v=%"PRIu64, tmp); } else if (type == PM_TYPE_FLOAT) { float tmp; memcpy((void *)&tmp, (void *)vp->pval->vbuf, sizeof(tmp)); fprintf(f, " v=%f", (double)tmp); } else if (type == PM_TYPE_DOUBLE) { double tmp; memcpy((void *)&tmp, (void *)vp->pval->vbuf, sizeof(tmp)); fprintf(f, " v=%f", tmp); } else fprintf(f, "v=??? (lval=%d)", vp->lval); } #endif static void update_bounds(__pmContext *ctxp, double t_req, pmResult *logrp, int do_mark, int *done_prior, int *done_next) { /* * for every metric in the result from the log * for every instance in the result from the log * if we have ever asked for this metric and instance, update the * range bounds, if necessary */ int k; int i; __pmHashCtl *hcp = &ctxp->c_archctl->ac_pmid_hc; __pmHashNode *hp; pmidcntl_t *pcp; instcntl_t *icp; double t_this; __pmTimeval tmp; int changed; tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec; tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec; t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start); if (logrp->numpmid == 0 && do_mark != UPD_MARK_NONE) { /* mark record, discontinuity in log */ for (icp = (instcntl_t *)ctxp->c_archctl->ac_want; icp != NULL; icp = icp->want) { if (t_this <= t_req && (t_this >= icp->t_prior || icp->t_prior > t_req)) { /* is closer than best lower bound to date */ icp->t_prior = t_this; icp->m_prior = 1; if (icp->metric->valfmt != PM_VAL_INSITU) { if (icp->v_prior.pval != NULL) __pmUnpinPDUBuf((void *)icp->v_prior.pval); icp->v_prior.pval = NULL; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP) { char strbuf[20]; fprintf(stderr, "pmid %s inst %d t_prior=%.6f t_first=%.6f t_last=%.6f\n", pmIDStr_r(icp->metric->desc.pmid, strbuf, sizeof(strbuf)), icp->inst, icp->t_prior, icp->t_first, icp->t_last); } #endif if (icp->search && done_prior != NULL) { icp->search = 0; (*done_prior)++; } } if (t_this >= t_req && ((t_this <= icp->t_next || icp->t_next < 0) || icp->t_next < t_req)) { /* is closer than best upper bound to date */ icp->t_next = t_this; icp->m_next = 1; if (icp->metric->valfmt != PM_VAL_INSITU) { if (icp->v_next.pval != NULL) __pmUnpinPDUBuf((void *)icp->v_next.pval); icp->v_next.pval = NULL; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP) { char strbuf[20]; fprintf(stderr, "pmid %s inst %d t_next=%.6f t_first=%.6f t_last=%.6f\n", pmIDStr_r(icp->metric->desc.pmid, strbuf, sizeof(strbuf)), icp->inst, icp->t_next, icp->t_first, icp->t_last); } #endif if (icp->search && done_next != NULL) { icp->search = 0; (*done_next)++; } } } return; } changed = 0; for (k = 0; k < logrp->numpmid; k++) { hp = __pmHashSearch((int)logrp->vset[k]->pmid, hcp); if (hp == NULL) continue; pcp = (pmidcntl_t *)hp->data; if (pcp->valfmt == -1 && logrp->vset[k]->numval > 0) pcp->valfmt = logrp->vset[k]->valfmt; for (icp = pcp->first; icp != NULL; icp = icp->next) { for (i = 0; i < logrp->vset[k]->numval; i++) { if (logrp->vset[k]->vlist[i].inst == icp->inst || icp->inst == PM_IN_NULL) { /* matched on instance */ #if defined(PCP_DEBUG) && defined(DESPERATE) if (pmDebug & DBG_TRACE_INTERP) { char strbuf[20]; fprintf(stderr, "update: match pmid %s inst %d t_this=%.6f t_prior=%.6f t_next=%.6f t_first=%.6f t_last=%.6f\n", pmIDStr_r(logrp->vset[k]->pmid, strbuf, sizeof(strbuf)), icp->inst, t_this, icp->t_prior, icp->t_next, icp->t_first, icp->t_last); } #endif if (t_this <= t_req && (icp->t_prior > t_req || t_this >= icp->t_prior)) { /* * at or before the requested time, and this is the * closest-to-date lower bound */ changed = 1; if (icp->t_prior < icp->t_next && icp->t_prior >= t_req) { /* shuffle prior to next */ icp->t_next = icp->t_prior; if (pcp->valfmt == PM_VAL_INSITU) icp->v_next.lval = icp->v_prior.lval; else { if (icp->v_next.pval != NULL) __pmUnpinPDUBuf((void *)icp->v_next.pval); icp->v_next.pval = icp->v_prior.pval; } } icp->t_prior = t_this; icp->m_prior = 0; if (pcp->valfmt == PM_VAL_INSITU) icp->v_prior.lval = logrp->vset[k]->vlist[i].value.lval; else { if (icp->v_prior.pval != NULL) __pmUnpinPDUBuf((void *)icp->v_prior.pval); icp->v_prior.pval = logrp->vset[k]->vlist[i].value.pval; __pmPinPDUBuf((void *)icp->v_prior.pval); } if (icp->search && done_prior != NULL) { /* one we were looking for */ changed |= 2; icp->search = 0; (*done_prior)++; } } if (t_this >= t_req && (icp->t_next < t_req || t_this <= icp->t_next)) { /* * at or after the requested time, and this is the * closest-to-date upper bound */ changed |= 1; if (icp->t_prior < icp->t_next && icp->t_next <= t_req) { /* shuffle next to prior */ icp->t_prior = icp->t_next; icp->m_prior = icp->m_next; if (pcp->valfmt == PM_VAL_INSITU) icp->v_prior.lval = icp->v_next.lval; else { if (icp->v_prior.pval != NULL) __pmUnpinPDUBuf((void *)icp->v_prior.pval); icp->v_prior.pval = icp->v_next.pval; } } icp->t_next = t_this; icp->m_next = 0; if (pcp->valfmt == PM_VAL_INSITU) icp->v_next.lval = logrp->vset[k]->vlist[i].value.lval; else { if (icp->v_next.pval != NULL) __pmUnpinPDUBuf((void *)icp->v_next.pval); icp->v_next.pval = logrp->vset[k]->vlist[i].value.pval; __pmPinPDUBuf((void *)icp->v_next.pval); } if (icp->search && done_next != NULL) { /* one we were looking for */ changed |= 2; icp->search = 0; (*done_next)++; } } #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_INTERP) && changed) { char strbuf[20]; fprintf(stderr, "update%s pmid %s inst %d prior: t=%.6f", changed & 2 ? "+search" : "", pmIDStr_r(logrp->vset[k]->pmid, strbuf, sizeof(strbuf)), icp->inst, icp->t_prior); dumpval(stderr, pcp->desc.type, icp->metric->valfmt, 1, icp); fprintf(stderr, " next: t=%.6f", icp->t_next); dumpval(stderr, pcp->desc.type, icp->metric->valfmt, 0, icp); fprintf(stderr, " t_first=%.6f t_last=%.6f\n", icp->t_first, icp->t_last); } #endif goto next_inst; } } next_inst: ; } } return; } static void do_roll(__pmContext *ctxp, double t_req) { pmResult *logrp; __pmTimeval tmp; double t_this; /* * now roll forwards in the direction of log reading * to make sure we are up to t_req */ if (ctxp->c_delta > 0) { while (cache_read(ctxp->c_archctl, PM_MODE_FORW, &logrp) >= 0) { tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec; tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec; t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start); if (t_this > t_req) break; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP) fprintf(stderr, "roll forw to t=%.6f%s\n", t_this, logrp->numpmid == 0 ? " " : ""); #endif ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp); assert(ctxp->c_archctl->ac_offset >= 0); ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol; update_bounds(ctxp, t_req, logrp, UPD_MARK_FORW, NULL, NULL); } } else { while (cache_read(ctxp->c_archctl, PM_MODE_BACK, &logrp) >= 0) { tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec; tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec; t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start); if (t_this < t_req) break; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP) fprintf(stderr, "roll back to t=%.6f%s\n", t_this, logrp->numpmid == 0 ? " " : ""); #endif ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp); assert(ctxp->c_archctl->ac_offset >= 0); ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol; update_bounds(ctxp, t_req, logrp, UPD_MARK_BACK, NULL, NULL); } } } #define pmXTBdeltaToTimeval(d, m, t) { \ (t)->tv_sec = 0; \ (t)->tv_usec = (long)0; \ switch(PM_XTB_GET(m)) { \ case PM_TIME_NSEC: (t)->tv_usec = (long)((d) / 1000); break; \ case PM_TIME_USEC: (t)->tv_usec = (long)(d); break; \ case PM_TIME_MSEC: (t)->tv_sec = (d) / 1000; (t)->tv_usec = (long)(1000 * ((d) % 1000)); break; \ case PM_TIME_SEC: (t)->tv_sec = (d); break; \ case PM_TIME_MIN: (t)->tv_sec = (d) * 60; break; \ case PM_TIME_HOUR: (t)->tv_sec = (d) * 360; break; \ default: (t)->tv_sec = (d) / 1000; (t)->tv_usec = (long)(1000 * ((d) % 1000)); break; \ } \ } int __pmLogFetchInterp(__pmContext *ctxp, int numpmid, pmID pmidlist[], pmResult **result) { int i; int j; int sts; double t_req; double t_this; pmResult *rp; pmResult *logrp; __pmHashCtl *hcp = &ctxp->c_archctl->ac_pmid_hc; __pmHashNode *hp; pmidcntl_t *pcp = NULL; /* initialize to pander to gcc */ instcntl_t *icp; int back = 0; int forw = 0; int done; int done_roll; static int dowrap = -1; __pmTimeval tmp; struct timeval delta_tv; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (dowrap == -1) { /* PCP_COUNTER_WRAP in environment enables "counter wrap" logic */ if (getenv("PCP_COUNTER_WRAP") == NULL) dowrap = 0; else dowrap = 1; } PM_UNLOCK(__pmLock_libpcp); t_req = __pmTimevalSub(&ctxp->c_origin, &ctxp->c_archctl->ac_log->l_label.ill_start); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP) { fprintf(stderr, "__pmLogFetchInterp @ "); __pmPrintTimeval(stderr, &ctxp->c_origin); fprintf(stderr, " t_req=%.6f curvol=%d posn=%ld (vol=%d) serial=%d\n", t_req, ctxp->c_archctl->ac_log->l_curvol, (long)ctxp->c_archctl->ac_offset, ctxp->c_archctl->ac_vol, ctxp->c_archctl->ac_serial); nr_cache[PM_MODE_FORW] = nr[PM_MODE_FORW] = 0; nr_cache[PM_MODE_BACK] = nr[PM_MODE_BACK] = 0; } #endif /* * the 0.001 is magic slop for 1 msec, which is about as accurate * as we can expect any of this timing stuff to be ... */ if (t_req < -0.001) { sts = PM_ERR_EOL; goto all_done; } if (t_req > ctxp->c_archctl->ac_end + 0.001) { struct timeval end; __pmTimeval tmp; /* * Past end of archive ... see if it has grown since we last looked. */ if (pmGetArchiveEnd(&end) >= 0) { tmp.tv_sec = (__int32_t)end.tv_sec; tmp.tv_usec = (__int32_t)end.tv_usec; ctxp->c_archctl->ac_end = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start); } if (t_req > ctxp->c_archctl->ac_end) { sts = PM_ERR_EOL; goto all_done; } } if ((rp = (pmResult *)malloc(sizeof(pmResult) + (numpmid - 1) * sizeof(pmValueSet *))) == NULL) return -oserror(); rp->timestamp.tv_sec = ctxp->c_origin.tv_sec; rp->timestamp.tv_usec = ctxp->c_origin.tv_usec; rp->numpmid = numpmid; /* zeroth pass ... clear search and inresult flags */ for (j = 0; j < hcp->hsize; j++) { for (hp = hcp->hash[j]; hp != NULL; hp = hp->next) { pcp = (pmidcntl_t *)hp->data; for (icp = pcp->first; icp != NULL; icp = icp->next) { icp->search = icp->inresult = 0; icp->unbound = icp->want = NULL; } } } /* * first pass ... scan all metrics, establish which ones are in * the log, and which instances are being requested ... also build * the skeletal pmResult */ ctxp->c_archctl->ac_want = NULL; for (j = 0; j < numpmid; j++) { if (pmidlist[j] == PM_ID_NULL) continue; hp = __pmHashSearch((int)pmidlist[j], hcp); if (hp == NULL) { /* first time we've been asked for this one in this context */ if ((pcp = (pmidcntl_t *)malloc(sizeof(pmidcntl_t))) == NULL) { __pmNoMem("__pmLogFetchInterp.pmidcntl_t", sizeof(pmidcntl_t), PM_FATAL_ERR); /*NOTREACHED*/ } pcp->valfmt = -1; pcp->first = NULL; sts = __pmHashAdd((int)pmidlist[j], (void *)pcp, hcp); if (sts < 0) { rp->numpmid = j; pmFreeResult(rp); free(pcp); return sts; } sts = __pmLogLookupDesc(ctxp->c_archctl->ac_log, pmidlist[j], &pcp->desc); if (sts < 0) /* not in the archive log */ pcp->desc.type = -1; else { /* enumerate all the instances from the domain underneath */ int *instlist = NULL; char **namelist = NULL; instcntl_t *lcp; if (pcp->desc.indom == PM_INDOM_NULL) { sts = 1; if ((instlist = (int *)malloc(sizeof(int))) == NULL) { __pmNoMem("__pmLogFetchInterp.instlist", sizeof(int), PM_FATAL_ERR); } instlist[0] = PM_IN_NULL; } else { sts = pmGetInDomArchive(pcp->desc.indom, &instlist, &namelist); } lcp = NULL; for (i = 0; i < sts; i++) { if ((icp = (instcntl_t *)malloc(sizeof(instcntl_t))) == NULL) { __pmNoMem("__pmLogFetchInterp.instcntl_t", sizeof(instcntl_t), PM_FATAL_ERR); } if (lcp) lcp->next = icp; else pcp->first = icp; lcp = icp; icp->metric = pcp; icp->inresult = icp->search = 0; icp->next = icp->want = icp->unbound = NULL; icp->inst = instlist[i]; icp->t_prior = icp->t_next = icp->t_first = icp->t_last = -1; icp->m_prior = icp->m_next = 1; icp->v_prior.pval = icp->v_next.pval = NULL; } if (instlist != NULL) free(instlist); if (namelist != NULL) free(namelist); } } else /* seen this one before */ pcp = (pmidcntl_t *)hp->data; pcp->numval = 0; if (pcp->desc.type == -1) { pcp->numval = PM_ERR_PMID_LOG; } else if (pcp->desc.indom != PM_INDOM_NULL) { /* use the profile to filter the instances to be returned */ for (icp = pcp->first; icp != NULL; icp = icp->next) { if (__pmInProfile(pcp->desc.indom, ctxp->c_instprof, icp->inst)) { icp->inresult = 1; icp->want = (instcntl_t *)ctxp->c_archctl->ac_want; ctxp->c_archctl->ac_want = icp; pcp->numval++; } else icp->inresult = 0; } } else { pcp->first->inresult = 1; pcp->first->want = (instcntl_t *)ctxp->c_archctl->ac_want; ctxp->c_archctl->ac_want = pcp->first; pcp->numval = 1; } } if (ctxp->c_archctl->ac_serial == 0) { /* need gross positioning from temporal index */ __pmLogSetTime(ctxp); ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp); assert(ctxp->c_archctl->ac_offset >= 0); ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol; /* * and now fine-tuning ... * back-up (relative to the direction we are reading the log) * to make sure */ if (ctxp->c_delta > 0) { while (cache_read(ctxp->c_archctl, PM_MODE_BACK, &logrp) >= 0) { tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec; tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec; t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start); if (t_this <= t_req) { break; } ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp); assert(ctxp->c_archctl->ac_offset >= 0); ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol; update_bounds(ctxp, t_req, logrp, UPD_MARK_NONE, NULL, NULL); } } else { while (cache_read(ctxp->c_archctl, PM_MODE_FORW, &logrp) >= 0) { tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec; tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec; t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start); if (t_this > t_req) { break; } ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp); assert(ctxp->c_archctl->ac_offset >= 0); ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol; update_bounds(ctxp, t_req, logrp, UPD_MARK_NONE, NULL, NULL); } } ctxp->c_archctl->ac_serial = 1; } /* get to the last remembered place */ __pmLogChangeVol(ctxp->c_archctl->ac_log, ctxp->c_archctl->ac_vol); fseek(ctxp->c_archctl->ac_log->l_mfp, ctxp->c_archctl->ac_offset, SEEK_SET); /* * optimization to supress roll forwards unless really needed ... * if the sample interval is much shorter than the time between log * records, then do not roll forwards unless some scanning is * required ... and if scanning is required in the "forwards" * direction, no need to roll forwards */ done_roll = 0; /* * second pass ... see which metrics are not currently bounded below */ ctxp->c_archctl->ac_unbound = NULL; for (j = 0; j < numpmid; j++) { if (pmidlist[j] == PM_ID_NULL) continue; hp = __pmHashSearch((int)pmidlist[j], hcp); assert(hp != NULL); pcp = (pmidcntl_t *)hp->data; if (pcp->numval > 0) { for (icp = pcp->first; icp != NULL; icp = icp->next) { if (!icp->inresult) continue; if (icp->t_first >= 0 && t_req < icp->t_first) /* before earliest, don't bother */ continue; retry_back: /* * At this stage there _may_ be a value earlier in the * archive of interest ... * t_prior = -1 => have not explored in this direction, * so need to go back * t_prior > t_req => need to push t_prior to be <= t_req * if possible, so go back * t_next is valid and a mark and t_next > t_req => need * to search back also */ if (icp->t_prior < 0 || icp->t_prior > t_req || (icp->t_next >= 0 && icp->m_next && icp->t_next > t_req)) { if (back == 0 && !done_roll) { done_roll = 1; if (ctxp->c_delta > 0) { /* forwards before scanning back */ do_roll(ctxp, t_req); goto retry_back; } } back++; icp->search = 1; icp->unbound = (instcntl_t *)ctxp->c_archctl->ac_unbound; ctxp->c_archctl->ac_unbound = icp; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP) { char strbuf[20]; fprintf(stderr, "search back for inst %d and pmid %s (t_first=%.6f t_prior=%.6f%s t_next=%.6f%s t_last=%.6f)\n", icp->inst, pmIDStr_r(pmidlist[j], strbuf, sizeof(strbuf)), icp->t_first, icp->t_prior, icp->m_prior ? " " : "", icp->t_next, icp->m_next ? " " : "", icp->t_last); } #endif } } } } if (back) { /* * at least one metric requires a bound from earlier in the log ... * position ourselves, ... and search */ __pmLogChangeVol(ctxp->c_archctl->ac_log, ctxp->c_archctl->ac_vol); fseek(ctxp->c_archctl->ac_log->l_mfp, ctxp->c_archctl->ac_offset, SEEK_SET); done = 0; while (done < back) { if (cache_read(ctxp->c_archctl, PM_MODE_BACK, &logrp) < 0) { /* ran into start of log */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP) { fprintf(stderr, "Start of Log, %d metric-inst not found\n", back - done); } #endif break; } tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec; tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec; t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start); if (ctxp->c_delta < 0 && t_this >= t_req) { /* going backwards, and not up to t_req yet */ ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp); assert(ctxp->c_archctl->ac_offset >= 0); ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol; } update_bounds(ctxp, t_req, logrp, UPD_MARK_BACK, &done, NULL); /* * forget about those that can never be found from here * in this direction */ for (icp = (instcntl_t *)ctxp->c_archctl->ac_unbound; icp != NULL; icp = icp->unbound) { if (icp->search && t_this <= icp->t_first) { icp->search = 0; done++; } } } /* end of search, trim t_first as required */ for (icp = (instcntl_t *)ctxp->c_archctl->ac_unbound; icp != NULL; icp = icp->unbound) { if ((icp->t_prior == -1 || icp->t_prior > t_req) && icp->t_first < t_req) { icp->t_first = t_req; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP) { char strbuf[20]; fprintf(stderr, "pmid %s inst %d no values before t_first=%.6f\n", pmIDStr_r(icp->metric->desc.pmid, strbuf, sizeof(strbuf)), icp->inst, icp->t_first); } #endif } icp->search = 0; } } /* * third pass ... see which metrics are not currently bounded above */ ctxp->c_archctl->ac_unbound = NULL; for (j = 0; j < numpmid; j++) { if (pmidlist[j] == PM_ID_NULL) continue; hp = __pmHashSearch((int)pmidlist[j], hcp); assert(hp != NULL); pcp = (pmidcntl_t *)hp->data; if (pcp->numval > 0) { for (icp = pcp->first; icp != NULL; icp = icp->next) { if (!icp->inresult) continue; if (icp->t_last >= 0 && t_req > icp->t_last) /* after latest, don't bother */ continue; retry_forw: /* * At this stage there _may_ be a value later in the * archive of interest ... * t_next = -1 => have not explored in this direction, * so need to go forward * t_next < t_req => need to push t_next to be >= t_req * if possible, so go forward * t_prior is valid and a mark and t_prior < t_req => need * to search forward also */ if (icp->t_next < 0 || icp->t_next < t_req || (icp->t_prior >= 0 && icp->m_prior && icp->t_prior < t_req)) { if (forw == 0 && !done_roll) { done_roll = 1; if (ctxp->c_delta < 0) { /* backwards before scanning forwards */ do_roll(ctxp, t_req); goto retry_forw; } } forw++; icp->search = 1; icp->unbound = (instcntl_t *)ctxp->c_archctl->ac_unbound; ctxp->c_archctl->ac_unbound = icp; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP) { char strbuf[20]; fprintf(stderr, "search forw for inst %d and pmid %s (t_first=%.6f t_prior=%.6f%s t_next=%.6f%s t_last=%.6f)\n", icp->inst, pmIDStr_r(pmidlist[j], strbuf, sizeof(strbuf)), icp->t_first, icp->t_prior, icp->m_prior ? " " : "", icp->t_next, icp->m_next ? " " : "", icp->t_last); } #endif } } } } if (forw) { /* * at least one metric requires a bound from later in the log ... * position ourselves ... and search */ __pmLogChangeVol(ctxp->c_archctl->ac_log, ctxp->c_archctl->ac_vol); fseek(ctxp->c_archctl->ac_log->l_mfp, ctxp->c_archctl->ac_offset, SEEK_SET); done = 0; while (done < forw) { if (cache_read(ctxp->c_archctl, PM_MODE_FORW, &logrp) < 0) { /* ran into end of log */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP) { fprintf(stderr, "End of Log, %d metric-inst not found\n", forw - done); } #endif break; } tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec; tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec; t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start); if (ctxp->c_delta > 0 && t_this <= t_req) { /* going forwards, and not up to t_req yet */ ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp); assert(ctxp->c_archctl->ac_offset >= 0); ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol; } update_bounds(ctxp, t_req, logrp, UPD_MARK_FORW, NULL, &done); /* * forget about those that can never be found from here * in this direction */ for (icp = (instcntl_t *)ctxp->c_archctl->ac_unbound; icp != NULL; icp = icp->unbound) { if (icp->search && icp->t_last >= 0 && t_this >= icp->t_last) { icp->search = 0; done++; } } } /* end of search, trim t_last as required */ for (icp = (instcntl_t *)ctxp->c_archctl->ac_unbound; icp != NULL; icp = icp->unbound) { if (icp->t_next < t_req && (icp->t_last < 0 || t_req < icp->t_last)) { icp->t_last = t_req; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP) { char strbuf[20]; fprintf(stderr, "pmid %s inst %d no values after t_last=%.6f\n", pmIDStr_r(icp->metric->desc.pmid, strbuf, sizeof(strbuf)), icp->inst, icp->t_last); } #endif } icp->search = 0; } } /* * check to see how many qualifying values there are really going to be */ for (j = 0; j < numpmid; j++) { if (pmidlist[j] == PM_ID_NULL) continue; hp = __pmHashSearch((int)pmidlist[j], hcp); assert(hp != NULL); pcp = (pmidcntl_t *)hp->data; for (icp = pcp->first; icp != NULL; icp = icp->next) { if (!icp->inresult) continue; if (pcp->desc.sem == PM_SEM_DISCRETE) { if (icp->m_prior || icp->t_prior == -1 || icp->t_prior > t_req) { /* no earlier value, so no value */ pcp->numval--; icp->inresult = 0; } } else { /* assume COUNTER or INSTANT */ if (icp->m_prior || icp->t_prior == -1 || icp->t_prior > t_req || icp->m_next || icp->t_next == -1 || icp->t_next < t_req) { /* in mid-range, and no bound, so no value */ pcp->numval--; icp->inresult = 0; } else if (pcp->desc.sem == PM_SEM_COUNTER) { /* * for counters, has to be arithmetic also, * else cannot interpolate ... */ if (pcp->desc.type != PM_TYPE_32 && pcp->desc.type != PM_TYPE_U32 && pcp->desc.type != PM_TYPE_64 && pcp->desc.type != PM_TYPE_U64 && pcp->desc.type != PM_TYPE_FLOAT && pcp->desc.type != PM_TYPE_DOUBLE) pcp->numval = PM_ERR_TYPE; } } } } for (j = 0; j < numpmid; j++) { if (pmidlist[j] == PM_ID_NULL) { rp->vset[j] = (pmValueSet *)malloc(sizeof(pmValueSet) - sizeof(pmValue)); } else { hp = __pmHashSearch((int)pmidlist[j], hcp); assert(hp != NULL); pcp = (pmidcntl_t *)hp->data; if (pcp->numval >= 1) rp->vset[j] = (pmValueSet *)malloc(sizeof(pmValueSet) + (pcp->numval - 1)*sizeof(pmValue)); else rp->vset[j] = (pmValueSet *)malloc(sizeof(pmValueSet) - sizeof(pmValue)); } if (rp->vset[j] == NULL) { __pmNoMem("__pmLogFetchInterp.vset", sizeof(pmValueSet), PM_FATAL_ERR); } rp->vset[j]->pmid = pmidlist[j]; if (pmidlist[j] == PM_ID_NULL) { rp->vset[j]->numval = 0; continue; } rp->vset[j]->numval = pcp->numval; rp->vset[j]->valfmt = pcp->valfmt; i = 0; if (pcp->numval > 0) { for (icp = pcp->first; icp != NULL; icp = icp->next) { if (!icp->inresult) continue; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP && done_roll) { char strbuf[20]; fprintf(stderr, "pmid %s inst %d prior: t=%.6f", pmIDStr_r(pmidlist[j], strbuf, sizeof(strbuf)), icp->inst, icp->t_prior); dumpval(stderr, pcp->desc.type, icp->metric->valfmt, 1, icp); fprintf(stderr, " next: t=%.6f", icp->t_next); dumpval(stderr, pcp->desc.type, icp->metric->valfmt, 0, icp); fprintf(stderr, " t_first=%.6f t_last=%.6f\n", icp->t_first, icp->t_last); } #endif rp->vset[j]->vlist[i].inst = icp->inst; if (pcp->desc.type == PM_TYPE_32 || pcp->desc.type == PM_TYPE_U32) { if (icp->t_prior == t_req) rp->vset[j]->vlist[i++].value.lval = icp->v_prior.lval; else if (icp->t_next == t_req) rp->vset[j]->vlist[i++].value.lval = icp->v_next.lval; else { if (pcp->desc.sem == PM_SEM_DISCRETE) { if (icp->t_prior >= 0) rp->vset[j]->vlist[i++].value.lval = icp->v_prior.lval; } else if (pcp->desc.sem == PM_SEM_INSTANT) { if (icp->t_prior >= 0 && icp->t_next >= 0) rp->vset[j]->vlist[i++].value.lval = icp->v_prior.lval; } else { /* assume COUNTER */ if (icp->t_prior >= 0 && icp->t_next >= 0) { if (pcp->desc.type == PM_TYPE_32) { if (icp->v_next.lval >= icp->v_prior.lval || dowrap == 0) { rp->vset[j]->vlist[i++].value.lval = 0.5 + icp->v_prior.lval + (t_req - icp->t_prior) * (icp->v_next.lval - icp->v_prior.lval) / (icp->t_next - icp->t_prior); } else { /* not monotonic increasing and want wrap */ rp->vset[j]->vlist[i++].value.lval = 0.5 + (t_req - icp->t_prior) * (__int32_t)(UINT_MAX - icp->v_prior.lval + 1 + icp->v_next.lval) / (icp->t_next - icp->t_prior); rp->vset[j]->vlist[i].value.lval += icp->v_prior.lval; } } else { pmAtomValue av; pmAtomValue *avp_prior = (pmAtomValue *)&icp->v_prior.lval; pmAtomValue *avp_next = (pmAtomValue *)&icp->v_next.lval; if (avp_next->ul >= avp_prior->ul) { av.ul = 0.5 + avp_prior->ul + (t_req - icp->t_prior) * (avp_next->ul - avp_prior->ul) / (icp->t_next - icp->t_prior); } else { /* not monotonic increasing */ if (dowrap) { av.ul = 0.5 + (t_req - icp->t_prior) * (__uint32_t)(UINT_MAX - avp_prior->ul + 1 + avp_next->ul ) / (icp->t_next - icp->t_prior); av.ul += avp_prior->ul; } else { __uint32_t tmp; tmp = avp_prior->ul - avp_next->ul; av.ul = 0.5 + avp_prior->ul - (t_req - icp->t_prior) * tmp / (icp->t_next - icp->t_prior); } } rp->vset[j]->vlist[i++].value.lval = av.ul; } } } } } else if (pcp->desc.type == PM_TYPE_FLOAT && icp->metric->valfmt == PM_VAL_INSITU) { /* OLD style FLOAT insitu */ if (icp->t_prior == t_req) rp->vset[j]->vlist[i++].value.lval = icp->v_prior.lval; else if (icp->t_next == t_req) rp->vset[j]->vlist[i++].value.lval = icp->v_next.lval; else { if (pcp->desc.sem == PM_SEM_DISCRETE) { if (icp->t_prior >= 0) rp->vset[j]->vlist[i++].value.lval = icp->v_prior.lval; } else if (pcp->desc.sem == PM_SEM_INSTANT) { if (icp->t_prior >= 0 && icp->t_next >= 0) rp->vset[j]->vlist[i++].value.lval = icp->v_prior.lval; } else { /* assume COUNTER */ pmAtomValue av; pmAtomValue *avp_prior = (pmAtomValue *)&icp->v_prior.lval; pmAtomValue *avp_next = (pmAtomValue *)&icp->v_next.lval; if (icp->t_prior >= 0 && icp->t_next >= 0) { av.f = avp_prior->f + (t_req - icp->t_prior) * (avp_next->f - avp_prior->f) / (icp->t_next - icp->t_prior); /* yes this IS correct ... */ rp->vset[j]->vlist[i++].value.lval = av.l; } } } } else if (pcp->desc.type == PM_TYPE_FLOAT) { /* NEW style FLOAT in pmValueBlock */ int need; pmValueBlock *vp; int ok = 1; need = PM_VAL_HDR_SIZE + sizeof(float); if ((vp = (pmValueBlock *)malloc(need)) == NULL) { sts = -oserror(); goto bad_alloc; } vp->vlen = need; vp->vtype = PM_TYPE_FLOAT; rp->vset[j]->valfmt = PM_VAL_DPTR; rp->vset[j]->vlist[i++].value.pval = vp; if (icp->t_prior == t_req) memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(float)); else if (icp->t_next == t_req) memcpy((void *)vp->vbuf, (void *)icp->v_next.pval->vbuf, sizeof(float)); else { if (pcp->desc.sem == PM_SEM_DISCRETE) { if (icp->t_prior >= 0) memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(float)); else ok = 0; } else if (pcp->desc.sem == PM_SEM_INSTANT) { if (icp->t_prior >= 0 && icp->t_next >= 0) memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(float)); else ok = 0; } else { /* assume COUNTER */ if (icp->t_prior >= 0 && icp->t_next >= 0) { pmAtomValue av; void *avp_prior = icp->v_prior.pval->vbuf; void *avp_next = icp->v_next.pval->vbuf; float f_prior; float f_next; memcpy((void *)&av.f, avp_prior, sizeof(av.f)); f_prior = av.f; memcpy((void *)&av.f, avp_next, sizeof(av.f)); f_next = av.f; av.f = f_prior + (t_req - icp->t_prior) * (f_next - f_prior) / (icp->t_next - icp->t_prior); memcpy((void *)vp->vbuf, (void *)&av.f, sizeof(av.f)); } else ok = 0; } } if (!ok) { i--; free(vp); } } else if (pcp->desc.type == PM_TYPE_64 || pcp->desc.type == PM_TYPE_U64) { int need; pmValueBlock *vp; int ok = 1; need = PM_VAL_HDR_SIZE + sizeof(__int64_t); if ((vp = (pmValueBlock *)malloc(need)) == NULL) { sts = -oserror(); goto bad_alloc; } vp->vlen = need; if (pcp->desc.type == PM_TYPE_64) vp->vtype = PM_TYPE_64; else vp->vtype = PM_TYPE_U64; rp->vset[j]->valfmt = PM_VAL_DPTR; rp->vset[j]->vlist[i++].value.pval = vp; if (icp->t_prior == t_req) memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(__int64_t)); else if (icp->t_next == t_req) memcpy((void *)vp->vbuf, (void *)icp->v_next.pval->vbuf, sizeof(__int64_t)); else { if (pcp->desc.sem == PM_SEM_DISCRETE) { if (icp->t_prior >= 0) memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(__int64_t)); else ok = 0; } else if (pcp->desc.sem == PM_SEM_INSTANT) { if (icp->t_prior >= 0 && icp->t_next >= 0) memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(__int64_t)); else ok = 0; } else { /* assume COUNTER */ if (icp->t_prior >= 0 && icp->t_next >= 0) { pmAtomValue av; void *avp_prior = (void *)icp->v_prior.pval->vbuf; void *avp_next = (void *)icp->v_next.pval->vbuf; if (pcp->desc.type == PM_TYPE_64) { __int64_t ll_prior; __int64_t ll_next; memcpy((void *)&av.ll, avp_prior, sizeof(av.ll)); ll_prior = av.ll; memcpy((void *)&av.ll, avp_next, sizeof(av.ll)); ll_next = av.ll; if (ll_next >= ll_prior || dowrap == 0) av.ll = ll_next - ll_prior; else /* not monotonic increasing and want wrap */ av.ll = (__int64_t)(ULONGLONG_MAX - ll_prior + 1 + ll_next); av.ll = (__int64_t)(0.5 + (double)ll_prior + (t_req - icp->t_prior) * (double)av.ll / (icp->t_next - icp->t_prior)); memcpy((void *)vp->vbuf, (void *)&av.ll, sizeof(av.ll)); } else { __int64_t ull_prior; __int64_t ull_next; memcpy((void *)&av.ull, avp_prior, sizeof(av.ull)); ull_prior = av.ull; memcpy((void *)&av.ull, avp_next, sizeof(av.ull)); ull_next = av.ull; if (ull_next >= ull_prior) { av.ull = ull_next - ull_prior; #if !defined(HAVE_CAST_U64_DOUBLE) { double tmp; if (SIGN_64_MASK & av.ull) tmp = (double)(__int64_t)(av.ull & (~SIGN_64_MASK)) + (__uint64_t)SIGN_64_MASK; else tmp = (double)(__int64_t)av.ull; av.ull = (__uint64_t)(0.5 + (double)ull_prior + (t_req - icp->t_prior) * tmp / (icp->t_next - icp->t_prior)); } #else av.ull = (__uint64_t)(0.5 + (double)ull_prior + (t_req - icp->t_prior) * (double)av.ull / (icp->t_next - icp->t_prior)); #endif } else { /* not monotonic increasing */ if (dowrap) { av.ull = ULONGLONG_MAX - ull_prior + 1 + ull_next; #if !defined(HAVE_CAST_U64_DOUBLE) { double tmp; if (SIGN_64_MASK & av.ull) tmp = (double)(__int64_t)(av.ull & (~SIGN_64_MASK)) + (__uint64_t)SIGN_64_MASK; else tmp = (double)(__int64_t)av.ull; av.ull = (__uint64_t)(0.5 + (double)ull_prior + (t_req - icp->t_prior) * tmp / (icp->t_next - icp->t_prior)); } #else av.ull = (__uint64_t)(0.5 + (double)ull_prior + (t_req - icp->t_prior) * (double)av.ull / (icp->t_next - icp->t_prior)); #endif } else { __uint64_t tmp; tmp = ull_prior - ull_next; #if !defined(HAVE_CAST_U64_DOUBLE) { double xtmp; if (SIGN_64_MASK & av.ull) xtmp = (double)(__int64_t)(tmp & (~SIGN_64_MASK)) + (__uint64_t)SIGN_64_MASK; else xtmp = (double)(__int64_t)tmp; av.ull = (__uint64_t)(0.5 + (double)ull_prior - (t_req - icp->t_prior) * xtmp / (icp->t_next - icp->t_prior)); } #else av.ull = (__uint64_t)(0.5 + (double)ull_prior - (t_req - icp->t_prior) * (double)tmp / (icp->t_next - icp->t_prior)); #endif } } memcpy((void *)vp->vbuf, (void *)&av.ull, sizeof(av.ull)); } } else ok = 0; } } if (!ok) { i--; free(vp); } } else if (pcp->desc.type == PM_TYPE_DOUBLE) { int need; pmValueBlock *vp; int ok = 1; need = PM_VAL_HDR_SIZE + sizeof(double); if ((vp = (pmValueBlock *)malloc(need)) == NULL) { sts = -oserror(); goto bad_alloc; } vp->vlen = need; vp->vtype = PM_TYPE_DOUBLE; rp->vset[j]->valfmt = PM_VAL_DPTR; rp->vset[j]->vlist[i++].value.pval = vp; if (icp->t_prior == t_req) memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(double)); else if (icp->t_next == t_req) memcpy((void *)vp->vbuf, (void *)icp->v_next.pval->vbuf, sizeof(double)); else { if (pcp->desc.sem == PM_SEM_DISCRETE) { if (icp->t_prior >= 0) memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(double)); else ok = 0; } else if (pcp->desc.sem == PM_SEM_INSTANT) { if (icp->t_prior >= 0 && icp->t_next >= 0) memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(double)); else ok = 0; } else { /* assume COUNTER */ if (icp->t_prior >= 0 && icp->t_next >= 0) { pmAtomValue av; void *avp_prior = (void *)icp->v_prior.pval->vbuf; void *avp_next = (void *)icp->v_next.pval->vbuf; double d_prior; double d_next; memcpy((void *)&av.d, avp_prior, sizeof(av.d)); d_prior = av.d; memcpy((void *)&av.d, avp_next, sizeof(av.d)); d_next = av.d; av.d = d_prior + (t_req - icp->t_prior) * (d_next - d_prior) / (icp->t_next - icp->t_prior); memcpy((void *)vp->vbuf, (void *)&av.d, sizeof(av.d)); } else ok = 0; } } if (!ok) { i--; free(vp); } } else if ((pcp->desc.type == PM_TYPE_AGGREGATE || pcp->desc.type == PM_TYPE_EVENT || pcp->desc.type == PM_TYPE_STRING) && icp->t_prior >= 0) { int need; pmValueBlock *vp; need = icp->v_prior.pval->vlen; vp = (pmValueBlock *)malloc(need); if (vp == NULL) { sts = -oserror(); goto bad_alloc; } rp->vset[j]->valfmt = PM_VAL_DPTR; rp->vset[j]->vlist[i++].value.pval = vp; memcpy((void *)vp, icp->v_prior.pval, need); } else { /* unknown type - skip it, else junk in result */ i--; } } } } *result = rp; sts = 0; all_done: pmXTBdeltaToTimeval(ctxp->c_delta, ctxp->c_mode, &delta_tv); ctxp->c_origin.tv_sec += delta_tv.tv_sec; ctxp->c_origin.tv_usec += delta_tv.tv_usec; while (ctxp->c_origin.tv_usec > 1000000) { ctxp->c_origin.tv_sec++; ctxp->c_origin.tv_usec -= 1000000; } while (ctxp->c_origin.tv_usec < 0) { ctxp->c_origin.tv_sec--; ctxp->c_origin.tv_usec += 1000000; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INTERP) { fprintf(stderr, "__pmLogFetchInterp: log reads: forward %ld", nr[PM_MODE_FORW]); if (nr_cache[PM_MODE_FORW]) fprintf(stderr, " (+%ld cached)", nr_cache[PM_MODE_FORW]); fprintf(stderr, " backwards %ld", nr[PM_MODE_BACK]); if (nr_cache[PM_MODE_BACK]) fprintf(stderr, " (+%ld cached)", nr_cache[PM_MODE_BACK]); fprintf(stderr, "\n"); } #endif return sts; bad_alloc: /* * leaks a little (vlist[] stuff) ... but does not really matter at * this point, chance of anything good happening from here on are * pretty remote */ rp->vset[j]->numval = i; while (++j < numpmid) rp->vset[j]->numval = 0; pmFreeResult(rp); return sts; } void __pmLogResetInterp(__pmContext *ctxp) { __pmHashCtl *hcp = &ctxp->c_archctl->ac_pmid_hc; double t_req; __pmHashNode *hp; int k; pmidcntl_t *pcp; instcntl_t *icp; if (hcp->hsize == 0) return; t_req = __pmTimevalSub(&ctxp->c_origin, &ctxp->c_archctl->ac_log->l_label.ill_start); for (k = 0; k < hcp->hsize; k++) { for (hp = hcp->hash[k]; hp != NULL; hp = hp->next) { pcp = (pmidcntl_t *)hp->data; for (icp = pcp->first; icp != NULL; icp = icp->next) { if (icp->t_prior > t_req || icp->t_next < t_req) { icp->t_prior = icp->t_next = -1; if (pcp->valfmt != PM_VAL_INSITU) { if (icp->v_prior.pval != NULL) __pmUnpinPDUBuf((void *)icp->v_prior.pval); if (icp->v_next.pval != NULL) __pmUnpinPDUBuf((void *)icp->v_next.pval); } icp->v_prior.pval = icp->v_next.pval = NULL; } } } } } pcp-3.8.12ubuntu1/src/libpcp/src/p_lcontrol.c0000664000000000000000000001352212272262501015753 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "internal.h" /* * PDU for __pmControlLogging request (PDU_LOG_CONTROL) */ typedef struct { pmID v_pmid; int v_numval; /* no. of vlist els to follow */ __pmValue_PDU v_list[1]; /* one or more */ } vlist_t; typedef struct { __pmPDUHdr c_hdr; int c_control; /* mandatory or advisory */ int c_state; /* off, maybe or on */ int c_delta; /* requested logging interval (msec) */ int c_numpmid; /* no. of vlist_ts to follow */ __pmPDU c_data[1]; /* one or more */ } control_req_t; int __pmSendLogControl(int fd, const pmResult *request, int control, int state, int delta) { pmValueSet *vsp; int i; int j; control_req_t *pp; int need; vlist_t *vp; int sts; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) __pmDumpResult(stderr, request); #endif /* advisory+maybe logging and retrospective logging (delta < 0) are not *permitted */ if (delta < 0 || (control == PM_LOG_ADVISORY && state == PM_LOG_MAYBE)) return -EINVAL; /* PDU header, control, state and count of metrics */ need = sizeof(control_req_t) - sizeof(pp->c_data); for (i = 0; i < request->numpmid; i++) { /* plus PMID and count of values */ if (request->vset[i]->numval > 0) need += sizeof(vlist_t) + (request->vset[i]->numval - 1)*sizeof(__pmValue_PDU); else need += sizeof(vlist_t) - sizeof(__pmValue_PDU); } if ((pp = (control_req_t *)__pmFindPDUBuf(need)) == NULL) return -oserror(); pp->c_hdr.len = need; pp->c_hdr.type = PDU_LOG_CONTROL; pp->c_hdr.from = FROM_ANON; /* context does not matter here */ pp->c_control = htonl(control); pp->c_state = htonl(state); pp->c_delta = htonl(delta); pp->c_numpmid = htonl(request->numpmid); vp = (vlist_t *)pp->c_data; for (i = 0; i < request->numpmid; i++) { vsp = request->vset[i]; vp->v_pmid = __htonpmID(vsp->pmid); vp->v_numval = htonl(vsp->numval); /* * Note: spec says only PM_VAL_INSITU can be used ... we don't * check vsp->valfmt -- this is OK, because the "value" is never * looked at! */ for (j = 0; j < vsp->numval; j++) { vp->v_list[j].inst = htonl(vsp->vlist[j].inst); vp->v_list[j].value.lval = htonl(vsp->vlist[j].value.lval); } if (vsp->numval > 0) vp = (vlist_t *)((__psint_t)vp + sizeof(*vp) + (vsp->numval-1)*sizeof(__pmValue_PDU)); else vp = (vlist_t *)((__psint_t)vp + sizeof(*vp) - sizeof(__pmValue_PDU)); } sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmDecodeLogControl(const __pmPDU *pdubuf, pmResult **request, int *control, int *state, int *delta) { int sts; int i; int j; int nv; const control_req_t *pp; char *pduend; int numpmid; size_t need; pmResult *req; pmValueSet *vsp; vlist_t *vp; pp = (const control_req_t *)pdubuf; pduend = (char *)pdubuf + pp->c_hdr.len; if (pduend - (char *)pdubuf < sizeof(control_req_t)) return PM_ERR_IPC; *control = ntohl(pp->c_control); *state = ntohl(pp->c_state); *delta = ntohl(pp->c_delta); numpmid = ntohl(pp->c_numpmid); vp = (vlist_t *)pp->c_data; if (numpmid < 0 || numpmid > pp->c_hdr.len) return PM_ERR_IPC; if (numpmid >= (INT_MAX - sizeof(pmResult)) / sizeof(pmValueSet *)) return PM_ERR_IPC; need = sizeof(pmResult) + (numpmid - 1) * sizeof(pmValueSet *); if ((req = (pmResult *)malloc(need)) == NULL) { __pmNoMem("__pmDecodeLogControl.req", need, PM_RECOV_ERR); return -oserror(); } req->numpmid = numpmid; sts = PM_ERR_IPC; for (i = 0; i < numpmid; i++) { /* check that numval field is within the input buffer */ if (pduend - (char *)vp < sizeof(vlist_t) - sizeof(__pmValue_PDU)) goto corrupt; nv = (int)ntohl(vp->v_numval); if (nv > pp->c_hdr.len) goto corrupt; if (nv <= 0) { need = sizeof(pmValueSet) - sizeof(pmValue); /* check that pointer cannot move beyond input buffer end */ if (pduend - (char *)vp < sizeof(vlist_t) - sizeof(__pmValue_PDU)) goto corrupt; } else { /* check that dynamic allocation argument will not wrap */ if (nv >= (INT_MAX - sizeof(pmValueSet)) / sizeof(pmValue)) goto corrupt; need = sizeof(pmValueSet) + ((nv - 1) * sizeof(pmValue)); /* check that pointer cannot move beyond input buffer end */ if (nv >= (INT_MAX - sizeof(vlist_t)) / sizeof(__pmValue_PDU)) goto corrupt; if (pduend - (char *)vp < sizeof(vlist_t) + ((nv - 1) * sizeof(__pmValue_PDU))) goto corrupt; } if ((vsp = (pmValueSet *)malloc(need)) == NULL) { __pmNoMem("__pmDecodeLogControl.vsp", need, PM_RECOV_ERR); sts = -oserror(); i--; goto corrupt; } req->vset[i] = vsp; vsp->pmid = __ntohpmID(vp->v_pmid); vsp->valfmt = PM_VAL_INSITU; vsp->numval = nv; for (j = 0; j < nv; j++) { vsp->vlist[j].inst = ntohl(vp->v_list[j].inst); vsp->vlist[j].value.lval = ntohl(vp->v_list[j].value.lval); } if (nv > 0) vp = (vlist_t *)((__psint_t)vp + sizeof(*vp) + (nv - 1)*sizeof(__pmValue_PDU)); else vp = (vlist_t *)((__psint_t)vp + sizeof(*vp) - sizeof(__pmValue_PDU)); } *request = req; return 0; corrupt: while (i) free(req->vset[i--]); free(req); return sts; } pcp-3.8.12ubuntu1/src/libpcp/src/checksum.c0000664000000000000000000000167312272262501015406 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ /* * __pmCheckSum(FILE *f) - algorithm stolen from sum(1), changed from 16-bit * to 32-bit */ #include "pmapi.h" #include "impl.h" __int32_t __pmCheckSum(FILE *f) { __int32_t sum = 0x19700520; int c; while ((c = fgetc(f)) != EOF) { if (sum & 1) sum = (sum >> 1) + 0x80000000; else sum >>= 1; sum += c; } return sum; } pcp-3.8.12ubuntu1/src/libpcp/src/events.c0000664000000000000000000003362012272262501015105 0ustar /* * Unpack an array of event records * Free space from unpack * * Copyright (c) 2010 Ken McDonell. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe notes * * The initialization of pmid_flags and pmid_missed both have a potential * race, but there are no side-effects and the end result will be the * same, so no locking is required. * */ #include #include "pmapi.h" #include "impl.h" #include "fault.h" /* * Dump a packed array of event records ... need to be paranoid * with checking here, because typically called after * __pmCheckEventRecords() finds an error. * Process the idx'th instance. */ void __pmDumpEventRecords(FILE *f, pmValueSet *vsp, int idx) { pmEventArray *eap; char *base; char *valend; /* end of the value */ pmEventRecord *erp; pmEventParameter *epp; char *vbuf; int r; /* records */ int p; /* parameters in a record ... */ pmAtomValue atom; char strbuf[20]; fprintf(f, "Event Records Dump ...\n"); fprintf(f, "PMID: %s numval: %d", pmIDStr_r(vsp->pmid, strbuf, sizeof(strbuf)), vsp->numval); if (vsp->numval <= 0) { fprintf(f, "\nError: bad numval\n"); return; } fprintf(f, " valfmt: %d", vsp->valfmt); if (vsp->valfmt != PM_VAL_DPTR && vsp->valfmt != PM_VAL_SPTR) { fprintf(f, "\nError: bad valfmt\n"); return; } if (vsp->vlist[idx].inst != PM_IN_NULL) fprintf(f, " inst: %d", vsp->vlist[idx].inst); eap = (pmEventArray *)vsp->vlist[idx].value.pval; fprintf(f, " vtype: %s vlen: %d\n", pmTypeStr_r(eap->ea_type, strbuf, sizeof(strbuf)), eap->ea_len); if (eap->ea_type != PM_TYPE_EVENT) { fprintf(f, "Error: bad vtype\n"); return; } if (eap->ea_len < PM_VAL_HDR_SIZE + sizeof(eap->ea_nrecords)) { fprintf(f, "Error: bad len (smaller than minimum size %lu)\n", (unsigned long)PM_VAL_HDR_SIZE + sizeof(eap->ea_nrecords)); return; } fprintf(f, "nrecords: %d\n", eap->ea_nrecords); if (eap->ea_nrecords < 0) { fprintf(f, "Error: bad nrecords\n"); return; } if (eap->ea_nrecords == 0) { fprintf(f, "Warning: no event records\n"); return; } /* have something plausible to report in the array buffer ... */ base = (char *)&eap->ea_record[0]; valend = &((char *)eap)[eap->ea_len]; for (r = 0; r < eap->ea_nrecords; r++) { fprintf(f, "Event Record [%d]", r); if (base + sizeof(erp->er_timestamp) + sizeof(erp->er_flags) + sizeof(erp->er_nparams) > valend) { fprintf(f, " Error: buffer overflow\n"); return; } erp = (pmEventRecord *)base; if (erp->er_flags != 0) fprintf(f, " flags=%x", erp->er_flags); base += sizeof(erp->er_timestamp) + sizeof(erp->er_flags) + sizeof(erp->er_nparams); if (erp->er_flags & PM_EVENT_FLAG_MISSED) { fprintf(f, "\n ==> %d missed records", erp->er_nparams); if (erp->er_flags != PM_EVENT_FLAG_MISSED) fprintf(f, " (Warning: extra flags %x ignored)", erp->er_flags & (~PM_EVENT_FLAG_MISSED)); fputc('\n', f); continue; } fprintf(f, " with %d parameters\n", erp->er_nparams); for (p = 0; p < erp->er_nparams; p++) { char *name; fprintf(f, " Parameter [%d]:", p); if (base + sizeof(pmEventParameter) > valend) { fprintf(f, " Error: buffer overflow\n"); return; } epp = (pmEventParameter *)base; if (base + sizeof(epp->ep_pmid) + PM_PDU_SIZE_BYTES(epp->ep_len) > valend) { fprintf(f, " Error: buffer overflow\n"); return; } if (pmNameID(epp->ep_pmid, &name) == 0) { fprintf(f, " %s", name); free(name); } else fprintf(f, " %s", pmIDStr_r(epp->ep_pmid, strbuf, sizeof(strbuf))); vbuf = (char *)epp + sizeof(epp->ep_pmid) + sizeof(int); switch (epp->ep_type) { case PM_TYPE_32: fprintf(f, " = %i", *((__int32_t *)vbuf)); break; case PM_TYPE_U32: fprintf(f, " = %u", *((__uint32_t *)vbuf)); break; case PM_TYPE_64: memcpy((void *)&atom.ll, (void *)vbuf, sizeof(atom.ll)); fprintf(f, " = %"PRIi64, atom.ll); break; case PM_TYPE_U64: memcpy((void *)&atom.ull, (void *)vbuf, sizeof(atom.ull)); fprintf(f, " = %"PRIu64, atom.ull); break; case PM_TYPE_FLOAT: memcpy((void *)&atom.f, (void *)vbuf, sizeof(atom.f)); fprintf(f, " = %.8g", (double)atom.f); break; case PM_TYPE_DOUBLE: memcpy((void *)&atom.d, (void *)vbuf, sizeof(atom.d)); fprintf(f, " = %.16g", atom.d); break; case PM_TYPE_STRING: fprintf(f, " = \"%*.*s\"", epp->ep_len-PM_VAL_HDR_SIZE, epp->ep_len-PM_VAL_HDR_SIZE, vbuf); break; case PM_TYPE_AGGREGATE: case PM_TYPE_AGGREGATE_STATIC: fprintf(f, " = [%08x...]", ((__uint32_t *)vbuf)[0]); break; default: fprintf(f, " : bad type %s", pmTypeStr_r(epp->ep_type, strbuf, sizeof(strbuf))); } fputc('\n', f); base += sizeof(epp->ep_pmid) + PM_PDU_SIZE_BYTES(epp->ep_len); } } } /* * Integrity checker for a packed array of event records, check * the idx'th instance. */ int __pmCheckEventRecords(pmValueSet *vsp, int idx) { pmEventArray *eap; char *base; char *valend; /* end of the value */ pmEventRecord *erp; pmEventParameter *epp; int r; /* records */ int p; /* parameters in a record ... */ int nparams; if (vsp->numval < 1) return vsp->numval; if (vsp->valfmt != PM_VAL_DPTR && vsp->valfmt != PM_VAL_SPTR) return PM_ERR_CONV; eap = (pmEventArray *)vsp->vlist[idx].value.pval; if (eap->ea_type != PM_TYPE_EVENT) return PM_ERR_TYPE; if (eap->ea_len < PM_VAL_HDR_SIZE + sizeof(eap->ea_nrecords)) return PM_ERR_TOOSMALL; if (eap->ea_nrecords < 0) return PM_ERR_TOOSMALL; base = (char *)&eap->ea_record[0]; valend = &((char *)eap)[eap->ea_len]; /* header seems OK, onto each event record */ for (r = 0; r < eap->ea_nrecords; r++) { if (base + sizeof(erp->er_timestamp) + sizeof(erp->er_flags) + sizeof(erp->er_nparams) > valend) return PM_ERR_TOOBIG; erp = (pmEventRecord *)base; base += sizeof(erp->er_timestamp) + sizeof(erp->er_flags) + sizeof(erp->er_nparams); if (erp->er_flags & PM_EVENT_FLAG_MISSED) { if (erp->er_flags == PM_EVENT_FLAG_MISSED) nparams = 0; else { /* * not legal to have other flag bits set when * PM_EVENT_FLAG_MISSED is set */ return PM_ERR_CONV; } } else nparams = erp->er_nparams; for (p = 0; p < nparams; p++) { if (base + sizeof(pmEventParameter) > valend) return PM_ERR_TOOBIG; epp = (pmEventParameter *)base; if (base + sizeof(epp->ep_pmid) + PM_PDU_SIZE_BYTES(epp->ep_len) > valend) return PM_ERR_TOOBIG; base += sizeof(epp->ep_pmid) + PM_PDU_SIZE_BYTES(epp->ep_len); } } return 0; } /* * Process the idx'th instance of an event record metric value * and unpack the array of event records into a pmResult. */ int pmUnpackEventRecords(pmValueSet *vsp, int idx, pmResult ***rap) { pmEventArray *eap; pmEventRecord *erp; pmEventParameter *epp; pmResult *rp; char *base; char *vbuf; int r; /* records */ int p; /* parameters in a record ... */ int numpmid; /* metrics in a pmResult */ int need; int want; int vsize; int sts; static int first = 1; static char *name_flags = "event.flags"; static char *name_missed = "event.missed"; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (first) { PM_FAULT_POINT("libpcp/" __FILE__ ":5", PM_FAULT_PMAPI); if (first == 1) { sts = __pmRegisterAnon(name_flags, PM_TYPE_U32); if (sts < 0) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "pmUnpackEventRecords: Warning: failed to register %s: %s\n", name_flags, pmErrStr_r(sts, errmsg, sizeof(errmsg))); PM_UNLOCK(__pmLock_libpcp); return sts; } first = 2; } PM_FAULT_POINT("libpcp/" __FILE__ ":6", PM_FAULT_PMAPI); sts = __pmRegisterAnon(name_missed, PM_TYPE_U32); if (sts < 0) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "pmUnpackEventRecords: Warning: failed to register %s: %s\n", name_missed, pmErrStr_r(sts, errmsg, sizeof(errmsg))); PM_UNLOCK(__pmLock_libpcp); return sts; } first = 0; } PM_UNLOCK(__pmLock_libpcp); sts = __pmCheckEventRecords(vsp, idx); if (sts < 0) { __pmDumpEventRecords(stderr, vsp, idx); return sts; } eap = (pmEventArray *)vsp->vlist[idx].value.pval; if (eap->ea_nrecords == 0) { *rap = NULL; return 0; } /* * allocate one more than needed as a NULL sentinel to be used * in pmFreeEventResult */ PM_FAULT_POINT("libpcp/" __FILE__ ":1", PM_FAULT_ALLOC); *rap = (pmResult **)malloc((eap->ea_nrecords+1) * sizeof(pmResult *)); if (*rap == NULL) { return -oserror(); } base = (char *)&eap->ea_record[0]; /* walk packed event record array */ for (r = 0; r < eap->ea_nrecords; r++) { rp = NULL; erp = (pmEventRecord *)base; /* * er_flags optionally unpacked into an extra anon events.flags metric * before all the event record parameters, and for PM_EVENT_FLAG_MISSED * er_nparams is a count of the missed records. */ if (erp->er_flags == 0) numpmid = erp->er_nparams; else if (erp->er_flags & PM_EVENT_FLAG_MISSED) numpmid = 2; else numpmid = erp->er_nparams + 1; need = sizeof(pmResult) + (numpmid-1)*sizeof(pmValueSet *); PM_FAULT_POINT("libpcp/" __FILE__ ":4", PM_FAULT_ALLOC); rp = (pmResult *)malloc(need); if (rp == NULL) { sts = -oserror(); r--; goto bail; } (*rap)[r] = rp; rp->timestamp.tv_sec = erp->er_timestamp.tv_sec; rp->timestamp.tv_usec = erp->er_timestamp.tv_usec; rp->numpmid = numpmid; base += sizeof(erp->er_timestamp) + sizeof(erp->er_flags) + sizeof(erp->er_nparams); for (p = 0; p < numpmid; p++) { /* always have numval == 1 */ PM_FAULT_POINT("libpcp/" __FILE__ ":2", PM_FAULT_ALLOC); rp->vset[p] = (pmValueSet *)malloc(sizeof(pmValueSet)); if (rp->vset[p] == NULL) { rp->numpmid = p; sts = -oserror(); goto bail; } if (p == 0 && erp->er_flags != 0) { /* rewrite non-zero er_flags as the anon event.flags metric */ static pmID pmid_flags = 0; int lsts; if (pmid_flags == 0) { lsts = pmLookupName(1, &name_flags, &pmid_flags); if (lsts < 0) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "pmUnpackEventRecords: Warning: failed to get PMID for %s: %s\n", name_flags, pmErrStr_r(lsts, errmsg, sizeof(errmsg))); __pmid_int(&pmid_flags)->item = 1; } } rp->vset[p]->pmid = pmid_flags; rp->vset[p]->numval = 1; rp->vset[p]->vlist[0].inst = PM_IN_NULL; rp->vset[p]->valfmt = PM_VAL_INSITU; rp->vset[p]->vlist[0].value.lval = erp->er_flags; continue; } if (p == 1 && erp->er_flags & PM_EVENT_FLAG_MISSED) { /* rewrite missed count as the anon event.missed metric */ static pmID pmid_missed = 0; int lsts; if (pmid_missed == 0) { lsts = pmLookupName(1, &name_missed, &pmid_missed); if (lsts < 0) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "pmUnpackEventRecords: Warning: failed to get PMID for %s: %s\n", name_missed, pmErrStr_r(lsts, errmsg, sizeof(errmsg))); __pmid_int(&pmid_missed)->item = 1; } } rp->vset[p]->pmid = pmid_missed; rp->vset[p]->numval = 1; rp->vset[p]->vlist[0].inst = PM_IN_NULL; rp->vset[p]->valfmt = PM_VAL_INSITU; rp->vset[p]->vlist[0].value.lval = erp->er_nparams; continue; } epp = (pmEventParameter *)base; rp->vset[p]->pmid = epp->ep_pmid; rp->vset[p]->numval = 1; rp->vset[p]->vlist[0].inst = PM_IN_NULL; vbuf = (char *)epp + sizeof(epp->ep_pmid) + sizeof(int); switch (epp->ep_type) { case PM_TYPE_32: case PM_TYPE_U32: rp->vset[p]->valfmt = PM_VAL_INSITU; memcpy((void *)&rp->vset[p]->vlist[0].value.lval, (void *)vbuf, sizeof(__int32_t)); goto done; case PM_TYPE_64: case PM_TYPE_U64: vsize = sizeof(__int64_t); break; case PM_TYPE_FLOAT: vsize = sizeof(float); break; case PM_TYPE_DOUBLE: vsize = sizeof(double); break; case PM_TYPE_AGGREGATE: case PM_TYPE_STRING: case PM_TYPE_AGGREGATE_STATIC: vsize = epp->ep_len - PM_VAL_HDR_SIZE; break; case PM_TYPE_EVENT: /* no nesting! */ default: while (p >= 0) { free(rp->vset[p]); p--; } free(rp); r--; sts = PM_ERR_TYPE; goto bail; } need = vsize + PM_VAL_HDR_SIZE; want = need; if (want < sizeof(pmValueBlock)) want = sizeof(pmValueBlock); PM_FAULT_POINT("libpcp/" __FILE__ ":3", PM_FAULT_ALLOC); rp->vset[p]->vlist[0].value.pval = (pmValueBlock *)malloc(want); if (rp->vset[p]->vlist[0].value.pval == NULL) { sts = -oserror(); rp->vset[p]->valfmt = PM_VAL_INSITU; goto bail; } rp->vset[p]->vlist[0].value.pval->vlen = need; rp->vset[p]->vlist[0].value.pval->vtype = epp->ep_type; memcpy((void *)rp->vset[p]->vlist[0].value.pval->vbuf, (void *)vbuf, vsize); rp->vset[p]->valfmt = PM_VAL_DPTR; done: base += sizeof(epp->ep_pmid) + PM_PDU_SIZE_BYTES(epp->ep_len); } } (*rap)[r] = NULL; /* sentinel */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_FETCH) { fprintf(stderr, "pmUnpackEventRecords returns ...\n"); for (r = 0; r < eap->ea_nrecords; r++) { fprintf(stderr, "pmResult[%d]\n", r); __pmDumpResult(stderr, (*rap)[r]); } } #endif return eap->ea_nrecords; bail: while (r >= 0) { if ((*rap)[r] != NULL) pmFreeResult((*rap)[r]); r--; } free(*rap); *rap = NULL; return sts; } void pmFreeEventResult(pmResult **rset) { int r; if (rset == NULL) return; for (r = 0; rset[r] != NULL; r++) pmFreeResult(rset[r]); free(rset); } pcp-3.8.12ubuntu1/src/libpcp/src/logutil.c0000664000000000000000000016746012272262501015272 0ustar /* * Copyright (c) 1995-2002,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe notes: * * __pmLogReads is a diagnostic counter that is maintained with * non-atomic updates ... we've decided that it is acceptable for the * value to be subject to possible (but unlikely) missed updates */ #include #include #include #include "pmapi.h" #include "impl.h" #include "internal.h" #if defined(HAVE_SYS_WAIT_H) #include #endif INTERN int __pmLogReads = 0; /* * Suffixes and associated compresssion application for compressed filenames. * These can appear _after_ the volume number in the name of a file for an * archive metric log file, e.g. /var/log/pmlogger/myhost/20101219.0.bz2 */ #define USE_NONE 0 #define USE_BZIP2 1 #define USE_GZIP 2 static const struct { const char *suff; const int appl; } compress_ctl[] = { { ".bz2", USE_BZIP2 }, { ".bz", USE_BZIP2 }, { ".gz", USE_GZIP }, { ".Z", USE_GZIP }, { ".z", USE_GZIP } }; static const int ncompress = sizeof(compress_ctl) / sizeof(compress_ctl[0]); /* * first two fields are made to look like a pmValueSet when no values are * present ... used to populate the pmValueSet in a pmResult when values * for particular metrics are not available from this log record. */ typedef struct { pmID pc_pmid; int pc_numval; /* MUST be 0 */ /* value control for interpolation */ } pmid_ctl; /* * Hash control for requested metrics, used to construct 'No values' * result when the corresponding metric is requested but there is * no values available in the pmResult * * Note, this hash table is global across all contexts. */ static __pmHashCtl pc_hc; #ifdef PCP_DEBUG static void dumpbuf(int nch, __pmPDU *pb) { int i, j; nch /= sizeof(__pmPDU); fprintf(stderr, "%03d: ", 0); for (j = 0, i = 0; j < nch; j++) { if (i == 8) { fprintf(stderr, "\n%03d: ", j); i = 0; } fprintf(stderr, "%8x ", pb[j]); i++; } fputc('\n', stderr); } #endif int __pmLogChkLabel(__pmLogCtl *lcp, FILE *f, __pmLogLabel *lp, int vol) { int len; int version = UNKNOWN_VERSION; int xpectlen = sizeof(__pmLogLabel) + 2 * sizeof(len); int n; if (vol >= 0 && vol < lcp->l_numseen && lcp->l_seen[vol]) { /* FastPath, cached result of previous check for this volume */ fseek(f, (long)(sizeof(__pmLogLabel) + 2*sizeof(int)), SEEK_SET); return 0; } if (vol >= 0 && vol >= lcp->l_numseen) { lcp->l_seen = (int *)realloc(lcp->l_seen, (vol+1)*(int)sizeof(lcp->l_seen[0])); if (lcp->l_seen == NULL) lcp->l_numseen = 0; else { int i; for (i = lcp->l_numseen; i < vol; i++) lcp->l_seen[i] = 0; lcp->l_numseen = vol+1; } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "__pmLogChkLabel: fd=%d vol=%d", fileno(f), vol); #endif fseek(f, (long)0, SEEK_SET); n = (int)fread(&len, 1, sizeof(len), f); len = ntohl(len); if (n != sizeof(len) || len != xpectlen) { if (feof(f)) { clearerr(f); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " file is empty\n"); #endif return PM_ERR_NODATA; } else { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " header read -> %d (expect %d) or bad header len=%d (expected %d)\n", n, (int)sizeof(len), len, xpectlen); #endif if (ferror(f)) { clearerr(f); return -oserror(); } else return PM_ERR_LABEL; } } if ((n = (int)fread(lp, 1, sizeof(__pmLogLabel), f)) != sizeof(__pmLogLabel)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " bad label len=%d: expected %d\n", n, (int)sizeof(__pmLogLabel)); #endif if (ferror(f)) { clearerr(f); return -oserror(); } else return PM_ERR_LABEL; } else { /* swab internal log label */ lp->ill_magic = ntohl(lp->ill_magic); lp->ill_pid = ntohl(lp->ill_pid); lp->ill_start.tv_sec = ntohl(lp->ill_start.tv_sec); lp->ill_start.tv_usec = ntohl(lp->ill_start.tv_usec); lp->ill_vol = ntohl(lp->ill_vol); } n = (int)fread(&len, 1, sizeof(len), f); len = ntohl(len); if (n != sizeof(len) || len != xpectlen) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " trailer read -> %d (expect %d) or bad trailer len=%d (expected %d)\n", n, (int)sizeof(len), len, xpectlen); #endif if (ferror(f)) { clearerr(f); return -oserror(); } else return PM_ERR_LABEL; } version = lp->ill_magic & 0xff; if ((lp->ill_magic & 0xffffff00) != PM_LOG_MAGIC || (version != PM_LOG_VERS02) || lp->ill_vol != vol) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { if ((lp->ill_magic & 0xffffff00) != PM_LOG_MAGIC) fprintf(stderr, " label magic 0x%x not 0x%x as expected", (lp->ill_magic & 0xffffff00), PM_LOG_MAGIC); if (version != PM_LOG_VERS02) fprintf(stderr, " label version %d not supported", version); if (lp->ill_vol != vol) fprintf(stderr, " label volume %d not %d as expected", lp->ill_vol, vol); fputc('\n', stderr); } #endif return PM_ERR_LABEL; } else { if (__pmSetVersionIPC(fileno(f), version) < 0) return -oserror(); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " [magic=%8x version=%d vol=%d pid=%d host=%s]\n", lp->ill_magic, version, lp->ill_vol, lp->ill_pid, lp->ill_hostname); #endif } if (vol >= 0 && vol < lcp->l_numseen) lcp->l_seen[vol] = 1; return version; } static int popen_uncompress(const char *cmd, const char *fname, const char *suffix, int fd) { char pipecmd[2*MAXPATHLEN+2]; char buffer[4096]; FILE *finp; ssize_t bytes; int sts, infd; snprintf(pipecmd, sizeof(pipecmd), "%s %s%s", cmd, fname, suffix); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "__pmLogOpen: uncompress using: %s\n", pipecmd); #endif if ((finp = popen(pipecmd, "r")) == NULL) return -1; infd = fileno(finp); while ((bytes = read(infd, buffer, sizeof(buffer))) > 0) { if (write(fd, buffer, bytes) != bytes) { bytes = -1; break; } } if ((sts = pclose(finp)) != 0) return sts; return (bytes == 0) ? 0 : -1; } static FILE * fopen_compress(const char *fname) { int sts; int fd; int i; char *cmd; char *msg; FILE *fp; char tmpname[MAXPATHLEN]; mode_t cur_umask; for (i = 0; i < ncompress; i++) { snprintf(tmpname, sizeof(tmpname), "%s%s", fname, compress_ctl[i].suff); if (access(tmpname, R_OK) == 0) { break; } } if (i == ncompress) { /* end up here if it does not look like a compressed file */ return NULL; } if (compress_ctl[i].appl == USE_BZIP2) cmd = "bzip2 -dc"; else if (compress_ctl[i].appl == USE_GZIP) cmd = "gzip -dc"; else { /* botch in compress_ctl[] ... should not happen */ return NULL; } cur_umask = umask(S_IXUSR | S_IRWXG | S_IRWXO); #if HAVE_MKSTEMP snprintf(tmpname, sizeof(tmpname), "%s/XXXXXX", pmGetConfig("PCP_TMPFILE_DIR")); msg = tmpname; fd = mkstemp(tmpname); #else if ((msg = tmpnam(NULL)) == NULL) { umask(cur_umask); return NULL; } fd = open(msg, O_RDWR|O_CREAT|O_EXCL, 0600); #endif /* * unlink temporary file to avoid namespace pollution and allow O/S * space cleanup on last close */ unlink(msg); umask(cur_umask); if (fd < 0) { sts = oserror(); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "__pmLogOpen: temp file create failed: %s\n", osstrerror()); #endif setoserror(sts); return NULL; } sts = popen_uncompress(cmd, fname, compress_ctl[i].suff, fd); if (sts == -1) { sts = oserror(); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmLogOpen: uncompress command failed: %s\n", osstrerror_r(errmsg, sizeof(errmsg))); } #endif close(fd); setoserror(sts); return NULL; } if (sts != 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { #if defined(HAVE_SYS_WAIT_H) if (WIFEXITED(sts)) fprintf(stderr, "__pmLogOpen: uncompress failed, exit status: %d\n", WEXITSTATUS(sts)); else if (WIFSIGNALED(sts)) fprintf(stderr, "__pmLogOpen: uncompress failed, signal: %d\n", WTERMSIG(sts)); else #endif fprintf(stderr, "__pmLogOpen: uncompress failed, popen() returns: %d\n", sts); } #endif close(fd); /* not a great error code, but the best we can do */ setoserror(-PM_ERR_LOGREC); return NULL; } if ((fp = fdopen(fd, "r")) == NULL) { sts = oserror(); close(fd); setoserror(sts); return NULL; } /* success */ return fp; } static FILE * _logpeek(__pmLogCtl *lcp, int vol) { int sts; FILE *f; __pmLogLabel label; char fname[MAXPATHLEN]; snprintf(fname, sizeof(fname), "%s.%d", lcp->l_name, vol); if ((f = fopen(fname, "r")) == NULL) { if ((f = fopen_compress(fname)) == NULL) return f; } if ((sts = __pmLogChkLabel(lcp, f, &label, vol)) < 0) { fclose(f); setoserror(sts); return NULL; } return f; } int __pmLogChangeVol(__pmLogCtl *lcp, int vol) { char name[MAXPATHLEN]; int sts; if (lcp->l_curvol == vol) return 0; if (lcp->l_mfp != NULL) { __pmResetIPC(fileno(lcp->l_mfp)); fclose(lcp->l_mfp); } snprintf(name, sizeof(name), "%s.%d", lcp->l_name, vol); if ((lcp->l_mfp = fopen(name, "r")) == NULL) { /* try for a compressed file */ if ((lcp->l_mfp = fopen_compress(name)) == NULL) return -oserror(); } if ((sts = __pmLogChkLabel(lcp, lcp->l_mfp, &lcp->l_label, vol)) < 0) return sts; lcp->l_curvol = vol; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "__pmLogChangeVol: change to volume %d\n", vol); #endif return sts; } int __pmLogLoadIndex(__pmLogCtl *lcp) { int sts = 0; FILE *f = lcp->l_tifp; int n; __pmLogTI *tip; lcp->l_numti = 0; lcp->l_ti = NULL; if (lcp->l_tifp != NULL) { fseek(f, (long)(sizeof(__pmLogLabel) + 2*sizeof(int)), SEEK_SET); for ( ; ; ) { lcp->l_ti = (__pmLogTI *)realloc(lcp->l_ti, (1 + lcp->l_numti) * sizeof(__pmLogTI)); if (lcp->l_ti == NULL) { sts = -oserror(); break; } tip = &lcp->l_ti[lcp->l_numti]; n = (int)fread(tip, 1, sizeof(__pmLogTI), f); if (n != sizeof(__pmLogTI)) { if (feof(f)) { clearerr(f); sts = 0; break; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "__pmLogLoadIndex: bad TI entry len=%d: expected %d\n", n, (int)sizeof(__pmLogTI)); #endif if (ferror(f)) { clearerr(f); sts = -oserror(); break; } else { sts = PM_ERR_LOGREC; break; } } else { /* swab the temporal index record */ tip->ti_stamp.tv_sec = ntohl(tip->ti_stamp.tv_sec); tip->ti_stamp.tv_usec = ntohl(tip->ti_stamp.tv_usec); tip->ti_vol = ntohl(tip->ti_vol); tip->ti_meta = ntohl(tip->ti_meta); tip->ti_log = ntohl(tip->ti_log); } lcp->l_numti++; }/*for*/ }/*not null*/ return sts; } const char * __pmLogName_r(const char *base, int vol, char *buf, int buflen) { switch (vol) { case PM_LOG_VOL_TI: snprintf(buf, buflen, "%s.index", base); break; case PM_LOG_VOL_META: snprintf(buf, buflen, "%s.meta", base); break; default: snprintf(buf, buflen, "%s.%d", base, vol); break; } return buf; } const char * __pmLogName(const char *base, int vol) { static char tbuf[MAXPATHLEN]; return __pmLogName_r(base, vol, tbuf, sizeof(tbuf)); } FILE * __pmLogNewFile(const char *base, int vol) { char fname[MAXPATHLEN]; FILE *f; int save_error; __pmLogName_r(base, vol, fname, sizeof(fname)); if (access(fname, R_OK) != -1) { /* exists and readable ... */ pmprintf("__pmLogNewFile: \"%s\" already exists, not over-written\n", fname); pmflush(); setoserror(EEXIST); return NULL; } if ((f = fopen(fname, "w")) == NULL) { char errmsg[PM_MAXERRMSGLEN]; save_error = oserror(); pmprintf("__pmLogNewFile: failed to create \"%s\": %s\n", fname, osstrerror_r(errmsg, sizeof(errmsg))); pmflush(); setoserror(save_error); return NULL; } if ((save_error = __pmSetVersionIPC(fileno(f), PDU_VERSION)) < 0) { char errmsg[PM_MAXERRMSGLEN]; pmprintf("__pmLogNewFile: failed to setup \"%s\": %s\n", fname, osstrerror_r(errmsg, sizeof(errmsg))); pmflush(); fclose(f); setoserror(save_error); return NULL; } return f; } int __pmLogWriteLabel(FILE *f, const __pmLogLabel *lp) { int len; int sts = 0; __pmLogLabel outll = *lp; len = sizeof(*lp) + 2 * sizeof(len); len = htonl(len); /* swab */ outll.ill_magic = htonl(outll.ill_magic); outll.ill_pid = htonl(outll.ill_pid); outll.ill_start.tv_sec = htonl(outll.ill_start.tv_sec); outll.ill_start.tv_usec = htonl(outll.ill_start.tv_usec); outll.ill_vol = htonl(outll.ill_vol); if ((int)fwrite(&len, 1, sizeof(len), f) != sizeof(len) || (int)fwrite(&outll, 1, sizeof(outll), f) != sizeof(outll) || (int)fwrite(&len, 1, sizeof(len), f) != sizeof(len)) { char errmsg[PM_MAXERRMSGLEN]; sts = -oserror(); pmprintf("__pmLogWriteLabel: %s\n", osstrerror_r(errmsg, sizeof(errmsg))); pmflush(); } return sts; } int __pmLogCreate(const char *host, const char *base, int log_version, __pmLogCtl *lcp) { int save_error = 0; char fname[MAXPATHLEN]; lcp->l_minvol = lcp->l_maxvol = lcp->l_curvol = 0; lcp->l_hashpmid.nodes = lcp->l_hashpmid.hsize = 0; lcp->l_hashindom.nodes = lcp->l_hashindom.hsize = 0; lcp->l_tifp = lcp->l_mdfp = lcp->l_mfp = NULL; if ((lcp->l_tifp = __pmLogNewFile(base, PM_LOG_VOL_TI)) != NULL) { if ((lcp->l_mdfp = __pmLogNewFile(base, PM_LOG_VOL_META)) != NULL) { if ((lcp->l_mfp = __pmLogNewFile(base, 0)) != NULL) { char tzbuf[PM_TZ_MAXLEN]; char *tz; int sts; tz = __pmTimezone_r(tzbuf, sizeof(tzbuf)); lcp->l_label.ill_magic = PM_LOG_MAGIC | log_version; /* * Warning ill_hostname may be truncated, but we * guarantee it will be null-byte terminated */ strncpy(lcp->l_label.ill_hostname, host, PM_LOG_MAXHOSTLEN-1); lcp->l_label.ill_hostname[PM_LOG_MAXHOSTLEN-1] = '\0'; lcp->l_label.ill_pid = (int)getpid(); /* * hack - how do you get the TZ for a remote host? */ strcpy(lcp->l_label.ill_tz, tz ? tz : ""); lcp->l_state = PM_LOG_STATE_NEW; /* * __pmLogNewFile sets the IPC version to PDU_VERSION * we want log_version instead */ sts = __pmSetVersionIPC(fileno(lcp->l_tifp), log_version); if (sts < 0) return sts; sts = __pmSetVersionIPC(fileno(lcp->l_mdfp), log_version); if (sts < 0) return sts; sts = __pmSetVersionIPC(fileno(lcp->l_mfp), log_version); return sts; } else { save_error = oserror(); unlink(__pmLogName_r(base, PM_LOG_VOL_TI, fname, sizeof(fname))); unlink(__pmLogName_r(base, PM_LOG_VOL_META, fname, sizeof(fname))); setoserror(save_error); } } else { save_error = oserror(); unlink(__pmLogName_r(base, PM_LOG_VOL_TI, fname, sizeof(fname))); setoserror(save_error); } } lcp->l_tifp = lcp->l_mdfp = lcp->l_mfp = NULL; return oserror() ? -oserror() : -EPERM; } /* * Close the log files. * Free up the space used by __pmLogCtl. */ void __pmLogClose(__pmLogCtl *lcp) { if (lcp->l_tifp != NULL) { __pmResetIPC(fileno(lcp->l_tifp)); fclose(lcp->l_tifp); lcp->l_tifp = NULL; } if (lcp->l_mdfp != NULL) { __pmResetIPC(fileno(lcp->l_mdfp)); fclose(lcp->l_mdfp); lcp->l_mdfp = NULL; } if (lcp->l_mfp != NULL) { __pmLogCacheClear(lcp->l_mfp); __pmResetIPC(fileno(lcp->l_mfp)); fclose(lcp->l_mfp); lcp->l_mfp = NULL; } if (lcp->l_name != NULL) { free(lcp->l_name); lcp->l_name = NULL; } if (lcp->l_seen != NULL) { free(lcp->l_seen); lcp->l_seen = NULL; lcp->l_numseen = 0; } if (lcp->l_pmns != NULL) { __pmFreePMNS(lcp->l_pmns); lcp->l_pmns = NULL; } if (lcp->l_ti != NULL) free(lcp->l_ti); if (lcp->l_hashpmid.hsize != 0) { __pmHashCtl *hcp = &lcp->l_hashpmid; __pmHashNode *hp; __pmHashNode *prior_hp; int i; for (i = 0; i < hcp->hsize; i++) { for (hp = hcp->hash[i], prior_hp = NULL; hp != NULL; hp = hp->next) { if (hp->data != NULL) free(hp->data); if (prior_hp != NULL) free(prior_hp); prior_hp = hp; } if (prior_hp != NULL) free(prior_hp); } free(hcp->hash); } if (lcp->l_hashindom.hsize != 0) { __pmHashCtl *hcp = &lcp->l_hashindom; __pmHashNode *hp; __pmHashNode *prior_hp; __pmLogInDom *idp; __pmLogInDom *prior_idp; int i; for (i = 0; i < hcp->hsize; i++) { for (hp = hcp->hash[i], prior_hp = NULL; hp != NULL; hp = hp->next) { for (idp = (__pmLogInDom *)hp->data, prior_idp = NULL; idp != NULL; idp = idp->next) { if (idp->buf != NULL) free(idp->buf); if (idp->allinbuf == 0 && idp->namelist != NULL) free(idp->namelist); if (prior_idp != NULL) free(prior_idp); prior_idp = idp; } if (prior_idp != NULL) free(prior_idp); if (prior_hp != NULL) free(prior_hp); prior_hp = hp; } if (prior_hp != NULL) free(prior_hp); } free(hcp->hash); } } int __pmLogLoadLabel(__pmLogCtl *lcp, const char *name) { int sts; int blen; int exists = 0; int i; int sep = __pmPathSeparator(); char *q; char *base; char *tbuf; char *tp; char *dir; DIR *dirp = NULL; char filename[MAXPATHLEN]; #if defined(HAVE_READDIR64) struct dirent64 *direntp; #else struct dirent *direntp; #endif /* * find directory name component ... copy as dirname() may clobber * the string */ if ((tbuf = strdup(name)) == NULL) return -oserror(); PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); dir = dirname(tbuf); /* * find file name component */ strncpy(filename, name, MAXPATHLEN); filename[MAXPATHLEN-1] = '\0'; if ((base = strdup(basename(filename))) == NULL) { sts = -oserror(); free(tbuf); PM_UNLOCK(__pmLock_libpcp); return sts; } PM_UNLOCK(__pmLock_libpcp); if (access(name, R_OK) == 0) { /* * file exists and is readable ... if name contains '.' and * suffix is "index", "meta" or a string of digits or a string * of digits followed by one of the compression suffixes, * strip the suffix */ int strip = 0; if ((q = strrchr(base, '.')) != NULL) { if (strcmp(q, ".index") == 0) { strip = 1; goto done; } if (strcmp(q, ".meta") == 0) { strip = 1; goto done; } for (i = 0; i < ncompress; i++) { if (strcmp(q, compress_ctl[i].suff) == 0) { char *q2; /* * name ends with one of the supported compressed file * suffixes, check for a string of digits before that, * e.g. if base is initially "foo.0.bz2", we want it * stripped to "foo" */ *q = '\0'; if ((q2 = strrchr(base, '.')) == NULL) { /* no . to the left of the suffix */ *q = '.'; goto done; } q = q2; break; } } if (q[1] != '\0') { char *end; /* * Below we don't care about the value from strtol(), * we're interested in updating the pointer "end". * The messiness is thanks to gcc and glibc ... strtol() * is marked __attribute__((warn_unused_result)) ... * to avoid warnings on all platforms, assign to a * dummy variable that is explicitly marked unused. */ long tmpl __attribute__((unused)); tmpl = strtol(q+1, &end, 10); if (*end == '\0') strip = 1; } } done: if (strip) { *q = '\0'; } } snprintf(filename, sizeof(filename), "%s%c%s", dir, sep, base); if ((lcp->l_name = strdup(filename)) == NULL) { sts = -oserror(); free(tbuf); free(base); return sts; } lcp->l_minvol = -1; lcp->l_tifp = lcp->l_mdfp = lcp->l_mfp = NULL; lcp->l_ti = NULL; lcp->l_hashpmid.nodes = lcp->l_hashpmid.hsize = 0; lcp->l_hashindom.nodes = lcp->l_hashindom.hsize = 0; lcp->l_numseen = 0; lcp->l_seen = NULL; lcp->l_pmns = NULL; blen = (int)strlen(base); PM_LOCK(__pmLock_libpcp); if ((dirp = opendir(dir)) != NULL) { #if defined(HAVE_READDIR64) while ((direntp = readdir64(dirp)) != NULL) #else while ((direntp = readdir(dirp)) != NULL) #endif { if (strncmp(base, direntp->d_name, blen) != 0) continue; if (direntp->d_name[blen] != '.') continue; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { snprintf(filename, sizeof(filename), "%s%c%s", dir, sep, direntp->d_name); fprintf(stderr, "__pmLogOpen: inspect file \"%s\"\n", filename); } #endif tp = &direntp->d_name[blen+1]; if (strcmp(tp, "index") == 0) { exists = 1; snprintf(filename, sizeof(filename), "%s%c%s", dir, sep, direntp->d_name); if ((lcp->l_tifp = fopen(filename, "r")) == NULL) { sts = -oserror(); PM_UNLOCK(__pmLock_libpcp); goto cleanup; } } else if (strcmp(tp, "meta") == 0) { exists = 1; snprintf(filename, sizeof(filename), "%s%c%s", dir, sep, direntp->d_name); if ((lcp->l_mdfp = fopen(filename, "r")) == NULL) { sts = -oserror(); PM_UNLOCK(__pmLock_libpcp); goto cleanup; } } else { char *q; int vol; vol = (int)strtol(tp, &q, 10); if (*q != '0') { /* may have one of the trailing compressed file suffixes */ int i; for (i = 0; i < ncompress; i++) { if (strcmp(q, compress_ctl[i].suff) == 0) { /* match */ *q = '\0'; break; } } } if (*q == '\0') { exists = 1; if (lcp->l_minvol == -1) { lcp->l_minvol = vol; lcp->l_maxvol = vol; } else { if (vol < lcp->l_minvol) lcp->l_minvol = vol; if (vol > lcp->l_maxvol) lcp->l_maxvol = vol; } } } } closedir(dirp); dirp = NULL; } else { #ifdef PCP_DEBUG sts = -oserror(); if (pmDebug & DBG_TRACE_LOG) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmLogOpen: cannot scan directory \"%s\": %s\n", dir, pmErrStr_r(sts, errmsg, sizeof(errmsg))); } PM_UNLOCK(__pmLock_libpcp); goto cleanup; #endif } PM_UNLOCK(__pmLock_libpcp); if (lcp->l_minvol == -1 || lcp->l_mdfp == NULL) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { if (lcp->l_minvol == -1) fprintf(stderr, "__pmLogOpen: Not found: data file \"%s.0\" (or similar)\n", base); if (lcp->l_mdfp == NULL) fprintf(stderr, "__pmLogOpen: Not found: metadata file \"%s.meta\"\n", base); } #endif if (exists) sts = PM_ERR_LOGFILE; else sts = -ENOENT; goto cleanup; } free(tbuf); free(base); return 0; cleanup: if (dirp != NULL) closedir(dirp); __pmLogClose(lcp); free(tbuf); free(base); return sts; } int __pmLogOpen(const char *name, __pmContext *ctxp) { __pmLogCtl *lcp = ctxp->c_archctl->ac_log; __pmLogLabel label; int version; int sts; if ((sts = __pmLogLoadLabel(lcp, name)) < 0) return sts; lcp->l_curvol = -1; if ((sts = __pmLogChangeVol(lcp, lcp->l_minvol)) < 0) goto cleanup; else version = sts; ctxp->c_origin = lcp->l_label.ill_start; if (lcp->l_tifp) { sts = __pmLogChkLabel(lcp, lcp->l_tifp, &label, PM_LOG_VOL_TI); if (sts < 0) goto cleanup; else if (sts != version) { /* mismatch between meta & actual data versions! */ sts = PM_ERR_LABEL; goto cleanup; } if (lcp->l_label.ill_pid != label.ill_pid || strcmp(lcp->l_label.ill_hostname, label.ill_hostname) != 0) { sts = PM_ERR_LABEL; goto cleanup; } } if ((sts = __pmLogChkLabel(lcp, lcp->l_mdfp, &label, PM_LOG_VOL_META)) < 0) goto cleanup; else if (sts != version) { /* version mismatch between meta & ti */ sts = PM_ERR_LABEL; goto cleanup; } if ((sts = __pmLogLoadMeta(lcp)) < 0) goto cleanup; if ((sts = __pmLogLoadIndex(lcp)) < 0) goto cleanup; if (lcp->l_label.ill_pid != label.ill_pid || strcmp(lcp->l_label.ill_hostname, label.ill_hostname) != 0) { sts = PM_ERR_LABEL; goto cleanup; } lcp->l_refcnt = 0; lcp->l_physend = -1; ctxp->c_mode = (ctxp->c_mode & 0xffff0000) | PM_MODE_FORW; return 0; cleanup: __pmLogClose(lcp); return sts; } void __pmLogPutIndex(const __pmLogCtl *lcp, const __pmTimeval *tp) { __pmLogTI ti; __pmLogTI oti; if (lcp->l_tifp == NULL || lcp->l_mdfp == NULL || lcp->l_mfp == NULL) { /* * archive not really created (failed in __pmLogCreate) ... * nothing to be done */ return; } if (tp == NULL) { struct timeval tmp; __pmtimevalNow(&tmp); ti.ti_stamp.tv_sec = (__int32_t)tmp.tv_sec; ti.ti_stamp.tv_usec = (__int32_t)tmp.tv_usec; } else ti.ti_stamp = *tp; /* struct assignment */ ti.ti_vol = lcp->l_curvol; fflush(lcp->l_mdfp); fflush(lcp->l_mfp); if (sizeof(off_t) > sizeof(__pm_off_t)) { /* check for overflow of the offset ... */ off_t tmp; tmp = ftell(lcp->l_mdfp); assert(tmp >= 0); ti.ti_meta = (__pm_off_t)tmp; if (tmp != ti.ti_meta) { __pmNotifyErr(LOG_ERR, "__pmLogPutIndex: PCP archive file (meta) too big\n"); exit(1); } tmp = ftell(lcp->l_mfp); assert(tmp >= 0); ti.ti_log = (__pm_off_t)tmp; if (tmp != ti.ti_log) { __pmNotifyErr(LOG_ERR, "__pmLogPutIndex: PCP archive file (data) too big\n"); exit(1); } } else { ti.ti_meta = (__pm_off_t)ftell(lcp->l_mdfp); ti.ti_log = (__pm_off_t)ftell(lcp->l_mfp); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "__pmLogPutIndex: timestamp=%d.06%d vol=%d meta posn=%ld log posn=%ld\n", (int)ti.ti_stamp.tv_sec, (int)ti.ti_stamp.tv_usec, ti.ti_vol, (long)ti.ti_meta, (long)ti.ti_log); } #endif oti.ti_stamp.tv_sec = htonl(ti.ti_stamp.tv_sec); oti.ti_stamp.tv_usec = htonl(ti.ti_stamp.tv_usec); oti.ti_vol = htonl(ti.ti_vol); oti.ti_meta = htonl(ti.ti_meta); oti.ti_log = htonl(ti.ti_log); if (fwrite(&oti, 1, sizeof(oti), lcp->l_tifp) != sizeof(oti)) __pmNotifyErr(LOG_ERR, "__pmLogPutIndex: PCP archive temporal index write failed\n"); if (fflush(lcp->l_tifp) != 0) __pmNotifyErr(LOG_ERR, "__pmLogPutIndex: PCP archive temporal index flush failed\n"); } int __pmLogPutResult(__pmLogCtl *lcp, __pmPDU *pb) { /* * This is a bit tricky ... * * Input * :---------:----------:----------:---------------- * | int len | int from | int from | timestamp, .... pmResult * :---------:----------:----------:---------------- * ^ * | * pb * * Output * :---------:----------:----------:---------------- .........:---------: * | int len | int from | int len | timestamp, .... pmResult | int len | * :---------:----------:----------:---------------- .........:---------: * ^ * | * start */ int sz; int sts = 0; __pmPDUHdr *php = (__pmPDUHdr *)pb; if (lcp->l_state == PM_LOG_STATE_NEW) { int i; __pmTimeval *tvp; /* * first result, do the label record */ i = sizeof(__pmPDUHdr) / sizeof(__pmPDU); tvp = (__pmTimeval *)&pb[i]; lcp->l_label.ill_start.tv_sec = ntohl(tvp->tv_sec); lcp->l_label.ill_start.tv_usec = ntohl(tvp->tv_usec); lcp->l_label.ill_vol = PM_LOG_VOL_TI; __pmLogWriteLabel(lcp->l_tifp, &lcp->l_label); lcp->l_label.ill_vol = PM_LOG_VOL_META; __pmLogWriteLabel(lcp->l_mdfp, &lcp->l_label); lcp->l_label.ill_vol = 0; __pmLogWriteLabel(lcp->l_mfp, &lcp->l_label); lcp->l_state = PM_LOG_STATE_INIT; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "__pmLogPutResult: pdubuf=" PRINTF_P_PFX "%p len=%d posn=%ld\n", pb, php->len, (long)ftell(lcp->l_mfp)); } #endif php->from = php->len - (int)sizeof(__pmPDUHdr) + 2 * (int)sizeof(int); sz = php->from - (int)sizeof(int); /* swab */ php->len = htonl(php->len); php->type = htonl(php->type); php->from = htonl(php->from); if ((int)fwrite(&php->from, 1, sz, lcp->l_mfp) != sz) sts = -oserror(); else if ((int)fwrite(&php->from, 1, sizeof(int), lcp->l_mfp) != sizeof(int)) sts = -oserror(); /* unswab */ php->len = ntohl(php->len); php->type = ntohl(php->type); php->from = ntohl(php->from); return sts; } /* * check if PDU buffer seems even half-way reasonable ... * only used when trying to locate end of archive. * return 0 for OK, -1 for bad. */ static int paranoidCheck(int len, __pmPDU *pb) { int numpmid; size_t hdrsz; /* bytes for the PDU head+tail */ int i; int j; int vsize; /* size of vlist_t's in PDU buffer */ int vbsize; /* size of pmValueBlocks */ int numval; /* number of values */ int valfmt; struct result_t { /* from p_result.c */ __pmPDUHdr hdr; __pmTimeval timestamp; /* when returned */ int numpmid; /* no. of PMIDs to follow */ __pmPDU data[1]; /* zero or more */ } *pp; struct vlist_t { /* from p_result.c */ pmID pmid; int numval; /* no. of vlist els to follow, or error */ int valfmt; /* insitu or pointer */ __pmValue_PDU vlist[1]; /* zero or more */ } *vlp; /* * to start with, need space for result_t with no data (__pmPDU) * ... this is the external size, which consists of *
* (2 words) * * * * it is confusing because *pb and result_t include the fake * __pmPDUHdr which is not really in the external file */ hdrsz = 5 * sizeof(__pmPDU); if (len < hdrsz) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "\nparanoidCheck: len=%d, min len=%d\n", len, (int)hdrsz); dumpbuf(len, &pb[3]); /* skip first 3 words, start @ timestamp */ } #endif return -1; } pp = (struct result_t *)pb; numpmid = ntohl(pp->numpmid); /* * This is a re-implementation of much of __pmDecodeResult() */ if (numpmid < 1) { if (len != hdrsz) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "\nparanoidCheck: numpmid=%d len=%d, expected len=%d\n", numpmid, len, (int)hdrsz); dumpbuf(len, &pb[3]); /* skip first 3 words, start @ timestamp */ } #endif return -1; } } /* * Calculate vsize and vbsize from the original PDU buffer ... * :---------:-----------:----------------:--------------------: * : numpmid : timestamp : ... vlists ... : .. pmValueBocks .. : * :---------:-----------:----------------:--------------------: * <--- vsize ---> <--- vbsize ---> * bytes bytes */ vsize = vbsize = 0; for (i = 0; i < numpmid; i++) { vlp = (struct vlist_t *)&pp->data[vsize/sizeof(__pmPDU)]; vsize += sizeof(vlp->pmid) + sizeof(vlp->numval); if (len < hdrsz + vsize + vbsize) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "\nparanoidCheck: vset[%d] len=%d, need len>=%d (%d+%d+%d)\n", i, len, (int)(hdrsz + vsize + vbsize), (int)hdrsz, vsize, vbsize); dumpbuf(len, &pb[3]); /* skip first 3 words, start @ timestamp */ } #endif return -1; } numval = ntohl(vlp->numval); if (numval > 0) { #ifdef DESPERATE pmID pmid; #endif valfmt = ntohl(vlp->valfmt); if (valfmt != PM_VAL_INSITU && valfmt != PM_VAL_DPTR && valfmt != PM_VAL_SPTR) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "\nparanoidCheck: vset[%d] bad valfmt=%d\n", i, valfmt); dumpbuf(len, &pb[3]); /* skip first 3 words, start @ timestamp */ } #endif return -1; } #ifdef DESPERATE { char strbuf[20]; if (i == 0) fputc('\n', stderr); pmid = __ntohpmID(vlp->pmid); fprintf(stderr, "vlist[%d] pmid: %s numval: %d valfmt: %d\n", i, pmIDStr_r(pmid, strbuf, sizeof(strbuf)), numval, valfmt); } #endif vsize += sizeof(vlp->valfmt) + numval * sizeof(__pmValue_PDU); if (valfmt != PM_VAL_INSITU) { for (j = 0; j < numval; j++) { int index = (int)ntohl((long)vlp->vlist[j].value.pval); pmValueBlock *pduvbp; int vlen; if (index < 0 || index * sizeof(__pmPDU) > len) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "\nparanoidCheck: vset[%d] val[%d], bad pval index=%d not in range 0..%d\n", i, j, index, (int)(len / sizeof(__pmPDU))); dumpbuf(len, &pb[3]); /* skip first 3 words, start @ timestamp */ } #endif return -1; } pduvbp = (pmValueBlock *)&pb[index]; __ntohpmValueBlock(pduvbp); vlen = pduvbp->vlen; __htonpmValueBlock(pduvbp); /* restore pdubuf! */ if (vlen < sizeof(__pmPDU)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "\nparanoidCheck: vset[%d] val[%d], bad vlen=%d\n", i, j, vlen); dumpbuf(len, &pb[3]); /* skip first 3 words, start @ timestamp */ } #endif return -1; } vbsize += PM_PDU_SIZE_BYTES(vlen); } } } } return 0; } static int paranoidLogRead(__pmLogCtl *lcp, int mode, FILE *peekf, pmResult **result) { return __pmLogRead(lcp, mode, peekf, result, PMLOGREAD_TO_EOF); } /* * read next forward or backward from the log * * by default (peekf == NULL) use lcp->l_mfp and roll volume * at end of file if another volume is available * * if peekf != NULL, use this stream, and do not roll volume */ int __pmLogRead(__pmLogCtl *lcp, int mode, FILE *peekf, pmResult **result, int option) { int head; int rlen; int trail; int sts; long offset; __pmPDU *pb; FILE *f; int n; /* * Strip any XTB data from mode, its not used here */ mode &= __PM_MODE_MASK; if (peekf != NULL) f = peekf; else f = lcp->l_mfp; offset = ftell(f); assert(offset >= 0); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "__pmLogRead: fd=%d%s mode=%s vol=%d posn=%ld ", fileno(f), peekf == NULL ? "" : " (peek)", mode == PM_MODE_FORW ? "forw" : "back", lcp->l_curvol, (long)offset); } #endif if (mode == PM_MODE_BACK) { for ( ; ; ) { if (offset <= sizeof(__pmLogLabel) + 2 * sizeof(int)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "BEFORE start\n"); #endif if (peekf == NULL) { int vol = lcp->l_curvol-1; while (vol >= lcp->l_minvol) { if (__pmLogChangeVol(lcp, vol) >= 0) { f = lcp->l_mfp; fseek(f, 0L, SEEK_END); offset = ftell(f); assert(offset >= 0); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "vol=%d posn=%ld ", lcp->l_curvol, (long)offset); } #endif break; } vol--; } if (vol < lcp->l_minvol) return PM_ERR_EOL; } else return PM_ERR_EOL; } else { fseek(f, -(long)sizeof(head), SEEK_CUR); break; } } } again: n = (int)fread(&head, 1, sizeof(head), f); head = ntohl(head); /* swab head */ if (n != sizeof(head)) { if (feof(f)) { /* no more data ... looks like End of Archive volume */ clearerr(f); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "AFTER end\n"); #endif fseek(f, offset, SEEK_SET); if (peekf == NULL) { int vol = lcp->l_curvol+1; while (vol <= lcp->l_maxvol) { if (__pmLogChangeVol(lcp, vol) >= 0) { f = lcp->l_mfp; goto again; } vol++; } } return PM_ERR_EOL; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "\nError: header fread got %d expected %d\n", n, (int)sizeof(head)); #endif if (ferror(f)) { /* I/O error */ clearerr(f); return -oserror(); } else /* corrupted archive */ return PM_ERR_LOGREC; } /* * This is pretty ugly (forward case shown backwards is similar) ... * * Input * head <--- rlen bytes -- ...---> tail * :---------:---------:---------:---------------- .........:---------: * | ??? | ??? | int len | timestamp, .... pmResult | int len | * :---------:---------:---------:---------------- .........:---------: * ^ ^ * | | * pb read into here * * Decode * <---- __pmPDUHdr -----------> * :---------:---------:---------:---------------- .........: * | length | pdutype | anon | timestamp, .... pmResult | * :---------:---------:---------:---------------- .........: * ^ * | * pb * * Note: cannot volume switch in the middle of a log record */ rlen = head - 2 * (int)sizeof(head); if (rlen < 0 || (mode == PM_MODE_BACK && rlen > offset)) { /* * corrupted! usually means a truncated log ... */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "\nError: truncated log? rlen=%d (offset %d)\n", rlen, (int)offset); #endif return PM_ERR_LOGREC; } if ((pb = __pmFindPDUBuf(rlen + (int)sizeof(__pmPDUHdr))) == NULL) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "\nError: __pmFindPDUBuf(%d) %s\n", (int)(rlen + sizeof(__pmPDUHdr)), osstrerror_r(errmsg, sizeof(errmsg))); } #endif fseek(f, offset, SEEK_SET); return -oserror(); } if (mode == PM_MODE_BACK) fseek(f, -(long)(sizeof(head) + rlen), SEEK_CUR); if ((n = (int)fread(&pb[3], 1, rlen, f)) != rlen) { /* data read failed */ __pmUnpinPDUBuf(pb); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "\nError: data fread got %d expected %d\n", n, rlen); #endif fseek(f, offset, SEEK_SET); if (ferror(f)) { /* I/O error */ clearerr(f); return -oserror(); } clearerr(f); /* corrupted archive */ return PM_ERR_LOGREC; } else { __pmPDUHdr *header = (__pmPDUHdr *)pb; header->len = sizeof(*header) + rlen; header->type = PDU_RESULT; header->from = FROM_ANON; /* swab pdu buffer - done later in __pmDecodeResult */ } if (mode == PM_MODE_BACK) fseek(f, -(long)(rlen + sizeof(head)), SEEK_CUR); if ((n = (int)fread(&trail, 1, sizeof(trail), f)) != sizeof(trail)) { __pmUnpinPDUBuf(pb); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "\nError: trailer fread got %d expected %d\n", n, (int)sizeof(trail)); #endif fseek(f, offset, SEEK_SET); if (ferror(f)) { /* I/O error */ clearerr(f); return -oserror(); } clearerr(f); /* corrupted archive */ return PM_ERR_LOGREC; } else { /* swab trail */ trail = ntohl(trail); } if (trail != head) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "\nError: record length mismatch: header (%d) != trailer (%d)\n", head, trail); #endif __pmUnpinPDUBuf(pb); return PM_ERR_LOGREC; } if (option == PMLOGREAD_TO_EOF && paranoidCheck(head, pb) == -1) { __pmUnpinPDUBuf(pb); return PM_ERR_LOGREC; } if (mode == PM_MODE_BACK) fseek(f, -(long)sizeof(trail), SEEK_CUR); __pmOverrideLastFd(fileno(f)); sts = __pmDecodeResult(pb, result); /* also swabs the result */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { head -= sizeof(head) + sizeof(trail); fprintf(stderr, "@"); if (sts >= 0) { __pmTimeval tmp; __pmPrintStamp(stderr, &(*result)->timestamp); tmp.tv_sec = (__int32_t)(*result)->timestamp.tv_sec; tmp.tv_usec = (__int32_t)(*result)->timestamp.tv_usec; fprintf(stderr, " (t=%.6f)", __pmTimevalSub(&tmp, &lcp->l_label.ill_start)); } else fprintf(stderr, "unknown time"); fprintf(stderr, " len=header+%d+trailer\n", head); } #endif /* exported to indicate how efficient we are ... */ __pmLogReads++; if (sts < 0) { __pmUnpinPDUBuf(pb); return PM_ERR_LOGREC; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) { fprintf(stderr, "__pmLogRead timestamp="); __pmPrintStamp(stderr, &(*result)->timestamp); fprintf(stderr, " " PRINTF_P_PFX "%p ... " PRINTF_P_PFX "%p", &pb[3], &pb[head/sizeof(__pmPDU)+3]); fputc('\n', stderr); dumpbuf(rlen, &pb[3]); /* see above to explain "3" */ } #endif __pmUnpinPDUBuf(pb); return 0; } static int check_all_derived(int numpmid, pmID pmidlist[]) { int i; /* * Special case ... if we ONLY have derived metrics in the input * pmidlist then all the derived metrics must be constant * expressions, so skip all the processing. * Derived metrics have domain == DYNAMIC_PMID and item != 0. * This rare, but avoids reading to the end of an archive * for no good reason. */ for (i = 0; i < numpmid; i++) { if (pmid_domain(pmidlist[i]) != DYNAMIC_PMID || pmid_item(pmidlist[i]) == 0) return 0; } return 1; } int __pmLogFetch(__pmContext *ctxp, int numpmid, pmID pmidlist[], pmResult **result) { int i; int j; int u; int all_derived; int sts = 0; int found; double tdiff; pmResult *newres; pmDesc desc; int kval; __pmHashNode *hp; pmid_ctl *pcp; int nskip; __pmTimeval tmp; int ctxp_mode = ctxp->c_mode & __PM_MODE_MASK; if (ctxp_mode == PM_MODE_INTERP) { return __pmLogFetchInterp(ctxp, numpmid, pmidlist, result); } all_derived = check_all_derived(numpmid, pmidlist); /* re-establish position */ __pmLogChangeVol(ctxp->c_archctl->ac_log, ctxp->c_archctl->ac_vol); fseek(ctxp->c_archctl->ac_log->l_mfp, (long)ctxp->c_archctl->ac_offset, SEEK_SET); more: found = 0; nskip = 0; *result = NULL; while (!found) { if (ctxp->c_archctl->ac_serial == 0) { /* * no serial access, so need to make sure we are * starting in the correct place */ int tmp_mode; nskip = 0; if (ctxp_mode == PM_MODE_FORW) tmp_mode = PM_MODE_BACK; else tmp_mode = PM_MODE_FORW; while (__pmLogRead(ctxp->c_archctl->ac_log, tmp_mode, NULL, result, PMLOGREAD_NEXT) >= 0) { nskip++; tmp.tv_sec = (__int32_t)(*result)->timestamp.tv_sec; tmp.tv_usec = (__int32_t)(*result)->timestamp.tv_usec; tdiff = __pmTimevalSub(&tmp, &ctxp->c_origin); if ((tdiff < 0 && ctxp_mode == PM_MODE_FORW) || (tdiff > 0 && ctxp_mode == PM_MODE_BACK)) { pmFreeResult(*result); *result = NULL; break; } else if (tdiff == 0) { /* exactly the one we wanted */ found = 1; break; } pmFreeResult(*result); *result = NULL; } ctxp->c_archctl->ac_serial = 1; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { if (nskip) { fprintf(stderr, "__pmLogFetch: ctx=%d skip reverse %d to ", pmWhichContext(), nskip); if (*result != NULL) __pmPrintStamp(stderr, &(*result)->timestamp); else fprintf(stderr, "unknown time"); fprintf(stderr, ", found=%d\n", found); } #ifdef DESPERATE else fprintf(stderr, "__pmLogFetch: ctx=%d no skip reverse\n", pmWhichContext()); #endif } #endif nskip = 0; } if (found) break; if ((sts = __pmLogRead(ctxp->c_archctl->ac_log, ctxp->c_mode, NULL, result, PMLOGREAD_NEXT)) < 0) break; tmp.tv_sec = (__int32_t)(*result)->timestamp.tv_sec; tmp.tv_usec = (__int32_t)(*result)->timestamp.tv_usec; tdiff = __pmTimevalSub(&tmp, &ctxp->c_origin); if ((tdiff < 0 && ctxp_mode == PM_MODE_FORW) || (tdiff > 0 && ctxp_mode == PM_MODE_BACK)) { nskip++; pmFreeResult(*result); *result = NULL; continue; } found = 1; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { if (nskip) { fprintf(stderr, "__pmLogFetch: ctx=%d skip %d to ", pmWhichContext(), nskip); __pmPrintStamp(stderr, &(*result)->timestamp); fputc('\n', stderr); } #ifdef DESPERATE else fprintf(stderr, "__pmLogFetch: ctx=%d no skip\n", pmWhichContext()); #endif } #endif } if (found) { ctxp->c_origin.tv_sec = (__int32_t)(*result)->timestamp.tv_sec; ctxp->c_origin.tv_usec = (__int32_t)(*result)->timestamp.tv_usec; } if (*result != NULL && (*result)->numpmid == 0) { /* * mark record, and not interpolating ... * if pmFetchArchive(), return it * otherwise keep searching */ if (numpmid == 0) newres = *result; else { pmFreeResult(*result); goto more; } } else if (found) { if (numpmid > 0) { /* * not necesssarily after them all, so cherry-pick the metrics * we wanted .. * there are two tricks here ... * (1) pmValueSets for metrics requested, but not in the pmResult * from the log are assigned using the first two fields in the * pmid_ctl struct -- since these are allocated once as * needed, and never free'd, we have to make sure pmFreeResult * finds a pmValueSet in a pinned pdu buffer ... this means * we must find at least one real value from the log to go * with any "unavailable" results * (2) real pmValueSets can be ignored, they are in a pdubuf * and will be reclaimed when the buffer is unpinned in * pmFreeResult */ i = (int)sizeof(pmResult) + numpmid * (int)sizeof(pmValueSet *); if ((newres = (pmResult *)malloc(i)) == NULL) { __pmNoMem("__pmLogFetch.newres", i, PM_FATAL_ERR); } newres->numpmid = numpmid; newres->timestamp = (*result)->timestamp; u = 0; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); for (j = 0; j < numpmid; j++) { hp = __pmHashSearch((int)pmidlist[j], &pc_hc); if (hp == NULL) { /* first time we've been asked for this one */ if ((pcp = (pmid_ctl *)malloc(sizeof(pmid_ctl))) == NULL) { __pmNoMem("__pmLogFetch.pmid_ctl", sizeof(pmid_ctl), PM_FATAL_ERR); } pcp->pc_pmid = pmidlist[j]; pcp->pc_numval = 0; sts = __pmHashAdd((int)pmidlist[j], (void *)pcp, &pc_hc); if (sts < 0) { PM_UNLOCK(__pmLock_libpcp); return sts; } } else pcp = (pmid_ctl *)hp->data; for (i = 0; i < (*result)->numpmid; i++) { if (pmidlist[j] == (*result)->vset[i]->pmid) { /* match */ newres->vset[j] = (*result)->vset[i]; u++; break; } } if (i == (*result)->numpmid) { /* * requested metric not returned from the log, construct * a "no values available" pmValueSet from the pmid_ctl */ newres->vset[j] = (pmValueSet *)pcp; } } PM_UNLOCK(__pmLock_libpcp); if (u == 0 && !all_derived) { /* * not one of our pmids was in the log record, try * another log record ... */ pmFreeResult(*result); free(newres); goto more; } /* * *result malloc'd in __pmLogRead, but vset[]'s are either in * pdubuf or the pmid_ctl struct */ free(*result); *result = newres; } else /* numpmid == 0, pmFetchArchive() call */ newres = *result; /* * Apply instance profile filtering ... * Note. This is a little strange, as in the numpmid == 0, * pmFetchArchive() case, this for-loop is not executed ... * this is correct, the instance profile is ignored for * pmFetchArchive() */ for (i = 0; i < numpmid; i++) { if (newres->vset[i]->numval <= 0) { /* * no need to xlate numval for an error ... already done * below __pmLogRead() in __pmDecodeResult() ... also xlate * here would have been skipped in the pmFetchArchive() case */ continue; } sts = __pmLogLookupDesc(ctxp->c_archctl->ac_log, newres->vset[i]->pmid, &desc); if (sts < 0) { char strbuf[20]; char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_WARNING, "__pmLogFetch: missing pmDesc for pmID %s: %s", pmIDStr_r(desc.pmid, strbuf, sizeof(strbuf)), pmErrStr_r(sts, errmsg, sizeof(errmsg))); pmFreeResult(newres); break; } if (desc.indom == PM_INDOM_NULL) /* no instance filtering to be done for these ones */ continue; /* * scan instances, keeping those "in" the instance profile * * WARNING * This compresses the pmValueSet INSITU, and since * these are in a pdu buffer, it trashes the the * pdu buffer and means there is no clever way of * re-using the pdu buffer to satisfy multiple * pmFetch requests * Fortunately, stdio buffering means copying to * make additional pdu buffers is not too expensive. */ kval = 0; for (j = 0; j < newres->vset[i]->numval; j++) { if (__pmInProfile(desc.indom, ctxp->c_instprof, newres->vset[i]->vlist[j].inst)) { if (kval != j) /* struct assignment */ newres->vset[i]->vlist[kval] = newres->vset[i]->vlist[j]; kval++; } } newres->vset[i]->numval = kval; } } /* remember your position in this context */ ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp); assert(ctxp->c_archctl->ac_offset >= 0); ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol; return sts; } /* * error handling wrapper around __pmLogChangeVol() to deal with * missing volumes ... return lcp->l_ti[] index for entry matching * success */ static int VolSkip(__pmLogCtl *lcp, int mode, int j) { int vol = lcp->l_ti[j].ti_vol; while (lcp->l_minvol <= vol && vol <= lcp->l_maxvol) { if (__pmLogChangeVol(lcp, vol) >= 0) return j; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "VolSkip: Skip missing vol %d\n", vol); } #endif if (mode == PM_MODE_FORW) { for (j++; j < lcp->l_numti; j++) if (lcp->l_ti[j].ti_vol != vol) break; if (j == lcp->l_numti) return PM_ERR_EOL; vol = lcp->l_ti[j].ti_vol; } else { for (j--; j >= 0; j--) if (lcp->l_ti[j].ti_vol != vol) break; if (j < 0) return PM_ERR_EOL; vol = lcp->l_ti[j].ti_vol; } } return PM_ERR_EOL; } void __pmLogSetTime(__pmContext *ctxp) { __pmLogCtl *lcp = ctxp->c_archctl->ac_log; int mode; mode = ctxp->c_mode & __PM_MODE_MASK; /* strip XTB data */ if (mode == PM_MODE_INTERP) mode = ctxp->c_delta > 0 ? PM_MODE_FORW : PM_MODE_BACK; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "__pmLogSetTime(%d) ", pmWhichContext()); __pmPrintTimeval(stderr, &ctxp->c_origin); fprintf(stderr, " delta=%d", ctxp->c_delta); } #endif if (lcp->l_numti) { /* we have a temporal index, use it! */ int i; int j = -1; int toobig = 0; int match = 0; int numti = lcp->l_numti; __pmLogTI *tip = lcp->l_ti; double t_hi; double t_lo; struct stat sbuf; sbuf.st_size = -1; for (i = 0; i < numti; i++, tip++) { if (tip->ti_vol < lcp->l_minvol) /* skip missing preliminary volumes */ continue; if (tip->ti_vol == lcp->l_maxvol) { /* truncated check for last volume */ if (sbuf.st_size < 0) { FILE *f = _logpeek(lcp, lcp->l_maxvol); sbuf.st_size = 0; if (f != NULL) { fstat(fileno(f), &sbuf); fclose(f); } } if (tip->ti_log > sbuf.st_size) { j = i; toobig++; break; } } t_hi = __pmTimevalSub(&tip->ti_stamp, &ctxp->c_origin); if (t_hi > 0) { j = i; break; } else if (t_hi == 0) { j = i; match = 1; break; } } if (i == numti) j = numti; ctxp->c_archctl->ac_serial = 1; if (match) { j = VolSkip(lcp, mode, j); if (j < 0) return; fseek(lcp->l_mfp, (long)lcp->l_ti[j].ti_log, SEEK_SET); if (mode == PM_MODE_BACK) ctxp->c_archctl->ac_serial = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, " at ti[%d]@", j); __pmPrintTimeval(stderr, &lcp->l_ti[j].ti_stamp); } #endif } else if (j < 1) { j = VolSkip(lcp, PM_MODE_FORW, 0); if (j < 0) return; fseek(lcp->l_mfp, (long)lcp->l_ti[j].ti_log, SEEK_SET); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, " before start ti@"); __pmPrintTimeval(stderr, &lcp->l_ti[j].ti_stamp); } #endif } else if (j == numti) { j = VolSkip(lcp, PM_MODE_BACK, numti-1); if (j < 0) return; fseek(lcp->l_mfp, (long)lcp->l_ti[j].ti_log, SEEK_SET); if (mode == PM_MODE_BACK) ctxp->c_archctl->ac_serial = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, " after end ti@"); __pmPrintTimeval(stderr, &lcp->l_ti[j].ti_stamp); } #endif } else { /* * [j-1] [origin] [j] * <----- t_lo -------><----- t_hi ----> * * choose closest index point. if toobig, [j] is not * really valid (log truncated or incomplete) */ t_hi = __pmTimevalSub(&lcp->l_ti[j].ti_stamp, &ctxp->c_origin); t_lo = __pmTimevalSub(&ctxp->c_origin, &lcp->l_ti[j-1].ti_stamp); if (t_hi <= t_lo && !toobig) { j = VolSkip(lcp, mode, j); if (j < 0) return; fseek(lcp->l_mfp, (long)lcp->l_ti[j].ti_log, SEEK_SET); if (mode == PM_MODE_FORW) ctxp->c_archctl->ac_serial = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, " before ti[%d]@", j); __pmPrintTimeval(stderr, &lcp->l_ti[j].ti_stamp); } #endif } else { j = VolSkip(lcp, mode, j-1); if (j < 0) return; fseek(lcp->l_mfp, (long)lcp->l_ti[j].ti_log, SEEK_SET); if (mode == PM_MODE_BACK) ctxp->c_archctl->ac_serial = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, " after ti[%d]@", j); __pmPrintTimeval(stderr, &lcp->l_ti[j].ti_stamp); } #endif } if (ctxp->c_archctl->ac_serial && mode == PM_MODE_FORW) { /* * back up one record ... * index points to the END of the record! */ pmResult *result; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " back up ...\n"); #endif if (__pmLogRead(lcp, PM_MODE_BACK, NULL, &result, PMLOGREAD_NEXT) >= 0) pmFreeResult(result); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, "..."); #endif } } } else { /* index either not available, or not useful */ if (mode == PM_MODE_FORW) { __pmLogChangeVol(lcp, lcp->l_minvol); fseek(lcp->l_mfp, (long)(sizeof(__pmLogLabel) + 2*sizeof(int)), SEEK_SET); } else if (mode == PM_MODE_BACK) { __pmLogChangeVol(lcp, lcp->l_maxvol); fseek(lcp->l_mfp, (long)0, SEEK_END); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " index not useful\n"); #endif } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) fprintf(stderr, " vol=%d posn=%ld serial=%d\n", lcp->l_curvol, (long)ftell(lcp->l_mfp), ctxp->c_archctl->ac_serial); #endif /* remember your position in this context */ ctxp->c_archctl->ac_offset = ftell(lcp->l_mfp); assert(ctxp->c_archctl->ac_offset >= 0); ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol; } int pmGetArchiveLabel(pmLogLabel *lp) { __pmContext *ctxp; ctxp = __pmHandleToPtr(pmWhichContext()); if (ctxp == NULL || ctxp->c_type != PM_CONTEXT_ARCHIVE) return PM_ERR_NOCONTEXT; else { __pmLogLabel *rlp; /* * we have to copy the structure to hide the differences * between the internal __pmTimeval and the external struct timeval */ rlp = &ctxp->c_archctl->ac_log->l_label; lp->ll_magic = rlp->ill_magic; lp->ll_pid = (pid_t)rlp->ill_pid; lp->ll_start.tv_sec = rlp->ill_start.tv_sec; lp->ll_start.tv_usec = rlp->ill_start.tv_usec; memcpy(lp->ll_hostname, rlp->ill_hostname, PM_LOG_MAXHOSTLEN); memcpy(lp->ll_tz, rlp->ill_tz, sizeof(lp->ll_tz)); PM_UNLOCK(ctxp->c_lock); return 0; } } int pmGetArchiveEnd(struct timeval *tp) { /* * set l_physend and l_endtime * at the end of ... ctxp->c_archctl->ac_log */ __pmContext *ctxp; int sts; ctxp = __pmHandleToPtr(pmWhichContext()); if (ctxp == NULL || ctxp->c_type != PM_CONTEXT_ARCHIVE) return PM_ERR_NOCONTEXT; sts = __pmGetArchiveEnd(ctxp->c_archctl->ac_log, tp); PM_UNLOCK(ctxp->c_lock); return sts; } int __pmGetArchiveEnd(__pmLogCtl *lcp, struct timeval *tp) { struct stat sbuf; FILE *f; long save = 0; pmResult *rp = NULL; pmResult *nrp; int i; int sts; int found; int head; long offset; int vol; __pm_off_t logend; __pm_off_t physend = 0; /* * expect things to be stable, so l_maxvol is not empty, and * l_physend does not change for l_maxvol ... the ugliness is * to handle situations where these expectations are not met */ found = 0; sts = PM_ERR_LOGREC; /* default error condition */ f = NULL; for (vol = lcp->l_maxvol; vol >= lcp->l_minvol; vol--) { if (lcp->l_curvol == vol) { f = lcp->l_mfp; save = ftell(f); assert(save >= 0); } else if ((f = _logpeek(lcp, vol)) == NULL) { sts = -oserror(); break; } if (fstat(fileno(f), &sbuf) < 0) { sts = -oserror(); break; } if (vol == lcp->l_maxvol && sbuf.st_size == lcp->l_physend) { /* nothing changed, return cached stuff */ tp->tv_sec = lcp->l_endtime.tv_sec; tp->tv_usec = lcp->l_endtime.tv_usec; sts = 0; break; } /* if this volume is empty, try previous volume */ if (sbuf.st_size <= (int)sizeof(__pmLogLabel) + 2*(int)sizeof(int)) { if (f != lcp->l_mfp) { fclose(f); f = NULL; } continue; } physend = (__pm_off_t)sbuf.st_size; if (sizeof(off_t) > sizeof(__pm_off_t)) { if (physend != sbuf.st_size) { __pmNotifyErr(LOG_ERR, "pmGetArchiveEnd: PCP archive file" " (meta) too big (%"PRIi64" bytes)\n", (uint64_t)sbuf.st_size); exit(1); } } /* try to read backwards for the last physical record ... */ fseek(f, (long)physend, SEEK_SET); if (paranoidLogRead(lcp, PM_MODE_BACK, f, &rp) >= 0) { /* success, we are done! */ found = 1; break; } /* * failure at the physical end of file may be related to a truncted * block flush for a growing archive. Scan temporal index, and use * last entry at or before end of physical file for this volume */ logend = (int)sizeof(__pmLogLabel) + 2*(int)sizeof(int); for (i = lcp->l_numti - 1; i >= 0; i--) { if (lcp->l_ti[i].ti_vol != vol) { if (f != lcp->l_mfp) { fclose(f); f = NULL; } continue; } if (lcp->l_ti[i].ti_log <= physend) { logend = lcp->l_ti[i].ti_log; break; } } /* * Now chase it forwards from the last index entry ... * * BUG 357003 - pmchart can't read archive file * turns out the index may point to the _end_ of the last * valid record, so if not at start of volume, back up one * record, then scan forwards. */ fseek(f, (long)logend, SEEK_SET); if (logend > (int)sizeof(__pmLogLabel) + 2*(int)sizeof(int)) { if (paranoidLogRead(lcp, PM_MODE_BACK, f, &rp) < 0) { /* this is badly damaged! */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOG) { fprintf(stderr, "pmGetArchiveEnd: " "Error reading record ending at posn=%d ti[%d]@", logend, i); __pmPrintTimeval(stderr, &lcp->l_ti[i].ti_stamp); fputc('\n', stderr); } #endif break; } } /* Keep reading records from "logend" until can do so no more... */ for ( ; ; ) { offset = ftell(f); assert(offset >= 0); if ((int)fread(&head, 1, sizeof(head), f) != sizeof(head)) /* cannot read header for log record !!?? */ break; head = ntohl(head); if (offset + head > physend) /* last record is incomplete */ break; fseek(f, offset, SEEK_SET); if (paranoidLogRead(lcp, PM_MODE_FORW, f, &nrp) < 0) /* this record is truncated, or bad, we lose! */ break; /* this one is ok, remember it as it may be the last one */ found = 1; if (rp != NULL) pmFreeResult(rp); rp = nrp; } if (found) break; /* * this probably means this volume contains no useful records, * try the previous volume */ }/*for*/ if (f == lcp->l_mfp) fseek(f, save, SEEK_SET); /* restore file pointer in current vol */ else if (f != NULL) /* temporary FILE * from _logpeek() */ fclose(f); if (found) { tp->tv_sec = (time_t)rp->timestamp.tv_sec; tp->tv_usec = (int)rp->timestamp.tv_usec; if (vol == lcp->l_maxvol) { lcp->l_endtime.tv_sec = (__int32_t)rp->timestamp.tv_sec; lcp->l_endtime.tv_usec = (__int32_t)rp->timestamp.tv_usec; lcp->l_physend = physend; } sts = 0; } if (rp != NULL) { /* * rp is not NULL from found==1 path _or_ from error break * after an initial paranoidLogRead() success */ pmFreeResult(rp); } return sts; } pcp-3.8.12ubuntu1/src/libpcp/src/avahi.c0000664000000000000000000004740512272262501014677 0ustar /* * Copyright (c) 2013-2014 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "internal.h" #include "avahi.h" /* Support for servers advertising their presence. */ static AvahiThreadedPoll *threadedPoll; static AvahiClient *client; static AvahiEntryGroup *group; static __pmServerPresence **activeServices; static int nActiveServices; static int szActiveServices; struct __pmServerAvahiPresence { char *serviceName; char *serviceTag; int collisions; }; static void entryGroupCallback(AvahiEntryGroup *, AvahiEntryGroupState, void *); static int renameService(__pmServerPresence *s) { /* * Each service must have a unique name on the local network. * When there is a collision, we try to rename the service. * However, we need to limit the number of attempts, since the * service namespace could be maliciously flooded with service * names designed to maximize collisions. * Arbitrarily choose a limit of 65535, which is the number of * TCP ports. */ ++s->avahi->collisions; if (s->avahi->collisions >= 65535) { __pmNotifyErr(LOG_ERR, "Too many service name collisions for Avahi service %s", s->avahi->serviceTag); return -EBUSY; } /* * Use the avahi-supplied function to generate a new service name. */ char *n = avahi_alternative_service_name(s->avahi->serviceName); if (pmDebug & DBG_TRACE_DISCOVERY) __pmNotifyErr(LOG_INFO, "Avahi service name collision, renaming service '%s' to '%s'", s->avahi->serviceName, n); avahi_free(s->avahi->serviceName); s->avahi->serviceName = n; return 0; } static int renameServices(void) { int i; int rc = 0; __pmServerPresence *s; for (i = 0; i < szActiveServices; ++i) { s = activeServices[i]; if (s == NULL) continue; /* empty entry */ if ((rc = renameService(s)) < 0) break; } return rc; } static void createServices(AvahiClient *c) { __pmServerPresence *s; int ret; int i; assert (c); /* * Create a new entry group, if necessary, or reset the existing one. */ if (group == NULL) { if ((group = avahi_entry_group_new(c, entryGroupCallback, NULL)) == NULL) { __pmNotifyErr(LOG_ERR, "avahi_entry_group_new () failed: %s", avahi_strerror (avahi_client_errno(c))); return; } } else avahi_entry_group_reset(group); /* * We will now add our services to the entry group. */ for (i = 0; i < szActiveServices; ++i) { s = activeServices[i]; if (s == NULL) continue; /* empty table entry */ if (pmDebug & DBG_TRACE_DISCOVERY) __pmNotifyErr(LOG_INFO, "Adding %s Avahi service on port %d", s->avahi->serviceName, s->port); /* Loop until no collisions */ for (;;) { ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0, s->avahi->serviceName, s->avahi->serviceTag, NULL, NULL, s->port, NULL); if (ret == AVAHI_OK) break; /* success! */ if (ret == AVAHI_ERR_COLLISION) { /* * A service name collision with a local service happened. * Pick a new name. Since a service may be listening on * multiple ports, this is expected to happen sometimes - * do not issue warnings here. */ if (renameService(s) < 0) { /* Too many collisions. Message already issued */ goto fail; } continue; /* try again */ } __pmNotifyErr(LOG_ERR, "Failed to add %s Avahi service on port %d: %s", s->avahi->serviceName, s->port, avahi_strerror(ret)); goto fail; } } /* Tell the server to register the services. */ if ((ret = avahi_entry_group_commit(group)) < 0) { __pmNotifyErr(LOG_ERR, "Failed to commit avahi entry group: %s", avahi_strerror(ret)); goto fail; } return; fail: avahi_entry_group_reset(group); } static void entryGroupCallback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *data) { (void)data; assert(g != NULL); assert(group == NULL || group == g); group = g; /* Called whenever the entry group state changes. */ switch (state) { case AVAHI_ENTRY_GROUP_ESTABLISHED: /* The entry group has been established successfully. */ if (pmDebug & DBG_TRACE_DISCOVERY) __pmNotifyErr(LOG_INFO, "Avahi services successfully established."); break; case AVAHI_ENTRY_GROUP_COLLISION: /* * A service name collision with a remote service happened. * Unfortunately, we don't know which entry collided. * We need to rename them all and recreate the services. */ if (renameServices() == 0) createServices(avahi_entry_group_get_client(g)); break; case AVAHI_ENTRY_GROUP_FAILURE: /* Some kind of failure happened. */ __pmNotifyErr(LOG_ERR, "Avahi entry group failure: %s", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g)))); break; case AVAHI_ENTRY_GROUP_UNCOMMITED: case AVAHI_ENTRY_GROUP_REGISTERING: break; } } static void cleanupClient(void) { /* This also frees the entry group, if any. */ if (client) { avahi_client_free(client); client = NULL; group = NULL; } } static void advertisingClientCallback(AvahiClient *c, AvahiClientState state, void *userData) { assert(c); (void)userData; /* Called whenever the client or server state changes. */ switch (state) { case AVAHI_CLIENT_S_RUNNING: /* * The server has started successfully and registered its host * name on the network, so it's time to create our services. */ createServices(c); break; case AVAHI_CLIENT_FAILURE: __pmNotifyErr(LOG_ERR, "Avahi client failure: %s", avahi_strerror(avahi_client_errno(c))); if (avahi_client_errno (c) == AVAHI_ERR_DISCONNECTED) { int error; /* * The client has been disconnected; probably because the * avahi daemon has been restarted. We can free the client * here and try to reconnect using a new one. * Passing AVAHI_CLIENT_NO_FAIL allows the new client to be * created, even if the avahi daemon is not running. Our * service will be advertised if/when the daemon is started. */ cleanupClient(); client = avahi_client_new(avahi_threaded_poll_get(threadedPoll), (AvahiClientFlags)AVAHI_CLIENT_NO_FAIL, advertisingClientCallback, NULL, & error); } break; case AVAHI_CLIENT_S_COLLISION: /* * Drop our registered services. When the server is back * in AVAHI_SERVER_RUNNING state we will register them * again with the new host name. * Fall through ... */ case AVAHI_CLIENT_S_REGISTERING: /* * The server records are now being established. This * might be caused by a host name change. We need to wait * for our own records to register until the host name is * properly esatblished. */ if (group) avahi_entry_group_reset (group); break; case AVAHI_CLIENT_CONNECTING: /* * The avahi-daemon is not currently running. Our service will be * advertised if/when the daemon is started. */ if (pmDebug & DBG_TRACE_DISCOVERY) __pmNotifyErr(LOG_INFO, "The Avahi daemon is not running. " "Avahi services will be established when the daemon is started"); break; } } static void cleanup(__pmServerAvahiPresence *s) { if (s == NULL) return; if (s->serviceName) { avahi_free(s->serviceName); s->serviceName = NULL; } if (s->serviceTag) { avahi_free(s->serviceTag); s->serviceTag = NULL; } } /* Publish a new service. */ static void addService(__pmServerPresence *s) { int i; size_t size; /* Find an empty slot in the table of active services. */ for (i = 0; i < szActiveServices; ++i) { if (activeServices[i] == NULL) break; } /* Do we need to grow the table? */ if (i >= szActiveServices) { ++szActiveServices; size = szActiveServices * sizeof(*activeServices); activeServices = realloc(activeServices, size); if (activeServices == NULL) { __pmNoMem("__pmServerAvahiAdvertisePresence: can't allocate service table", size, PM_FATAL_ERR); } } /* Add the service to the table. */ activeServices[i] = s; ++nActiveServices; } /* Publish a new service. */ static void removeService(__pmServerPresence *s) { int i; /* * Find the service in the table of active services. * We can do this by comparing the pointers directly, since * that's how the services were added. */ for (i = 0; i < szActiveServices; ++i) { /* * Did we find it? If so, clear the entry. * We don't free it here. */ if (activeServices[i] == s) { activeServices[i] = NULL; --nActiveServices; return; } } } /* Publish a new service. */ static void publishService(__pmServerPresence *s) { int error; /* Add the service to our list of active services. */ addService(s); /* Is this the first service to be added? */ if (threadedPoll == NULL) { /* Allocate main loop object. */ if ((threadedPoll = avahi_threaded_poll_new()) == NULL) { __pmNotifyErr(LOG_ERR, "Failed to create avahi threaded poll object."); goto fail; } /* * Always allocate a new client. Passing AVAHI_CLIENT_NO_FAIL allows * the client to be created, even if the avahi daemon is not running. * Our service will be advertised if/when the daemon is started. */ client = avahi_client_new(avahi_threaded_poll_get(threadedPoll), (AvahiClientFlags)AVAHI_CLIENT_NO_FAIL, advertisingClientCallback, NULL, &error); /* Check whether creating the client object succeeded. */ if (! client) { __pmNotifyErr(LOG_ERR, "Failed to create avahi client: %s", avahi_strerror(error)); goto fail; } /* Start the main loop. */ avahi_threaded_poll_start(threadedPoll); } else { /* Stop the main loop while we recreate the services. */ avahi_threaded_poll_lock(threadedPoll); createServices(client); avahi_threaded_poll_unlock(threadedPoll); } return; fail: cleanup(s->avahi); free(s->avahi); } void __pmServerAvahiAdvertisePresence(__pmServerPresence *s) { size_t size; char host[MAXHOSTNAMELEN]; /* Allocate the avahi server presence. */ s->avahi = malloc(sizeof(*s->avahi)); if (s->avahi == NULL) { __pmNoMem("__pmServerAvahiAdvertisePresence: can't allocate avahi service data", sizeof(*s->avahi), PM_FATAL_ERR); } /* * The service spec is simply the name of the server. Use it to * construct the avahi service name and service tag. * The service name cannot be longer than AVAHI_LABEL_MAX - 1. */ gethostname(host, sizeof(host)); host[sizeof(host)-1] = '\0'; size = sizeof("PCP..on.") + strlen(host) + strlen(s->serviceSpec); /* includes room for the nul */ if (size > AVAHI_LABEL_MAX) size = AVAHI_LABEL_MAX; if ((s->avahi->serviceName = avahi_malloc(size)) == NULL) { __pmNoMem("__pmServerAvahiAdvertisePresence: can't allocate service name", size, PM_FATAL_ERR); } snprintf(s->avahi->serviceName, size, "PCP %s on %s", s->serviceSpec, host); assert (avahi_is_valid_service_name(s->avahi->serviceName)); size = sizeof("_._tcp") + strlen(s->serviceSpec); /* includes room for the nul */ if ((s->avahi->serviceTag = avahi_malloc(size)) == NULL) { __pmNoMem("__pmServerAvahiAdvertisePresence: can't allocate service tag", size, PM_FATAL_ERR); } sprintf(s->avahi->serviceTag, "_%s._tcp", s->serviceSpec); s->avahi->collisions = 0; /* Now publish the avahi service. */ publishService(s); } void __pmServerAvahiUnadvertisePresence(__pmServerPresence *s) { /* Not an avahi service? */ if (s->avahi == NULL) return; if (pmDebug & DBG_TRACE_DISCOVERY) __pmNotifyErr(LOG_INFO, "Removing Avahi service '%s' on port %d", s->avahi->serviceName , s->port); /* Remove and cleanup the service. */ removeService(s); cleanup(s->avahi); free(s->avahi); s->avahi = NULL; /* Nothing to do if the client is not running. */ if (threadedPoll == NULL) return; /* Stop the main loop. */ /* If no services remain, then shut down the avahi client. */ if (nActiveServices == 0) { /* Clean up the avahi objects. The order of freeing these is significant. */ avahi_threaded_poll_stop(threadedPoll); cleanupClient(); avahi_threaded_poll_free(threadedPoll); threadedPoll = NULL; return; } /* Otherwise, stop the main loop while we recreate the services. */ avahi_threaded_poll_lock(threadedPoll); createServices(client); avahi_threaded_poll_unlock(threadedPoll); } /* Support for clients searching for services. */ typedef struct browsingContext { AvahiSimplePoll *simplePoll; char ***urls; int numUrls; int error; } browsingContext; /* Called whenever a service has been resolved successfully or timed out. */ static void resolveCallback( AvahiServiceResolver *r, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *hostName, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *userdata ) { char addressString[AVAHI_ADDRESS_STR_MAX]; browsingContext *context = (browsingContext *)userdata; char ***urls = context->urls; int numUrls = context->numUrls; __pmServiceInfo serviceInfo; /* Unused arguments. */ (void)protocol; (void)hostName; (void)txt; (void)flags; assert(r); switch (event) { case AVAHI_RESOLVER_FAILURE: context->error = avahi_client_errno(avahi_service_resolver_get_client(r)); break; case AVAHI_RESOLVER_FOUND: /* Currently, only pmcd is supported. */ if (strcmp(type, "_pmcd._tcp") == 0) { serviceInfo.spec = PM_SERVER_SERVICE_SPEC; avahi_address_snprint(addressString, sizeof(addressString), address); serviceInfo.address = __pmStringToSockAddr(addressString); if (serviceInfo.address == NULL) { context->error = ENOMEM; break; } __pmSockAddrSetPort(serviceInfo.address, port); __pmSockAddrSetScope(serviceInfo.address, interface); context->numUrls = __pmAddDiscoveredService(&serviceInfo, numUrls, urls); __pmSockAddrFree(serviceInfo.address); } else context->error = EINVAL; break; default: break; } avahi_service_resolver_free(r); } /* * Called whenever a new service becomes available on the LAN * or is removed from the LAN. */ static void browseCallback( AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void *userdata ) { browsingContext *context = (browsingContext *)userdata; AvahiClient *c = avahi_service_browser_get_client(b); AvahiSimplePoll *simplePoll = context->simplePoll; assert(b); /* Unused argument. */ (void)flags; switch (event) { case AVAHI_BROWSER_FAILURE: context->error = avahi_client_errno(c); avahi_simple_poll_quit(simplePoll); break; case AVAHI_BROWSER_NEW: /* * We ignore the returned resolver object. In the callback * function we free it. If the server is terminated before * the callback function is called the server will free * the resolver for us. */ if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, (AvahiLookupFlags)0, resolveCallback, context))) { context->error = avahi_client_errno(c); } break; case AVAHI_BROWSER_REMOVE: case AVAHI_BROWSER_ALL_FOR_NOW: case AVAHI_BROWSER_CACHE_EXHAUSTED: break; } } /* Called whenever the client or server state changes. */ static void browsingClientCallback(AvahiClient *c, AvahiClientState state, void *userdata) { assert(c); if (state == AVAHI_CLIENT_FAILURE) { browsingContext *context = (browsingContext *)userdata; AvahiSimplePoll *simplePoll = context->simplePoll; context->error = avahi_client_errno(c); avahi_simple_poll_quit(simplePoll); } } static void timeoutCallback(AvahiTimeout *e, void *userdata) { browsingContext *context = (browsingContext *)userdata; AvahiSimplePoll *simplePoll = context->simplePoll; (void)e; avahi_simple_poll_quit(simplePoll); } static double discoveryTimeout(void) { static int done_default = 0; static double def_timeout = 0.5; /* 0.5 seconds */ PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (!done_default) { char *timeout_str; char *end_ptr; double new_timeout; if ((timeout_str = getenv("AVAHI_DISCOVERY_TIMEOUT")) != NULL) { new_timeout = strtod(timeout_str, &end_ptr); if (*end_ptr != '\0' || def_timeout < 0.0) { __pmNotifyErr(LOG_WARNING, "ignored bad AVAHI_DISCOVERY_TIMEOUT = '%s'\n", timeout_str); } else def_timeout = new_timeout; } done_default = 1; } PM_UNLOCK(__pmLock_libpcp); return def_timeout; } int __pmAvahiDiscoverServices(const char *service, int numUrls, char ***urls) { AvahiClient *client = NULL; AvahiServiceBrowser *sb = NULL; AvahiSimplePoll *simplePoll; struct timeval tv; browsingContext context; char *serviceTag; size_t size; /* Allocate the main loop object. */ if (!(simplePoll = avahi_simple_poll_new())) return -ENOMEM; context.error = 0; context.simplePoll = simplePoll; context.urls = urls; context.numUrls = numUrls; /* Allocate a new Avahi client */ client = avahi_client_new(avahi_simple_poll_get(simplePoll), (AvahiClientFlags)0, browsingClientCallback, &context, &context.error); /* Check whether creating the client object succeeded. */ if (! client) goto done; /* Create the service browser. */ size = sizeof("_._tcp") + strlen(service); /* includes room for the nul */ if ((serviceTag = malloc(size)) == NULL) { context.error = ENOMEM; goto done; } sprintf(serviceTag, "_%s._tcp", service); sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, serviceTag, NULL, (AvahiLookupFlags)0, browseCallback, & context); free(serviceTag); if (sb == NULL) { context.error = ENOMEM; goto done; } /* Set the timeout. */ avahi_simple_poll_get(simplePoll)->timeout_new( avahi_simple_poll_get(simplePoll), avahi_elapse_time(&tv, (unsigned)(discoveryTimeout() * 1000), 0), timeoutCallback, &context); /* * Run the main loop. The discovered services will be added to 'urls' * during the call back to resolveCallback */ avahi_simple_poll_loop(simplePoll); numUrls = context.numUrls; done: /* Cleanup. */ if (client) { /* Also frees the service browser. */ avahi_client_free(client); } if (simplePoll) avahi_simple_poll_free(simplePoll); /* Check to see if there was an error. */ if (context.error) return -context.error; return numUrls; } pcp-3.8.12ubuntu1/src/libpcp/src/logmeta.c0000664000000000000000000005236212272262501015235 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "fault.h" #include "internal.h" #include /* bytes for a length field in a header/trailer, or a string length field */ #define LENSIZE 4 #ifdef PCP_DEBUG static void StrTimeval(__pmTimeval *tp) { if (tp == NULL) fprintf(stderr, ""); else __pmPrintTimeval(stderr, tp); } #endif static int addindom(__pmLogCtl *lcp, pmInDom indom, const __pmTimeval *tp, int numinst, int *instlist, char **namelist, int *indom_buf, int allinbuf) { __pmLogInDom *idp; __pmHashNode *hp; int sts; PM_FAULT_POINT("libpcp/" __FILE__ ":1", PM_FAULT_ALLOC); if ((idp = (__pmLogInDom *)malloc(sizeof(__pmLogInDom))) == NULL) return -oserror(); idp->stamp = *tp; /* struct assignment */ idp->numinst = numinst; idp->instlist = instlist; idp->namelist = namelist; idp->buf = indom_buf; idp->allinbuf = allinbuf; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { char strbuf[20]; fprintf(stderr, "addindom( ..., %s, ", pmInDomStr_r(indom, strbuf, sizeof(strbuf))); StrTimeval((__pmTimeval *)tp); fprintf(stderr, ", numinst=%d)\n", numinst); } #endif if ((hp = __pmHashSearch((unsigned int)indom, &lcp->l_hashindom)) == NULL) { idp->next = NULL; sts = __pmHashAdd((unsigned int)indom, (void *)idp, &lcp->l_hashindom); } else { idp->next = (__pmLogInDom *)hp->data; hp->data = (void *)idp; sts = 0; } return sts; } /* * Load _all_ of the hashed pmDesc and __pmLogInDom structures from the metadata * log file -- used at the initialization (NewContext) of an archive. * Also load all the metric names from the metadata log file and create l_pmns. */ int __pmLogLoadMeta(__pmLogCtl *lcp) { int rlen; int check; pmDesc *dp; int sts = 0; __pmLogHdr h; FILE *f = lcp->l_mdfp; int numpmid = 0; int n; if ((sts = __pmNewPMNS(&(lcp->l_pmns))) < 0) goto end; fseek(f, (long)(sizeof(__pmLogLabel) + 2*sizeof(int)), SEEK_SET); for ( ; ; ) { n = (int)fread(&h, 1, sizeof(__pmLogHdr), f); /* swab hdr */ h.len = ntohl(h.len); h.type = ntohl(h.type); if (n != sizeof(__pmLogHdr) || h.len <= 0) { if (feof(f)) { clearerr(f); sts = 0; goto end; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { fprintf(stderr, "__pmLogLoadMeta: header read -> %d: expected: %d or len=%d\n", n, (int)sizeof(__pmLogHdr), h.len); } #endif if (ferror(f)) { clearerr(f); sts = -oserror(); } else sts = PM_ERR_LOGREC; goto end; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { fprintf(stderr, "__pmLogLoadMeta: record len=%d, type=%d @ offset=%d\n", h.len, h.type, (int)(ftell(f) - sizeof(__pmLogHdr))); } #endif rlen = h.len - (int)sizeof(__pmLogHdr) - (int)sizeof(int); if (h.type == TYPE_DESC) { numpmid++; PM_FAULT_POINT("libpcp/" __FILE__ ":2", PM_FAULT_ALLOC); if ((dp = (pmDesc *)malloc(sizeof(pmDesc))) == NULL) { sts = -oserror(); goto end; } if ((n = (int)fread(dp, 1, sizeof(pmDesc), f)) != sizeof(pmDesc)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { fprintf(stderr, "__pmLogLoadMeta: pmDesc read -> %d: expected: %d\n", n, (int)sizeof(pmDesc)); } #endif if (ferror(f)) { clearerr(f); sts = -oserror(); } else sts = PM_ERR_LOGREC; free(dp); goto end; } else { /* swab desc */ dp->type = ntohl(dp->type); dp->sem = ntohl(dp->sem); dp->indom = __ntohpmInDom(dp->indom); dp->units = __ntohpmUnits(dp->units); dp->pmid = __ntohpmID(dp->pmid); } if ((sts = __pmHashAdd((int)dp->pmid, (void *)dp, &lcp->l_hashpmid)) < 0) { free(dp); goto end; } else { char name[MAXPATHLEN]; int numnames; int i; int len; /* read in the names & store in PMNS tree ... */ if ((n = (int)fread(&numnames, 1, sizeof(numnames), f)) != sizeof(numnames)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { fprintf(stderr, "__pmLogLoadMeta: numnames read -> %d: expected: %d\n", n, (int)sizeof(numnames)); } #endif if (ferror(f)) { clearerr(f); sts = -oserror(); } else sts = PM_ERR_LOGREC; goto end; } else { /* swab numnames */ numnames = ntohl(numnames); } for (i = 0; i < numnames; i++) { if ((n = (int)fread(&len, 1, sizeof(len), f)) != sizeof(len)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { fprintf(stderr, "__pmLogLoadMeta: len name[%d] read -> %d: expected: %d\n", i, n, (int)sizeof(len)); } #endif if (ferror(f)) { clearerr(f); sts = -oserror(); } else sts = PM_ERR_LOGREC; goto end; } else { /* swab len */ len = ntohl(len); } if ((n = (int)fread(name, 1, len, f)) != len) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { fprintf(stderr, "__pmLogLoadMeta: name[%d] read -> %d: expected: %d\n", i, n, len); } #endif if (ferror(f)) { clearerr(f); sts = -oserror(); } else sts = PM_ERR_LOGREC; goto end; } name[len] = '\0'; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { char strbuf[20]; fprintf(stderr, "__pmLogLoadMeta: PMID: %s name: %s\n", pmIDStr_r(dp->pmid, strbuf, sizeof(strbuf)), name); } #endif if ((sts = __pmAddPMNSNode(lcp->l_pmns, dp->pmid, name)) < 0) { /* * If we see a duplicate PMID, its a recoverable error. * We wont be able to see all of the data in the log, but * its better to provide access to some rather than none, * esp. when only one or two metric IDs may be corrupted * in this way (which we may not be interested in anyway). */ if (sts != PM_ERR_PMID) goto end; sts = 0; } }/*for*/ } } else if (h.type == TYPE_INDOM) { int *tbuf; pmInDom indom; __pmTimeval *when; int numinst; int *instlist; char **namelist; char *namebase; int *stridx; int i; int k; int allinbuf = 0; PM_FAULT_POINT("libpcp/" __FILE__ ":3", PM_FAULT_ALLOC); if ((tbuf = (int *)malloc(rlen)) == NULL) { sts = -oserror(); goto end; } if ((n = (int)fread(tbuf, 1, rlen, f)) != rlen) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { fprintf(stderr, "__pmLogLoadMeta: indom read -> %d: expected: %d\n", n, rlen); } #endif if (ferror(f)) { clearerr(f); sts = -oserror(); } else sts = PM_ERR_LOGREC; free(tbuf); goto end; } k = 0; when = (__pmTimeval *)&tbuf[k]; when->tv_sec = ntohl(when->tv_sec); when->tv_usec = ntohl(when->tv_usec); k += sizeof(*when)/sizeof(int); indom = __ntohpmInDom((unsigned int)tbuf[k++]); numinst = ntohl(tbuf[k++]); if (numinst > 0) { instlist = &tbuf[k]; k += numinst; stridx = &tbuf[k]; #if defined(HAVE_32BIT_PTR) namelist = (char **)stridx; allinbuf = 1; /* allocation is all in tbuf */ #else allinbuf = 0; /* allocation for namelist + tbuf */ /* need to allocate to hold the pointers */ PM_FAULT_POINT("libpcp/" __FILE__ ":4", PM_FAULT_ALLOC); namelist = (char **)malloc(numinst*sizeof(char*)); if (namelist == NULL) { sts = -oserror(); free(tbuf); goto end; } #endif k += numinst; namebase = (char *)&tbuf[k]; for (i = 0; i < numinst; i++) { instlist[i] = ntohl(instlist[i]); namelist[i] = &namebase[ntohl(stridx[i])]; } } else { /* no instances, or an error */ instlist = NULL; namelist = NULL; } if ((sts = addindom(lcp, indom, when, numinst, instlist, namelist, tbuf, allinbuf)) < 0) { free(tbuf); if (allinbuf == 0) free(namelist); goto end; } } else fseek(f, (long)rlen, SEEK_CUR); n = (int)fread(&check, 1, sizeof(check), f); check = ntohl(check); if (n != sizeof(check) || h.len != check) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { fprintf(stderr, "__pmLogLoadMeta: trailer read -> %d or len=%d: expected %d @ offset=%d\n", n, check, h.len, (int)(ftell(f) - sizeof(check))); } #endif if (ferror(f)) { clearerr(f); sts = -oserror(); } else sts = PM_ERR_LOGREC; goto end; } }/*for*/ end: fseek(f, (long)(sizeof(__pmLogLabel) + 2*sizeof(int)), SEEK_SET); if (sts == 0) { if (numpmid == 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { fprintf(stderr, "__pmLogLoadMeta: no metrics found?\n"); } #endif sts = PM_ERR_LOGREC; } else __pmFixPMNSHashTab(lcp->l_pmns, numpmid, 1); } return sts; } /* * scan the hashed data structures to find a pmDesc, given a pmid */ int __pmLogLookupDesc(__pmLogCtl *lcp, pmID pmid, pmDesc *dp) { __pmHashNode *hp; pmDesc *tp; if ((hp = __pmHashSearch((unsigned int)pmid, &lcp->l_hashpmid)) == NULL) return PM_ERR_PMID_LOG; tp = (pmDesc *)hp->data; *dp = *tp; /* struct assignment */ return 0; } /* * Add a new pmDesc into the metadata log, and to the hashed data structures * If numnames is positive, then write out any associated PMNS names. */ int __pmLogPutDesc(__pmLogCtl *lcp, const pmDesc *dp, int numnames, char **names) { __pmLogHdr h; FILE *f = lcp->l_mdfp; pmDesc *tdp; pmDesc *odp; /* pmDesc to write out */ int onumnames; /* numnames to write out */ int olen; /* length to write out */ int i; int len; pmDesc tmp; h.type = htonl(TYPE_DESC); len = sizeof(__pmLogHdr) + sizeof(pmDesc) + LENSIZE; tmp.type = htonl(dp->type); tmp.sem = htonl(dp->sem); tmp.indom = __htonpmInDom(dp->indom); tmp.units = __htonpmUnits(dp->units); tmp.pmid = __htonpmID(dp->pmid); odp = &tmp; if (numnames > 0) { len += sizeof(numnames); for (i = 0; i < numnames; i++) len += LENSIZE + (int)strlen(names[i]); h.len = htonl(len); onumnames = htonl(numnames); if (fwrite(&h, 1, sizeof(__pmLogHdr), f) != sizeof(__pmLogHdr) || fwrite(odp, 1, sizeof(pmDesc), f) != sizeof(pmDesc) || fwrite(&onumnames, 1, sizeof(numnames), f) != sizeof(numnames)) return -oserror(); /* write out the names */ for (i = 0; i < numnames; i++) { int slen = (int)strlen(names[i]); olen = htonl(slen); if (fwrite(&olen, 1, LENSIZE, f) != LENSIZE) return -oserror(); if (fwrite(names[i], 1, slen, f) != slen) return -oserror(); } olen = htonl(len); if (fwrite(&olen, 1, LENSIZE, f) != LENSIZE) return -oserror(); } else { h.len = htonl(len); olen = htonl(len); if (fwrite(&h, 1, sizeof(__pmLogHdr), f) != sizeof(__pmLogHdr) || fwrite(odp, 1, sizeof(pmDesc), f) != sizeof(pmDesc) || fwrite(&olen, 1, LENSIZE, f) != LENSIZE) return -oserror(); } /* * need to make a copy of the pmDesc, and add this, since caller * may re-use *dp */ PM_FAULT_POINT("libpcp/" __FILE__ ":5", PM_FAULT_ALLOC); if ((tdp = (pmDesc *)malloc(sizeof(pmDesc))) == NULL) return -oserror(); *tdp = *dp; /* struct assignment */ return __pmHashAdd((int)dp->pmid, (void *)tdp, &lcp->l_hashpmid); } static __pmLogInDom * searchindom(__pmLogCtl *lcp, pmInDom indom, __pmTimeval *tp) { __pmHashNode *hp; __pmLogInDom *idp; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { char strbuf[20]; fprintf(stderr, "searchindom( ..., %s, ", pmInDomStr_r(indom, strbuf, sizeof(strbuf))); StrTimeval(tp); fprintf(stderr, ")\n"); } #endif if ((hp = __pmHashSearch((unsigned int)indom, &lcp->l_hashindom)) == NULL) return NULL; idp = (__pmLogInDom *)hp->data; if (tp != NULL) { for ( ; idp != NULL; idp = idp->next) { /* * need first one at or earlier than the requested time */ if (__pmTimevalSub(&idp->stamp, tp) <= 0) break; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { fprintf(stderr, "request @ "); StrTimeval(tp); fprintf(stderr, " is too early for indom @ "); StrTimeval(&idp->stamp); fputc('\n', stderr); } #endif } if (idp == NULL) return NULL; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LOGMETA) { fprintf(stderr, "success for indom @ "); StrTimeval(&idp->stamp); fputc('\n', stderr); } #endif return idp; } /* * for the given indom retrieve the instance domain that is correct * as of the latest time (tp == NULL) or at a designated * time */ int __pmLogGetInDom(__pmLogCtl *lcp, pmInDom indom, __pmTimeval *tp, int **instlist, char ***namelist) { __pmLogInDom *idp = searchindom(lcp, indom, tp); if (idp == NULL) return PM_ERR_INDOM_LOG; *instlist = idp->instlist; *namelist = idp->namelist; return idp->numinst; } int __pmLogLookupInDom(__pmLogCtl *lcp, pmInDom indom, __pmTimeval *tp, const char *name) { __pmLogInDom *idp = searchindom(lcp, indom, tp); int i; if (idp == NULL) return PM_ERR_INDOM_LOG; if (idp->numinst < 0) return idp->numinst; /* full match */ for (i = 0; i < idp->numinst; i++) { if (strcmp(name, idp->namelist[i]) == 0) return idp->instlist[i]; } /* half-baked match to first space */ for (i = 0; i < idp->numinst; i++) { char *p = idp->namelist[i]; while (*p && *p != ' ') p++; if (*p == ' ') { if (strncmp(name, idp->namelist[i], p - idp->namelist[i]) == 0) return idp->instlist[i]; } } return PM_ERR_INST_LOG; } int __pmLogNameInDom(__pmLogCtl *lcp, pmInDom indom, __pmTimeval *tp, int inst, char **name) { __pmLogInDom *idp = searchindom(lcp, indom, tp); int i; if (idp == NULL) return PM_ERR_INDOM_LOG; if (idp->numinst < 0) return idp->numinst; for (i = 0; i < idp->numinst; i++) { if (inst == idp->instlist[i]) { *name = idp->namelist[i]; return 0; } } return PM_ERR_INST_LOG; } int __pmLogPutInDom(__pmLogCtl *lcp, pmInDom indom, const __pmTimeval *tp, int numinst, int *instlist, char **namelist) { int sts = 0; __pmLogHdr h; int i; int wlen; int strsize; int *stridx; int real_numinst; int onuminst; pmInDom oindom; __pmTimeval otp; /* * Note: this routine depends upon the names pointed to by namelist[] * being packed, and starting at namelist[0] ... this is exactly * the format returned by pmGetInDom and __pmLogLoadMeta, so it * should be OK */ real_numinst = numinst > 0 ? numinst : 0; PM_FAULT_POINT("libpcp/" __FILE__ ":6", PM_FAULT_ALLOC); if ((stridx = (int *)malloc(real_numinst * sizeof(stridx[0]))) == NULL) return -oserror(); h.len = (int)sizeof(__pmLogHdr) + (int)sizeof(*tp) + (int)sizeof(indom) + (int)sizeof(numinst) + real_numinst * ((int)sizeof(instlist[0]) + (int)sizeof(stridx[0])) + (int)sizeof(h.len); strsize = 0; for (i = 0; i < numinst; i++) { strsize += (int)strlen(namelist[i]) + 1; /* see Note */ stridx[i] = (int)((ptrdiff_t)namelist[i] - (ptrdiff_t)namelist[0]); stridx[i] = htonl(stridx[i]); /* swab */ instlist[i] = htonl(instlist[i]); /* swab: this is changed back after writing */ } h.len += strsize; /* swab all output buffers */ h.len = htonl(h.len); h.type = htonl(TYPE_INDOM); otp.tv_sec = htonl(tp->tv_sec); otp.tv_usec = htonl(tp->tv_usec); oindom = __htonpmInDom(indom); onuminst = htonl(numinst); wlen = (int)fwrite(&h, 1, sizeof(__pmLogHdr), lcp->l_mdfp); wlen += fwrite(&otp, 1, sizeof(otp), lcp->l_mdfp); wlen += fwrite(&oindom, 1, sizeof(oindom), lcp->l_mdfp); wlen += fwrite(&onuminst, 1, sizeof(onuminst), lcp->l_mdfp); if (numinst > 0) { wlen += fwrite(instlist, 1, real_numinst * sizeof(instlist[0]), lcp->l_mdfp); wlen += fwrite(stridx, 1, real_numinst * sizeof(stridx[0]), lcp->l_mdfp); /* see Note */ wlen += fwrite(namelist[0], 1, strsize, lcp->l_mdfp); } wlen += fwrite(&h.len, 1, sizeof(h.len), lcp->l_mdfp); free(stridx); if (wlen != (int)ntohl(h.len)) { char errmsg[PM_MAXERRMSGLEN]; pmprintf("__pmLogPutInDom: wrote %d, expected %d: %s\n", wlen, (int)ntohl(h.len), osstrerror_r(errmsg, sizeof(errmsg))); pmflush(); return -oserror(); } sts = addindom(lcp, indom, tp, numinst, instlist, namelist, NULL, 0); /* swab instance list back again so as to not upset the caller */ for (i = 0; i < numinst; i++) { instlist[i] = ntohl(instlist[i]); } return sts; } int pmLookupInDomArchive(pmInDom indom, const char *name) { int n; int j; __pmHashNode *hp; __pmLogInDom *idp; __pmContext *ctxp; if (indom == PM_INDOM_NULL) return PM_ERR_INDOM; if ((n = pmWhichContext()) >= 0) { ctxp = __pmHandleToPtr(n); if (ctxp == NULL) return PM_ERR_NOCONTEXT; if (ctxp->c_type != PM_CONTEXT_ARCHIVE) { PM_UNLOCK(ctxp->c_lock); return PM_ERR_NOTARCHIVE; } if ((hp = __pmHashSearch((unsigned int)indom, &ctxp->c_archctl->ac_log->l_hashindom)) == NULL) { PM_UNLOCK(ctxp->c_lock); return PM_ERR_INDOM_LOG; } for (idp = (__pmLogInDom *)hp->data; idp != NULL; idp = idp->next) { /* full match */ for (j = 0; j < idp->numinst; j++) { if (strcmp(name, idp->namelist[j]) == 0) { PM_UNLOCK(ctxp->c_lock); return idp->instlist[j]; } } /* half-baked match to first space */ for (j = 0; j < idp->numinst; j++) { char *p = idp->namelist[j]; while (*p && *p != ' ') p++; if (*p == ' ') { if (strncmp(name, idp->namelist[j], p - idp->namelist[j]) == 0) { PM_UNLOCK(ctxp->c_lock); return idp->instlist[j]; } } } } n = PM_ERR_INST_LOG; PM_UNLOCK(ctxp->c_lock); } return n; } int pmNameInDomArchive(pmInDom indom, int inst, char **name) { int n; int j; __pmHashNode *hp; __pmLogInDom *idp; __pmContext *ctxp; if (indom == PM_INDOM_NULL) return PM_ERR_INDOM; if ((n = pmWhichContext()) >= 0) { ctxp = __pmHandleToPtr(n); if (ctxp == NULL) return PM_ERR_NOCONTEXT; if (ctxp->c_type != PM_CONTEXT_ARCHIVE) { PM_UNLOCK(ctxp->c_lock); return PM_ERR_NOTARCHIVE; } if ((hp = __pmHashSearch((unsigned int)indom, &ctxp->c_archctl->ac_log->l_hashindom)) == NULL) { PM_UNLOCK(ctxp->c_lock); return PM_ERR_INDOM_LOG; } for (idp = (__pmLogInDom *)hp->data; idp != NULL; idp = idp->next) { for (j = 0; j < idp->numinst; j++) { if (idp->instlist[j] == inst) { if ((*name = strdup(idp->namelist[j])) == NULL) n = -oserror(); else n = 0; PM_UNLOCK(ctxp->c_lock); return n; } } } n = PM_ERR_INST_LOG; PM_UNLOCK(ctxp->c_lock); } return n; } int pmGetInDomArchive(pmInDom indom, int **instlist, char ***namelist) { int n; int i; int j; char *p; __pmContext *ctxp; __pmHashNode *hp; __pmLogInDom *idp; int numinst = 0; int strsize = 0; int *ilist = NULL; char **nlist = NULL; char **olist; /* avoid ambiguity when no instances or errors */ *instlist = NULL; *namelist = NULL; if (indom == PM_INDOM_NULL) return PM_ERR_INDOM; if ((n = pmWhichContext()) >= 0) { ctxp = __pmHandleToPtr(n); if (ctxp == NULL) return PM_ERR_NOCONTEXT; if (ctxp->c_type != PM_CONTEXT_ARCHIVE) { PM_UNLOCK(ctxp->c_lock); return PM_ERR_NOTARCHIVE; } if ((hp = __pmHashSearch((unsigned int)indom, &ctxp->c_archctl->ac_log->l_hashindom)) == NULL) { PM_UNLOCK(ctxp->c_lock); return PM_ERR_INDOM_LOG; } for (idp = (__pmLogInDom *)hp->data; idp != NULL; idp = idp->next) { for (j = 0; j < idp->numinst; j++) { for (i = 0; i < numinst; i++) { if (idp->instlist[j] == ilist[i]) break; } if (i == numinst) { numinst++; PM_FAULT_POINT("libpcp/" __FILE__ ":7", PM_FAULT_ALLOC); if ((ilist = (int *)realloc(ilist, numinst*sizeof(ilist[0]))) == NULL) { __pmNoMem("pmGetInDomArchive: ilist", numinst*sizeof(ilist[0]), PM_FATAL_ERR); } PM_FAULT_POINT("libpcp/" __FILE__ ":8", PM_FAULT_ALLOC); if ((nlist = (char **)realloc(nlist, numinst*sizeof(nlist[0]))) == NULL) { __pmNoMem("pmGetInDomArchive: nlist", numinst*sizeof(nlist[0]), PM_FATAL_ERR); } ilist[numinst-1] = idp->instlist[j]; nlist[numinst-1] = idp->namelist[j]; strsize += strlen(idp->namelist[j])+1; } } } PM_FAULT_POINT("libpcp/" __FILE__ ":9", PM_FAULT_ALLOC); if ((olist = (char **)malloc(numinst*sizeof(olist[0]) + strsize)) == NULL) { __pmNoMem("pmGetInDomArchive: olist", numinst*sizeof(olist[0]) + strsize, PM_FATAL_ERR); } p = (char *)olist; p += numinst * sizeof(olist[0]); for (i = 0; i < numinst; i++) { olist[i] = p; strcpy(p, nlist[i]); p += strlen(nlist[i]) + 1; } free(nlist); *instlist = ilist; *namelist = olist; n = numinst; PM_UNLOCK(ctxp->c_lock); } return n; } pcp-3.8.12ubuntu1/src/libpcp/src/optfetch.c0000664000000000000000000004236412272262501015422 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Generic routines to provide the "optimized" pmFetch bundling * services ... the optimization is driven by the crude heuristics * weights defined in optcost below. * * Thread-safe notes * * lrand48() is not thread-safe, but we don't really care here. */ /* if DESPERATE, we need DEBUG */ #if defined(DESPERATE) && !defined(PCP_DEBUG) #define DEBUG #endif #include "pmapi.h" #include "impl.h" #include /* * elements of optcost are * * c_pmid cost per PMD for PMIDs in a fetch * c_indom cost per PMD for indoms in a fetch * c_fetch cost of a new fetch group (should be less than * c_indomsize * c_xtrainst, else all fetches will go * into a single group, unless the scope is global) * c_indomsize expected numer of instances for an indom * c_xtrainst cost of retrieving an unwanted metric inst * c_scope cost opt., 0 for incremental, 1 for global */ /* default costs */ static optcost_t optcost = { 4, 1, 15, 10, 2, 0 }; static int addpmid(fetchctl_t *fp, pmID pmid) { int i; int j; for (i = 0; i < fp->f_numpmid; i++) { if (pmid == fp->f_pmidlist[i]) return 0; if (pmid > fp->f_pmidlist[i]) break; } fp->f_numpmid++; fp->f_pmidlist = (pmID *)realloc(fp->f_pmidlist, fp->f_numpmid*sizeof(pmID)); if (fp->f_pmidlist == NULL) { __pmNoMem("addpmid", fp->f_numpmid*sizeof(pmID), PM_FATAL_ERR); } for (j = fp->f_numpmid-1; j > i; j--) fp->f_pmidlist[j] = fp->f_pmidlist[j-1]; fp->f_pmidlist[i] = pmid; return 1; } static int addinst(int *numinst, int **instlist, optreq_t *new) { int i; int j; int k; int numi; int *ilist; int match; if (*numinst == 0) return 0; if (new->r_numinst == 0) { *numinst = 0; if (*instlist != NULL) { free(*instlist); *instlist = NULL; } return 1; } numi = *numinst; if (numi == -1) numi = 0; ilist = (int *)realloc(*instlist, (numi + new->r_numinst)*sizeof(int)); if (ilist == NULL) { __pmNoMem("addinst.up", (numi + new->r_numinst)*sizeof(int), PM_FATAL_ERR); } for (j = 0; j < new->r_numinst; j++) { match = 0; for (i = 0; i < numi; i++) { if (ilist[i] == new->r_instlist[j]) { match = 1; break; } if (ilist[i] > new->r_instlist[j]) break; } if (match) continue; for (k = numi; k > i; k--) ilist[k] = ilist[k-1]; ilist[i] = new->r_instlist[j]; numi++; } ilist = (int *)realloc(ilist, numi*sizeof(int)); if (ilist == NULL) { __pmNoMem("addinst.down", numi*sizeof(int), PM_FATAL_ERR); } *numinst = numi; *instlist = ilist; return 1; } /* * if we retrieve the instances identified by numa and lista[], how much larger * is this than the set of instances identified by numb and listb[]? */ static int missinst(int numa, int *lista, int numb, int *listb) { int xtra = 0; int i; int j; PM_LOCK(__pmLock_libpcp); /* count in lista[] but _not_ in listb[] */ if (numa == 0) { /* special case for all instances in lista[] */ if (numb != 0 && numb < optcost.c_indomsize) xtra += optcost.c_indomsize - numb; } else { /* not all instances for both lista[] and listb[] */ i = 0; j = 0; while (i < numa && j < numb) { if (lista[i] == listb[j]) { i++; j++; } else if (lista[i] < listb[j]) { i++; xtra++; } else { j++; xtra++; } } xtra += (numa - i) + (numb - j); } PM_UNLOCK(__pmLock_libpcp); return xtra; } static void redoinst(fetchctl_t *fp) { indomctl_t *idp; pmidctl_t *pmp; optreq_t *rqp; for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) { idp->i_numinst = -1; for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) { pmp->p_numinst = -1; for (rqp = pmp->p_rqp; rqp != NULL; rqp = rqp->r_next) { addinst(&pmp->p_numinst, &pmp->p_instlist, rqp); addinst(&idp->i_numinst, &idp->i_instlist, rqp); } } } } static void redopmid(fetchctl_t *fp) { indomctl_t *idp; pmidctl_t *pmp; fp->f_numpmid = 0; for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) { for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) { addpmid(fp, pmp->p_pmid); } } } static int optCost(fetchctl_t *fp) { indomctl_t *idp; indomctl_t *xidp; pmidctl_t *pmp; pmidctl_t *xpmp; __pmID_int *pmidp; __pmInDom_int *indomp; int pmd; int cost = 0; int done; PM_LOCK(__pmLock_libpcp); /* * cost per PMD for the pmids in this fetch */ for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) { for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) { pmidp = (__pmID_int *)&pmp->p_pmid; pmd = pmidp->domain; done = 0; for (xidp = fp->f_idp; xidp != NULL; xidp = xidp->i_next) { for (xpmp = xidp->i_pmp; xpmp != NULL; xpmp = xpmp->p_next) { pmidp = (__pmID_int *)&xpmp->p_pmid; if (xpmp != pmp && pmd == pmidp->domain) { done = 1; break; } if (xpmp == pmp) { cost += optcost.c_pmid; done = 1; break; } } if (done || xidp == idp) break; } } } /* * cost per PMD for the indoms in this fetch */ for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) { indomp = (__pmInDom_int *)&idp->i_indom; pmd = indomp->domain; for (xidp = fp->f_idp; xidp != idp; xidp = xidp->i_next) { indomp = (__pmInDom_int *)&xidp->i_indom; if (pmd == indomp->domain) break; } if (xidp == idp) cost += optcost.c_indom; } /* * cost for extra retrievals due to multiple metrics over the same indom */ for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) { for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) { cost += optcost.c_xtrainst * missinst(idp->i_numinst, idp->i_instlist, pmp->p_numinst, pmp->p_instlist); } } PM_UNLOCK(__pmLock_libpcp); return cost; } #ifdef PCP_DEBUG static char * statestr(int state, char *sbuf) { sbuf[0] = '\0'; if (state & OPT_STATE_NEW) strcat(sbuf, "NEW "); if (state & OPT_STATE_PMID) strcat(sbuf, "PMID "); if (state & OPT_STATE_PROFILE) strcat(sbuf, "PROFILE "); if (state & OPT_STATE_XREQ) strcat(sbuf, "XREQ "); if (state & OPT_STATE_XPMID) strcat(sbuf, "XPMID "); if (state & OPT_STATE_XINDOM) strcat(sbuf, "XINDOM "); if (state & OPT_STATE_XFETCH) strcat(sbuf, "XFETCH "); if (state & OPT_STATE_XPROFILE) strcat(sbuf, "XPROFILE "); return sbuf; } static void dumplist(FILE *f, int style, char *tag, int numi, int *ilist) { char strbuf[20]; fprintf(f, "%s: [%d]", tag, numi); if (ilist == NULL) fprintf(f, " (nil)\n"); else { int i; for (i = 0; i < numi; i++) { if (style == 1) fprintf(f, " %s", pmIDStr_r((pmID)ilist[i], strbuf, sizeof(strbuf))); else fprintf(f, " %d", ilist[i]); } fputc('\n', f); } } static void ___pmOptFetchDump(FILE *f, const fetchctl_t *fp) { indomctl_t *idp; pmidctl_t *pmp; optreq_t *rqp; char strbuf[100]; fflush(stderr); fflush(stdout); fprintf(f, "Dump optfetch structures from " PRINTF_P_PFX "%p next=" PRINTF_P_PFX "%p\n", fp, fp->f_next); fprintf(f, "Fetch Control @ " PRINTF_P_PFX "%p: cost=%d state=%s\n", fp, fp->f_cost, statestr(fp->f_state, strbuf)); dumplist(f, 1, "PMIDs", fp->f_numpmid, (int *)fp->f_pmidlist); for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) { fprintf(f, " InDom %s Control @ " PRINTF_P_PFX "%p:\n", pmInDomStr_r(idp->i_indom, strbuf, sizeof(strbuf)), idp); dumplist(f, 0, " instances", idp->i_numinst, idp->i_instlist); for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) { fprintf(f, " PMID %s Control @ " PRINTF_P_PFX "%p:\n", pmIDStr_r(pmp->p_pmid, strbuf, sizeof(strbuf)), pmp); dumplist(f, 0, " instances", pmp->p_numinst, pmp->p_instlist); for (rqp = pmp->p_rqp; rqp != NULL; rqp = rqp->r_next) { fprintf(f, " Request @ " PRINTF_P_PFX "%p:\n", rqp); dumplist(f, 0, " instances", rqp->r_numinst, rqp->r_instlist); } } } fputc('\n', f); fflush(f); } void __pmOptFetchDump(FILE *f, const fetchctl_t *root) { const fetchctl_t *fp; for (fp = root; fp != NULL; fp = fp->f_next) ___pmOptFetchDump(f, fp); } #endif /* DEBUG */ /* * add a new request into a group of fetches ... * only failure is from calloc() and this is fatal */ void __pmOptFetchAdd(fetchctl_t **root, optreq_t *new) { fetchctl_t *fp; fetchctl_t *tfp; indomctl_t *idp; pmidctl_t *pmp = NULL; int mincost; int change; pmInDom indom = new->r_desc->indom; pmID pmid = new->r_desc->pmid; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); /* add new fetch as first option ... will be reclaimed later if not used */ if ((fp = (fetchctl_t *)calloc(1, sizeof(fetchctl_t))) == NULL) { __pmNoMem("optAddFetch.fetch", sizeof(fetchctl_t), PM_FATAL_ERR); } fp->f_next = *root; *root = fp; for (fp = *root; fp != NULL; fp = fp->f_next) { fp->f_cost = optCost(fp); change = OPT_STATE_XINDOM | OPT_STATE_XPMID | OPT_STATE_XREQ; for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) { if (idp->i_indom != indom) continue; change = OPT_STATE_XPMID | OPT_STATE_XREQ; for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) { if (pmp->p_pmid == pmid) { change = OPT_STATE_XREQ; break; } } break; } if (fp == *root) change |= OPT_STATE_XFETCH; fp->f_state = (fp->f_state & OPT_STATE_UMASK) | change; if (change & OPT_STATE_XINDOM) { if ((idp = (indomctl_t *)calloc(1, sizeof(indomctl_t))) == NULL) { __pmNoMem("optAddFetch.indomctl", sizeof(indomctl_t), PM_FATAL_ERR); } idp->i_indom = indom; idp->i_next = fp->f_idp; idp->i_numinst = -1; fp->f_idp = idp; } if (change & OPT_STATE_XPMID) { if ((pmp = (pmidctl_t *)calloc(1, sizeof(pmidctl_t))) == NULL) { __pmNoMem("optAddFetch.pmidctl", sizeof(pmidctl_t), PM_FATAL_ERR); } pmp->p_next = idp->i_pmp; idp->i_pmp = pmp; pmp->p_pmid = pmid; pmp->p_numinst = -1; } addinst(&pmp->p_numinst, &pmp->p_instlist, new); if (addinst(&idp->i_numinst, &idp->i_instlist, new)) fp->f_state |= OPT_STATE_XPROFILE; fp->f_newcost = optCost(fp); if (fp == *root) fp->f_newcost += optcost.c_fetch; #ifdef DESPERATE if (pmDebug & DBG_TRACE_OPTFETCH) { char strbuf[100]; fprintf(stderr, "optFetch: cost="); if (fp->f_cost == OPT_COST_INFINITY) fprintf(stderr, "INFINITY"); else fprintf(stderr, "%d", fp->f_cost); fprintf(stderr, ", newcost="); if (fp->f_newcost == OPT_COST_INFINITY) fprintf(stderr, "INFINITY"); else fprintf(stderr, "%d", fp->f_newcost); fprintf(stderr, ", for %s @ grp 0x%x,", pmIDStr_r(pmid, strbuf, sizeof(strbuf)), fp); fprintf(stderr, " state %s\n", statestr(fp->f_state, strbuf)); } #endif } tfp = NULL; mincost = OPT_COST_INFINITY; for (fp = *root; fp != NULL; fp = fp->f_next) { int cost; if (optcost.c_scope) /* global */ cost = fp->f_newcost; else /* local */ cost = fp->f_newcost - fp->f_cost; if (cost < mincost) { mincost = cost; tfp = fp; } } #ifdef DESPERATE if (pmDebug & DBG_TRACE_OPTFETCH) { char strbuf[100]; fprintf(stderr, "optFetch: chose %s cost=%d for %s @ grp 0x%x,", optcost.c_scope ? "global" : "incremental", mincost, pmIDStr_r(pmid, strbuf, sizeof(strbuf)), tfp); fprintf(stderr, " change %s\n", statestr(tfp->f_state, strbuf)); } #endif /* * Warning! Traversal of the list is a bit tricky, because the * current element (fp) may be freed, making fp->fp_next * a bad idea at the end of each iteration ... */ for (fp = *root; fp != NULL; ) { for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) { if (idp->i_indom != indom) continue; for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) { if (pmp->p_pmid == pmid) break; } break; } assert(idp != NULL && pmp != NULL); if (fp == tfp) { /* * The chosen one ... */ if (fp->f_state & OPT_STATE_XFETCH) fp->f_state |= OPT_STATE_NEW; if (addpmid(tfp, pmid)) fp->f_state |= OPT_STATE_PMID; if (fp->f_state & OPT_STATE_XPROFILE) fp->f_state |= OPT_STATE_PROFILE; new->r_next = pmp->p_rqp; new->r_fetch = tfp; pmp->p_rqp = new; fp->f_cost = fp->f_newcost; fp->f_state &= OPT_STATE_UMASK; fp = fp->f_next; } else { /* * Otherwise, need to undo changes made to data structures. * Note. if new structures added, they will be at the start of * their respective lists. */ if (fp->f_state & OPT_STATE_XPMID) { idp->i_pmp = pmp->p_next; free(pmp); } if (fp->f_state & OPT_STATE_XINDOM) { fp->f_idp = idp->i_next; free(idp); } if (fp->f_state & OPT_STATE_XFETCH) { *root = fp->f_next; free(fp); fp = *root; } else { redoinst(fp); fp->f_state &= OPT_STATE_UMASK; fp = fp->f_next; } } } PM_UNLOCK(__pmLock_libpcp); return; } /* * remove a request from a group of fetches */ int __pmOptFetchDel(fetchctl_t **root, optreq_t *new) { fetchctl_t *fp; fetchctl_t *p_fp; indomctl_t *idp; indomctl_t *p_idp; pmidctl_t *pmp; pmidctl_t *p_pmp; optreq_t *rqp; optreq_t *p_rqp; p_fp = NULL; for (fp = *root; fp != NULL; fp = fp->f_next) { p_idp = NULL; for (idp = fp->f_idp; idp != NULL; idp = idp->i_next) { p_pmp = NULL; for (pmp = idp->i_pmp; pmp != NULL; pmp = pmp->p_next) { p_rqp = NULL; for (rqp = pmp->p_rqp; rqp != NULL; rqp = rqp->r_next) { if (rqp == new) { if (p_rqp != NULL) /* not first request for this metric */ p_rqp->r_next = rqp->r_next; else if (rqp->r_next != NULL) /* first of several requests for this metric */ pmp->p_rqp = rqp->r_next; else { /* only request for this metric */ if (p_pmp != NULL) /* not first metric for this indom */ p_pmp->p_next = pmp->p_next; else if (pmp->p_next != NULL) /* first of several metrics for this indom */ idp->i_pmp = pmp->p_next; else { /* only metric for this indom */ if (p_idp != NULL) /* not first indom for this fetch */ p_idp->i_next = idp->i_next; else if (idp->i_next != NULL) /* first of several idoms for this fetch */ fp->f_idp = idp->i_next; else { /* only indom for this fetch */ if (p_fp != NULL) /* not first fetch for the group */ p_fp->f_next = fp->f_next; else /* first of fetch for the group */ *root = fp->f_next; free(fp); fp = NULL; } free(idp); } free(pmp); } /* data structures repaired, now redo lists */ if (fp != NULL) { redoinst(fp); redopmid(fp); fp->f_state = OPT_STATE_PMID | OPT_STATE_PROFILE; fp->f_cost = optCost(fp); } return 0; } p_rqp = rqp; } p_pmp = pmp; } p_idp = idp; } p_fp = fp; } return -1; } void __pmOptFetchRedo(fetchctl_t **root) { fetchctl_t *newroot = NULL; fetchctl_t *fp; fetchctl_t *t_fp; indomctl_t *idp; indomctl_t *t_idp; pmidctl_t *pmp; pmidctl_t *t_pmp; optreq_t *rqp; optreq_t *t_rqp; optreq_t *p_rqp; optreq_t *rlist; int numreq; rlist = NULL; numreq = 0; /* * collect all of the requests first */ for (fp = *root; fp != NULL; ) { for (idp = fp->f_idp; idp != NULL; ) { for (pmp = idp->i_pmp; pmp != NULL; ) { for (rqp = pmp->p_rqp; rqp != NULL; ) { t_rqp = rqp->r_next; rqp->r_next = rlist; rlist = rqp; rqp = t_rqp; numreq++; } t_pmp = pmp; pmp = pmp->p_next; free(t_pmp); } t_idp = idp; idp = idp->i_next; free(t_idp); } t_fp = fp; fp = fp->f_next; free(t_fp); } if (numreq) { /* something to do, randomly cut and splice the list of requests */ numreq = (int)lrand48() % numreq; t_rqp = rlist; p_rqp = NULL; for (rqp = rlist; rqp != NULL; rqp = rqp->r_next) { if (numreq == 0) t_rqp = rqp; numreq--; p_rqp = rqp; } if (p_rqp == NULL || t_rqp == rlist) /* do nothing */ ; else { /* p_rqp is end of list, t_rqp is new head */ p_rqp->r_next = rlist; rlist = t_rqp->r_next; t_rqp->r_next = NULL; } /* now add them all back again */ for (rqp = rlist; rqp != NULL; ) { /* warning, rqp->r_next may change */ t_rqp = rqp->r_next; __pmOptFetchAdd(&newroot, rqp); rqp = t_rqp; } } *root = newroot; return; } void __pmOptFetchGetParams(optcost_t *ocp) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); *ocp = optcost; PM_UNLOCK(__pmLock_libpcp); return; } void __pmOptFetchPutParams(optcost_t *ocp) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); optcost = *ocp; PM_UNLOCK(__pmLock_libpcp); return; } pcp-3.8.12ubuntu1/src/libpcp/src/GNUmakefile0000664000000000000000000001020612272262501015502 0ustar # # Copyright (c) 2012-2013 Red Hat. # Copyright (c) 2008 Aconex. All Rights Reserved. # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs CFILES = connect.c context.c desc.c err.c fetch.c freeresult.c \ help.c instance.c p_desc.c p_error.c p_fetch.c p_instance.c \ p_profile.c p_result.c p_text.c p_pmns.c p_creds.c p_auth.c \ pdu.c pdubuf.c pmns.c profile.c store.c units.c util.c ipc.c \ sortinst.c logmeta.c logportmap.c logutil.c tz.c interp.c \ checksum.c rtime.c tv.c spec.c fetchlocal.c optfetch.c AF.c \ stuffvalue.c endian.c config.c auxconnect.c auxserver.c discovery.c \ p_lcontrol.c p_lrequest.c p_lstatus.c logconnect.c logcontrol.c \ connectlocal.c derive.c derive_fetch.c events.c lock.c hash.c \ fault.c access.c HFILES = derive.h internal.h VERSION_SCRIPT = exports LSRCFILES = check-statics $(VERSION_SCRIPT) ifeq "$(ENABLE_SECURE)" "true" LLDLIBS += $(LIB_FOR_SSL) $(LIB_FOR_NSS) $(LIB_FOR_NSPR) $(LIB_FOR_SASL) LCFLAGS += $(NSSCFLAGS) $(NSPRCFLAGS) $(SASLCFLAGS) CFILES += secureserver.c secureconnect.c else LSRCFILES += secureserver.c secureconnect.c endif ifeq "$(ENABLE_AVAHI)" "true" LLDLIBS += $(LIB_FOR_AVAHI) LCFLAGS += $(AVAHICFLAGS) CFILES += avahi.c HFILES += avahi.h else LSRCFILES += avahi.c avahi.h endif ifneq "$(TARGET_OS)" "mingw" CFILES += accounts.c LSRCFILES += win32.c else CFILES += win32.c LSRCFILES += accounts.c LLDLIBS += -lpsapi endif ifeq "$(TARGET_OS)" "solaris" # enables standards compliant thread-safe interfaces (accounts.c) LCFLAGS += -D_POSIX_PTHREAD_SEMANTICS endif ifeq "$(LIB_FOR_BASENAME)" "-lpcp" # don't need to be linked to myself in this case! LIB_FOR_BASENAME = endif LLDLIBS += $(LIB_FOR_MATH) $(LIB_FOR_PTHREADS) LCFLAGS += -DLIBPCP_INTERNAL '-DEXEC_SUFFIX="$(EXECSUFFIX)"' \ '-DDSO_SUFFIX="$(DSOSUFFIX)"' DSOVERSION = 3 STATICLIBTARGET = libpcp.a LIBTARGET = libpcp.$(DSOSUFFIX).$(DSOVERSION) SYMTARGET = libpcp.$(DSOSUFFIX) libpcp.$(DSOSUFFIX).2 ifeq "$(PACKAGE_DISTRIBUTION)" "debian" SYMTARGET = libpcp.$(DSOSUFFIX) endif ifeq "$(TARGET_OS)" "darwin" LIBTARGET = libpcp.$(DSOVERSION).$(DSOSUFFIX) SYMTARGET = libpcp.$(DSOSUFFIX) endif ifeq "$(TARGET_OS)" "mingw" STATICLIBTARGET = LIBTARGET = libpcp.$(DSOSUFFIX) SYMTARGET = endif ifeq "$(ENABLE_SHARED)" "no" LIBTARGET = SYMTARGET = endif LDIRT += $(SYMTARGET) check.done base default : $(LIBTARGET) check.done $(SYMTARGET) $(STATICLIBTARGET) ifneq "$(SYMTARGET)" "" $(SYMTARGET): $(LN_S) -f $(LIBTARGET) $@ endif include $(BUILDRULES) *.o: internal.h derive.o derive_fetch.o: derive.h util.o: $(TOPDIR)/src/include/pcp/pmdbg.h $(OBJECTS): $(TOPDIR)/src/include/pcp/pmapi.h \ $(TOPDIR)/src/include/pcp/impl.h \ $(TOPDIR)/src/include/pcp/platform_defs.h ifeq "$(TARGET_OS)" "mingw" kernel_pmda_dso = windows else kernel_pmda_dso = $(TARGET_OS) endif install : default ifneq ($(LIBTARGET),) $(INSTALL) -m 755 $(LIBTARGET) $(PCP_LIB_DIR)/$(LIBTARGET) endif ifneq ($(SYMTARGET),) for tt in $(SYMTARGET); do \ $(INSTALL) -S $(LIBTARGET) $(PCP_LIB_DIR)/$$tt || exit 1; \ done endif ifneq ($(STATICLIBTARGET),) $(INSTALL) -m 755 $(STATICLIBTARGET) $(PCP_LIB_DIR)/$(STATICLIBTARGET) endif default_pcp : default install_pcp : install $(TOPDIR)/src/pmns/stdpmid: cd $(@D); $(MAKE) $(@F) # The library is thread-safe ... check-statics will force a build failure # if there has been any change to the static variables and their disposition # ... refer to check-statics to add exceptions and annotations for new # cases # check.done: $(OBJECTS) ./check-statics touch check.done ifneq ($(LIBTARGET),) $(LIBTARGET): $(VERSION_SCRIPT) endif pcp-3.8.12ubuntu1/src/libpcp/src/logcontrol.c0000664000000000000000000000321412272262501015757 0ustar /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe note * * This routine is not thread-safe as there is no serialization on the * use of the fd between the __pmSendLogControl() and the reading of * the reply PDU. It is assumed that the caller is single-threaded, * which is true for the only current user of this routine, pmlc(1). */ #include "pmapi.h" #include "impl.h" int __pmControlLog(int fd, const pmResult *request, int control, int state, int delta, pmResult **status) { int n; __pmPDU *pb; if (request->numpmid < 1) return PM_ERR_TOOSMALL; /* send a PCP 2.0 log control request */ n = __pmSendLogControl(fd, request, control, state, delta); if (n < 0) n = __pmMapErrno(n); else { int pinpdu; /* get the reply */ pinpdu = n = __pmGetPDU(fd, ANY_SIZE, __pmLoggerTimeout(), &pb); if (n == PDU_RESULT) { n = __pmDecodeResult(pb, status); } else if (n == PDU_ERROR) __pmDecodeError(pb, &n); else if (n != PM_ERR_TIMEOUT) n = PM_ERR_IPC; /* unknown reply type */ if (pinpdu > 0) __pmUnpinPDUBuf(pb); } return n; } pcp-3.8.12ubuntu1/src/libpcp/src/profile.c0000664000000000000000000002316212272262501015241 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" static int * _subtract(int *list, int *list_len, int *arg, int arg_len) { int *new; int len = *list_len; int new_len = 0; int i, j; if (list == NULL) /* noop */ return NULL; new = (int *)malloc(len * sizeof(int)); if (new == NULL) return NULL; for (i=0; i < len; i++) { for (j=0; j < arg_len; j++) if (list[i] == arg[j]) break; if (j == arg_len) /* this instance survived */ new[new_len++] = list[i]; } free(list); *list_len = new_len; return new; } static int * _union(int *list, int *list_len, int *arg, int arg_len) { int *new; int len = *list_len; int new_len = *list_len; int i, j; if (list == NULL) { list = (int *)malloc(arg_len * sizeof(int)); memcpy((void *)list, (void *)arg, arg_len * sizeof(int)); *list_len = arg_len; return list; } new = (int *)realloc((void *)list, (len + arg_len) * sizeof(int)); if (new == NULL) return NULL; for (i=0; i < arg_len; i++) { for (j=0; j < new_len; j++) { if (arg[i] == new[j]) break; } if (j == new_len) /* instance is not already in the list */ new[new_len++] = arg[i]; } *list_len = new_len; return new; } static void _setGlobalState(__pmContext *ctxp, int state) { __pmInDomProfile *p, *p_end; /* free everything and set the global state */ if (ctxp->c_instprof->profile) { for (p=ctxp->c_instprof->profile, p_end = p + ctxp->c_instprof->profile_len; p < p_end; p++) { if (p->instances) free(p->instances); p->instances_len = 0; } free(ctxp->c_instprof->profile); ctxp->c_instprof->profile = NULL; ctxp->c_instprof->profile_len = 0; } ctxp->c_instprof->state = state; ctxp->c_sent = 0; } static __pmInDomProfile * _newprof(pmInDom indom, __pmContext *ctxp) { __pmInDomProfile *p; if (ctxp->c_instprof->profile == NULL) { /* create a new profile for this inDom in the default state */ p = ctxp->c_instprof->profile = (__pmInDomProfile *)malloc( sizeof(__pmInDomProfile)); if (p == NULL) /* fail, no changes */ return NULL; ctxp->c_instprof->profile_len = 1; } else { /* append a new profile to the end of the list */ ctxp->c_instprof->profile_len++; p = (__pmInDomProfile *)realloc((void *)ctxp->c_instprof->profile, ctxp->c_instprof->profile_len * sizeof(__pmInDomProfile)); if (p == NULL) /* fail, no changes */ return NULL; ctxp->c_instprof->profile = p; p = ctxp->c_instprof->profile + ctxp->c_instprof->profile_len - 1; } /* initialise a new profile entry : default = include all instances */ p->indom = indom; p->instances = NULL; p->instances_len = 0; p->state = PM_PROFILE_INCLUDE; return p; } __pmInDomProfile * __pmFindProfile(pmInDom indom, const __pmProfile *prof) { __pmInDomProfile *p, *p_end; if (prof != NULL && prof->profile_len > 0) /* search for the profile entry for this instance domain */ for (p=prof->profile, p_end=p+prof->profile_len; p < p_end; p++) { if (p->indom == indom) /* found : an entry for this instance domain already exists */ return p; } /* not found */ return NULL; } int __pmInProfile(pmInDom indom, const __pmProfile *prof, int inst) { __pmInDomProfile *p; int *in, *in_end; if (prof == NULL) /* default if no profile for any instance domains */ return 1; if ((p = __pmFindProfile(indom, prof)) == NULL) /* no profile for this indom => use global default */ return (prof->state == PM_PROFILE_INCLUDE) ? 1 : 0; for (in=p->instances, in_end=in+p->instances_len; in < in_end; in++) if (*in == inst) /* present in the list => inverse of default for this indom */ return (p->state == PM_PROFILE_INCLUDE) ? 0 : 1; /* not in the list => use default for this indom */ return (p->state == PM_PROFILE_INCLUDE) ? 1 : 0; } void __pmFreeProfile(__pmProfile *prof) { __pmInDomProfile *p, *p_end; if (prof != NULL) { if (prof->profile != NULL) { for (p=prof->profile, p_end = p+prof->profile_len; p < p_end; p++) { if (p->instances) free(p->instances); } if (prof->profile_len) free(prof->profile); } free(prof); } } int pmAddProfile(pmInDom indom, int instlist_len, int instlist[]) { int sts; __pmContext *ctxp; __pmInDomProfile *prof; if (indom == PM_INDOM_NULL && instlist != NULL) /* semantic disconnect! */ return PM_ERR_PROFILESPEC; if ((sts = pmWhichContext()) < 0) return sts; ctxp = __pmHandleToPtr(sts); if (ctxp == NULL) return PM_ERR_NOCONTEXT; if (indom == PM_INDOM_NULL && instlist_len == 0) { _setGlobalState(ctxp, PM_PROFILE_INCLUDE); goto SUCCESS; } if ((prof = __pmFindProfile(indom, ctxp->c_instprof)) == NULL) { if ((prof = _newprof(indom, ctxp)) == NULL) { /* fail */ PM_UNLOCK(ctxp->c_lock); return -oserror(); } else { /* starting state: exclude all except the supplied list */ prof->state = PM_PROFILE_EXCLUDE; } } /* include all instances? */ if (instlist_len == 0 || instlist == NULL) { /* include all instances in this domain */ if (prof->instances) free(prof->instances); prof->instances = NULL; prof->instances_len = 0; prof->state = PM_PROFILE_INCLUDE; goto SUCCESS; } switch (prof->state) { case PM_PROFILE_INCLUDE: /* * prof->instances is an exclusion list (all else included) * => traverse and remove the specified instances (if present) */ prof->instances = _subtract( prof->instances, &prof->instances_len, instlist, instlist_len); break; case PM_PROFILE_EXCLUDE: /* * prof->instances is an inclusion list (all else excluded) * => traverse and add the specified instances (if not already present) */ prof->instances = _union( prof->instances, &prof->instances_len, instlist, instlist_len); break; } SUCCESS: ctxp->c_sent = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PROFILE) { char strbuf[20]; fprintf(stderr, "pmAddProfile() indom: %s\n", pmInDomStr_r(indom, strbuf, sizeof(strbuf))); __pmDumpProfile(stderr, indom, ctxp->c_instprof); } #endif PM_UNLOCK(ctxp->c_lock); return 0; } int pmDelProfile(pmInDom indom, int instlist_len, int instlist[]) { int sts; __pmContext *ctxp; __pmInDomProfile *prof; if (indom == PM_INDOM_NULL && instlist != NULL) /* semantic disconnect! */ return PM_ERR_PROFILESPEC; if ((sts = pmWhichContext()) < 0) return sts; ctxp = __pmHandleToPtr(sts); if (ctxp == NULL) return PM_ERR_NOCONTEXT; if (indom == PM_INDOM_NULL && instlist_len == 0) { _setGlobalState(ctxp, PM_PROFILE_EXCLUDE); goto SUCCESS; } if ((prof = __pmFindProfile(indom, ctxp->c_instprof)) == NULL) { if ((prof = _newprof(indom, ctxp)) == NULL) { /* fail */ PM_UNLOCK(ctxp->c_lock); return -oserror(); } else { /* starting state: include all except the supplied list */ prof->state = PM_PROFILE_EXCLUDE; } } /* include all instances? */ if (instlist_len == 0 || instlist == NULL) { /* include all instances in this domain */ if (prof->instances) free(prof->instances); prof->instances = NULL; prof->instances_len = 0; prof->state = PM_PROFILE_EXCLUDE; goto SUCCESS; } switch (prof->state) { case PM_PROFILE_INCLUDE: /* * prof->instances is an exclusion list (all else included) * => traverse and add the specified instances (if not already present) */ prof->instances = _union( prof->instances, &prof->instances_len, instlist, instlist_len); break; case PM_PROFILE_EXCLUDE: /* * prof->instances is an inclusion list (all else excluded) * => traverse and remove the specified instances (if present) */ prof->instances = _subtract( prof->instances, &prof->instances_len, instlist, instlist_len); break; } SUCCESS: ctxp->c_sent = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PROFILE) { char strbuf[20]; fprintf(stderr, "pmDelProfile() indom: %s\n", pmInDomStr_r(indom, strbuf, sizeof(strbuf))); __pmDumpProfile(stderr, indom, ctxp->c_instprof); } #endif PM_UNLOCK(ctxp->c_lock); return 0; } void __pmDumpProfile(FILE *f, int indom, const __pmProfile *pp) { int j; int k; __pmInDomProfile *prof; char strbuf[20]; fprintf(f, "Dump Instance Profile state=%s, %d profiles", pp->state == PM_PROFILE_INCLUDE ? "INCLUDE" : "EXCLUDE", pp->profile_len); if (indom != PM_INDOM_NULL) fprintf(f, ", dump restricted to indom=%d [%s]", indom, pmInDomStr_r(indom, strbuf, sizeof(strbuf))); fprintf(f, "\n"); for (prof=pp->profile, j=0; j < pp->profile_len; j++, prof++) { if (indom != PM_INDOM_NULL && indom != prof->indom) continue; fprintf(f, "\tProfile [%d] indom=%d [%s] state=%s %d instances\n", j, prof->indom, pmInDomStr_r(prof->indom, strbuf, sizeof(strbuf)), (prof->state == PM_PROFILE_INCLUDE) ? "INCLUDE" : "EXCLUDE", prof->instances_len); if (prof->instances_len) { fprintf(f, "\t\tInstances:"); for (k=0; k < prof->instances_len; k++) fprintf(f, " [%d]", prof->instances[k]); fprintf(f, "\n"); } } } pcp-3.8.12ubuntu1/src/libpcp/src/sortinst.c0000664000000000000000000000174212272262501015466 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include "pmapi.h" static int comp(const void *a, const void *b) { pmValue *ap = (pmValue *)a; pmValue *bp = (pmValue *)b; return ap->inst - bp->inst; } void pmSortInstances(pmResult *rp) { int i; for (i = 0; i < rp->numpmid; i++) { if (rp->vset[i]->numval > 1) { qsort(rp->vset[i]->vlist, rp->vset[i]->numval, sizeof(pmValue), comp); } } } pcp-3.8.12ubuntu1/src/libpcp/src/config.c0000664000000000000000000002345012272262501015046 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2008-2009 Aconex. All Rights Reserved. * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #ifdef HAVE_STRINGS_H #include #endif #ifdef IS_MINGW /* * Fix up the Windows path separator quirkiness - PCP code deals * typically with forward-slash separators (i.e. if not passed in * on the command line, but hard-coded), but only very little now. * In addition, we also need to cater for native Windows programs * versus the MinimalSYStem POSIX-alike shell (which translates a * drive letter into a root filesystem entry for us). Yee-hah! * NB: Only single drive letters allowed (Wikipedia says so) */ char * dos_native_path(char *path) { char *p = path; if (path[0] == '/' && isalpha((int)path[1]) && path[2] == '/') { p[0] = tolower(p[1]); p[1] = ':'; p += 2; } for (; *p; p++) if (*p == '/') *p = '\\'; return path; } static int dos_absolute_path(char *path) { return (isalpha((int)path[0]) && path[1] == ':' && path[2] == '\\'); } static char * msys_native_path(char *path) { char *p = path; /* Only single drive letters allowed (Wikipedia says so) */ if (isalpha((int)path[0]) && path[1] == ':') { p[1] = tolower(p[0]); p[0] = '/'; p += 2; } for (; *p; p++) { if (*p == '\\') *p = '/'; else *p = tolower(*p); } return path; } static char * dos_rewrite_path(char *var, char *val, int msys) { char *p = (char *)rindex(var, '_'); if (p && (strcmp(p, "_PATH") == 0 || strcmp(p, "_DIR") == 0)) { if (msys) return msys_native_path(val); return dos_native_path(val); } return NULL; } /* * For native Win32 console tools, we need to translate the paths * used in scripts to native paths with PCP_DIR prefix prepended. * * For Win32 MSYS shell usage, we need to translate the paths * used in scripts to paths with PCP_DIR prefix prepended AND * drive letter path mapping done AND posix-style separators. * * Choose which way to go based on our environment (SHELL). */ static int posix_style(void) { char *s; int sts; PM_LOCK(__pmLock_libpcp); s = getenv("SHELL"); sts = (s && strncmp(s, "/bin/", 5) == 0); PM_UNLOCK(__pmLock_libpcp); return sts; } static void dos_formatter(char *var, char *prefix, char *val) { char envbuf[MAXPATHLEN]; int msys = posix_style(); if (prefix && dos_rewrite_path(var, val, msys)) { char *p = msys ? msys_native_path(prefix) : prefix; snprintf(envbuf, sizeof(envbuf), "%s=%s%s", var, p, val); } else { snprintf(envbuf, sizeof(envbuf), "%s=%s", var, val); } PM_LOCK(__pmLock_libpcp); putenv(strdup(envbuf)); PM_UNLOCK(__pmLock_libpcp); } INTERN const __pmConfigCallback __pmNativeConfig = dos_formatter; char *__pmNativePath(char *path) { return dos_native_path(path); } int __pmPathSeparator() { return posix_style() ? '/' : '\\'; } int __pmAbsolutePath(char *path) { return posix_style() ? path[0] == '/' : dos_absolute_path(path); } #else char *__pmNativePath(char *path) { return path; } int __pmAbsolutePath(char *path) { return path[0] == '/'; } int __pmPathSeparator() { return '/'; } static void posix_formatter(char *var, char *prefix, char *val) { /* +40 bytes for max PCP env variable name */ char envbuf[MAXPATHLEN+40]; char *vp; char *vend; snprintf(envbuf, sizeof(envbuf), "%s=", var); vend = &val[strlen(val)-1]; if (val[0] == *vend && (val[0] == '\'' || val[0] == '"')) { /* * have quoted value like "gawk --posix" for $PCP_AWK_PROG ... * strip quotes */ vp = &val[1]; vend--; } else vp = val; strncat(envbuf, vp, vend-vp+1); envbuf[strlen(var)+1+vend-vp+1+1] = '\0'; PM_LOCK(__pmLock_libpcp); putenv(strdup(envbuf)); PM_UNLOCK(__pmLock_libpcp); (void)prefix; } INTERN const __pmConfigCallback __pmNativeConfig = posix_formatter; #endif void __pmConfig(__pmConfigCallback formatter) { /* * Scan ${PCP_CONF-$PCP_DIR/etc/pcp.conf} and put all PCP config * variables found therein into the environment. */ FILE *fp; char confpath[32]; char dir[MAXPATHLEN]; char var[MAXPATHLEN]; char *prefix; char *conf; char *val; char *p; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); prefix = getenv("PCP_DIR"); if ((conf = getenv("PCP_CONF")) == NULL) { strncpy(confpath, "/etc/pcp.conf", sizeof(confpath)); if (prefix == NULL) conf = __pmNativePath(confpath); else { snprintf(dir, sizeof(dir), "%s%s", prefix, __pmNativePath(confpath)); conf = dir; } } if (access((const char *)conf, R_OK) < 0 || (fp = fopen(conf, "r")) == (FILE *)NULL) { char errmsg[PM_MAXERRMSGLEN]; pmprintf("FATAL PCP ERROR: could not open config file \"%s\" : %s\n", conf, osstrerror_r(errmsg, sizeof(errmsg))); pmprintf("You may need to set PCP_CONF or PCP_DIR in your environment.\n"); pmflush(); PM_UNLOCK(__pmLock_libpcp); exit(1); } while (fgets(var, sizeof(var), fp) != NULL) { if (var[0] == '#' || (p = strchr(var, '=')) == NULL) continue; *p = '\0'; val = p+1; if ((p = strrchr(val, '\n')) != NULL) *p = '\0'; if ((p = getenv(var)) != NULL) val = p; else formatter(var, prefix, val); if (pmDebug & DBG_TRACE_CONFIG) fprintf(stderr, "pmGetConfig: (init) %s=%s\n", var, val); } fclose(fp); PM_UNLOCK(__pmLock_libpcp); } char * pmGetConfig(const char *name) { /* * state controls one-trip initialization, and recursion guard * for pathological failures in initialization */ static int state = 0; char *val; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (state == 0) { state = 1; PM_UNLOCK(__pmLock_libpcp); __pmConfig(__pmNativeConfig); PM_LOCK(__pmLock_libpcp); state = 2; } else if (state == 1) { /* recursion from error in __pmConfig() ... no value is possible */ PM_UNLOCK(__pmLock_libpcp); if (pmDebug & DBG_TRACE_CONFIG) fprintf(stderr, "pmGetConfig: %s= ... recursion error\n", name); val = ""; return val; } if ((val = getenv(name)) == NULL) { val = ""; } if (pmDebug & DBG_TRACE_CONFIG) fprintf(stderr, "pmGetConfig: %s=%s\n", name, val); PM_UNLOCK(__pmLock_libpcp); return val; } /* * Details of runtime features available in the built libpcp */ static const char *enabled(void) { return "true"; } static const char *disabled(void) { return "false"; } #define STRINGIFY(s) #s #define TO_STRING(s) STRINGIFY(s) static const char *pmapi_version(void) { return TO_STRING(PMAPI_VERSION); } static const char *pcp_version(void) { return PCP_VERSION; } #if defined(HAVE_SECURE_SOCKETS) #include "nss.h" #include "nspr.h" #include "sasl.h" static const char *nspr_version(void) { return PR_VERSION; } static const char *nss_version(void) { return NSS_VERSION; } static const char *sasl_version_string(void) { return TO_STRING(SASL_VERSION_MAJOR.SASL_VERSION_MINOR.SASL_VERSION_STEP); } #endif static const char * ipv6_enabled(void) { #if defined(IS_LINUX) return access("/proc/net/if_inet6", F_OK) == 0 ? enabled() : disabled(); #else return enabled(); #endif } #ifdef PM_MULTI_THREAD #define MULTI_THREAD_ENABLED enabled #else #define MULTI_THREAD_ENABLED disabled #endif #ifdef PM_FAULT_INJECTION #define FAULT_INJECTION_ENABLED enabled #else #define FAULT_INJECTION_ENABLED disabled #endif #if defined(HAVE_SECURE_SOCKETS) #define SECURE_SOCKETS_ENABLED enabled #define AUTHENTICATION_ENABLED enabled #else #define SECURE_SOCKETS_ENABLED disabled #define AUTHENTICATION_ENABLED disabled #endif #if defined(HAVE_STRUCT_SOCKADDR_UN) #define UNIX_DOMAIN_SOCKETS_ENABLED enabled #else #define UNIX_DOMAIN_SOCKETS_ENABLED disabled #endif #if defined(HAVE_STATIC_PROBES) #define STATIC_PROBES_ENABLED enabled #else #define STATIC_PROBES_ENABLED disabled #endif #if defined(HAVE_SERVICE_DISCOVERY) #define SERVICE_DISCOVERY_ENABLED enabled #else #define SERVICE_DISCOVERY_ENABLED disabled #endif typedef const char *(*feature_detector)(void); static struct { const char *feature; feature_detector detector; } features[] = { { "pcp_version", pcp_version }, { "pmapi_version", pmapi_version }, #if defined(HAVE_SECURE_SOCKETS) { "nss_version", nss_version }, { "nspr_version", nspr_version }, { "sasl_version", sasl_version_string }, #endif { "multi_threaded", MULTI_THREAD_ENABLED }, { "fault_injection", FAULT_INJECTION_ENABLED }, { "secure_sockets", SECURE_SOCKETS_ENABLED }, /* from pcp-3.7.x */ { "ipv6", ipv6_enabled }, { "authentication", AUTHENTICATION_ENABLED }, /* from pcp-3.8.x */ { "unix_domain_sockets",UNIX_DOMAIN_SOCKETS_ENABLED }, /* from pcp-3.8.2 */ { "static_probes", STATIC_PROBES_ENABLED }, /* from pcp-3.8.3 */ { "service_discovery", SERVICE_DISCOVERY_ENABLED }, /* from pcp-3.8.6 */ }; void __pmAPIConfig(__pmAPIConfigCallback formatter) { int i; for (i = 0; i < sizeof(features)/sizeof(features[0]); i++) { const char *value = features[i].detector(); if (pmDebug & DBG_TRACE_CONFIG) fprintf(stderr, "__pmAPIConfig: %s=%s\n", features[i].feature, value); formatter(features[i].feature, value); } } const char * __pmGetAPIConfig(const char *name) { int i; for (i = 0; i < sizeof(features)/sizeof(features[0]); i++) if (strcasecmp(name, features[i].feature) == 0) return features[i].detector(); return NULL; } pcp-3.8.12ubuntu1/src/libpcp/src/discovery.c0000664000000000000000000001203312272262501015603 0ustar /* * Copyright (c) 2013-2014 Red Hat. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "internal.h" #include "avahi.h" #if defined(HAVE_SERVICE_DISCOVERY) /* * Advertise the given service using all available means. The implementation * must support adding and removing individual service specs on the fly. * e.g. "pmcd" on port 1234 */ __pmServerPresence * __pmServerAdvertisePresence(const char *serviceSpec, int port) { __pmServerPresence *s; /* Allocate a server presence and copy the given data. */ if ((s = malloc(sizeof(*s))) == NULL) { __pmNoMem("__pmServerAdvertisePresence: can't allocate __pmServerPresence", sizeof(*s), PM_FATAL_ERR); } s->serviceSpec = strdup(serviceSpec); if (s->serviceSpec == NULL) { __pmNoMem("__pmServerAdvertisePresence: can't allocate service spec", strlen(serviceSpec) + 1, PM_FATAL_ERR); } s->port = port; /* Now advertise our presence using all available means. If a particular * method is not available or not configured, then the respective call * will have no effect. Currently, only Avahi is supported. */ __pmServerAvahiAdvertisePresence(s); return s; } /* * Unadvertise the given service using all available means. The implementation * must support removing individual service specs on the fly. * e.g. "pmcd" on port 1234 */ void __pmServerUnadvertisePresence(__pmServerPresence *s) { /* Unadvertise our presence for all available means. If a particular * method is not active, then the respective call will have no effect. */ __pmServerAvahiUnadvertisePresence(s); free(s->serviceSpec); free(s); } int pmDiscoverServices(const char *service, const char *mechanism, char ***urls) { int numUrls; /* * Attempt to discover the requested service(s) using the requested or * all available means. * If a particular method is not available or not configured, then the * respective call will have no effect. */ *urls = NULL; numUrls = 0; if (mechanism == NULL || strcmp(mechanism, "avahi") == 0) numUrls += __pmAvahiDiscoverServices(service, numUrls, urls); else return -EOPNOTSUPP; return numUrls; } /* For manually adding a service. Also used by pmDiscoverServices(). */ int __pmAddDiscoveredService(__pmServiceInfo *info, int numUrls, char ***urls) { const char* prefix; char *addressString; char *url; size_t size; int isIPv6; int port; /* * Add the given address and port to the given list of urls. * Build the new entry first, so that we can filter out duplicates. * Currently, only "pmcd" is supported. */ if (strcmp(info->spec, PM_SERVER_SERVICE_SPEC) == 0) { prefix = "pcp://"; } else { __pmNotifyErr(LOG_ERR, "__pmAddDiscoveredService: Unsupported service: '%s'", info->spec); return EOPNOTSUPP; } /* * Allocate the new entry. We need room for the url prefix, the address * and the port. IPv6 addresses require a set of [] surrounding the * address in order to distinguish the port. */ port = __pmSockAddrGetPort(info->address); addressString = __pmSockAddrToString(info->address); if (addressString == NULL) { __pmNoMem("__pmAddDiscoveredService: can't allocate address buffer", 0, PM_FATAL_ERR); } size = strlen(prefix) + strlen(addressString) + sizeof(":65535"); if ((isIPv6 = (__pmSockAddrGetFamily(info->address) == AF_INET6))) size += 2; url = malloc(size); if (url == NULL) { __pmNoMem("__pmAddDiscoveredService: can't allocate new entry", size, PM_FATAL_ERR); } if (isIPv6) snprintf(url, size, "%s[%s]:%u", prefix, addressString, (uint16_t)port); else snprintf(url, size, "%s%s:%u", prefix, addressString, (uint16_t)port); free(addressString); /* * Now search the current list for the new entry. * Add it if not found. We don't want any duplicates. */ if (__pmStringListFind(url, numUrls, *urls) == NULL) numUrls = __pmStringListAdd(url, numUrls, urls); free(url); return numUrls; } #else /* !HAVE_SERVICE_DISCOVERY */ __pmServerPresence * __pmServerAdvertisePresence(const char *serviceSpec, int port) { (void)serviceSpec; (void)port; return NULL; } void __pmServerUnadvertisePresence(__pmServerPresence *s) { (void)s; } int pmDiscoverServices(const char *service, const char *mechanism, char ***urls) { /* No services to discover. */ (void)service; (void)mechanism; (void)urls; return -EOPNOTSUPP; } #endif /* !HAVE_SERVICE_DISCOVERY */ pcp-3.8.12ubuntu1/src/libpcp/src/p_lstatus.c0000664000000000000000000001005212272262501015611 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe note * * Unlike most of the other __pmSend*() routines, there is no wrapper * routine in libpcp for __pmSendLogStatus() so there is no place in * the library to enforce serialization between the receiving the * LOG_REQUEST_STATUS PDU and calling __pmSendLogStatus(). * * It is assumed that the caller of __pmSendLogStatus() either manages * this serialization or is single-threaded, which is true for * the only current user of this routine, pmlogger(1). */ #include #include "pmapi.h" #include "impl.h" #include "internal.h" /* * PDU for logger status information transfer (PDU_LOG_STATUS) */ typedef struct { __pmPDUHdr hdr; int pad; /* force status to be double word aligned */ __pmLoggerStatus status; } logstatus_t; int __pmSendLogStatus(int fd, __pmLoggerStatus *status) { logstatus_t *pp; int sts; if ((pp = (logstatus_t *)__pmFindPDUBuf(sizeof(logstatus_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(logstatus_t); pp->hdr.type = PDU_LOG_STATUS; pp->hdr.from = FROM_ANON; /* context does not matter here */ memcpy(&pp->status, status, sizeof(__pmLoggerStatus)); /* Conditional convertion from host to network byteorder HAVE to be * unconditional if one cares about endianess compatibiltity at all! */ pp->status.ls_state = htonl(pp->status.ls_state); pp->status.ls_vol = htonl(pp->status.ls_vol); __htonll((char *)&pp->status.ls_size); pp->status.ls_start.tv_sec = htonl(pp->status.ls_start.tv_sec); pp->status.ls_start.tv_usec = htonl(pp->status.ls_start.tv_usec); pp->status.ls_last.tv_sec = htonl(pp->status.ls_last.tv_sec); pp->status.ls_last.tv_usec = htonl(pp->status.ls_last.tv_usec); pp->status.ls_timenow.tv_sec = htonl(pp->status.ls_timenow.tv_sec); pp->status.ls_timenow.tv_usec = htonl(pp->status.ls_timenow.tv_usec); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) { int version = __pmVersionIPC(fd); fprintf(stderr, "__pmSendLogStatus: sending PDU (toversion=%d)\n", version == UNKNOWN_VERSION ? LOG_PDU_VERSION : version); } #endif sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmDecodeLogStatus(__pmPDU *pdubuf, __pmLoggerStatus **status) { logstatus_t *pp; char *pduend; pp = (logstatus_t *)pdubuf; pduend = (char *)pdubuf + pp->hdr.len; if ((pduend - (char*)pp) != sizeof(logstatus_t)) return PM_ERR_IPC; /* Conditional convertion from host to network byteorder HAVE to be * unconditional if one cares about endianess compatibiltity at all! */ pp->status.ls_state = ntohl(pp->status.ls_state); pp->status.ls_vol = ntohl(pp->status.ls_vol); __ntohll((char *)&pp->status.ls_size); pp->status.ls_start.tv_sec = ntohl(pp->status.ls_start.tv_sec); pp->status.ls_start.tv_usec = ntohl(pp->status.ls_start.tv_usec); pp->status.ls_last.tv_sec = ntohl(pp->status.ls_last.tv_sec); pp->status.ls_last.tv_usec = ntohl(pp->status.ls_last.tv_usec); pp->status.ls_timenow.tv_sec = ntohl(pp->status.ls_timenow.tv_sec); pp->status.ls_timenow.tv_usec = ntohl(pp->status.ls_timenow.tv_usec); *status = &pp->status; __pmPinPDUBuf(pdubuf); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) { int version = __pmLastVersionIPC(); fprintf(stderr, "__pmDecodeLogStatus: got PDU (fromversion=%d)\n", version == UNKNOWN_VERSION ? LOG_PDU_VERSION : version); } #endif return 0; } pcp-3.8.12ubuntu1/src/libpcp/src/derive_fetch.c0000664000000000000000000010700712272262501016231 0ustar /* * Copyright (c) 2009 Ken McDonell. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Debug Flags * DERIVE - high-level diagnostics * DERIVE & APPL0 - configuration and static syntax analysis * DERIVE & APPL1 - expression binding and semantic analysis * DERIVE & APPL2 - fetch handling */ #include #include #include "pmapi.h" #include "impl.h" #include "internal.h" static void get_pmids(node_t *np, int *cnt, pmID **list) { assert(np != NULL); if (np->left != NULL) get_pmids(np->left, cnt, list); if (np->right != NULL) get_pmids(np->right, cnt, list); if (np->type == L_NAME) { (*cnt)++; if ((*list = (pmID *)realloc(*list, (*cnt)*sizeof(pmID))) == NULL) { __pmNoMem("__dmprefetch: realloc xtralist", (*cnt)*sizeof(pmID), PM_FATAL_ERR); /*NOTREACHED*/ } (*list)[*cnt-1] = np->info->pmid; } } /* * Walk the pmidlist[] from pmFetch. * For each derived metric found in the list add all the operand metrics, * and build a combined pmID list (newlist). * * Return 0 if no derived metrics in the list, else the number of pmIDs * in the combined list. * * The derived metric pmIDs are left in the combined list (they will * return PM_ERR_NOAGENT from the fetch) to simplify the post-processing * of the pmResult in __dmpostfetch() */ int __dmprefetch(__pmContext *ctxp, int numpmid, const pmID *pmidlist, pmID **newlist) { int i; int j; int m; int xtracnt = 0; pmID *xtralist = NULL; pmID *list; ctl_t *cp = (ctl_t *)ctxp->c_dm; /* if needed, init() called in __dmopencontext beforehand */ if (cp == NULL) return 0; /* * save numpmid to be used in __dmpostfetch() ... works because calls * to pmFetch cannot be nested (at all, but certainly for the same * context). * Ditto for the fast path flag (fetch_has_dm). */ cp->numpmid = numpmid; cp->fetch_has_dm = 0; for (m = 0; m < numpmid; m++) { if (pmid_domain(pmidlist[m]) != DYNAMIC_PMID || pmid_item(pmidlist[m]) == 0) continue; for (i = 0; i < cp->nmetric; i++) { if (pmidlist[m] == cp->mlist[i].pmid) { if (cp->mlist[i].expr != NULL) { get_pmids(cp->mlist[i].expr, &xtracnt, &xtralist); cp->fetch_has_dm = 1; } break; } } } if (xtracnt == 0) { if (cp->fetch_has_dm) return numpmid; else return 0; } /* * Some of the "extra" ones, may already be in the caller's pmFetch * list, or repeated in xtralist[] (if the same metric operand appears * more than once as a leaf node in the expression tree. * Remove these duplicates */ j = 0; for (i = 0; i < xtracnt; i++) { for (m = 0; m < numpmid; m++) { if (xtralist[i] == pmidlist[m]) /* already in pmFetch list */ break; } if (m < numpmid) continue; for (m = 0; m < j; m++) { if (xtralist[i] == xtralist[m]) /* already in xtralist[] */ break; } if (m == j) xtralist[j++] = xtralist[i]; } xtracnt = j; if (xtracnt == 0) { free(xtralist); return numpmid; } #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { char strbuf[20]; fprintf(stderr, "derived metrics prefetch added %d metrics:", xtracnt); for (i = 0; i < xtracnt; i++) fprintf(stderr, " %s", pmIDStr_r(xtralist[i], strbuf, sizeof(strbuf))); fputc('\n', stderr); } #endif if ((list = (pmID *)malloc((numpmid+xtracnt)*sizeof(pmID))) == NULL) { __pmNoMem("__dmprefetch: alloc list", (numpmid+xtracnt)*sizeof(pmID), PM_FATAL_ERR); /*NOTREACHED*/ } for (m = 0; m < numpmid; m++) { list[m] = pmidlist[m]; } for (i = 0; i < xtracnt; i++) { list[m++] = xtralist[i]; } free(xtralist); *newlist = list; return m; } /* * Free the old ivlist[] (if any) ... may need to walk the list because * the pmAtomValues may have buffers attached in the type STRING, * type AGGREGATE* and type EVENT cases. * Includes logic to save one history sample (for delta()). */ static void free_ivlist(node_t *np) { int i; assert(np->info != NULL); if (np->save_last) { if (np->info->last_ivlist != NULL) { /* * no STRING, AGGREGATE or EVENT types for delta(), * so simple free() */ free(np->info->last_ivlist); } np->info->last_numval = np->info->numval; np->info->last_ivlist = np->info->ivlist; } else { /* no history */ if (np->info->ivlist != NULL) { if (np->desc.type == PM_TYPE_STRING) { for (i = 0; i < np->info->numval; i++) { if (np->info->ivlist[i].value.cp != NULL) free(np->info->ivlist[i].value.cp); } } else if (np->desc.type == PM_TYPE_AGGREGATE || np->desc.type == PM_TYPE_AGGREGATE_STATIC || np->desc.type == PM_TYPE_EVENT) { for (i = 0; i < np->info->numval; i++) { if (np->info->ivlist[i].value.vbp != NULL) free(np->info->ivlist[i].value.vbp); } } } free(np->info->ivlist); np->info->ivlist = NULL; np->info->numval = 0; } } /* * Binary arithmetic. * * result = * ltype, rtype and type are the types of , and the result * respectively * * If type is PM_TYPE_DOUBLE then lmul, ldiv, rmul and rdiv are * the scale factors for units scale conversion of and * respectively, so lmul*/ldiv ... all are 1 in the common cases. */ static pmAtomValue bin_op(int type, int op, pmAtomValue a, int ltype, int lmul, int ldiv, pmAtomValue b, int rtype, int rmul, int rdiv) { pmAtomValue res; pmAtomValue l; pmAtomValue r; l = a; /* struct assignments */ r = b; /* * Promote each operand to the type of the result ... there are limited * cases to be considered here, see promote[][] and map_desc(). */ switch (type) { case PM_TYPE_32: case PM_TYPE_U32: /* do nothing */ break; case PM_TYPE_64: switch (ltype) { case PM_TYPE_32: l.ll = a.l; break; case PM_TYPE_U32: l.ll = a.ul; break; case PM_TYPE_64: case PM_TYPE_U64: /* do nothing */ break; } switch (rtype) { case PM_TYPE_32: r.ll = b.l; break; case PM_TYPE_U32: r.ll = b.ul; break; case PM_TYPE_64: case PM_TYPE_U64: /* do nothing */ break; } break; case PM_TYPE_U64: switch (ltype) { case PM_TYPE_32: l.ull = a.l; break; case PM_TYPE_U32: l.ull = a.ul; break; case PM_TYPE_64: case PM_TYPE_U64: /* do nothing */ break; } switch (rtype) { case PM_TYPE_32: r.ull = b.l; break; case PM_TYPE_U32: r.ull = b.ul; break; case PM_TYPE_64: case PM_TYPE_U64: /* do nothing */ break; } break; case PM_TYPE_FLOAT: switch (ltype) { case PM_TYPE_32: l.f = a.l; break; case PM_TYPE_U32: l.f = a.ul; break; case PM_TYPE_64: l.f = a.ll; break; case PM_TYPE_U64: l.f = a.ull; break; case PM_TYPE_FLOAT: /* do nothing */ break; } switch (rtype) { case PM_TYPE_32: r.f = b.l; break; case PM_TYPE_U32: r.f = b.ul; break; case PM_TYPE_64: r.f = b.ll; break; case PM_TYPE_U64: r.f = b.ull; break; case PM_TYPE_FLOAT: /* do nothing */ break; } break; case PM_TYPE_DOUBLE: switch (ltype) { case PM_TYPE_32: l.d = a.l; break; case PM_TYPE_U32: l.d = a.ul; break; case PM_TYPE_64: l.d = a.ll; break; case PM_TYPE_U64: l.d = a.ull; break; case PM_TYPE_FLOAT: l.d = a.f; break; case PM_TYPE_DOUBLE: /* do nothing */ break; } l.d = (l.d / ldiv) * lmul; switch (rtype) { case PM_TYPE_32: r.d = b.l; break; case PM_TYPE_U32: r.d = b.ul; break; case PM_TYPE_64: r.d = b.ll; break; case PM_TYPE_U64: r.d = b.ull; break; case PM_TYPE_FLOAT: r.d = b.f; break; case PM_TYPE_DOUBLE: /* do nothing */ break; } r.d = (r.d / rdiv) * rmul; break; } /* * Do the aritmetic ... messy! */ switch (type) { case PM_TYPE_32: switch (op) { case L_PLUS: res.l = l.l + r.l; break; case L_MINUS: res.l = l.l - r.l; break; case L_STAR: res.l = l.l * r.l; break; /* semantics enforce no L_SLASH for integer results */ } break; case PM_TYPE_U32: switch (op) { case L_PLUS: res.ul = l.ul + r.ul; break; case L_MINUS: res.ul = l.ul - r.ul; break; case L_STAR: res.ul = l.ul * r.ul; break; /* semantics enforce no L_SLASH for integer results */ } break; case PM_TYPE_64: switch (op) { case L_PLUS: res.ll = l.ll + r.ll; break; case L_MINUS: res.ll = l.ll - r.ll; break; case L_STAR: res.ll = l.ll * r.ll; break; /* semantics enforce no L_SLASH for integer results */ } break; case PM_TYPE_U64: switch (op) { case L_PLUS: res.ull = l.ull + r.ull; break; case L_MINUS: res.ull = l.ull - r.ull; break; case L_STAR: res.ull = l.ull * r.ull; break; /* semantics enforce no L_SLASH for integer results */ } break; case PM_TYPE_FLOAT: switch (op) { case L_PLUS: res.f = l.f + r.f; break; case L_MINUS: res.f = l.f - r.f; break; case L_STAR: res.f = l.f * r.f; break; /* semantics enforce no L_SLASH for float results */ } break; case PM_TYPE_DOUBLE: switch (op) { case L_PLUS: res.d = l.d + r.d; break; case L_MINUS: res.d = l.d - r.d; break; case L_STAR: res.d = l.d * r.d; break; case L_SLASH: if (l.d == 0) res.d = 0; else res.d = l.d / r.d; break; } break; } return res; } /* * Walk an expression tree, filling in operand values from the * pmResult at the leaf nodes and propagating the computed values * towards the root node of the tree. */ static int eval_expr(node_t *np, pmResult *rp, int level) { int sts; int i; int j; int k; size_t need; assert(np != NULL); if (np->left != NULL) { sts = eval_expr(np->left, rp, level+1); if (sts < 0) return sts; } if (np->right != NULL) { sts = eval_expr(np->right, rp, level+1); if (sts < 0) return sts; } /* mostly, np->left is not NULL ... */ assert (np->type == L_NUMBER || np->type == L_NAME || np->left != NULL); switch (np->type) { case L_NUMBER: if (np->info->numval == 0) { /* initialize ivlist[] for singular instance first time through */ np->info->numval = 1; if ((np->info->ivlist = (val_t *)malloc(sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: number ivlist", sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } np->info->ivlist[0].inst = PM_INDOM_NULL; /* don't need error checking, done in the lexical scanner */ np->info->ivlist[0].value.l = atoi(np->value); } return 1; break; case L_DELTA: /* * this and the last values are in the left expr */ free_ivlist(np); np->info->numval = np->left->info->numval <= np->left->info->last_numval ? np->left->info->numval : np->left->info->last_numval; if (np->info->numval <= 0) return np->info->numval; if ((np->info->ivlist = (val_t *)malloc(np->info->numval*sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: delta() ivlist", np->info->numval*sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } /* * ivlist[k] = left-ivlist[i] - left-last-ivlist[j] */ for (i = k = 0; i < np->left->info->numval; i++) { j = i; if (j >= np->left->info->last_numval) j = 0; if (np->left->info->ivlist[i].inst != np->left->info->last_ivlist[j].inst) { /* current ith inst != last jth inst ... search in last */ #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { fprintf(stderr, "eval_expr: inst[%d] mismatch left [%d]=%d last [%d]=%d\n", k, i, np->left->info->ivlist[i].inst, j, np->left->info->last_ivlist[j].inst); } #endif for (j = 0; j < np->left->info->last_numval; j++) { if (np->left->info->ivlist[i].inst == np->left->info->last_ivlist[j].inst) break; } if (j == np->left->info->last_numval) { /* no match, skip this instance from this result */ continue; } #ifdef PCP_DEBUG else { if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { fprintf(stderr, "eval_expr: recover @ last [%d]=%d\n", j, np->left->info->last_ivlist[j].inst); } } #endif } np->info->ivlist[k].inst = np->left->info->ivlist[i].inst; switch (np->desc.type) { case PM_TYPE_32: np->info->ivlist[k].value.l = np->left->info->ivlist[i].value.l - np->left->info->last_ivlist[j].value.l; break; case PM_TYPE_U32: np->info->ivlist[k].value.ul = np->left->info->ivlist[i].value.ul - np->left->info->last_ivlist[j].value.ul; break; case PM_TYPE_64: np->info->ivlist[k].value.ll = np->left->info->ivlist[i].value.ll - np->left->info->last_ivlist[j].value.ll; break; case PM_TYPE_U64: np->info->ivlist[k].value.ull = np->left->info->ivlist[i].value.ull - np->left->info->last_ivlist[j].value.ull; break; case PM_TYPE_FLOAT: np->info->ivlist[k].value.f = np->left->info->ivlist[i].value.f - np->left->info->last_ivlist[j].value.f; break; case PM_TYPE_DOUBLE: np->info->ivlist[k].value.d = np->left->info->ivlist[i].value.d - np->left->info->last_ivlist[j].value.d; break; default: /* * Nothing should end up here as check_expr() checks * for numeric data type at bind time */ return PM_ERR_CONV; } k++; } np->info->numval = k; return np->info->numval; break; case L_AVG: case L_COUNT: case L_SUM: case L_MAX: case L_MIN: if (np->info->ivlist == NULL) { /* initialize ivlist[] for singular instance first time through */ if ((np->info->ivlist = (val_t *)malloc(sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: aggr ivlist", sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } np->info->ivlist[0].inst = PM_IN_NULL; } /* * values are in the left expr */ if (np->type == L_COUNT) { np->info->numval = 1; np->info->ivlist[0].value.l = np->left->info->numval; } else { np->info->numval = 1; if (np->type == L_AVG) np->info->ivlist[0].value.f = 0; else if (np->type == L_SUM) { switch (np->desc.type) { case PM_TYPE_32: np->info->ivlist[0].value.l = 0; break; case PM_TYPE_U32: np->info->ivlist[0].value.ul = 0; break; case PM_TYPE_64: np->info->ivlist[0].value.ll = 0; break; case PM_TYPE_U64: np->info->ivlist[0].value.ull = 0; break; case PM_TYPE_FLOAT: np->info->ivlist[0].value.f = 0; break; case PM_TYPE_DOUBLE: np->info->ivlist[0].value.d = 0; break; } } for (i = 0; i < np->left->info->numval; i++) { switch (np->type) { case L_AVG: switch (np->left->desc.type) { case PM_TYPE_32: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.l / np->left->info->numval; break; case PM_TYPE_U32: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.ul / np->left->info->numval; break; case PM_TYPE_64: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.ll / np->left->info->numval; break; case PM_TYPE_U64: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.ull / np->left->info->numval; break; case PM_TYPE_FLOAT: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.f / np->left->info->numval; break; case PM_TYPE_DOUBLE: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.d / np->left->info->numval; break; default: /* * check_expr() checks for numeric data * type at bind time ... if here, botch! */ return PM_ERR_CONV; } break; case L_MAX: switch (np->desc.type) { case PM_TYPE_32: if (i == 0 || np->info->ivlist[0].value.l < np->left->info->ivlist[i].value.l) np->info->ivlist[0].value.l = np->left->info->ivlist[i].value.l; break; case PM_TYPE_U32: if (i == 0 || np->info->ivlist[0].value.ul < np->left->info->ivlist[i].value.ul) np->info->ivlist[0].value.ul = np->left->info->ivlist[i].value.ul; break; case PM_TYPE_64: if (i == 0 || np->info->ivlist[0].value.ll < np->left->info->ivlist[i].value.ll) np->info->ivlist[0].value.ll = np->left->info->ivlist[i].value.ll; break; case PM_TYPE_U64: if (i == 0 || np->info->ivlist[0].value.ull < np->left->info->ivlist[i].value.ull) np->info->ivlist[0].value.ull = np->left->info->ivlist[i].value.ull; break; case PM_TYPE_FLOAT: if (i == 0 || np->info->ivlist[0].value.f < np->left->info->ivlist[i].value.f) np->info->ivlist[0].value.f = np->left->info->ivlist[i].value.f; break; case PM_TYPE_DOUBLE: if (i == 0 || np->info->ivlist[0].value.d < np->left->info->ivlist[i].value.d) np->info->ivlist[0].value.d = np->left->info->ivlist[i].value.d; break; default: /* * check_expr() checks for numeric data * type at bind time ... if here, botch! */ return PM_ERR_CONV; } break; case L_MIN: switch (np->desc.type) { case PM_TYPE_32: if (i == 0 || np->info->ivlist[0].value.l > np->left->info->ivlist[i].value.l) np->info->ivlist[0].value.l = np->left->info->ivlist[i].value.l; break; case PM_TYPE_U32: if (i == 0 || np->info->ivlist[0].value.ul > np->left->info->ivlist[i].value.ul) np->info->ivlist[0].value.ul = np->left->info->ivlist[i].value.ul; break; case PM_TYPE_64: if (i == 0 || np->info->ivlist[0].value.ll > np->left->info->ivlist[i].value.ll) np->info->ivlist[0].value.ll = np->left->info->ivlist[i].value.ll; break; case PM_TYPE_U64: if (i == 0 || np->info->ivlist[0].value.ull > np->left->info->ivlist[i].value.ull) np->info->ivlist[0].value.ull = np->left->info->ivlist[i].value.ull; break; case PM_TYPE_FLOAT: if (i == 0 || np->info->ivlist[0].value.f > np->left->info->ivlist[i].value.f) np->info->ivlist[0].value.f = np->left->info->ivlist[i].value.f; break; case PM_TYPE_DOUBLE: if (i == 0 || np->info->ivlist[0].value.d > np->left->info->ivlist[i].value.d) np->info->ivlist[0].value.d = np->left->info->ivlist[i].value.d; break; default: /* * check_expr() checks for numeric data * type at bind time ... if here, botch! */ return PM_ERR_CONV; } break; case L_SUM: switch (np->desc.type) { case PM_TYPE_32: np->info->ivlist[0].value.l += np->left->info->ivlist[i].value.l; break; case PM_TYPE_U32: np->info->ivlist[0].value.ul += np->left->info->ivlist[i].value.ul; break; case PM_TYPE_64: np->info->ivlist[0].value.ll += np->left->info->ivlist[i].value.ll; break; case PM_TYPE_U64: np->info->ivlist[0].value.ull += np->left->info->ivlist[i].value.ull; break; case PM_TYPE_FLOAT: np->info->ivlist[0].value.f += np->left->info->ivlist[i].value.f; break; case PM_TYPE_DOUBLE: np->info->ivlist[0].value.d += np->left->info->ivlist[i].value.d; break; default: /* * check_expr() checks for numeric data * type at bind time ... if here, botch! */ return PM_ERR_CONV; } break; } } } return np->info->numval; break; case L_NAME: /* * Extract instance-values from pmResult and store them in * ivlist[] as pairs */ for (j = 0; j < rp->numpmid; j++) { if (np->info->pmid == rp->vset[j]->pmid) { free_ivlist(np); np->info->numval = rp->vset[j]->numval; if (np->info->numval <= 0) return np->info->numval; if ((np->info->ivlist = (val_t *)malloc(np->info->numval*sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: metric ivlist", np->info->numval*sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } for (i = 0; i < np->info->numval; i++) { np->info->ivlist[i].inst = rp->vset[j]->vlist[i].inst; switch (np->desc.type) { case PM_TYPE_32: case PM_TYPE_U32: np->info->ivlist[i].value.l = rp->vset[j]->vlist[i].value.lval; break; case PM_TYPE_64: case PM_TYPE_U64: memcpy((void *)&np->info->ivlist[i].value.ll, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, sizeof(__int64_t)); break; case PM_TYPE_FLOAT: if (rp->vset[j]->valfmt == PM_VAL_INSITU) { /* old style insitu float */ np->info->ivlist[i].value.l = rp->vset[j]->vlist[i].value.lval; } else { assert(rp->vset[j]->vlist[i].value.pval->vtype == PM_TYPE_FLOAT); memcpy((void *)&np->info->ivlist[i].value.f, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, sizeof(float)); } break; case PM_TYPE_DOUBLE: memcpy((void *)&np->info->ivlist[i].value.d, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, sizeof(double)); break; case PM_TYPE_STRING: need = rp->vset[j]->vlist[i].value.pval->vlen-PM_VAL_HDR_SIZE; if ((np->info->ivlist[i].value.cp = (char *)malloc(need)) == NULL) { __pmNoMem("eval_expr: string value", rp->vset[j]->vlist[i].value.pval->vlen, PM_FATAL_ERR); /*NOTREACHED*/ } memcpy((void *)np->info->ivlist[i].value.cp, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, need); np->info->ivlist[i].vlen = need; break; case PM_TYPE_AGGREGATE: case PM_TYPE_AGGREGATE_STATIC: case PM_TYPE_EVENT: if ((np->info->ivlist[i].value.vbp = (pmValueBlock *)malloc(rp->vset[j]->vlist[i].value.pval->vlen)) == NULL) { __pmNoMem("eval_expr: aggregate value", rp->vset[j]->vlist[i].value.pval->vlen, PM_FATAL_ERR); /*NOTREACHED*/ } memcpy(np->info->ivlist[i].value.vbp, (void *)rp->vset[j]->vlist[i].value.pval, rp->vset[j]->vlist[i].value.pval->vlen); np->info->ivlist[i].vlen = rp->vset[j]->vlist[i].value.pval->vlen; break; default: /* * really only PM_TYPE_NOSUPPORT should * end up here */ return PM_ERR_TYPE; } } return np->info->numval; } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { char strbuf[20]; fprintf(stderr, "eval_expr: botch: operand %s not in the extended pmResult\n", pmIDStr_r(np->info->pmid, strbuf, sizeof(strbuf))); __pmDumpResult(stderr, rp); } #endif return PM_ERR_PMID; case L_ANON: /* no values available for anonymous metrics */ return 0; default: /* * binary operator cases ... always have a left and right * operand and no errors (these are caught earlier when the * recursive call on each of the operands would may have * returned an error */ assert(np->left != NULL); assert(np->right != NULL); free_ivlist(np); /* * empty result cases first */ if (np->left->info->numval == 0) { np->info->numval = 0; return np->info->numval; } if (np->right->info->numval == 0) { np->info->numval = 0; return np->info->numval; } /* * really got some work to do ... */ if (np->left->desc.indom == PM_INDOM_NULL) np->info->numval = np->right->info->numval; else if (np->right->desc.indom == PM_INDOM_NULL) np->info->numval = np->left->info->numval; else { /* * Generally have the same number of instances because * both operands are over the same instance domain, * fetched with the same profile. When not the case, * the result can contain no more instances than in * the smaller of the operands. */ if (np->left->info->numval <= np->right->info->numval) np->info->numval = np->left->info->numval; else np->info->numval = np->right->info->numval; } if ((np->info->ivlist = (val_t *)malloc(np->info->numval*sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: expr ivlist", np->info->numval*sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } /* * ivlist[k] = left-ivlist[i] right-ivlist[j] */ for (i = j = k = 0; k < np->info->numval; ) { if (i >= np->left->info->numval || j >= np->right->info->numval) { /* run out of operand instances, quit */ np->info->numval = k; break; } if (np->left->desc.indom != PM_INDOM_NULL && np->right->desc.indom != PM_INDOM_NULL) { if (np->left->info->ivlist[i].inst != np->right->info->ivlist[j].inst) { /* left ith inst != right jth inst ... search in right */ #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { fprintf(stderr, "eval_expr: inst[%d] mismatch left [%d]=%d right [%d]=%d\n", k, i, np->left->info->ivlist[i].inst, j, np->right->info->ivlist[j].inst); } #endif for (j = 0; j < np->right->info->numval; j++) { if (np->left->info->ivlist[i].inst == np->right->info->ivlist[j].inst) break; } if (j == np->right->info->numval) { /* * no match, so next instance on left operand, * and reset to start from first instance of * right operand */ i++; j = 0; continue; } #ifdef PCP_DEBUG else { if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { fprintf(stderr, "eval_expr: recover @ right [%d]=%d\n", j, np->right->info->ivlist[j].inst); } } #endif } } np->info->ivlist[k].value = bin_op(np->desc.type, np->type, np->left->info->ivlist[i].value, np->left->desc.type, np->left->info->mul_scale, np->left->info->div_scale, np->right->info->ivlist[j].value, np->right->desc.type, np->right->info->mul_scale, np->right->info->div_scale); if (np->left->desc.indom != PM_INDOM_NULL) np->info->ivlist[k].inst = np->left->info->ivlist[i].inst; else np->info->ivlist[k].inst = np->right->info->ivlist[j].inst; k++; if (np->left->desc.indom != PM_INDOM_NULL) { i++; if (np->right->desc.indom != PM_INDOM_NULL) { j++; if (j >= np->right->info->numval) { /* rescan if need be */ j = 0; } } } else if (np->right->desc.indom != PM_INDOM_NULL) { j++; } } return np->info->numval; } /*NOTREACHED*/ } /* * Algorithm here is complicated by trying to re-write the pmResult. * * On entry the pmResult is likely to be built over a pinned PDU buffer, * which means individual pmValueSets cannot be selectively replaced * (this would come to tears badly in pmFreeResult() where as soon as * one pmValueSet is found to be in a pinned PDU buffer it is assumed * they are all so ... leaving a memory leak for any ones we'd modified * here). * * So the only option is to COPY the pmResult, selectively replacing * the pmValueSets for the derived metrics, and then calling * pmFreeResult() to free the input structure and return the new one. * * In making the COPY it is critical that we reverse the algorithm * used in pmFreeResult() so that a later call to pmFreeResult() will * not cause a memory leak. * This means ... * - malloc() the pmResult (padded out to the right number of vset[] * entries) * - if valfmt is not PM_VAL_INSITU use PM_VAL_DPTR (not PM_VAL_SPTR), * so anything we point to is going to be released when our caller * calls pmFreeResult() * - use one malloc() for each pmValueSet with vlist[] sized to be 0 * if numval < 0 else numval * - pmValueBlocks are from malloc() * * For reference, the same logic appears in __pmLogFetchInterp() to * sythesize a pmResult there. */ void __dmpostfetch(__pmContext *ctxp, pmResult **result) { int i; int j; int m; int numval; int valfmt; size_t need; int rewrite; ctl_t *cp = (ctl_t *)ctxp->c_dm; pmResult *rp = *result; pmResult *newrp; /* if needed, init() called in __dmopencontext beforehand */ if (cp == NULL || cp->fetch_has_dm == 0) return; newrp = (pmResult *)malloc(sizeof(pmResult)+(cp->numpmid-1)*sizeof(pmValueSet *)); if (newrp == NULL) { __pmNoMem("__dmpostfetch: newrp", sizeof(pmResult)+(cp->numpmid-1)*sizeof(pmValueSet *), PM_FATAL_ERR); /*NOTREACHED*/ } newrp->timestamp = rp->timestamp; newrp->numpmid = cp->numpmid; for (j = 0; j < newrp->numpmid; j++) { numval = rp->vset[j]->numval; valfmt = rp->vset[j]->valfmt; rewrite = 0; /* * pandering to gcc ... m is not used unless rewrite == 1 in * which case m is well-defined */ m = 0; if (pmid_domain(rp->vset[j]->pmid) == DYNAMIC_PMID && pmid_item(rp->vset[j]->pmid) != 0) { for (m = 0; m < cp->nmetric; m++) { if (rp->vset[j]->pmid == cp->mlist[m].pmid) { if (cp->mlist[m].expr == NULL) { numval = PM_ERR_PMID; } else { rewrite = 1; if (cp->mlist[m].expr->desc.type == PM_TYPE_32 || cp->mlist[m].expr->desc.type == PM_TYPE_U32) valfmt = PM_VAL_INSITU; else valfmt = PM_VAL_DPTR; numval = eval_expr(cp->mlist[m].expr, rp, 1); #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { int k; char strbuf[20]; fprintf(stderr, "__dmpostfetch: [%d] root node %s: numval=%d", j, pmIDStr_r(rp->vset[j]->pmid, strbuf, sizeof(strbuf)), numval); for (k = 0; k < numval; k++) { fprintf(stderr, " vset[%d]: inst=%d", k, cp->mlist[m].expr->info->ivlist[k].inst); if (cp->mlist[m].expr->desc.type == PM_TYPE_32) fprintf(stderr, " l=%d", cp->mlist[m].expr->info->ivlist[k].value.l); else if (cp->mlist[m].expr->desc.type == PM_TYPE_U32) fprintf(stderr, " u=%u", cp->mlist[m].expr->info->ivlist[k].value.ul); else if (cp->mlist[m].expr->desc.type == PM_TYPE_64) fprintf(stderr, " ll=%"PRIi64, cp->mlist[m].expr->info->ivlist[k].value.ll); else if (cp->mlist[m].expr->desc.type == PM_TYPE_U64) fprintf(stderr, " ul=%"PRIu64, cp->mlist[m].expr->info->ivlist[k].value.ull); else if (cp->mlist[m].expr->desc.type == PM_TYPE_FLOAT) fprintf(stderr, " f=%f", (double)cp->mlist[m].expr->info->ivlist[k].value.f); else if (cp->mlist[m].expr->desc.type == PM_TYPE_DOUBLE) fprintf(stderr, " d=%f", cp->mlist[m].expr->info->ivlist[k].value.d); else if (cp->mlist[m].expr->desc.type == PM_TYPE_STRING) { fprintf(stderr, " cp=%s (len=%d)", cp->mlist[m].expr->info->ivlist[k].value.cp, cp->mlist[m].expr->info->ivlist[k].vlen); } else { fprintf(stderr, " vbp=" PRINTF_P_PFX "%p (len=%d)", cp->mlist[m].expr->info->ivlist[k].value.vbp, cp->mlist[m].expr->info->ivlist[k].vlen); } } fputc('\n', stderr); if (cp->mlist[m].expr->info != NULL) __dmdumpexpr(cp->mlist[m].expr, 1); } #endif } break; } } } if (numval <= 0) { /* only need pmid and numval */ need = sizeof(pmValueSet) - sizeof(pmValue); } else { /* already one pmValue in a pmValueSet */ need = sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue); } if (need > 0) { if ((newrp->vset[j] = (pmValueSet *)malloc(need)) == NULL) { __pmNoMem("__dmpostfetch: vset", need, PM_FATAL_ERR); /*NOTREACHED*/ } } newrp->vset[j]->pmid = rp->vset[j]->pmid; newrp->vset[j]->numval = numval; newrp->vset[j]->valfmt = valfmt; if (numval < 0) continue; for (i = 0; i < numval; i++) { pmValueBlock *vp; if (!rewrite) { newrp->vset[j]->vlist[i].inst = rp->vset[j]->vlist[i].inst; if (newrp->vset[j]->valfmt == PM_VAL_INSITU) { newrp->vset[j]->vlist[i].value.lval = rp->vset[j]->vlist[i].value.lval; } else { need = rp->vset[j]->vlist[i].value.pval->vlen; vp = (pmValueBlock *)malloc(need); if (vp == NULL) { __pmNoMem("__dmpostfetch: copy value", need, PM_FATAL_ERR); /*NOTREACHED*/ } memcpy((void *)vp, (void *)rp->vset[j]->vlist[i].value.pval, need); newrp->vset[j]->vlist[i].value.pval = vp; } continue; } /* * the rewrite case ... */ newrp->vset[j]->vlist[i].inst = cp->mlist[m].expr->info->ivlist[i].inst; switch (cp->mlist[m].expr->desc.type) { case PM_TYPE_32: case PM_TYPE_U32: newrp->vset[j]->vlist[i].value.lval = cp->mlist[m].expr->info->ivlist[i].value.l; break; case PM_TYPE_64: case PM_TYPE_U64: need = PM_VAL_HDR_SIZE + sizeof(__int64_t); if ((vp = (pmValueBlock *)malloc(need)) == NULL) { __pmNoMem("__dmpostfetch: 64-bit int value", need, PM_FATAL_ERR); /*NOTREACHED*/ } vp->vlen = need; vp->vtype = cp->mlist[m].expr->desc.type; memcpy((void *)vp->vbuf, (void *)&cp->mlist[m].expr->info->ivlist[i].value.ll, sizeof(__int64_t)); newrp->vset[j]->vlist[i].value.pval = vp; break; case PM_TYPE_FLOAT: need = PM_VAL_HDR_SIZE + sizeof(float); if ((vp = (pmValueBlock *)malloc(need)) == NULL) { __pmNoMem("__dmpostfetch: float value", need, PM_FATAL_ERR); /*NOTREACHED*/ } vp->vlen = need; vp->vtype = PM_TYPE_FLOAT; memcpy((void *)vp->vbuf, (void *)&cp->mlist[m].expr->info->ivlist[i].value.f, sizeof(float)); newrp->vset[j]->vlist[i].value.pval = vp; break; case PM_TYPE_DOUBLE: need = PM_VAL_HDR_SIZE + sizeof(double); if ((vp = (pmValueBlock *)malloc(need)) == NULL) { __pmNoMem("__dmpostfetch: double value", need, PM_FATAL_ERR); /*NOTREACHED*/ } vp->vlen = need; vp->vtype = PM_TYPE_DOUBLE; memcpy((void *)vp->vbuf, (void *)&cp->mlist[m].expr->info->ivlist[i].value.f, sizeof(double)); newrp->vset[j]->vlist[i].value.pval = vp; break; case PM_TYPE_STRING: need = PM_VAL_HDR_SIZE + cp->mlist[m].expr->info->ivlist[i].vlen; vp = (pmValueBlock *)malloc(need); if (vp == NULL) { __pmNoMem("__dmpostfetch: string value", need, PM_FATAL_ERR); /*NOTREACHED*/ } vp->vlen = need; vp->vtype = cp->mlist[m].expr->desc.type; memcpy((void *)vp->vbuf, cp->mlist[m].expr->info->ivlist[i].value.cp, cp->mlist[m].expr->info->ivlist[i].vlen); newrp->vset[j]->vlist[i].value.pval = vp; break; case PM_TYPE_AGGREGATE: case PM_TYPE_AGGREGATE_STATIC: case PM_TYPE_EVENT: need = cp->mlist[m].expr->info->ivlist[i].vlen; vp = (pmValueBlock *)malloc(need); if (vp == NULL) { __pmNoMem("__dmpostfetch: aggregate or event value", need, PM_FATAL_ERR); /*NOTREACHED*/ } memcpy((void *)vp, cp->mlist[m].expr->info->ivlist[i].value.vbp, cp->mlist[m].expr->info->ivlist[i].vlen); newrp->vset[j]->vlist[i].value.pval = vp; break; default: /* * really nothing should end up here ... * do nothing as numval should have been < 0 */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { char strbuf[20]; fprintf(stderr, "__dmpostfetch: botch: drived metric[%d]: operand %s has odd type (%d)\n", m, pmIDStr_r(rp->vset[j]->pmid, strbuf, sizeof(strbuf)), cp->mlist[m].expr->desc.type); } #endif break; } } } /* * cull the original pmResult and return the rewritten one */ pmFreeResult(rp); *result = newrp; return; } pcp-3.8.12ubuntu1/src/libpcp/src/auxconnect.c0000664000000000000000000007401112272262501015747 0ustar /* * Copyright (c) 2012-2014 Red Hat. * Copyright (c) 2000,2004,2005 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #define SOCKET_INTERNAL #include "internal.h" /* default connect timeout is 5 seconds */ static struct timeval canwait = { 5, 000000 }; __pmHostEnt * __pmHostEntAlloc(void) { return calloc(1, sizeof(__pmHostEnt)); } __pmSockAddr * __pmSockAddrAlloc(void) { return calloc(1, sizeof(__pmSockAddr)); } __pmSockAddr * __pmSockAddrDup(const __pmSockAddr *sockaddr) { __pmSockAddr *new = malloc(sizeof(__pmSockAddr)); if (new) *new = *sockaddr; return new; } size_t __pmSockAddrSize(void) { return sizeof(__pmSockAddr); } int __pmSockAddrIsLoopBack(const __pmSockAddr *addr) { int rc; int family; __pmSockAddr *loopBackAddr; family = __pmSockAddrGetFamily(addr); loopBackAddr = __pmLoopBackAddress(family); if (loopBackAddr == NULL) return 0; rc = __pmSockAddrCompare(addr, loopBackAddr); __pmSockAddrFree(loopBackAddr); return rc == 0; } void __pmSockAddrFree(__pmSockAddr *sockaddr) { free(sockaddr); } __pmSockAddr * __pmLoopBackAddress(int family) { __pmSockAddr* addr; #if defined(HAVE_STRUCT_SOCKADDR_UN) /* There is no loopback address for a unix domain socket. */ if (family == AF_UNIX) return NULL; #endif addr = __pmSockAddrAlloc(); if (addr != NULL) __pmSockAddrInit(addr, family, INADDR_LOOPBACK, 0); return addr; } int __pmInitSocket(int fd, int family) { int sts; int nodelay = 1; struct linger nolinger = {1, 0}; char errmsg[PM_MAXERRMSGLEN]; if ((sts = __pmSetSocketIPC(fd)) < 0) { __pmCloseSocket(fd); return sts; } /* Don't linger on close */ if (__pmSetSockOpt(fd, SOL_SOCKET, SO_LINGER, (char *)&nolinger, (__pmSockLen)sizeof(nolinger)) < 0) { __pmNotifyErr(LOG_WARNING, "%s:__pmCreateSocket(%d): __pmSetSockOpt SO_LINGER: %s\n", __FILE__, fd, netstrerror_r(errmsg, sizeof(errmsg))); } #if defined(HAVE_STRUCT_SOCKADDR_UN) if (family == AF_UNIX) return fd; #endif /* Avoid 200 ms delay. This option is not supported for unix domain sockets. */ if (__pmSetSockOpt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, (__pmSockLen)sizeof(nodelay)) < 0) { __pmNotifyErr(LOG_WARNING, "%s:__pmCreateSocket(%d): __pmSetSockOpt TCP_NODELAY: %s\n", __FILE__, fd, netstrerror_r(errmsg, sizeof(errmsg))); } return fd; } int __pmConnectTo(int fd, const __pmSockAddr *addr, int port) { int sts, fdFlags = __pmGetFileStatusFlags(fd); __pmSockAddr myAddr; myAddr = *addr; if (port >= 0) __pmSockAddrSetPort(&myAddr, port); if (__pmSetFileStatusFlags(fd, fdFlags | FNDELAY) < 0) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "%s:__pmConnectTo: cannot set FNDELAY - " "fcntl(%d,F_SETFL,0x%x) failed: %s\n", __FILE__, fd, fdFlags|FNDELAY , osstrerror_r(errmsg, sizeof(errmsg))); } if (__pmConnect(fd, &myAddr, sizeof(myAddr)) < 0) { sts = neterror(); if (sts != EINPROGRESS) { __pmCloseSocket(fd); return -sts; } } return fdFlags; } int __pmConnectCheckError(int fd) { int so_err = 0; __pmSockLen olen = sizeof(int); char errmsg[PM_MAXERRMSGLEN]; if (__pmGetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void *)&so_err, &olen) < 0) { so_err = neterror(); __pmNotifyErr(LOG_ERR, "%s:__pmConnectCheckError: __pmGetSockOpt(SO_ERROR) failed: %s\n", __FILE__, netstrerror_r(errmsg, sizeof(errmsg))); } return so_err; } static int __pmConnectRestoreFlags(int fd, int fdFlags) { int sts; char errmsg[PM_MAXERRMSGLEN]; if (__pmSetFileStatusFlags(fd, fdFlags) < 0) { __pmNotifyErr(LOG_WARNING, "%s:__pmConnectRestoreFlags: cannot restore " "flags fcntl(%d,F_SETFL,0x%x) failed: %s\n", __FILE__, fd, fdFlags, osstrerror_r(errmsg, sizeof(errmsg))); } if ((fdFlags = __pmGetFileDescriptorFlags(fd)) >= 0) sts = __pmSetFileDescriptorFlags(fd, fdFlags | FD_CLOEXEC); else sts = fdFlags; if (sts == -1) { __pmNotifyErr(LOG_WARNING, "%s:__pmConnectRestoreFlags: " "fcntl(%d) get/set flags failed: %s\n", __FILE__, fd, osstrerror_r(errmsg, sizeof(errmsg))); __pmCloseSocket(fd); return sts; } return fd; } const struct timeval * __pmConnectTimeout(void) { static int first_time = 1; /* * get optional stuff from environment ... * PMCD_CONNECT_TIMEOUT * PMCD_PORT */ PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (first_time) { char *env_str; first_time = 0; if ((env_str = getenv("PMCD_CONNECT_TIMEOUT")) != NULL) { char *end_ptr; double timeout = strtod(env_str, &end_ptr); if (*end_ptr != '\0' || timeout < 0.0) __pmNotifyErr(LOG_WARNING, "%s:__pmAuxConnectPMCDPort: " "ignored bad PMCD_CONNECT_TIMEOUT = '%s'\n", __FILE__, env_str); else { canwait.tv_sec = (time_t)timeout; canwait.tv_usec = (int)((timeout - (double)canwait.tv_sec) * 1000000); } } } PM_UNLOCK(__pmLock_libpcp); return (&canwait); } /* * This interface is private to libpcp (although exposed in impl.h) and * deprecated (replaced by __pmAuxConnectPMCDPort()). * The implementation here is retained for IRIX and any 3rd party apps * that might have called this interface directly ... the implementation * is correct when $PMCD_PORT is unset, or set to a single numeric * port number, i.e. the old semantics */ int __pmAuxConnectPMCD(const char *hostname) { static int pmcd_port; static int first_time = 1; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (first_time) { char *env_str; char *end_ptr; first_time = 0; if ((env_str = getenv("PMCD_PORT")) != NULL) { pmcd_port = (int)strtol(env_str, &end_ptr, 0); if (*end_ptr != '\0' || pmcd_port < 0) { __pmNotifyErr(LOG_WARNING, "%s:__pmAuxConnectPMCD: ignored bad PMCD_PORT = '%s'\n", __FILE__, env_str); pmcd_port = SERVER_PORT; } } else pmcd_port = SERVER_PORT; } PM_UNLOCK(__pmLock_libpcp); return __pmAuxConnectPMCDPort(hostname, pmcd_port); } int __pmAuxConnectPMCDPort(const char *hostname, int pmcd_port) { __pmSockAddr *myAddr; __pmHostEnt *servInfo; int fd = -1; /* Fd for socket connection to pmcd */ int sts; int fdFlags = 0; void *enumIx; if ((servInfo = __pmGetAddrInfo(hostname)) == NULL) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { fprintf(stderr, "%s:__pmAuxConnectPMCDPort(%s, %d) : hosterror=%d, ``%s''\n", __FILE__, hostname, pmcd_port, hosterror(), hoststrerror()); } #endif return -EHOSTUNREACH; } __pmConnectTimeout(); enumIx = NULL; for (myAddr = __pmHostEntGetSockAddr(servInfo, &enumIx); myAddr != NULL; myAddr = __pmHostEntGetSockAddr(servInfo, &enumIx)) { /* Create a socket */ if (__pmSockAddrIsInet(myAddr)) fd = __pmCreateSocket(); else if (__pmSockAddrIsIPv6(myAddr)) fd = __pmCreateIPv6Socket(); else { __pmNotifyErr(LOG_ERR, "%s:__pmAuxConnectPMCDPort(%s, %d) : invalid address family %d\n", __FILE__, hostname, pmcd_port, __pmSockAddrGetFamily(myAddr)); fd = -EINVAL; } if (fd < 0) { __pmSockAddrFree(myAddr); continue; /* Try the next address */ } /* Attempt to connect */ fdFlags = __pmConnectTo(fd, myAddr, pmcd_port); __pmSockAddrFree(myAddr); if (fdFlags < 0) { /* * Mark failure in case we fall out the end of the loop * and try next address */ fd = -ECONNREFUSED; continue; } /* FNDELAY and we're in progress - wait on select */ struct timeval stv = canwait; struct timeval *pstv = (stv.tv_sec || stv.tv_usec) ? &stv : NULL; __pmFdSet wfds; int rc; __pmFD_ZERO(&wfds); __pmFD_SET(fd, &wfds); sts = 0; if ((rc = __pmSelectWrite(fd+1, &wfds, pstv)) == 1) { sts = __pmConnectCheckError(fd); } else if (rc == 0) { sts = ETIMEDOUT; } else { sts = (rc < 0) ? neterror() : EINVAL; } /* Successful connection? */ if (sts == 0) break; /* Unsuccessful connection. */ __pmCloseSocket(fd); fd = -sts; } __pmHostEntFree(servInfo); if (fd < 0) return fd; /* * If we're here, it means we have a valid connection; restore the * flags and make sure this file descriptor is closed if exec() is * called */ return __pmConnectRestoreFlags(fd, fdFlags); } /* * Return the path to the default PMCD local unix domain socket. * Returns a pointer to a static buffer which can be used directly. * Return the path regardless of whether unix domain sockets are * supported by our build. Other functions can then print reasonable * messages if an attempt is made to use one. */ const char * __pmPMCDLocalSocketDefault(void) { static char pmcd_socket[MAXPATHLEN]; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (pmcd_socket[0] == '\0') { char *envstr; if ((envstr = getenv("PMCD_SOCKET")) != NULL) snprintf(pmcd_socket, sizeof(pmcd_socket), "%s", envstr); else snprintf(pmcd_socket, sizeof(pmcd_socket), "%s%c" "pmcd.socket", pmGetConfig("PCP_RUN_DIR"), __pmPathSeparator()); } PM_UNLOCK(__pmLock_libpcp); return pmcd_socket; } int __pmAuxConnectPMCDUnixSocket(const char *sock_path) { #if defined(HAVE_STRUCT_SOCKADDR_UN) __pmSockAddr *myAddr; int fd = -1; /* Fd for socket connection to pmcd */ int sts; int fdFlags = 0; struct timeval stv; struct timeval *pstv; __pmFdSet wfds; int rc; __pmConnectTimeout(); /* Initialize the socket address. */ myAddr = __pmSockAddrAlloc(); if (myAddr == NULL) { __pmNotifyErr(LOG_ERR, "%s:__pmAuxConnectPMCDUnixSocket(%s): out of memory\n", __FILE__, sock_path); return -1; } __pmSockAddrSetFamily(myAddr, AF_UNIX); __pmSockAddrSetPath(myAddr, sock_path); /* Create a socket */ fd = __pmCreateUnixSocket(); if (fd < 0) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "%s:__pmAuxConnectPMCDUnixSocket(%s): unable to create socket: %s\n", __FILE__, sock_path, osstrerror_r(errmsg, sizeof(errmsg))); __pmSockAddrFree(myAddr); return fd; } /* Attempt to connect */ fdFlags = __pmConnectTo(fd, myAddr, -1); __pmSockAddrFree(myAddr); if (fdFlags < 0) return -ECONNREFUSED; /* FNDELAY and we're in progress - wait on select */ stv = canwait; pstv = (stv.tv_sec || stv.tv_usec) ? &stv : NULL; __pmFD_ZERO(&wfds); __pmFD_SET(fd, &wfds); sts = 0; if ((rc = __pmSelectWrite(fd+1, &wfds, pstv)) == 1) { sts = __pmConnectCheckError(fd); } else if (rc == 0) { sts = ETIMEDOUT; } else { sts = (rc < 0) ? neterror() : EINVAL; } if (sts != 0) { /* Unsuccessful connection. */ if (sts == ENOENT) sts = ECONNREFUSED; __pmCloseSocket(fd); fd = -sts; } if (fd < 0) return fd; /* * If we're here, it means we have a valid connection; restore the * flags and make sure this file descriptor is closed if exec() is * called */ return __pmConnectRestoreFlags(fd, fdFlags); #else __pmNotifyErr(LOG_ERR, "%s:__pmAuxConnectPMCDUnixSocket(%s) is not supported\n", __FILE__, sock_path); return -1; #endif } char * __pmHostEntGetName(__pmHostEnt *he) { __pmSockAddr *addr; void *enumIx; if (he->name == NULL) { /* Try to reverse lookup the host name. * Check each address until the reverse lookup succeeds. */ enumIx = NULL; for (addr = __pmHostEntGetSockAddr(he, &enumIx); addr != NULL; addr = __pmHostEntGetSockAddr(he, &enumIx)) { he->name = __pmGetNameInfo(addr); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DESPERATE) fprintf(stderr, "%s:__pmHostEntGetName: __pmGetNameInfo(%s) returns %s\n", __FILE__, __pmSockAddrToString(addr), he->name); #endif __pmSockAddrFree(addr); if (he->name != NULL) break; } if (he->name == NULL) return NULL; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DESPERATE) fprintf(stderr, "%s:__pmHostEntGetName -> %s\n", __FILE__, he->name); #endif return strdup(he->name); } #if !defined(HAVE_SECURE_SOCKETS) void __pmHostEntFree(__pmHostEnt *hostent) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DESPERATE) fprintf(stderr, "%s:__pmHostEntFree(hostent=%p) name=%p (%s) addresses=%p\n", __FILE__, hostent, hostent->name, hostent->name, hostent-> addresses); #endif if (hostent->name != NULL) free(hostent->name); if (hostent->addresses != NULL) freeaddrinfo(hostent->addresses); free(hostent); } int __pmCreateSocket(void) { int sts, fd; if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) return -neterror(); if ((sts = __pmInitSocket(fd, AF_INET)) < 0) return sts; return fd; } int __pmCreateIPv6Socket(void) { int sts, fd, on; __pmSockLen onlen = sizeof(on); if ((fd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) return -neterror(); /* * Disable IPv4-mapped connections * Must explicitly check whether that worked, for ipv6.enabled=false * kernels. Setting then testing is the most reliable way we've found. */ on = 1; __pmSetSockOpt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); on = 0; sts = __pmGetSockOpt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, &onlen); if (sts < 0 || on != 1) { __pmNotifyErr(LOG_ERR, "%s:__pmCreateIPv6Socket: IPV6 is not supported\n", __FILE__); close(fd); return -EOPNOTSUPP; } if ((sts = __pmInitSocket(fd, AF_INET6)) < 0) return sts; return fd; } int __pmCreateUnixSocket(void) { #if defined(HAVE_STRUCT_SOCKADDR_UN) int sts, fd; if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) return -neterror(); if ((sts = __pmInitSocket(fd, AF_UNIX)) < 0) return sts; return fd; #else __pmNotifyErr(LOG_ERR, "%s:__pmCreateUnixSocket: AF_UNIX is not supported\n", __FILE__); return -EOPNOTSUPP; #endif } void __pmCloseSocket(int fd) { __pmResetIPC(fd); #if defined(IS_MINGW) closesocket(fd); #else close(fd); #endif } int __pmSetSockOpt(int socket, int level, int option_name, const void *option_value, __pmSockLen option_len) { return setsockopt(socket, level, option_name, option_value, option_len); } int __pmGetSockOpt(int socket, int level, int option_name, void *option_value, __pmSockLen *option_len) { return getsockopt(socket, level, option_name, option_value, option_len); } /* Initialize a socket address. The integral address must be INADDR_ANY or INADDR_LOOPBACK in host byte order. */ void __pmSockAddrInit(__pmSockAddr *addr, int family, int address, int port) { memset(addr, 0, sizeof(*addr)); if (family == AF_INET) { addr->sockaddr.inet.sin_family = family; addr->sockaddr.inet.sin_addr.s_addr = htonl(address); addr->sockaddr.inet.sin_port = htons(port); } else if (family == AF_INET6) { addr->sockaddr.ipv6.sin6_family = family; addr->sockaddr.ipv6.sin6_port = htons(port); if (address == INADDR_LOOPBACK) addr->sockaddr.ipv6.sin6_addr.s6_addr[15] = 1; } else __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrInit: Invalid address family: %d\n", __FILE__, addr->sockaddr.raw.sa_family); } void __pmSockAddrSetFamily(__pmSockAddr *addr, int family) { addr->sockaddr.raw.sa_family = family; } int __pmSockAddrGetFamily(const __pmSockAddr *addr) { return addr->sockaddr.raw.sa_family; } void __pmSockAddrSetPort(__pmSockAddr *addr, int port) { if (addr->sockaddr.raw.sa_family == AF_INET) addr->sockaddr.inet.sin_port = htons(port); else if (addr->sockaddr.raw.sa_family == AF_INET6) addr->sockaddr.ipv6.sin6_port = htons(port); else __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrSetPort: Invalid address family: %d\n", __FILE__, addr->sockaddr.raw.sa_family); } int __pmSockAddrGetPort(const __pmSockAddr *addr) { if (addr->sockaddr.raw.sa_family == AF_INET) return ntohs(addr->sockaddr.inet.sin_port); if (addr->sockaddr.raw.sa_family == AF_INET6) return ntohs(addr->sockaddr.ipv6.sin6_port); __pmNotifyErr(LOG_ERR, "__pmSockAddrGetPort: Invalid address family: %d\n", addr->sockaddr.raw.sa_family); return 0; /* not set */ } void __pmSockAddrSetScope(__pmSockAddr *addr, int scope) { if (addr->sockaddr.raw.sa_family == AF_INET6) addr->sockaddr.ipv6.sin6_scope_id = scope; } void __pmSockAddrSetPath(__pmSockAddr *addr, const char *path) { #if defined(HAVE_STRUCT_SOCKADDR_UN) if (addr->sockaddr.raw.sa_family == AF_UNIX) strncpy(addr->sockaddr.local.sun_path, path, sizeof(addr->sockaddr.local.sun_path)); else __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrSetPath: Invalid address family: %d\n", __FILE__, addr->sockaddr.raw.sa_family); #else __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrSetPath: AF_UNIX is not supported\n", __FILE__); #endif } int __pmInitCertificates(void) { return 0; } int __pmShutdownCertificates(void) { return 0; } int __pmInitSecureSockets(void) { return 0; } int __pmShutdownSecureSockets(void) { return 0; } int __pmInitAuthClients(void) { return 0; } int __pmDataIPCSize(void) { return 0; } int __pmSecureClientHandshake(int fd, int flags, const char *hostname, __pmHashCtl *attrs) { (void)fd; (void)hostname; /* * We cannot handle many flags here (no support), in particular: * PDU_FLAG_SECURE (NSS) * PDU_FLAG_COMPRESS (NSS) * PDU_FLAG_AUTH (SASL2) * * But we can still talk to a pmcd that requires credentials, provided * we are using unix domain sockets (the kernel provides the auth info * to pmcd in this case, with no other special sauce required). */ if (flags == PDU_FLAG_CREDS_REQD) if (__pmHashSearch(PCP_ATTR_UNIXSOCK, attrs) != NULL) return 0; return -EOPNOTSUPP; } int __pmSocketClosed(void) { switch (oserror()) { /* * Treat this like end of file on input. * * failed as a result of pmcd exiting and the connection * being reset, or as a result of the kernel ripping * down the connection (most likely because the host at * the other end just took a dive) * * from IRIX BDS kernel sources, seems like all of the * following are peers here: * ECONNRESET (pmcd terminated?) * ETIMEDOUT ENETDOWN ENETUNREACH EHOSTDOWN EHOSTUNREACH * ECONNREFUSED * peers for BDS but not here: * ENETRESET ENONET ESHUTDOWN (cache_fs only?) * ECONNABORTED (accept, user req only?) * ENOTCONN (udp?) * EPIPE EAGAIN (nfs, bds & ..., but not ip or tcp?) */ case ECONNRESET: case EPIPE: case ETIMEDOUT: case ENETDOWN: case ENETUNREACH: case EHOSTDOWN: case EHOSTUNREACH: case ECONNREFUSED: return 1; } return 0; } int __pmListen(int fd, int backlog) { return listen(fd, backlog); } int __pmAccept(int fd, void *addr, __pmSockLen *addrlen) { __pmSockAddr *sockAddr = (__pmSockAddr *)addr; fd = accept(fd, &sockAddr->sockaddr.raw, addrlen); __pmCheckAcceptedAddress(sockAddr); return fd; } int __pmBind(int fd, void *addr, __pmSockLen addrlen) { __pmSockAddr *sock = (__pmSockAddr *)addr; #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_CONTEXT) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "%s:__pmBind(fd=%d, family=%d, port=%d, addr=%s)\n", __FILE__, fd, __pmSockAddrGetFamily(sock), __pmSockAddrGetPort(sock), __pmSockAddrToString(sock)); } #endif if (sock->sockaddr.raw.sa_family == AF_INET) return bind(fd, &sock->sockaddr.raw, sizeof(sock->sockaddr.inet)); if (sock->sockaddr.raw.sa_family == AF_INET6) return bind(fd, &sock->sockaddr.raw, sizeof(sock->sockaddr.ipv6)); #if defined(HAVE_STRUCT_SOCKADDR_UN) if (sock->sockaddr.raw.sa_family == AF_UNIX) return bind(fd, &sock->sockaddr.raw, sizeof(sock->sockaddr.local)); #endif __pmNotifyErr(LOG_ERR, "%s:__pmBind: Invalid address family: %d\n", __FILE__, sock->sockaddr.raw.sa_family); errno = EAFNOSUPPORT; return -1; /* failure */ } int __pmConnect(int fd, void *addr, __pmSockLen addrlen) { __pmSockAddr *sock = (__pmSockAddr *)addr; if (sock->sockaddr.raw.sa_family == AF_INET) return connect(fd, &sock->sockaddr.raw, sizeof(sock->sockaddr.inet)); if (sock->sockaddr.raw.sa_family == AF_INET6) return connect(fd, &sock->sockaddr.raw, sizeof(sock->sockaddr.ipv6)); #if defined(HAVE_STRUCT_SOCKADDR_UN) if (sock->sockaddr.raw.sa_family == AF_UNIX) return connect(fd, &sock->sockaddr.raw, sizeof(sock->sockaddr.local)); #endif __pmNotifyErr(LOG_ERR, "%s:__pmConnect: Invalid address family: %d\n", __FILE__, sock->sockaddr.raw.sa_family); errno = EAFNOSUPPORT; return -1; /* failure */ } int __pmGetFileStatusFlags(int fd) { return fcntl(fd, F_GETFL); } int __pmSetFileStatusFlags(int fd, int flags) { return fcntl(fd, F_SETFL, flags); } int __pmGetFileDescriptorFlags(int fd) { return fcntl(fd, F_GETFD); } int __pmSetFileDescriptorFlags(int fd, int flags) { return fcntl(fd, F_SETFD, flags); } ssize_t __pmWrite(int socket, const void *buffer, size_t length) { return write(socket, buffer, length); } ssize_t __pmRead(int socket, void *buffer, size_t length) { return read(socket, buffer, length); } ssize_t __pmSend(int socket, const void *buffer, size_t length, int flags) { return send(socket, buffer, length, flags); } ssize_t __pmRecv(int socket, void *buffer, size_t length, int flags) { ssize_t size; size = recv(socket, buffer, length, flags); #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_PDU) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "%s:__pmRecv(%d, ..., %d, " PRINTF_P_PFX "%x) -> %d\n", __FILE__, socket, (int)length, flags, (int)size); } #endif return size; } int __pmFD(int fd) { return fd; } void __pmFD_CLR(int fd, __pmFdSet *set) { FD_CLR(fd, set); } int __pmFD_ISSET(int fd, __pmFdSet *set) { return FD_ISSET(fd, set); } void __pmFD_SET(int fd, __pmFdSet *set) { FD_SET(fd, set); } void __pmFD_ZERO(__pmFdSet *set) { FD_ZERO(set); } void __pmFD_COPY(__pmFdSet *s1, const __pmFdSet *s2) { memcpy(s1, s2, sizeof(*s1)); } int __pmSelectRead(int nfds, __pmFdSet *readfds, struct timeval *timeout) { return select(nfds, readfds, NULL, NULL, timeout); } int __pmSelectWrite(int nfds, __pmFdSet *writefds, struct timeval *timeout) { return select(nfds, NULL, writefds, NULL, timeout); } int __pmSocketReady(int fd, struct timeval *timeout) { __pmFdSet onefd; FD_ZERO(&onefd); FD_SET(fd, &onefd); return select(fd+1, &onefd, NULL, NULL, timeout); } char * __pmGetNameInfo(__pmSockAddr *address) { int sts; char buf[NI_MAXHOST]; if (address->sockaddr.raw.sa_family == AF_INET) { sts = getnameinfo(&address->sockaddr.raw, sizeof(address->sockaddr.inet), buf, sizeof(buf), NULL, 0, 0); } else if (address->sockaddr.raw.sa_family == AF_INET6) { sts = getnameinfo(&address->sockaddr.raw, sizeof(address->sockaddr.ipv6), buf, sizeof(buf), NULL, 0, 0); } #if defined(HAVE_STRUCT_SOCKADDR_UN) else if (address->sockaddr.raw.sa_family == AF_UNIX) { /* The name info is the socket path. */ return strdup(address->sockaddr.local.sun_path); } #endif else { __pmNotifyErr(LOG_ERR, "%s:__pmGetNameInfo: Invalid address family: %d\n", __FILE__, address->sockaddr.raw.sa_family); sts = EAI_FAMILY; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DESPERATE) { if (sts != 0) { fprintf(stderr, "%s:__pmGetNameInfo: family=%d getnameinfo()-> %d %s\n", __FILE__, address->sockaddr.raw.sa_family, sts, gai_strerror(sts)); } } #endif return sts == 0 ? strdup(buf) : NULL; } __pmHostEnt * __pmGetAddrInfo(const char *hostName) { __pmHostEnt *hostEntry; struct addrinfo hints; int sts; hostEntry = __pmHostEntAlloc(); if (hostEntry != NULL) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ #ifdef HAVE_AI_ADDRCONFIG hints.ai_flags = AI_ADDRCONFIG; /* Only return configured address types */ #endif sts = getaddrinfo(hostName, NULL, &hints, &hostEntry->addresses); if (sts != 0) { __pmHostEntFree(hostEntry); hostEntry = NULL; } /* Leave the host name NULL. It will be looked up on demand in __pmHostEntGetName(). */ } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DESPERATE) { if (hostEntry == NULL) fprintf(stderr, "%s:__pmGetAddrInfo(%s) -> NULL\n", __FILE__, hostName); else fprintf(stderr, "%s:__pmGetAddrInfo(%s) -> %s\n", __FILE__, hostName, hostEntry->name); } #endif return hostEntry; } __pmSockAddr * __pmHostEntGetSockAddr(const __pmHostEnt *he, void **ei) { __pmAddrInfo *ai; __pmSockAddr *addr; /* The enumerator index (*ei) is actually a pointer to the current address info. */ if (*ei == NULL) *ei = ai = he->addresses; else { ai = *ei; *ei = ai = ai->ai_next; } if (*ei == NULL) return NULL; /* no (more) addresses in the chain. */ /* Now allocate a socket address and copy the data. */ addr = __pmSockAddrAlloc(); if (addr == NULL) { __pmNotifyErr(LOG_ERR, "%s:__pmHostEntGetSockAddr: out of memory\n", __FILE__); *ei = NULL; return NULL; } memcpy(&addr->sockaddr.raw, ai->ai_addr, ai->ai_addrlen); return addr; } __pmSockAddr * __pmSockAddrMask(__pmSockAddr *addr, const __pmSockAddr *mask) { int i; if (addr->sockaddr.raw.sa_family != mask->sockaddr.raw.sa_family) { __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrMask: Address family of the address (%d) must match that of the mask (%d)\n", __FILE__, addr->sockaddr.raw.sa_family, mask->sockaddr.raw.sa_family); } else if (addr->sockaddr.raw.sa_family == AF_INET) addr->sockaddr.inet.sin_addr.s_addr &= mask->sockaddr.inet.sin_addr.s_addr; else if (addr->sockaddr.raw.sa_family == AF_INET6) { /* IPv6: Mask it byte by byte */ unsigned char *addrBytes = addr->sockaddr.ipv6.sin6_addr.s6_addr; const unsigned char *maskBytes = mask->sockaddr.ipv6.sin6_addr.s6_addr; for (i = 0; i < sizeof(addr->sockaddr.ipv6.sin6_addr.s6_addr); ++i) addrBytes[i] &= maskBytes[i]; } #if defined(HAVE_STRUCT_SOCKADDR_UN) else if (addr->sockaddr.raw.sa_family == AF_UNIX) { /* Simply truncate the path in the address to the length of the mask. */ i = strlen(mask->sockaddr.local.sun_path); addr->sockaddr.local.sun_path[i] = '\0'; } #endif else /* not applicable to other address families. */ __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrMask: Invalid address family: %d\n", __FILE__, addr->sockaddr.raw.sa_family); return addr; } int __pmSockAddrCompare(const __pmSockAddr *addr1, const __pmSockAddr *addr2) { if (addr1->sockaddr.raw.sa_family != addr2->sockaddr.raw.sa_family) return addr1->sockaddr.raw.sa_family - addr2->sockaddr.raw.sa_family; if (addr1->sockaddr.raw.sa_family == AF_INET) return addr1->sockaddr.inet.sin_addr.s_addr - addr2->sockaddr.inet.sin_addr.s_addr; if (addr1->sockaddr.raw.sa_family == AF_INET6) { /* IPv6: Compare it byte by byte */ return memcmp(&addr1->sockaddr.ipv6.sin6_addr.s6_addr, &addr2->sockaddr.ipv6.sin6_addr.s6_addr, sizeof(addr1->sockaddr.ipv6.sin6_addr.s6_addr)); } #if defined(HAVE_STRUCT_SOCKADDR_UN) if (addr1->sockaddr.raw.sa_family == AF_UNIX) { /* Unix Domain: Compare the paths */ return strncmp(addr1->sockaddr.local.sun_path, addr2->sockaddr.local.sun_path, sizeof(addr1->sockaddr.local.sun_path)); } #endif /* Unknown address family. */ __pmNotifyErr(LOG_ERR, "%s:__pmSockAddrCompare: Invalid address family: %d\n", __FILE__, addr1->sockaddr.raw.sa_family); return 1; /* not equal */ } int __pmSockAddrIsInet(const __pmSockAddr *addr) { return addr->sockaddr.raw.sa_family == AF_INET; } int __pmSockAddrIsIPv6(const __pmSockAddr *addr) { return addr->sockaddr.raw.sa_family == AF_INET6; } int __pmSockAddrIsUnix(const __pmSockAddr *addr) { #if defined(HAVE_STRUCT_SOCKADDR_UN) return addr->sockaddr.raw.sa_family == AF_UNIX; #else return 0; #endif } __pmSockAddr * __pmStringToSockAddr(const char *cp) { __pmSockAddr *addr = __pmSockAddrAlloc(); if (addr) { if (cp == NULL || strcmp(cp, "INADDR_ANY") == 0) { addr->sockaddr.inet.sin_addr.s_addr = INADDR_ANY; /* Set the address family to 0, meaning "not set". */ addr->sockaddr.raw.sa_family = 0; } else { int sts; /* Determine the address family. */ #if defined(HAVE_STRUCT_SOCKADDR_UN) if (*cp == __pmPathSeparator()) { if (strlen(cp) >= sizeof(addr->sockaddr.local.sun_path)) sts = -1; /* too long */ else { addr->sockaddr.raw.sa_family = AF_UNIX; strcpy(addr->sockaddr.local.sun_path, cp); sts = 1; } } else #endif if (strchr(cp, ':') != NULL) { addr->sockaddr.raw.sa_family = AF_INET6; sts = inet_pton(AF_INET6, cp, &addr->sockaddr.ipv6.sin6_addr); } else { addr->sockaddr.raw.sa_family = AF_INET; sts = inet_pton(AF_INET, cp, &addr->sockaddr.inet.sin_addr); } if (sts <= 0) { __pmSockAddrFree(addr); addr = NULL; } } } return addr; } /* * Convert an address to a string. * The caller must free the buffer. */ char * __pmSockAddrToString(__pmSockAddr *addr) { char str[INET6_ADDRSTRLEN]; int family; const char *sts; sts = NULL; family = addr->sockaddr.raw.sa_family; if (family == AF_INET) sts = inet_ntop(family, &addr->sockaddr.inet.sin_addr, str, sizeof(str)); else if (family == AF_INET6) sts = inet_ntop(family, &addr->sockaddr.ipv6.sin6_addr, str, sizeof(str)); #if defined(HAVE_STRUCT_SOCKADDR_UN) else if (family == AF_UNIX) return strdup(addr->sockaddr.local.sun_path); #endif if (sts == NULL) return NULL; return strdup(str); } #endif /* !HAVE_SECURE_SOCKETS */ pcp-3.8.12ubuntu1/src/libpcp/src/pmns.c0000664000000000000000000016301712272262501014562 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe notes * * locerr - no serious side-effects, most unlikely to be used, and * repeated calls are likely to produce the same result, so don't bother * to make thread-safe */ #include #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "internal.h" #ifdef HAVE_STRINGS_H #include #endif /* token types */ #define NAME 1 #define PATH 2 #define PMID 3 #define LBRACE 4 #define RBRACE 5 #define BOGUS 10 #define UNKNOWN_MARK_STATE -1 /* tree not all marked the same way */ /* * Note: bit masks below are designed to clear and set the "flag" field * of a __pmID_int (i.e. a PMID) */ #define PMID_MASK 0x7fffffff /* 31 bits of PMID */ #define MARK_BIT 0x80000000 /* mark bit */ static int lineno; static char linebuf[256]; static char *linep; static char fname[256]; static char tokbuf[256]; static pmID tokpmid; static int seenpmid; static __pmnsNode *seen; /* list of pass-1 subtree nodes */ /* Last modification time for loading main_pmns file. */ #if defined(HAVE_STAT_TIMESTRUC) static timestruc_t last_mtim; #elif defined(HAVE_STAT_TIMESPEC) static struct timespec last_mtim; #elif defined(HAVE_STAT_TIMESPEC_T) static timespec_t last_mtim; #elif defined(HAVE_STAT_TIME_T) static time_t last_mtim; #else !bozo! #endif /* The curr_pmns points to PMNS to use for API ops. * Curr_pmns will point to either the main_pmns or * a pmns from a version 2 archive context. */ static __pmnsTree *curr_pmns = NULL; /* The main_pmns points to the loaded PMNS (not from archive). */ static __pmnsTree *main_pmns = NULL; /* == 1 if PMNS loaded and __pmExportPMNS has been called */ static int export; static int havePmLoadCall; static int useExtPMNS; /* set by __pmUsePMNS() */ static int load(const char *filename, int dupok); static __pmnsNode *locate(const char *name, __pmnsNode *root); /* * Set current pmns to an externally supplied PMNS. * Useful for testing the API routines during debugging. */ void __pmUsePMNS(__pmnsTree *t) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); useExtPMNS = 1; curr_pmns = t; PM_UNLOCK(__pmLock_libpcp); } static char * pmPMNSLocationStr(int location) { if (location < 0) { /* see thread-safe note above */ static char locerr[PM_MAXERRMSGLEN]; return pmErrStr_r(location, locerr, sizeof(locerr)); } switch(location) { case PMNS_LOCAL: return "Local"; case PMNS_REMOTE: return "Remote"; case PMNS_ARCHIVE: return "Archive"; } return "Internal Error"; } static int LoadDefault(char *reason_msg) { if (main_pmns == NULL) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "pmGetPMNSLocation: Loading local PMNS for %s PMAPI context\n", reason_msg); } #endif if (load(PM_NS_DEFAULT, 0) < 0) return PM_ERR_NOPMNS; else return PMNS_LOCAL; } return PMNS_LOCAL; } /* * Return the pmns_location. Possibly load the default PMNS. */ int pmGetPMNSLocation(void) { int pmns_location = PM_ERR_NOPMNS; int n; int sts; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (useExtPMNS) { PM_UNLOCK(__pmLock_libpcp); pmns_location = PMNS_LOCAL; goto done; } PM_UNLOCK(__pmLock_libpcp); /* * Determine if we are to use PDUs or local PMNS file. * Load PMNS if necessary. */ if (!havePmLoadCall) { __pmContext *ctxp; int version; if ((n = pmWhichContext()) >= 0 && (ctxp = __pmHandleToPtr(n)) != NULL) { switch(ctxp->c_type) { case PM_CONTEXT_HOST: if (ctxp->c_pmcd->pc_fd == -1) { pmns_location = PM_ERR_IPC; goto done; } if ((sts = version = __pmVersionIPC(ctxp->c_pmcd->pc_fd)) < 0) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "pmGetPMNSLocation: version lookup failed " "(context=%d, fd=%d): %s", n, ctxp->c_pmcd->pc_fd, pmErrStr_r(sts, errmsg, sizeof(errmsg))); pmns_location = PM_ERR_NOPMNS; } else if (version == PDU_VERSION2) { pmns_location = PMNS_REMOTE; } else { __pmNotifyErr(LOG_ERR, "pmGetPMNSLocation: bad host PDU version " "(context=%d, fd=%d, ver=%d)", n, ctxp->c_pmcd->pc_fd, version); pmns_location = PM_ERR_NOPMNS; } break; case PM_CONTEXT_LOCAL: if (PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) /* Local context requires single-threaded applications */ pmns_location = PM_ERR_THREAD; else pmns_location = LoadDefault("local"); break; case PM_CONTEXT_ARCHIVE: version = ctxp->c_archctl->ac_log->l_label.ill_magic & 0xff; if (version == PM_LOG_VERS02) { pmns_location = PMNS_ARCHIVE; PM_LOCK(__pmLock_libpcp); curr_pmns = ctxp->c_archctl->ac_log->l_pmns; PM_UNLOCK(__pmLock_libpcp); } else { __pmNotifyErr(LOG_ERR, "pmGetPMNSLocation: bad archive " "version (context=%d, fd=%d, ver=%d)", n, ctxp->c_pmcd->pc_fd, version); pmns_location = PM_ERR_NOPMNS; } break; default: __pmNotifyErr(LOG_ERR, "pmGetPMNSLocation: bogus context " "type: %d", ctxp->c_type); pmns_location = PM_ERR_NOPMNS; break; } PM_UNLOCK(ctxp->c_lock); } else { pmns_location = PM_ERR_NOPMNS; /* no context for client */ } } else { /* have explicit external load call */ if (main_pmns == NULL) pmns_location = PM_ERR_NOPMNS; else pmns_location = PMNS_LOCAL; } PM_LOCK(__pmLock_libpcp); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { static int last_pmns_location = -1; if (pmns_location != last_pmns_location) { fprintf(stderr, "pmGetPMNSLocation() -> %s\n", pmPMNSLocationStr(pmns_location)); last_pmns_location = pmns_location; } } #endif /* fix up curr_pmns for API ops */ if (pmns_location == PMNS_LOCAL) curr_pmns = main_pmns; PM_UNLOCK(__pmLock_libpcp); done: return pmns_location; } /* * Our own PMNS locator. Don't distinguish between ARCHIVE or LOCAL. */ static int GetLocation(void) { int loc = pmGetPMNSLocation(); if (loc == PMNS_ARCHIVE) return PMNS_LOCAL; return loc; } /* * For debugging, and visible via __pmDumpNameSpace() * * verbosity is 0 (name), 1 (names and pmids) or 2 (names, pmids and * linked-list structures) */ static void dumptree(FILE *f, int level, __pmnsNode *rp, int verbosity) { int i; __pmID_int *pp; if (rp != NULL) { if (verbosity > 1) fprintf(f, "" PRINTF_P_PFX "%p", rp); for (i = 0; i < level; i++) { fprintf(f, " "); } fprintf(f, " %-16.16s", rp->name); pp = (__pmID_int *)&rp->pmid; if (verbosity > 0 && rp->first == NULL) fprintf(f, " %d %d.%d.%d 0x%08x", rp->pmid, pp->domain, pp->cluster, pp->item, rp->pmid); if (verbosity > 1) { fprintf(f, "\t[first: "); if (rp->first) fprintf(f, "" PRINTF_P_PFX "%p", rp->first); else fprintf(f, ""); fprintf(f, " next: "); if (rp->next) fprintf(f, "" PRINTF_P_PFX "%p", rp->next); else fprintf(f, ""); fprintf(f, " parent: "); if (rp->parent) fprintf(f, "" PRINTF_P_PFX "%p", rp->parent); else fprintf(f, ""); fprintf(f, " hash: "); if (rp->hash) fprintf(f, "" PRINTF_P_PFX "%p", rp->hash); else fprintf(f, ""); } fputc('\n', f); dumptree(f, level+1, rp->first, verbosity); dumptree(f, level, rp->next, verbosity); } } static void err(char *s) { if (lineno > 0) pmprintf("[%s:%d] ", fname, lineno); pmprintf("Error Parsing ASCII PMNS: %s\n", s); if (lineno > 0) { char *p; pmprintf(" %s", linebuf); for (p = linebuf; *p; p++) ; if (p[-1] != '\n') pmprintf("\n"); if (linep) { p = linebuf; for (p = linebuf; p < linep; p++) { if (!isspace((int)*p)) *p = ' '; } *p++ = '^'; *p++ = '\n'; *p = '\0'; pmprintf(" %s", linebuf); } } pmflush(); } /* * lexical analyser for loading the ASCII pmns */ static int lex(int reset) { static int first = 1; static FILE *fin; static char *lp; char *tp; int colon; int type; int d, c, i; __pmID_int pmid_int; if (reset) { /* reset! */ linep = NULL; first = 1; return 0; } if (first) { char *alt; char cmd[80+MAXPATHLEN]; first = 0; if ((alt = getenv("PCP_ALT_CPP")) != NULL) { /* $PCP_ALT_CPP used in the build before pmcpp installed */ snprintf(cmd, sizeof(cmd), "%s %s", alt, fname); } else { /* the normal case ... */ int sep = __pmPathSeparator(); char *bin_dir = pmGetConfig("PCP_BINADM_DIR"); snprintf(cmd, sizeof(cmd), "%s%c%s %s", bin_dir, sep, "pmcpp" EXEC_SUFFIX, fname); } fin = popen(cmd, "r"); if (fin == NULL) return -oserror(); lp = linebuf; *lp = '\0'; } while (*lp && isspace((int)*lp)) lp++; while (*lp == '\0') { for ( ; ; ) { char *p; char *q; int inspace = 0; if (fgets(linebuf, sizeof(linebuf), fin) == NULL) { if (pclose(fin) != 0) { lineno = -1; /* We're outside of line counting range now */ err("pmcpp returned non-zero exit status"); return PM_ERR_PMNS; } else { return 0; } } for (q = p = linebuf; *p; p++) { if (isspace((int)*p)) { if (!inspace) { if (q > linebuf && q[-1] != ':') *q++ = *p; inspace = 1; } } else if (*p == ':') { if (inspace) { q--; inspace = 0; } *q++ = *p; } else { *q++ = *p; inspace = 0; } } if (p[-1] != '\n') { err("Absurdly long line, cannot recover"); pclose(fin); /* wait for pmcpp to finish */ exit(1); } *q = '\0'; if (linebuf[0] == '#') { /* pmcpp line number control line */ if (sscanf(linebuf, "# %d \"%s", &lineno, fname) != 2) { err ("Illegal line number control number"); return PM_ERR_PMNS; } --lineno; for (p = fname; *p; p++) ; *--p = '\0'; continue; } else lineno++; lp = linebuf; while (*lp && isspace((int)*lp)) lp++; break; } } linep = lp; tp = tokbuf; while (!isspace((int)*lp)) *tp++ = *lp++; *tp = '\0'; if (tokbuf[0] == '{' && tokbuf[1] == '\0') return LBRACE; else if (tokbuf[0] == '}' && tokbuf[1] == '\0') return RBRACE; else if (isalpha((int)tokbuf[0])) { type = NAME; for (tp = &tokbuf[1]; *tp; tp++) { if (*tp == '.') type = PATH; else if (!isalpha((int)*tp) && !isdigit((int)*tp) && *tp != '_') break; } if (*tp == '\0') return type; } colon = 0; for (tp = tokbuf; *tp; tp++) { if (*tp == ':') { if (++colon > 3) return BOGUS; } else if (!isdigit((int)*tp) && *tp != '*') return BOGUS; } /* * Internal PMID format * domain 9 bits * cluster 12 bits * item 10 bits */ if (sscanf(tokbuf, "%d:%d:%d", &d, &c, &i) == 3) { if (d > 510) { err("Illegal domain field in PMID"); return BOGUS; } else if (c > 4095) { err("Illegal cluster field in PMID"); return BOGUS; } else if (i > 1023) { err("Illegal item field in PMID"); return BOGUS; } pmid_int.flag = 0; pmid_int.domain = d; pmid_int.cluster = c; pmid_int.item = i; } else { for (tp = tokbuf; *tp; tp++) { if (*tp == ':') { if (strcmp("*:*", ++tp) != 0) { err("Illegal PMID"); return BOGUS; } break; } } if (sscanf(tokbuf, "%d:", &d) != 1) { err("Illegal PMID"); return BOGUS; } if (d > 510) { err("Illegal domain field in dynamic PMID"); return BOGUS; } else { /* * this node is the base of a dynamic subtree in the PMNS * ... identified by setting the domain field to the reserved * value DYNAMIC_PMID and storing the real domain of the PMDA * that can enumerate the subtree in the cluster field, while * the item field is not used (and set to zero) */ pmid_int.flag = 0; pmid_int.domain = DYNAMIC_PMID; pmid_int.cluster = d; pmid_int.item = 0; } } tokpmid = *(pmID *)&pmid_int; return PMID; } /* * Remove the named node from the seen list and return it. * The seen-list is a list of subtrees from pass 1. */ static __pmnsNode * findseen(char *name) { __pmnsNode *np; __pmnsNode *lnp; /* last np */ for (np = seen, lnp = NULL; np != NULL; lnp = np, np = np->next) { if (strcmp(np->name, name) == 0) { if (np == seen) seen = np->next; else lnp->next = np->next; np->next = NULL; return np; } } return NULL; } /* * Attach the subtrees from pass-1 to form a whole * connected tree. */ static int attach(char *base, __pmnsNode *rp) { int i; __pmnsNode *np; __pmnsNode *xp; char *path; if (rp != NULL) { for (np = rp->first; np != NULL; np = np->next) { if (np->pmid == PM_ID_NULL) { /* non-terminal node ... */ if (*base == '\0') { if ((path = (char *)malloc(strlen(np->name)+1)) == NULL) return -oserror(); strcpy(path, np->name); } else { if ((path = (char *)malloc(strlen(base)+strlen(np->name)+2)) == NULL) return -oserror(); strcpy(path, base); strcat(path, "."); strcat(path, np->name); } if ((xp = findseen(path)) == NULL) { snprintf(linebuf, sizeof(linebuf), "Cannot find definition for non-terminal node \"%s\" in name space", path); err(linebuf); free(path); return PM_ERR_PMNS; } np->first = xp->first; /* node xp and name no longer needed */ free(xp->name); free(xp); seenpmid--; i = attach(path, np); free(path); if (i != 0) return i; } } } return 0; } /* * Create a fullpath name by walking from the current * tree node up to the root. */ static int backname(__pmnsNode *np, char **name) { __pmnsNode *xp; char *p; int nch; nch = 0; xp = np; while (xp->parent != NULL) { nch += (int)strlen(xp->name)+1; xp = xp->parent; } if ((p = (char *)malloc(nch)) == NULL) return -oserror(); p[--nch] = '\0'; xp = np; while (xp->parent != NULL) { int xl; xl = (int)strlen(xp->name); nch -= xl; strncpy(&p[nch], xp->name, xl); xp = xp->parent; if (xp->parent == NULL) break; else p[--nch] = '.'; } *name = p; return 0; } /* * Fixup the parent pointers of the tree. * Fill in the hash table with nodes from the tree. * Hashing is done on pmid. */ static int backlink(__pmnsTree *tree, __pmnsNode *root, int dupok) { __pmnsNode *np; int status; for (np = root->first; np != NULL; np = np->next) { np->parent = root; if (np->pmid != PM_ID_NULL) { int i; __pmnsNode *xp; i = np->pmid % tree->htabsize; for (xp = tree->htab[i]; xp != NULL; xp = xp->hash) { if (xp->pmid == np->pmid && !dupok && (pmid_domain(np->pmid) != DYNAMIC_PMID || pmid_item(np->pmid) != 0)) { char *nn, *xn; char strbuf[20]; backname(np, &nn); backname(xp, &xn); snprintf(linebuf, sizeof(linebuf), "Duplicate metric id (%s) in name space for metrics \"%s\" and \"%s\"\n", pmIDStr_r(np->pmid, strbuf, sizeof(strbuf)), nn, xn); err(linebuf); free(nn); free(xn); return PM_ERR_PMNS; } } np->hash = tree->htab[i]; tree->htab[i] = np; } if ((status = backlink(tree, np, dupok))) return status; } return 0; } /* * Build up the whole tree by attaching the subtrees * from the seen list. * Create the hash table keyed on pmid. * */ static int pass2(int dupok) { __pmnsNode *np; int status; lineno = -1; main_pmns = (__pmnsTree*)malloc(sizeof(*main_pmns)); if (main_pmns == NULL) { return -oserror(); } /* Get the root subtree out of the seen list */ if ((main_pmns->root = findseen("root")) == NULL) { err("No name space entry for \"root\""); return PM_ERR_PMNS; } if (findseen("root") != NULL) { err("Multiple name space entries for \"root\""); return PM_ERR_PMNS; } /* Build up main tree from subtrees in seen-list */ if ((status = attach("", main_pmns->root))) return status; /* Make sure all subtrees have been used in the main tree */ for (np = seen; np != NULL; np = np->next) { snprintf(linebuf, sizeof(linebuf), "Disconnected subtree (\"%s\") in name space", np->name); err(linebuf); status = PM_ERR_PMNS; } if (status) return status; main_pmns->symbol = NULL; main_pmns->contiguous = 0; main_pmns->mark_state = UNKNOWN_MARK_STATE; return __pmFixPMNSHashTab(main_pmns, seenpmid, dupok); } /* * clear/set the "mark" bit used by pmTrimNameSpace, for all pmids */ static void mark_all(__pmnsTree *pmns, int bit) { int i; __pmnsNode *np; __pmnsNode *pp; if (pmns->mark_state == bit) return; pmns->mark_state = bit; for (i = 0; i < pmns->htabsize; i++) { for (np = pmns->htab[i]; np != NULL; np = np->hash) { for (pp = np ; pp != NULL; pp = pp->parent) { if (bit) pp->pmid |= MARK_BIT; else pp->pmid &= ~MARK_BIT; } } } } /* * clear/set the "mark" bit used by pmTrimNameSpace, for one pmid, and * for all parent nodes on the path to the root of the PMNS */ static void mark_one(__pmnsTree *pmns, pmID pmid, int bit) { __pmnsNode *np; if (pmns->mark_state == bit) return; pmns->mark_state = UNKNOWN_MARK_STATE; for (np = pmns->htab[pmid % pmns->htabsize]; np != NULL; np = np->hash) { if ((np->pmid & PMID_MASK) == (pmid & PMID_MASK)) { for ( ; np != NULL; np = np->parent) { if (bit) np->pmid |= MARK_BIT; else np->pmid &= ~MARK_BIT; } return; } } } /* * Create a new empty PMNS for Adding nodes to. * Use with __pmAddPMNSNode() and __pmFixPMNSHashTab() */ int __pmNewPMNS(__pmnsTree **pmns) { __pmnsTree *t = NULL; __pmnsNode *np = NULL; t = (__pmnsTree*)malloc(sizeof(*main_pmns)); if (t == NULL) return -oserror(); /* Insert the "root" node first */ if ((np = (__pmnsNode *)malloc(sizeof(*np))) == NULL) { free(t); return -oserror(); } np->pmid = PM_ID_NULL; np->parent = np->first = np->hash = np->next = NULL; np->name = strdup("root"); if (np->name == NULL) { free(t); free(np); return -oserror(); } t->root = np; t->htab = NULL; t->htabsize = 0; t->symbol = NULL; t->contiguous = 0; t->mark_state = UNKNOWN_MARK_STATE; *pmns = t; return 0; } /* * Go through the tree and build a hash table. * Fix up parent links while we're there. * Unmark all nodes. */ int __pmFixPMNSHashTab(__pmnsTree *tree, int numpmid, int dupok) { int sts; int htabsize = numpmid/5; /* * make the average hash list no longer than 5, and the number * of hash table entries not a multiple of 2, 3 or 5 */ if (htabsize % 2 == 0) htabsize++; if (htabsize % 3 == 0) htabsize += 2; if (htabsize % 5 == 0) htabsize += 2; tree->htabsize = htabsize; tree->htab = (__pmnsNode **)calloc(htabsize, sizeof(__pmnsNode *)); if (tree->htab == NULL) return -oserror(); PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if ((sts = backlink(tree, tree->root, dupok)) < 0) { PM_UNLOCK(__pmLock_libpcp); return sts; } mark_all(tree, 0); PM_UNLOCK(__pmLock_libpcp); return 0; } /* * Add a new node for fullpath, name, with pmid. * Does NOT update the hash table; * need to call __pmFixPMNSHashTab() for that. * Recursive routine. */ static int AddPMNSNode(__pmnsNode *root, int pmid, const char *name) { __pmnsNode *np = NULL; const char *tail; int nch; /* Traverse until '.' or '\0' */ for (tail = name; *tail && *tail != '.'; tail++) ; nch = (int)(tail - name); /* Compare name with all the child nodes */ for (np = root->first; np != NULL; np = np->next) { if (strncmp(name, np->name, (int)nch) == 0 && np->name[(int)nch] == '\0') break; } if (np == NULL) { /* no match with child */ __pmnsNode *parent_np = root; const char *name_p = name; int is_first = 1; /* create nodes until reach leaf */ for ( ; ; ) { if ((np = (__pmnsNode *)malloc(sizeof(*np))) == NULL) return -oserror(); /* fixup name */ if ((np->name = (char *)malloc(nch+1)) == NULL) { free(np); return -oserror(); } strncpy(np->name, name_p, nch); np->name[nch] = '\0'; /* fixup some links */ np->first = np->hash = np->next = NULL; np->parent = parent_np; if (is_first) { is_first = 0; if (root->first != NULL) { /* chuck new node at front of list */ np->next = root->first; } } parent_np->first = np; /* at this stage, assume np is a non-leaf */ np->pmid = PM_ID_NULL; parent_np = np; if (*tail == '\0') break; name_p += nch+1; /* skip over node + dot */ for (tail = name_p; *tail && *tail != '.'; tail++) ; nch = (int)(tail - name_p); } np->pmid = pmid; /* set pmid of leaf node */ return 0; } else if (*tail == '\0') { /* matched with whole path */ if (np->pmid != pmid) return PM_ERR_PMID; else return 0; } else { return AddPMNSNode(np, pmid, tail+1); /* try matching with rest of pathname */ } } /* * Add a new node for fullpath, name, with pmid. * NOTE: Need to call __pmFixPMNSHashTab() to update hash table * when have finished adding nodes. */ int __pmAddPMNSNode(__pmnsTree *tree, int pmid, const char *name) { if (tree->contiguous) { pmprintf("Cannot add node to contiguously allocated tree!\n"); pmflush(); exit(1); } return AddPMNSNode(tree->root, pmid, name); } /* * fsa for parser * * old token new * 0 NAME 1 * 0 PATH 1 * 1 LBRACE 2 * 2 NAME 3 * 2 RBRACE 0 * 3 NAME 3 * 3 PMID 2 * 3 RBRACE 0 */ static int loadascii(int dupok) { int state = 0; int type; __pmnsNode *np = NULL; /* pander to gcc */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) fprintf(stderr, "loadascii(file=%s)\n", fname); #endif /* do some resets */ lex(1); /* reset analyzer */ seen = NULL; /* make seen-list empty */ seenpmid = 0; if (access(fname, R_OK) == -1) { snprintf(linebuf, sizeof(linebuf), "Cannot open \"%s\"", fname); err(linebuf); return -oserror(); } lineno = 1; while ((type = lex(0)) > 0) { switch (state) { case 0: if (type != NAME && type != PATH) { err("Expected NAME or PATH"); return PM_ERR_PMNS; } state = 1; break; case 1: if (type != LBRACE) { err("{ expected"); return PM_ERR_PMNS; } state = 2; break; case 2: if (type == NAME) { state = 3; } else if (type == RBRACE) { state = 0; } else { err("Expected NAME or }"); return PM_ERR_PMNS; } break; case 3: if (type == NAME) { state = 3; } else if (type == PMID) { np->pmid = tokpmid; state = 2; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { char strbuf[20]; fprintf(stderr, "pmLoadNameSpace: %s -> %s\n", np->name, pmIDStr_r(np->pmid, strbuf, sizeof(strbuf))); } #endif } else if (type == RBRACE) { state = 0; } else { err("Expected NAME, PMID or }"); return PM_ERR_PMNS; } break; } if (state == 1 || state == 3) { if ((np = (__pmnsNode *)malloc(sizeof(*np))) == NULL) return -oserror(); seenpmid++; if ((np->name = (char *)malloc(strlen(tokbuf)+1)) == NULL) { free(np); return -oserror(); } strcpy(np->name, tokbuf); np->first = np->hash = np->next = np->parent = NULL; np->pmid = PM_ID_NULL; if (state == 1) { np->next = seen; seen = np; } else { if (seen->hash) seen->hash->next = np; else seen->first = np; seen->hash = np; } } else if (state == 0) { if (seen) { __pmnsNode *xp; for (np = seen->first; np != NULL; np = np->next) { for (xp = np->next; xp != NULL; xp = xp->next) { if (strcmp(xp->name, np->name) == 0) { snprintf(linebuf, sizeof(linebuf), "Duplicate name \"%s\" in subtree for \"%s\"\n", np->name, seen->name); err(linebuf); return PM_ERR_PMNS; } } } } } } if (type == 0) type = pass2(dupok); if (type == 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) fprintf(stderr, "Loaded ASCII PMNS\n"); #endif } return type; } static const char * getfname(const char *filename) { /* * 0xffffffff is there to maintain backwards compatibility with PCP 1.0 */ if (filename == PM_NS_DEFAULT || (__psint_t)filename == 0xffffffff) { char *def_pmns; def_pmns = getenv("PMNS_DEFAULT"); if (def_pmns != NULL) { /* get default PMNS name from environment */ return def_pmns; } else { static char repname[MAXPATHLEN]; int sep = __pmPathSeparator(); snprintf(repname, sizeof(repname), "%s%c" "pmns" "%c" "root", pmGetConfig("PCP_VAR_DIR"), sep, sep); return repname; } } return filename; } int __pmHasPMNSFileChanged(const char *filename) { const char *f; int sts; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); f = getfname(filename); if (f == NULL) { /* error encountered -> must have changed :) */ sts = 1; goto done; } /* if still using same filename ... */ if (strcmp(f, fname) == 0) { struct stat statbuf; if (stat(f, &statbuf) == 0) { /* If the modification times have changed */ #if defined(HAVE_ST_MTIME_WITH_E) && defined(HAVE_STAT_TIME_T) #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "__pmHasPMNSFileChanged(%s) -> %s last=%d now=%d\n", filename == PM_NS_DEFAULT || (__psint_t)filename == 0xffffffff ? "PM_NS_DEFAULT" : filename, f, (int)last_mtim, (int)statbuf.st_mtime); } #endif sts = (statbuf.st_mtime == last_mtim) ? 0 : 1; goto done; #elif defined(HAVE_ST_MTIME_WITH_SPEC) #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "__pmHasPMNSFileChanged(%s) -> %s last=%d.%09ld now=%d.%09ld\n", filename == PM_NS_DEFAULT || (__psint_t)filename == 0xffffffff ? "PM_NS_DEFAULT" : filename, f, (int)last_mtim.tv_sec, last_mtim.tv_nsec, (int)statbuf.st_mtimespec.tv_sec, statbuf.st_mtimespec.tv_nsec); } #endif sts = (statbuf.st_mtimespec.tv_sec == last_mtim.tv_sec && statbuf.st_mtimespec.tv_nsec == last_mtim.tv_nsec) ? 0 : 1; goto done; #elif defined(HAVE_STAT_TIMESTRUC) || defined(HAVE_STAT_TIMESPEC) || defined(HAVE_STAT_TIMESPEC_T) #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "__pmHasPMNSFileChanged(%s) -> %s last=%d.%09ld now=%d.%09ld\n", filename == PM_NS_DEFAULT || (__psint_t)filename == 0xffffffff ? "PM_NS_DEFAULT" : filename, f, (int)last_mtim.tv_sec, last_mtim.tv_nsec, (int)statbuf.st_mtim.tv_sec, statbuf.st_mtim.tv_nsec); } #endif sts = (statbuf.st_mtim.tv_sec == last_mtim.tv_sec && (statbuf.st_mtim.tv_nsec == last_mtim.tv_nsec)) ? 0 : 1; goto done; #else !bozo! #endif } else { /* error encountered -> must have changed */ sts = 1; goto done; } } /* different filenames at least */ sts = 1; done: PM_UNLOCK(__pmLock_libpcp); return sts; } static int load(const char *filename, int dupok) { int i = 0; if (main_pmns != NULL) { if (export) { export = 0; /* * drop the loaded PMNS ... huge memory leak, but it is * assumed the caller has saved the previous PMNS after calling * __pmExportPMNS() ... only user of this service is pmnsmerge */ main_pmns = NULL; } else { return PM_ERR_DUPPMNS; } } strcpy(fname, getfname(filename)); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) fprintf(stderr, "load(name=%s, dupok=%d) lic case=%d fname=%s\n", filename, dupok, i, fname); #endif /* Note modification time of pmns file */ { struct stat statbuf; if (stat(fname, &statbuf) == 0) { #if defined(HAVE_ST_MTIME_WITH_E) last_mtim = statbuf.st_mtime; /* possible struct assignment */ #elif defined(HAVE_ST_MTIME_WITH_SPEC) last_mtim = statbuf.st_mtimespec; /* possible struct assignment */ #else last_mtim = statbuf.st_mtim; /* possible struct assignment */ #endif } } /* * load ASCII PMNS */ return loadascii(dupok); } /* * just for pmnsmerge to use */ __pmnsTree* __pmExportPMNS(void) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); export = 1; PM_UNLOCK(__pmLock_libpcp); /* * Warning: this is _not_ thread-safe, and cannot be guarded/protected */ return main_pmns; } /* * Find and return the named node in the tree, root. */ static __pmnsNode * locate(const char *name, __pmnsNode *root) { const char *tail; ptrdiff_t nch; __pmnsNode *np; /* Traverse until '.' or '\0' */ for (tail = name; *tail && *tail != '.'; tail++) ; nch = tail - name; /* Compare name with all the child nodes */ for (np = root->first; np != NULL; np = np->next) { if (strncmp(name, np->name, (int)nch) == 0 && np->name[(int)nch] == '\0' && (np->pmid & MARK_BIT) == 0) break; } if (np == NULL) /* no match with child */ return NULL; else if (*tail == '\0') /* matched with whole path */ return np; else return locate(tail+1, np); /* try matching with rest of pathname */ } /* * PMAPI routines from here down */ /* * As of PCP 3.6, there is _only_ the ASCII version of the PMNS */ int pmLoadNameSpace(const char *filename) { return pmLoadASCIINameSpace(filename, 0); } int pmLoadASCIINameSpace(const char *filename, int dupok) { int sts; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); havePmLoadCall = 1; sts = load(filename, dupok); PM_UNLOCK(__pmLock_libpcp); return sts; } /* * Assume that each node has been malloc'ed separately. * This is the case for an ASCII loaded PMNS. * Traverse entire tree and free each node. */ static void FreeTraversePMNS(__pmnsNode *this) { __pmnsNode *np, *next; if (this == NULL) return; /* Free child sub-trees */ for (np = this->first; np != NULL; np = next) { next = np->next; FreeTraversePMNS(np); } free(this->name); free(this); } void __pmFreePMNS(__pmnsTree *pmns) { if (pmns != NULL) { if (pmns->contiguous) { free(pmns->root); free(pmns->htab); free(pmns->symbol); } else { free(pmns->htab); FreeTraversePMNS(pmns->root); } free(pmns); } } void pmUnloadNameSpace(void) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); havePmLoadCall = 0; __pmFreePMNS(main_pmns); main_pmns = NULL; PM_UNLOCK(__pmLock_libpcp); } int pmLookupName(int numpmid, char *namelist[], pmID pmidlist[]) { int pmns_location = GetLocation(); int sts = 0; __pmContext *ctxp; int c_type; int lsts; int ctx; int i; int nfail = 0; if (numpmid < 1) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "pmLookupName(%d, ...) bad numpmid!\n", numpmid); } #endif return PM_ERR_TOOSMALL; } PM_INIT_LOCKS(); ctx = lsts = pmWhichContext(); if (lsts >= 0) { ctxp = __pmHandleToPtr(ctx); c_type = ctxp->c_type; } else { ctxp = NULL; /* * set c_type to be NONE of PM_CONTEXT_HOST, PM_CONTEXT_ARCHIVE * nor PM_CONTEXT_LOCAL */ c_type = 0; } if (ctxp != NULL && c_type == PM_CONTEXT_LOCAL && PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) { /* Local context requires single-threaded applications */ PM_UNLOCK(ctxp->c_lock); return PM_ERR_THREAD; } /* * Guarantee that derived metrics preparation is done, for all possible * paths through this routine which might end at "Try derived metrics.." * below. */ memset(pmidlist, PM_ID_NULL, numpmid * sizeof(pmID)); if (pmns_location < 0) { if (ctxp != NULL) PM_UNLOCK(ctxp->c_lock); sts = pmns_location; /* only hope is derived metrics ... set up for this */ nfail += numpmid; } else if (pmns_location == PMNS_LOCAL) { char *xname; char *xp; __pmnsNode *np; if (ctxp != NULL) PM_UNLOCK(ctxp->c_lock); for (i = 0; i < numpmid; i++) { /* * if we locate the name and it is a leaf in the PMNS * this is good */ PM_LOCK(__pmLock_libpcp); np = locate(namelist[i], curr_pmns->root); PM_UNLOCK(__pmLock_libpcp); if (np != NULL ) { if (np->first == NULL) pmidlist[i] = np->pmid; else { sts = PM_ERR_NONLEAF; nfail++; } continue; } nfail++; /* * did not match name in PMNS ... try for prefix matching * the name to the root of a dynamic subtree of the PMNS, * or possibly we're using a local context and then we may * be able to ship request to PMDA */ xname = strdup(namelist[i]); if (xname == NULL) { __pmNoMem("pmLookupName", strlen(namelist[i])+1, PM_RECOV_ERR); sts = -oserror(); continue; } while ((xp = rindex(xname, '.')) != NULL) { *xp = '\0'; lsts = 0; PM_LOCK(__pmLock_libpcp); np = locate(xname, curr_pmns->root); PM_UNLOCK(__pmLock_libpcp); if (np != NULL && np->first == NULL && pmid_domain(np->pmid) == DYNAMIC_PMID && pmid_item(np->pmid) == 0) { /* root of dynamic subtree */ if (c_type == PM_CONTEXT_LOCAL) { /* have PM_CONTEXT_LOCAL ... ship request to PMDA */ int domain = ((__pmID_int *)&np->pmid)->cluster; __pmDSO *dp; if ((dp = __pmLookupDSO(domain)) == NULL) { if (sts >= 0) sts = PM_ERR_NOAGENT; break; } if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_4) { lsts = dp->dispatch.version.four.pmid(namelist[i], &pmidlist[i], dp->dispatch.version.four.ext); if (lsts >= 0) nfail--; break; } } else { /* No PM_LOCAL_CONTEXT, use PMID from PMNS */ pmidlist[i] = np->pmid; nfail--; break; } } } free(xname); } sts = (sts == 0 ? numpmid - nfail : sts); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { int i; char strbuf[20]; fprintf(stderr, "pmLookupName(%d, ...) using local PMNS returns %d and ...\n", numpmid, sts); for (i = 0; i < numpmid; i++) { fprintf(stderr, " name[%d]: \"%s\"", i, namelist[i]); if (sts >= 0) fprintf(stderr, " PMID: 0x%x %s", pmidlist[i], pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf))); fputc('\n', stderr); } } #endif } else { /* * PMNS_REMOTE so there must be a current host context */ assert(c_type == PM_CONTEXT_HOST); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "pmLookupName: request_names ->"); for (i = 0; i < numpmid; i++) fprintf(stderr, " [%d] %s", i, namelist[i]); fputc('\n', stderr); } #endif PM_LOCK(ctxp->c_pmcd->pc_lock); sts = __pmSendNameList(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), numpmid, namelist, NULL); if (sts < 0) sts = __pmMapErrno(sts); else { __pmPDU *pb; int pinpdu; pinpdu = sts = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, ctxp->c_pmcd->pc_tout_sec, &pb); if (sts == PDU_PMNS_IDS) { /* Note: * pmLookupName may return an error even though * it has a valid list of ids. * This is why we need op_status. */ int op_status; sts = __pmDecodeIDList(pb, numpmid, pmidlist, &op_status); if (sts >= 0) sts = op_status; } else if (sts == PDU_ERROR) { __pmDecodeError(pb, &sts); } else if (sts != PM_ERR_TIMEOUT) { sts = PM_ERR_IPC; } if (pinpdu > 0) __pmUnpinPDUBuf(pb); if (sts >= 0) nfail = numpmid - sts; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { char strbuf[20]; char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "pmLookupName: receive_names <-"); if (sts >= 0) { for (i = 0; i < numpmid; i++) fprintf(stderr, " [%d] %s", i, pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf))); fputc('\n', stderr); } else fprintf(stderr, " %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } #endif } PM_UNLOCK(ctxp->c_pmcd->pc_lock); PM_UNLOCK(ctxp->c_lock); } if (sts < 0 || nfail > 0) { /* * Try derived metrics for any remaining unknown pmids. * The return status is a little tricky ... prefer the status * from above unless all of the remaining unknown PMIDs are * resolved by __dmgetpmid() in which case success (numpmid) * is the right return status */ nfail = 0; for (i = 0; i < numpmid; i++) { if (pmidlist[i] == PM_ID_NULL) { lsts = __dmgetpmid(namelist[i], &pmidlist[i]); if (lsts < 0) { nfail++; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { char strbuf[20]; char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__dmgetpmid: metric \"%s\" -> ", namelist[i]); if (lsts < 0) fprintf(stderr, "%s\n", pmErrStr_r(lsts, errmsg, sizeof(errmsg))); else fprintf(stderr, "PMID %s\n", pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf))); } #endif } } if (nfail == 0) sts = numpmid; } /* * special case for a single metric, PM_ERR_NAME is more helpful than * returning 0 and having one PM_ID_NULL pmid */ if (sts == 0 && numpmid == 1) sts = PM_ERR_NAME; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "pmLookupName(%d, ...) -> ", numpmid); if (sts < 0) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "%s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } else fprintf(stderr, "%d\n", sts); } #endif return sts; } static int GetChildrenStatusRemote(__pmContext *ctxp, const char *name, char ***offspring, int **statuslist) { int n; PM_LOCK(ctxp->c_pmcd->pc_lock); n = __pmSendChildReq(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), name, statuslist == NULL ? 0 : 1); if (n < 0) n = __pmMapErrno(n); else { __pmPDU *pb; int pinpdu; pinpdu = n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, ctxp->c_pmcd->pc_tout_sec, &pb); if (n == PDU_PMNS_NAMES) { int numnames; n = __pmDecodeNameList(pb, &numnames, offspring, statuslist); if (n >= 0) n = numnames; } else if (n == PDU_ERROR) __pmDecodeError(pb, &n); else if (n != PM_ERR_TIMEOUT) n = PM_ERR_IPC; if (pinpdu > 0) __pmUnpinPDUBuf(pb); } PM_UNLOCK(ctxp->c_pmcd->pc_lock); return n; } static void stitch_list(int *num, char ***offspring, int **statuslist, int x_num, char **x_offspring, int *x_statuslist) { /* * so this gets tricky ... need to stitch the additional metrics * (derived metrics or dynamic metrics) at the end of the existing * metrics (if any) after removing any duplicates (!) ... and honour * the bizarre pmGetChildren contract in terms of malloc'ing the * result arrays */ int n_num; char **n_offspring; int *n_statuslist = NULL; int i; int j; char *q; size_t need; if (*num > 0) n_num = *num + x_num; else n_num = x_num; for (i = 0; i < x_num; i++) { for (j = 0; j < *num; j++) { if (strcmp(x_offspring[i], (*offspring)[j]) == 0) { /* duplicate ... bugger */ n_num--; free(x_offspring[i]); x_offspring[i] = NULL; break; } } } need = n_num*sizeof(char *); for (j = 0; j < *num; j++) { need += strlen((*offspring)[j]) + 1; } for (i = 0; i < x_num; i++) { if (x_offspring[i] != NULL) { need += strlen(x_offspring[i]) + 1; } } if ((n_offspring = (char **)malloc(need)) == NULL) { __pmNoMem("pmGetChildrenStatus: n_offspring", need, PM_FATAL_ERR); /*NOTREACHED*/ } if (statuslist != NULL) { if ((n_statuslist = (int *)malloc(n_num*sizeof(n_statuslist[0]))) == NULL) { __pmNoMem("pmGetChildrenStatus: n_statuslist", n_num*sizeof(n_statuslist[0]), PM_FATAL_ERR); /*NOTREACHED*/ } } q = (char *)&n_offspring[n_num]; for (j = 0; j < *num; j++) { n_offspring[j] = q; strcpy(q, (*offspring)[j]); q += strlen(n_offspring[j]) + 1; if (statuslist != NULL) n_statuslist[j] = (*statuslist)[j]; } for (i = 0; i < x_num; i++) { if (x_offspring[i] != NULL) { n_offspring[j] = q; strcpy(q, x_offspring[i]); q += strlen(n_offspring[j]) + 1; if (statuslist != NULL) n_statuslist[j] = x_statuslist[i]; j++; } } if (*num > 0) { free(*offspring); if (statuslist != NULL) free(*statuslist); } *num = n_num; if (statuslist != NULL) *statuslist = n_statuslist; *offspring = n_offspring; } /* * It is allowable to pass in a statuslist arg of NULL. It is therefore * important to check that this is not NULL before accessing it. */ int pmGetChildrenStatus(const char *name, char ***offspring, int **statuslist) { int *status = NULL; int pmns_location = GetLocation(); int num; int dm_num; char **dm_offspring; int *dm_statuslist; int sts; int ctx; __pmContext *ctxp; if (pmns_location < 0) return pmns_location; if (name == NULL) return PM_ERR_NAME; PM_INIT_LOCKS(); ctx = sts = pmWhichContext(); if (sts >= 0) ctxp = __pmHandleToPtr(sts); else ctxp = NULL; if (pmns_location == PMNS_LOCAL) { __pmnsNode *np; __pmnsNode *tnp; int i; int need; char **result; char *p; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "pmGetChildren(name=\"%s\") [local]\n", name); } #endif /* avoids ambiguity, for errors and leaf nodes */ *offspring = NULL; num = 0; if (statuslist) *statuslist = NULL; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (*name == '\0') np = curr_pmns->root; /* use "" to name the root of the PMNS */ else np = locate(name, curr_pmns->root); if (np == NULL) { if (ctxp != NULL && ctxp->c_type == PM_CONTEXT_LOCAL) { /* * No match in PMNS and using PM_CONTEXT_LOCAL so for * dynamic metrics, need to consider prefix matches back to * the root on the PMNS to find a possible root of a dynamic * subtree, and hence the domain of the responsible PMDA */ char *xname = strdup(name); char *xp; if (xname == NULL) { __pmNoMem("pmGetChildrenStatus", strlen(name)+1, PM_RECOV_ERR); num = -oserror(); PM_UNLOCK(__pmLock_libpcp); goto report; } while ((xp = rindex(xname, '.')) != NULL) { *xp = '\0'; np = locate(xname, curr_pmns->root); if (np != NULL && np->first == NULL && pmid_domain(np->pmid) == DYNAMIC_PMID && pmid_item(np->pmid) == 0) { int domain = ((__pmID_int *)&np->pmid)->cluster; __pmDSO *dp; if ((dp = __pmLookupDSO(domain)) == NULL) { num = PM_ERR_NOAGENT; free(xname); PM_UNLOCK(__pmLock_libpcp); goto check; } if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_4) { char **x_offspring = NULL; int *x_statuslist = NULL; int x_num; x_num = dp->dispatch.version.four.children( name, 0, &x_offspring, &x_statuslist, dp->dispatch.version.four.ext); if (x_num < 0) num = x_num; else stitch_list(&num, offspring, statuslist, x_num, x_offspring, x_statuslist); free(xname); PM_UNLOCK(__pmLock_libpcp); goto check; } else { /* Not PMDA_INTERFACE_4 or later */ num = PM_ERR_NAME; free(xname); PM_UNLOCK(__pmLock_libpcp); goto check; } } } free(xname); } num = PM_ERR_NAME; PM_UNLOCK(__pmLock_libpcp); goto check; } PM_UNLOCK(__pmLock_libpcp); if (np != NULL && np->first == NULL) { /* * this is a leaf node ... if it is the root of a dynamic * subtree of the PMNS and we have an existing context * of type PM_CONTEXT_LOCAL than we should chase the * relevant PMDA to provide the details */ if (pmid_domain(np->pmid) == DYNAMIC_PMID && pmid_item(np->pmid) == 0) { if (ctxp != NULL && ctxp->c_type == PM_CONTEXT_LOCAL) { int domain = ((__pmID_int *)&np->pmid)->cluster; __pmDSO *dp; if ((dp = __pmLookupDSO(domain)) == NULL) { num = PM_ERR_NOAGENT; goto check; } if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_4) { char **x_offspring = NULL; int *x_statuslist = NULL; int x_num; x_num = dp->dispatch.version.four.children(name, 0, &x_offspring, &x_statuslist, dp->dispatch.version.four.ext); if (x_num < 0) num = x_num; else stitch_list(&num, offspring, statuslist, x_num, x_offspring, x_statuslist); goto check; } else { /* Not PMDA_INTERFACE_4 or later */ num = PM_ERR_NAME; goto check; } } } num = 0; goto check; } need = 0; num = 0; if (np != NULL) { for (i = 0, tnp = np->first; tnp != NULL; tnp = tnp->next, i++) { if ((tnp->pmid & MARK_BIT) == 0) { num++; need += sizeof(**offspring) + strlen(tnp->name) + 1; } } } if ((result = (char **)malloc(need)) == NULL) { num = -oserror(); goto report; } if (statuslist != NULL) { if ((status = (int *)malloc(num*sizeof(int))) == NULL) { num = -oserror(); free(result); goto report; } } p = (char *)&result[num]; if (np != NULL) { for (i = 0, tnp = np->first; tnp != NULL; tnp = tnp->next) { if ((tnp->pmid & MARK_BIT) == 0) { result[i] = p; /* * a name at the root of a dynamic metrics subtree * needs some special handling ... they will have a * "special" PMID, but need the status set to indicate * they are not a leaf node of the PMNS */ if (statuslist != NULL) { if (pmid_domain(tnp->pmid) == DYNAMIC_PMID && pmid_item(tnp->pmid) == 0) { status[i] = PMNS_NONLEAF_STATUS; } else /* node has children? */ status[i] = (tnp->first == NULL ? PMNS_LEAF_STATUS : PMNS_NONLEAF_STATUS); } strcpy(result[i], tnp->name); p += strlen(tnp->name) + 1; i++; } } } *offspring = result; if (statuslist != NULL) *statuslist = status; } else { /* * PMNS_REMOTE so there must be a current host context */ assert(ctxp != NULL && ctxp->c_type == PM_CONTEXT_HOST); num = GetChildrenStatusRemote(ctxp, name, offspring, statuslist); } check: if (ctxp != NULL) PM_UNLOCK(ctxp->c_lock); /* * see if there are derived metrics that qualify */ dm_num = __dmchildren(name, &dm_offspring, &dm_statuslist); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { char errmsg[PM_MAXERRMSGLEN]; if (num < 0) fprintf(stderr, "pmGetChildren(name=\"%s\") no regular children (%s)", name, pmErrStr_r(num, errmsg, sizeof(errmsg))); else fprintf(stderr, "pmGetChildren(name=\"%s\") %d regular children", name, num); if (dm_num < 0) fprintf(stderr, ", no derived children (%s)\n", pmErrStr_r(dm_num, errmsg, sizeof(errmsg))); else if (dm_num == 0) fprintf(stderr, ", derived leaf\n"); else fprintf(stderr, ", %d derived children\n", dm_num); } #endif if (dm_num > 0) { stitch_list(&num, offspring, statuslist, dm_num, dm_offspring, dm_statuslist); free(dm_offspring); free(dm_statuslist); } else if (dm_num == 0 && num < 0) { /* leaf node and derived metric */ num = 0; } report: #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PMNS) { fprintf(stderr, "pmGetChildren(name=\"%s\") -> ", name); if (num == 0) fprintf(stderr, "leaf\n"); else if (num > 0) { if (statuslist != NULL) __pmDumpNameAndStatusList(stderr, num, *offspring, *statuslist); else __pmDumpNameList(stderr, num, *offspring); } else { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "%s\n", pmErrStr_r(num, errmsg, sizeof(errmsg))); } } #endif return num; } int pmGetChildren(const char *name, char ***offspring) { return pmGetChildrenStatus(name, offspring, NULL); } static int request_namebypmid(__pmContext *ctxp, pmID pmid) { int n; n = __pmSendIDList(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), 1, &pmid, 0); if (n < 0) n = __pmMapErrno(n); return n; } static int receive_namesbyid(__pmContext *ctxp, char ***namelist) { int n; __pmPDU *pb; int pinpdu; pinpdu = n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, ctxp->c_pmcd->pc_tout_sec, &pb); if (n == PDU_PMNS_NAMES) { int numnames; n = __pmDecodeNameList(pb, &numnames, namelist, NULL); if (n >= 0) n = numnames; } else if (n == PDU_ERROR) __pmDecodeError(pb, &n); else if (n != PM_ERR_TIMEOUT) n = PM_ERR_IPC; if (pinpdu > 0) __pmUnpinPDUBuf(pb); return n; } static int receive_a_name(__pmContext *ctxp, char **name) { int n; char **namelist; if ((n = receive_namesbyid(ctxp, &namelist)) >= 0) { char *newname = strdup(namelist[0]); free(namelist); if (newname == NULL) { n = -oserror(); } else { *name = newname; n = 0; } } return n; } int pmNameID(pmID pmid, char **name) { int pmns_location = GetLocation(); if (pmns_location < 0) return pmns_location; PM_INIT_LOCKS(); if (pmns_location == PMNS_LOCAL) { __pmnsNode *np; PM_LOCK(__pmLock_libpcp); for (np = curr_pmns->htab[pmid % curr_pmns->htabsize]; np != NULL; np = np->hash) { if (np->pmid == pmid) { int sts; if (pmid_domain(np->pmid) != DYNAMIC_PMID || pmid_item(np->pmid) != 0) sts = backname(np, name); else sts = PM_ERR_PMID; PM_UNLOCK(__pmLock_libpcp); return sts; } } PM_UNLOCK(__pmLock_libpcp); /* not found so far, try derived metrics ... */ return __dmgetname(pmid, name); } else { /* assume PMNS_REMOTE */ int n; __pmContext *ctxp; /* As we have PMNS_REMOTE there must be a current host context */ if ((n = pmWhichContext()) < 0 || (ctxp = __pmHandleToPtr(n)) == NULL) return PM_ERR_NOCONTEXT; PM_LOCK(ctxp->c_pmcd->pc_lock); if ((n = request_namebypmid(ctxp, pmid)) >= 0) { n = receive_a_name(ctxp, name); } PM_UNLOCK(ctxp->c_pmcd->pc_lock); PM_UNLOCK(ctxp->c_lock); if (n >= 0) return n; return __dmgetname(pmid, name); } } int pmNameAll(pmID pmid, char ***namelist) { int pmns_location = GetLocation(); char **tmp = NULL; int n = 0; int len = 0; char *sp; if (pmns_location < 0) return pmns_location; PM_INIT_LOCKS(); if (pmns_location == PMNS_LOCAL) { __pmnsNode *np; int sts = 0; int i; if (pmid_domain(pmid) == DYNAMIC_PMID && pmid_item(pmid) == 0) { /* * pmid is for the root of a dynamic subtree in the PMNS ... * there is no matching leaf name */ return PM_ERR_PMID; } PM_LOCK(__pmLock_libpcp); for (np = curr_pmns->htab[pmid % curr_pmns->htabsize]; np != NULL; np = np->hash) { if (np->pmid == pmid) { n++; if ((tmp = (char **)realloc(tmp, n * sizeof(tmp[0]))) == NULL) { sts = -oserror(); break; } if ((sts = backname(np, &tmp[n-1])) < 0) { /* error, ... free any partial allocations */ for (i = n-2; i >= 0; i--) free(tmp[i]); free(tmp); break; } len += strlen(tmp[n-1])+1; } } PM_UNLOCK(__pmLock_libpcp); if (sts < 0) return sts; if (n == 0) goto try_derive; len += n * sizeof(tmp[0]); if ((tmp = (char **)realloc(tmp, len)) == NULL) return -oserror(); sp = (char *)&tmp[n]; for (i = 0; i < n; i++) { strcpy(sp, tmp[i]); free(tmp[i]); tmp[i] = sp; sp += strlen(sp)+1; } *namelist = tmp; return n; } else { /* assume PMNS_REMOTE */ int n; __pmContext *ctxp; /* As we have PMNS_REMOTE there must be a current host context */ if ((n = pmWhichContext()) < 0 || (ctxp = __pmHandleToPtr(n)) == NULL) return PM_ERR_NOCONTEXT; PM_LOCK(ctxp->c_pmcd->pc_lock); if ((n = request_namebypmid (ctxp, pmid)) >= 0) { n = receive_namesbyid (ctxp, namelist); } PM_UNLOCK(ctxp->c_pmcd->pc_lock); PM_UNLOCK(ctxp->c_lock); if (n == 0) goto try_derive; return n; } try_derive: if ((tmp = (char **)malloc(sizeof(tmp[0]))) == NULL) return -oserror(); n = __dmgetname(pmid, tmp); if (n < 0) { free(tmp); return n; } len = sizeof(tmp[0]) + strlen(tmp[0])+1; if ((tmp = (char **)realloc(tmp, len)) == NULL) return -oserror(); sp = (char *)&tmp[1]; strcpy(sp, tmp[0]); free(tmp[0]); tmp[0] = sp; *namelist = tmp; return 1; } /* * generic depth-first recursive descent of the PMNS */ static int TraversePMNS_local(const char *name, void(*func)(const char *), void(*func_r)(const char *, void *), void *closure) { int sts = 0; int nchildren; char **enfants; if ((nchildren = pmGetChildren(name, &enfants)) < 0) { return nchildren; } else if (nchildren > 0) { int j; char *newname; for (j = 0; j < nchildren; j++) { newname = (char *)malloc(strlen(name) + 1 + strlen(enfants[j]) + 1); if (newname == NULL) { char errmsg[PM_MAXERRMSGLEN]; printf("pmTraversePMNS: malloc: %s\n", osstrerror_r(errmsg, sizeof(errmsg))); exit(1); } if (*name == '\0') strcpy(newname, enfants[j]); else { strcpy(newname, name); strcat(newname, "."); strcat(newname, enfants[j]); } sts = TraversePMNS_local(newname, func, func_r, closure); free(newname); if (sts < 0) break; } free(enfants); } else { /* leaf node, name is full name of a metric */ if (func_r == NULL) (*func)(name); else (*func_r)(name, closure); } return sts; } static int TraversePMNS(const char *name, void(*func)(const char *), void(*func_r)(const char *, void *), void *closure) { int pmns_location = GetLocation(); if (pmns_location < 0) return pmns_location; if (name == NULL) return PM_ERR_NAME; PM_INIT_LOCKS(); if (pmns_location == PMNS_LOCAL) { int sts; PM_LOCK(__pmLock_libpcp); sts = TraversePMNS_local(name, func, func_r, closure); PM_UNLOCK(__pmLock_libpcp); return sts; } else { int sts; __pmPDU *pb; __pmContext *ctxp; /* As we have PMNS_REMOTE there must be a current host context */ if ((sts = pmWhichContext()) < 0 || (ctxp = __pmHandleToPtr(sts)) == NULL) return PM_ERR_NOCONTEXT; PM_LOCK(ctxp->c_pmcd->pc_lock); sts = __pmSendTraversePMNSReq(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), name); if (sts < 0) { sts = __pmMapErrno(sts); PM_UNLOCK(ctxp->c_pmcd->pc_lock); PM_UNLOCK(ctxp->c_lock); return sts; } else { int numnames; int i; int xtra; char **namelist; int pinpdu; pinpdu = sts = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb); PM_UNLOCK(ctxp->c_pmcd->pc_lock); PM_UNLOCK(ctxp->c_lock); if (sts == PDU_PMNS_NAMES) { sts = __pmDecodeNameList(pb, &numnames, &namelist, NULL); if (sts > 0) { for (i=0; i 0) __pmUnpinPDUBuf(pb); return (sts == PM_ERR_TIMEOUT) ? sts : PM_ERR_IPC; } if (pinpdu > 0) __pmUnpinPDUBuf(pb); /* * add any derived metrics that have "name" as * their prefix */ xtra = __dmtraverse(name, &namelist); if (xtra > 0) { sts = 0; for (i=0; i 0 ? numnames : sts; } } } int pmTraversePMNS(const char *name, void(*func)(const char *)) { return TraversePMNS(name, func, NULL, NULL); } int pmTraversePMNS_r(const char *name, void(*func)(const char *, void *), void *closure) { return TraversePMNS(name, NULL, func, closure); } int pmTrimNameSpace(void) { int i; __pmContext *ctxp; __pmHashCtl *hcp; __pmHashNode *hp; int pmns_location = GetLocation(); if (pmns_location < 0) return pmns_location; else if (pmns_location == PMNS_REMOTE) return 0; /* for PMNS_LOCAL ... */ PM_INIT_LOCKS(); if ((ctxp = __pmHandleToPtr(pmWhichContext())) == NULL) return PM_ERR_NOCONTEXT; if (ctxp->c_type != PM_CONTEXT_ARCHIVE) { /* unset all of the marks */ PM_LOCK(__pmLock_libpcp); mark_all(curr_pmns, 0); PM_UNLOCK(__pmLock_libpcp); PM_UNLOCK(ctxp->c_lock); return 0; } /* Don't do any trimming for archives. * Exception: if an explicit load PMNS call was made. */ PM_LOCK(__pmLock_libpcp); if (havePmLoadCall) { /* * (1) set all of the marks, and * (2) clear the marks for those metrics defined in the archive */ mark_all(curr_pmns, 1); hcp = &ctxp->c_archctl->ac_log->l_hashpmid; for (i = 0; i < hcp->hsize; i++) { for (hp = hcp->hash[i]; hp != NULL; hp = hp->next) { mark_one(curr_pmns, (pmID)hp->key, 0); } } } PM_UNLOCK(__pmLock_libpcp); PM_UNLOCK(ctxp->c_lock); return 0; } void __pmDumpNameSpace(FILE *f, int verbosity) { int pmns_location = GetLocation(); if (pmns_location < 0) fprintf(f, "__pmDumpNameSpace: Unable to determine PMNS location\n"); else if (pmns_location == PMNS_REMOTE) fprintf(f, "__pmDumpNameSpace: Name Space is remote !\n"); PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); dumptree(f, 0, curr_pmns->root, verbosity); PM_UNLOCK(__pmLock_libpcp); } pcp-3.8.12ubuntu1/src/libpcp/src/p_lrequest.c0000664000000000000000000000475012272262501015766 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe note * * Unlike most of the other __pmSend*() routines, there is no wrapper * routine in libpcp for __pmSendLogRequest() so there is no place in * the library to enforce serialization between the sending of the * PDU in __pmSendLogRequest() and reading the result PDU. * * It is assumed that the caller of __pmSendLogRequest() either manages * this serialization or is single-threaded, which is true for * the only current user of this routine, pmlc(1). */ #include #include "pmapi.h" #include "impl.h" /* * PDU for general pmlogger notification (PDU_LOG_REQUEST) */ typedef struct { __pmPDUHdr hdr; int type; /* notification type */ } notify_t; int __pmSendLogRequest(int fd, int type) { notify_t *pp; int sts; if ((pp = (notify_t *)__pmFindPDUBuf(sizeof(notify_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(notify_t); pp->hdr.type = PDU_LOG_REQUEST; pp->hdr.from = FROM_ANON; /* context does not matter here */ pp->type = htonl(type); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) { int version = __pmVersionIPC(fd); fprintf(stderr, "_pmSendRequest: sending PDU (type=%d, version=%d)\n", pp->type, version==UNKNOWN_VERSION? LOG_PDU_VERSION : version); } #endif sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmDecodeLogRequest(const __pmPDU *pdubuf, int *type) { const notify_t *pp; const char *pduend; pp = (const notify_t *)pdubuf; pduend = (const char *)pdubuf + pp->hdr.len; if (pduend - (char*)pp < sizeof(notify_t)) return PM_ERR_IPC; *type = ntohl(pp->type); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) { int version = __pmLastVersionIPC(); fprintf(stderr, "__pmDecodeLogRequest: got PDU (type=%d, version=%d)\n", *type, version==UNKNOWN_VERSION? LOG_PDU_VERSION : version); } #endif return 0; } pcp-3.8.12ubuntu1/src/libpcp/src/accounts.c0000664000000000000000000002747312272262501015431 0ustar /* * Copyright (c) 2012-2013 Red Hat. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include "pmapi.h" #include "impl.h" #include "internal.h" #if defined(HAVE_PWD_H) #include #endif #if defined(HAVE_GRP_H) #include #endif int __pmEqualUserIDs(__pmUserID uid1, __pmUserID uid2) { return uid1 == uid2; } int __pmEqualGroupIDs(__pmGroupID gid1, __pmGroupID gid2) { return gid1 == gid2; } int __pmValidUserID(__pmUserID uid) { return uid >= 0; } int __pmValidGroupID(__pmGroupID gid) { return gid >= 0; } void __pmUserIDFromString(const char *userid, __pmUserID *uid) { *uid = atoi(userid); } void __pmGroupIDFromString(const char *groupid, __pmGroupID *gid) { *gid = atoi(groupid); } char * __pmUserIDToString(__pmUserID uid, char *buf, size_t size) { snprintf(buf, size, "%u", (unsigned int)uid); buf[size-1] = '\0'; return buf; } char * __pmGroupIDToString(__pmGroupID gid, char *buf, size_t size) { snprintf(buf, size, "%u", (unsigned int)gid); buf[size-1] = '\0'; return buf; } #if defined(HAVE_GETGRGID_R) char * __pmGroupnameFromID(gid_t gid, char *buf, size_t size) { char namebuf[1024]; struct group grp, *result; getgrgid_r(gid, &grp, namebuf, sizeof(namebuf), &result); snprintf(buf, size, "%s", result ? result->gr_name : "unknown"); buf[size-1] = '\0'; return buf; } #elif defined(HAVE_GETGRGID) char * __pmGroupnameFromID(gid_t gid, char *buf, size_t size) { struct group *result; result = getgrgid(gid); snprintf(buf, size, "%s", result ? result->gr_name : "unknown"); buf[size-1] = '\0'; return buf; } #else !bozo! #endif #if defined(HAVE_GETPWUID_R) char * __pmUsernameFromID(uid_t uid, char *buf, size_t size) { char namebuf[1024]; struct passwd pwd, *result; getpwuid_r(uid, &pwd, namebuf, sizeof(namebuf), &result); snprintf(buf, size, "%s", result ? result->pw_name : "unknown"); buf[size-1] = '\0'; return buf; } #elif defined(HAVE_GETPWUID) char * __pmUsernameFromID(uid_t uid, char *buf, size_t size) { struct passwd *result; result = getpwuid(uid); snprintf(buf, size, "%s", result ? result->pw_name : "unknown"); buf[size-1] = '\0'; return buf; } #else !bozo! #endif #if defined(HAVE_GETPWNAM_R) int __pmUsernameToID(const char *name, uid_t *uid) { char namebuf[1024]; struct passwd pwd, *result = NULL; getpwnam_r(name, &pwd, namebuf, sizeof(namebuf), &result); if (!result) return -ENOENT; *uid = result->pw_uid; return 0; } #elif defined(HAVE_GETPWNAM) int __pmUsernameToID(const char *name, uid_t *uid) { struct passwd *result; result = getpwnam(name); if (!result) return -ENOENT; *uid = result->pw_uid; return 0; } #else !bozo! #endif #if defined(HAVE_GETGRNAM_R) int __pmGroupnameToID(const char *name, gid_t *gid) { char namebuf[512]; struct group grp, *result = NULL; getgrnam_r(name, &grp, namebuf, sizeof(namebuf), &result); if (result == NULL) return -ENOENT; *gid = result->gr_gid; return 0; } #elif defined(HAVE_GETGRNAM) int __pmGroupnameToID(const char *name, gid_t *gid) { struct group *result; result = getgrnam(name); if (result == NULL) return -ENOENT; *gid = result->gr_gid; return 0; } #else !bozo! #endif /* * Add a group ID into a group list, if it is not there already. * The current group ID list and size are passed in, updated if * changed, and passed back out. */ static int __pmAddGroupID(gid_t gid, gid_t **gidlist, unsigned int *count) { gid_t *gids = *gidlist; size_t need; unsigned int i, total = *count; for (i = 0; i < total; i++) if (gids[i] == gid) return 0; /* already in the list, we're done */ need = (total + 1) * sizeof(gid_t); if ((gids = (gid_t *)realloc(gids, need)) == NULL) return -ENOMEM; gids[total++] = gid; *gidlist = gids; *count = total; return 0; } #if defined(HAVE_GETPWNAM_R) && defined(HAVE_GETGRENT_R) int __pmUsersGroupIDs(const char *username, gid_t **groupids, unsigned int *ngroups) { int i, sts; unsigned int count = 0; char grbuf[1024]; gid_t *gidlist = NULL; struct passwd pwd, *result = NULL; struct group gr, *grp; getpwnam_r(username, &pwd, grbuf, sizeof(grbuf), &result); if (!result) return -ENOENT; /* add the primary group in right away, before supplementary groups */ if ((sts = __pmAddGroupID(result->pw_gid, &gidlist, &count)) < 0) return sts; /* search for groups in which the given user is a member */ setgrent(); while (1) { grp = NULL; #ifdef IS_SOLARIS if ((grp = getgrent_r(&gr, grbuf, sizeof(grbuf))) == NULL) break; #else if (getgrent_r(&gr, grbuf, sizeof(grbuf), &grp) != 0 || grp == NULL) break; #endif for (i = 0; grp->gr_mem[i]; i++) { if (strcmp(username, grp->gr_mem[i]) != 0) continue; if ((sts = __pmAddGroupID(grp->gr_gid, &gidlist, &count)) < 0) { endgrent(); return sts; } break; } } endgrent(); *groupids = gidlist; *ngroups = count; return 0; } #elif defined(HAVE_GETPWNAM) && defined(HAVE_GETGRENT) int __pmUsersGroupIDs(const char *username, gid_t **groupids, unsigned int *ngroups) { int i, sts; unsigned int count = 0; gid_t *gidlist = NULL; struct passwd *result; struct group *grp; result = getpwnam(username); if (!result) return -ENOENT; /* add the primary group in right away, before supplementary groups */ if ((sts = __pmAddGroupID(result->pw_gid, &gidlist, &count)) < 0) return sts; /* search for groups in which the given user is a member */ setgrent(); while (1) { grp = NULL; if ((grp = getgrent()) == NULL) break; for (i = 0; grp->gr_mem[i]; i++) { if (strcmp(username, grp->gr_mem[i]) != 0) continue; if ((sts = __pmAddGroupID(grp->gr_gid, &gidlist, &count)) < 0) { endgrent(); return sts; } break; } } endgrent(); *groupids = gidlist; *ngroups = count; return 0; } #else !bozo! #endif /* * Add a user ID into a user list, if it is not there already. * The current user ID list and size are passed in, updated if * changed, and passed back out. */ static int __pmAddUserID(uid_t uid, uid_t **uidlist, unsigned int *count) { uid_t *uids = *uidlist; size_t need; unsigned int i, total = *count; for (i = 0; i < total; i++) if (uids[i] == uid) return 0; /* already in the list, we're done */ need = (total + 1) * sizeof(uid_t); if ((uids = (uid_t *)realloc(uids, need)) == NULL) return -ENOMEM; uids[total++] = uid; *uidlist = uids; *count = total; return 0; } #if defined(HAVE_GETGRNAM_R) && defined(HAVE_GETPWENT_R) int __pmGroupsUserIDs(const char *groupname, uid_t **userids, unsigned int *nusers) { int sts; uid_t *uidlist = NULL; gid_t groupid; char grbuf[1024]; char buf[512]; char **names = NULL; struct group gr, *grp = NULL; struct passwd pw, *pwp; unsigned int i, count = 0; /* for a given group name, find gid and user names */ getgrnam_r(groupname, &gr, grbuf, sizeof(grbuf), &grp); if (grp == NULL) return -EINVAL; groupid = grp->gr_gid; names = grp->gr_mem; /* supplementaries */ /* for a given list of usernames, lookup the user IDs */ setpwent(); while (1) { #ifdef IS_SOLARIS if ((pwp = getpwent_r(&pw, buf, sizeof(buf))) == NULL) break; #else pwp = NULL; if (getpwent_r(&pw, buf, sizeof(buf), &pwp) != 0 || pwp == NULL) break; #endif /* check to see if this user has given group as primary */ if (pwp->pw_gid == groupid && (sts = __pmAddUserID(pwp->pw_uid, &uidlist, &count)) < 0) { endpwent(); return sts; } /* check to see if this user is listed in groups file */ for (i = 0; names[i]; i++) { if (strcmp(pwp->pw_name, names[i]) == 0) { if ((sts = __pmAddUserID(pwp->pw_uid, &uidlist, &count)) < 0) { endpwent(); return sts; } break; } } } endpwent(); *userids = uidlist; *nusers = count; return 0; } #elif defined(HAVE_GETGRNAM) && defined(HAVE_GETPWENT) int __pmGroupsUserIDs(const char *name, uid_t **userids, unsigned int *nusers) { int sts; uid_t *uidlist = NULL; gid_t groupid; char **names = NULL; struct group *grp = NULL; struct passwd *pwp; unsigned int i, count = 0; /* for a given group name, find gid and user names */ if ((grp = getgrnam(name)) == NULL) return -EINVAL; groupid = grp->gr_gid; names = grp->gr_mem; setpwent(); while (1) { if ((pwp = getpwent()) == NULL) break; /* check to see if this user has given group as primary */ if (pwp->pw_gid == groupid && (sts = __pmAddUserID(pwp->pw_uid, &uidlist, &count)) < 0) { endpwent(); return sts; } for (i = 0; names[i]; i++) { if (strcmp(pwp->pw_name, names[i]) == 0) { if ((sts = __pmAddUserID(pwp->pw_uid, &uidlist, &count)) < 0) { endpwent(); return sts; } break; } } } endpwent(); *userids = uidlist; *nusers = count; return 0; } #else !bozo! #endif #if defined(HAVE_GETPWNAM_R) int __pmGetUserIdentity(const char *username, uid_t *uid, gid_t *gid, int mode) { int sts; char buf[4096]; struct passwd pwd, *pw; sts = getpwnam_r(username, &pwd, buf, sizeof(buf), &pw); if (pw == NULL) { __pmNotifyErr(LOG_CRIT, "cannot find the %s user to switch to\n", username); if (mode == PM_FATAL_ERR) exit(1); return -ENOENT; } else if (sts != 0) { __pmNotifyErr(LOG_CRIT, "getpwnam_r(%s) failed: %s\n", username, pmErrStr_r(sts, buf, sizeof(buf))); if (mode == PM_FATAL_ERR) exit(1); return -ENOENT; } *uid = pwd.pw_uid; *gid = pwd.pw_gid; return 0; } #elif defined(HAVE_GETPWNAM) int __pmGetUserIdentity(const char *username, uid_t *uid, gid_t *gid, int mode) { int sts; char errmsg[128]; struct passwd *pw; setoserror(0); if ((pw = getpwnam(username)) == 0) { __pmNotifyErr(LOG_CRIT, "cannot find the %s user to switch to\n", username); if (mode == PM_FATAL_ERR) exit(1); return -ENOENT; } else if (oserror() != 0) { __pmNotifyErr(LOG_CRIT, "getpwnam(%s) failed: %s\n", username, pmErrStr_r(oserror(), errmsg, sizeof(errmsg))); if (mode == PM_FATAL_ERR) exit(1); return -ENOENT; } *uid = pw->pw_uid; *gid = pw->pw_gid; return 0; } #else !bozo! #endif int __pmSetProcessIdentity(const char *username) { gid_t gid; uid_t uid; char msg[256]; __pmGetUserIdentity(username, &uid, &gid, PM_FATAL_ERR); if (setgid(gid) < 0) { __pmNotifyErr(LOG_CRIT, "setgid to gid of %s user (gid=%d): %s", username, gid, osstrerror_r(msg, sizeof(msg))); exit(1); } /* * We must allow initgroups to fail with EPERM, as this * is the behaviour when the parent process has already * dropped privileges (e.g. pmcd receives SIGHUP). */ if (initgroups(username, gid) < 0 && oserror() != EPERM) { __pmNotifyErr(LOG_CRIT, "initgroups with gid of %s user (gid=%d): %s", username, gid, osstrerror_r(msg, sizeof(msg))); exit(1); } if (setuid(uid) < 0) { __pmNotifyErr(LOG_CRIT, "setuid to uid of %s user (uid=%d): %s", username, uid, osstrerror_r(msg, sizeof(msg))); exit(1); } return 0; } int __pmGetUsername(char **username) { char *user = pmGetConfig("PCP_USER"); if (user && user[0] != '\0') { *username = user; return 1; } *username = "pcp"; return 0; } pcp-3.8.12ubuntu1/src/libpcp/src/help.c0000664000000000000000000000621212272262501014526 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "internal.h" static int lookuptext(int ident, int type, char **buffer) { int n; __pmContext *ctxp; __pmDSO *dp; if ((n = pmWhichContext()) >= 0) { int ctx = n; ctxp = __pmHandleToPtr(ctx); if (ctxp == NULL) return PM_ERR_NOCONTEXT; if (ctxp->c_type == PM_CONTEXT_HOST) { PM_LOCK(ctxp->c_pmcd->pc_lock); again: n = __pmSendTextReq(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), ident, type); if (n < 0) n = __pmMapErrno(n); else { __pmPDU *pb; int pinpdu; pinpdu = n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, ctxp->c_pmcd->pc_tout_sec, &pb); if (n == PDU_TEXT) { int x_ident; n = __pmDecodeText(pb, &x_ident, buffer); } else if (n == PDU_ERROR) __pmDecodeError(pb, &n); else if (n != PM_ERR_TIMEOUT) n = PM_ERR_IPC; if (pinpdu > 0) __pmUnpinPDUBuf(pb); /* * Note: __pmDecodeText does not swab ident because it * does not know whether it's a pmID or a pmInDom. */ if (n == 0 && (*buffer)[0] == '\0' && (type & PM_TEXT_HELP)) { /* fall back to one-line, if possible */ free(*buffer); type &= ~PM_TEXT_HELP; type |= PM_TEXT_ONELINE; goto again; } } PM_UNLOCK(ctxp->c_pmcd->pc_lock); } else if (ctxp->c_type == PM_CONTEXT_LOCAL) { if (PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) /* Local context requires single-threaded applications */ n = PM_ERR_THREAD; else if ((dp = __pmLookupDSO(((__pmID_int *)&ident)->domain)) == NULL) n = PM_ERR_NOAGENT; else { again_local: if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; n = dp->dispatch.version.any.text(ident, type, buffer, dp->dispatch.version.any.ext); if (n == 0 && (*buffer)[0] == '\0' && (type & PM_TEXT_HELP)) { /* fall back to one-line, if possible */ type &= ~PM_TEXT_HELP; type |= PM_TEXT_ONELINE; goto again_local; } if (n == 0) { /* * PMDAs don't malloc the buffer but the caller will * free it, so malloc and copy */ *buffer = strdup(*buffer); } } } else { /* assume PM_CONTEXT_ARCHIVE -- this is an error */ n = PM_ERR_NOTHOST; } PM_UNLOCK(ctxp->c_lock); } return n; } int pmLookupText(pmID pmid, int level, char **buffer) { return lookuptext((int)pmid, level | PM_TEXT_PMID, buffer); } int pmLookupInDomText(pmInDom indom, int level, char **buffer) { return lookuptext((int)indom, level | PM_TEXT_INDOM, buffer); } pcp-3.8.12ubuntu1/src/libpcp/src/tz.c0000664000000000000000000003035512272262501014240 0ustar /* * Copyright (c) 1995-2003,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe notes * * These routines manipulate the environment and call lots of routines * like localtime(), asctime(), gmtime(), getenv(), putenv() ... all of * which are not thread-safe. * * We use the big lock to prevent concurrent execution. * * Need to call PM_INIT_LOCKS() in all the exposed routines because we * may be called before a context has been created, and missed the * lock initialization in pmNewContext(). */ #include "pmapi.h" #include "impl.h" static char *envtz; /* buffer in env */ static int envtzlen; static char *savetz; /* real $TZ from env */ static char **savetzp; static int nzone; /* table of zones */ static int curzone = -1; static char **zone; #if !defined(HAVE_UNDERBAR_ENVIRON) #define _environ environ #endif extern char **_environ; static void _pushTZ(void) { char **p; savetzp = NULL; for (p = _environ; *p != NULL; p++) { if (strncmp(*p, "TZ=", 3) == 0) { savetz = *p; *p = envtz; savetzp = p; break; } } if (*p == NULL) putenv(envtz); tzset(); } static void _popTZ(void) { if (savetzp != NULL) *savetzp = savetz; else putenv("TZ="); tzset(); } /* * Construct TZ=... subject to the constraint that the length of the * timezone part is not more than PM_TZ_MAXLEN bytes * Assumes TZ= is in the start of tzbuffer and this is not touched. * And finally set TZ in the environment. */ static void __pmSquashTZ(char *tzbuffer) { time_t now = time(NULL); struct tm *t; char *tzn; #ifndef IS_MINGW time_t offset; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); tzset(); t = localtime(&now); #ifdef HAVE_ALTZONE offset = (t->tm_isdst > 0) ? altzone : timezone; #elif defined HAVE_STRFTIME_z { char tzoffset[6]; /* +1200\0 */ strftime (tzoffset, sizeof (tzoffset), "%z", t); offset = -strtol (tzoffset, NULL, 10); offset = ((offset/100) * 3600) + ((offset%100) * 60); } #else { struct tm *gmt = gmtime(&now); offset = (gmt->tm_hour - t->tm_hour) * 3600 + (gmt->tm_min - t->tm_min) * 60; } #endif tzn = tzname[(t->tm_isdst > 0)]; if (offset != 0) { int hours = offset / 3600; int mins = abs ((offset % 3600) / 60); int len = (int) strlen(tzn); if (mins == 0) { /* -3 for +HH in worst case */ if (len > PM_TZ_MAXLEN-3) len = PM_TZ_MAXLEN-3; snprintf(tzbuffer+3, PM_TZ_MAXLEN, "%*.*s%+d", len, len, tzn, hours); } else { /* -6 for +HH:MM in worst case */ if (len > PM_TZ_MAXLEN-6) len = PM_TZ_MAXLEN-6; snprintf(tzbuffer+3, PM_TZ_MAXLEN, "%*.*s%+d:%02d", len, len, tzn, hours, mins); } } else { strncpy(tzbuffer+3, tzn, PM_TZ_MAXLEN); tzbuffer[PM_TZ_MAXLEN+4-1] = '\0'; } putenv(tzbuffer); PM_UNLOCK(__pmLock_libpcp); return; #else /* IS_MINGW */ /* * Use the native Win32 API to extract the timezone. This is * a Windows timezone, we want the POSIX style but there's no * API, really. What we've found works, is the same approach * the MSYS dll takes - we set TZ their way (below) and then * use tzset, then extract. Note that the %Z and %z strftime * parameters do not contain abbreviated names/offsets (they * both contain Windows timezone, and both are the same with * no TZ). Note also that putting the Windows name into the * environment as TZ does not do anything good (see the tzset * MSDN docs). */ #define is_upper(c) ((unsigned)(c) - 'A' <= 26) TIME_ZONE_INFORMATION tz; static const char wildabbr[] = "GMT"; char tzbuf[256], tzoff[64]; char *cp, *dst, *off; wchar_t *src; div_t d; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); GetTimeZoneInformation(&tz); dst = cp = tzbuf; off = tzoff; for (src = tz.StandardName; *src; src++) if (is_upper(*src)) *dst++ = *src; if (cp == dst) { /* In Asian Windows, tz.StandardName may not contain the timezone name. */ strcpy(cp, wildabbr); cp += strlen(wildabbr); } else cp = dst; d = div(tz.Bias+tz.StandardBias, 60); sprintf(cp, "%d", d.quot); sprintf(off, "%d", d.quot); if (d.rem) { sprintf(cp=strchr(cp, 0), ":%d", abs(d.rem)); sprintf(off=strchr(off, 0), ":%d", abs(d.rem)); } if (tz.StandardDate.wMonth) { cp = strchr(cp, 0); dst = cp; for (src = tz.DaylightName; *src; src++) if (is_upper(*src)) *dst++ = *src; if (cp == dst) { /* In Asian Windows, tz.StandardName may not contain the daylight name. */ strcpy(tzbuf, wildabbr); cp += strlen(wildabbr); } else cp = dst; d = div(tz.Bias+tz.DaylightBias, 60); sprintf(cp, "%d", d.quot); if (d.rem) sprintf(cp=strchr(cp, 0), ":%d", abs(d.rem)); cp = strchr(cp, 0); sprintf(cp=strchr(cp, 0), ",M%d.%d.%d/%d", tz.DaylightDate.wMonth, tz.DaylightDate.wDay, tz.DaylightDate.wDayOfWeek, tz.DaylightDate.wHour); if (tz.DaylightDate.wMinute || tz.DaylightDate.wSecond) sprintf(cp=strchr(cp, 0), ":%d", tz.DaylightDate.wMinute); if (tz.DaylightDate.wSecond) sprintf(cp=strchr(cp, 0), ":%d", tz.DaylightDate.wSecond); cp = strchr(cp, 0); sprintf(cp=strchr(cp, 0), ",M%d.%d.%d/%d", tz.StandardDate.wMonth, tz.StandardDate.wDay, tz.StandardDate.wDayOfWeek, tz.StandardDate.wHour); if (tz.StandardDate.wMinute || tz.StandardDate.wSecond) sprintf(cp=strchr(cp, 0), ":%d", tz.StandardDate.wMinute); if (tz.StandardDate.wSecond) sprintf(cp=strchr(cp, 0), ":%d", tz.StandardDate.wSecond); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_TIMECONTROL) fprintf(stderr, "Win32 TZ=%s\n", tzbuf); #endif snprintf(tzbuffer+3, PM_TZ_MAXLEN, "%s", tzbuf); putenv(tzbuffer); tzset(); t = localtime(&now); tzn = tzname[(t->tm_isdst > 0)]; snprintf(tzbuffer+3, PM_TZ_MAXLEN, "%s%s", tzn, tzoff); putenv(tzbuffer); PM_UNLOCK(__pmLock_libpcp); return; #endif } /* * __pmTimezone: work out local timezone */ char * __pmTimezone(void) { static char *tzbuffer = NULL; char *tz; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); tz = getenv("TZ"); if (tzbuffer == NULL) { /* * size is PM_TZ_MAXLEN + length of "TZ=" + null byte terminator */ tzbuffer = (char *)malloc(PM_TZ_MAXLEN+4); if (tzbuffer == NULL) { /* not much we can do here ... */ PM_UNLOCK(__pmLock_libpcp); return NULL; } strcpy(tzbuffer, "TZ="); } if (tz == NULL || tz[0] == ':') { /* NO TZ in the environment - invent one. If TZ starts with a colon, * it's an Olson-style TZ and it does not supported on all IRIXes, so * squash it into a simple one (pv#788431). */ __pmSquashTZ(tzbuffer); tz = &tzbuffer[3]; } else if (strlen(tz) > PM_TZ_MAXLEN) { /* TZ is too long to fit into the internal PCP timezone structs * let's try to sqash it a bit */ char *tb; if ((tb = strdup(tz)) == NULL) { /* sorry state of affairs, go squash w/out copying buffer */ __pmSquashTZ(tzbuffer); tz = &tzbuffer[3]; } else { char *ptz = tz; char *zeros; char *end = tb; while ((zeros = strstr(ptz, ":00")) != NULL) { strncpy(end, ptz, zeros-ptz); end += zeros-ptz; *end = '\0'; ptz = zeros+3; } if (strlen(tb) > PM_TZ_MAXLEN) { /* Still too long - let's pretend it's Olson */ __pmSquashTZ(tzbuffer); tz = &tzbuffer[3]; } else { strcpy(tzbuffer+3, tb); putenv(tzbuffer); tz = tzbuffer+3; } free(tb); } } PM_UNLOCK(__pmLock_libpcp); return tz; } /* * buffer should be at least PM_TZ_MAXLEN bytes long */ char * __pmTimezone_r(char *buf, int buflen) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); strcpy(buf, __pmTimezone()); PM_UNLOCK(__pmLock_libpcp); return buf; } int pmUseZone(const int tz_handle) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (tz_handle < 0 || tz_handle >= nzone) { PM_UNLOCK(__pmLock_libpcp); return -1; } curzone = tz_handle; strcpy(&envtz[3], zone[curzone]); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmUseZone(%d) tz=%s\n", curzone, zone[curzone]); #endif PM_UNLOCK(__pmLock_libpcp); return 0; } int pmNewZone(const char *tz) { int len; int hack = 0; int sts; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); len = (int)strlen(tz); if (len == 3) { /* * things like TZ=GMT may be broken in libc, particularly * in _ltzset() of time_comm.c, where changes to TZ are * sometimes not properly reflected. * TZ=GMT+0 avoids the problem. */ len += 2; hack = 1; } if (len+4 > envtzlen) { /* expand buffer for env */ if (envtz != NULL) free(envtz); envtzlen = len+4; envtz = (char *)malloc(envtzlen); strcpy(envtz, "TZ="); } strcpy(&envtz[3], tz); if (hack) /* see above */ strcpy(&envtz[6], "+0"); curzone = nzone++; zone = (char **)realloc(zone, nzone * sizeof(char *)); if (zone == NULL) { __pmNoMem("pmNewZone", nzone * sizeof(char *), PM_FATAL_ERR); } zone[curzone] = strdup(&envtz[3]); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "pmNewZone(%s) -> %d\n", zone[curzone], curzone); #endif sts = curzone; PM_UNLOCK(__pmLock_libpcp); return sts; } int pmNewContextZone(void) { __pmContext *ctxp; int sts; if ((ctxp = __pmHandleToPtr(pmWhichContext())) == NULL) return PM_ERR_NOCONTEXT; if (ctxp->c_type == PM_CONTEXT_ARCHIVE) { sts = pmNewZone(ctxp->c_archctl->ac_log->l_label.ill_tz); PM_UNLOCK(ctxp->c_lock); } else if (ctxp->c_type == PM_CONTEXT_LOCAL) { char tzbuf[PM_TZ_MAXLEN]; /* from env, not PMCD */ PM_UNLOCK(ctxp->c_lock); __pmTimezone_r(tzbuf, sizeof(tzbuf)); sts = pmNewZone(tzbuf); } else { /* assume PM_CONTEXT_HOST */ char *name = "pmcd.timezone"; pmID pmid; pmResult *rp; PM_UNLOCK(ctxp->c_lock); if ((sts = pmLookupName(1, &name, &pmid)) < 0) return sts; if ((sts = pmFetch(1, &pmid, &rp)) >= 0) { if (rp->vset[0]->numval == 1 && (rp->vset[0]->valfmt == PM_VAL_DPTR || rp->vset[0]->valfmt == PM_VAL_SPTR)) sts = pmNewZone((char *)rp->vset[0]->vlist[0].value.pval->vbuf); else sts = PM_ERR_VALUE; pmFreeResult(rp); } } return sts; } char * pmCtime(const time_t *clock, char *buf) { #if !defined(IS_SOLARIS) && !defined(IS_MINGW) struct tm tbuf; #endif PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (curzone >= 0) { _pushTZ(); #if defined(IS_SOLARIS) || defined(IS_MINGW) strcpy(buf, asctime(localtime(clock))); #else asctime_r(localtime_r(clock, &tbuf), buf); #endif _popTZ(); } else { #if defined(IS_SOLARIS) || defined(IS_MINGW) strcpy(buf, asctime(localtime(clock))); #else asctime_r(localtime_r(clock, &tbuf), buf); #endif } PM_UNLOCK(__pmLock_libpcp); return buf; } struct tm * pmLocaltime(const time_t *clock, struct tm *result) { #if defined(IS_SOLARIS) || defined(IS_MINGW) struct tm *tmp; #endif PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (curzone >= 0) { _pushTZ(); #if defined(IS_SOLARIS) || defined(IS_MINGW) tmp = localtime(clock); memcpy(result, tmp, sizeof(*result)); #else localtime_r(clock, result); #endif _popTZ(); } else { #if defined(IS_SOLARIS) || defined(IS_MINGW) tmp = localtime(clock); memcpy(result, tmp, sizeof(*result)); #else localtime_r(clock, result); #endif } PM_UNLOCK(__pmLock_libpcp); return result; } time_t __pmMktime(struct tm *timeptr) { time_t ans; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (curzone >= 0) { _pushTZ(); ans = mktime(timeptr); _popTZ(); } else ans = mktime(timeptr); PM_UNLOCK(__pmLock_libpcp); return ans; } int pmWhichZone(char **tz) { int sts; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (curzone >= 0) *tz = zone[curzone]; sts = curzone; PM_UNLOCK(__pmLock_libpcp); return sts; } pcp-3.8.12ubuntu1/src/libpcp/src/units.c0000664000000000000000000006074112272262501014747 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include #if defined(HAVE_MATH_H) #include #endif #if !defined(ABS) #define ABS(a) ((a) < 0 ? -(a) : (a)) #endif #if defined(HAVE_CONST_LONGLONG) #define SIGN_64_MASK 0x8000000000000000LL #else #define SIGN_64_MASK 0x8000000000000000 #endif /* * pmAtomValue -> string, max length is 80 bytes * * To avoid alignment problems, avp _must_ be aligned appropriately * for a pmAtomValue pointer by the caller. */ char * pmAtomStr_r(const pmAtomValue *avp, int type, char *buf, int buflen) { int i; int vlen; char strbuf[40]; switch (type) { case PM_TYPE_32: snprintf(buf, buflen, "%d", avp->l); break; case PM_TYPE_U32: snprintf(buf, buflen, "%u", avp->ul); break; case PM_TYPE_64: snprintf(buf, buflen, "%"PRIi64, avp->ll); break; case PM_TYPE_U64: snprintf(buf, buflen, "%"PRIu64, avp->ull); break; case PM_TYPE_FLOAT: snprintf(buf, buflen, "%e", (double)avp->f); break; case PM_TYPE_DOUBLE: snprintf(buf, buflen, "%e", avp->d); break; case PM_TYPE_STRING: if (avp->cp == NULL) snprintf(buf, buflen, ""); else { i = (int)strlen(avp->cp); if (i < 38) snprintf(buf, buflen, "\"%s\"", avp->cp); else snprintf(buf, buflen, "\"%34.34s...\"", avp->cp); } break; case PM_TYPE_AGGREGATE: case PM_TYPE_AGGREGATE_STATIC: if (avp->vbp == NULL) { snprintf(buf, buflen, ""); break; } vlen = avp->vbp->vlen - PM_VAL_HDR_SIZE; if (vlen == 0) snprintf(buf, buflen, "[type=%s len=%d]", pmTypeStr_r(avp->vbp->vtype, strbuf, sizeof(strbuf)), vlen); else { char *cp; char *bp; snprintf(buf, buflen, "[type=%s len=%d]", pmTypeStr_r(avp->vbp->vtype, strbuf, sizeof(strbuf)), vlen); cp = (char *)avp->vbp->vbuf; for (i = 0; i < vlen && i < 12; i++) { bp = &buf[strlen(buf)]; if ((i % 4) == 0) snprintf(bp, sizeof(buf) - (bp-buf), " %02x", *cp & 0xff); else snprintf(bp, sizeof(buf) - (bp-buf), "%02x", *cp & 0xff); cp++; } if (vlen > 12) { bp = &buf[strlen(buf)]; snprintf(bp, sizeof(buf) - (bp-buf), " ..."); } } break; case PM_TYPE_EVENT: { /* have to assume alignment is OK in this case */ pmEventArray *eap = (pmEventArray *)avp->vbp; if (eap->ea_nrecords == 1) snprintf(buf, buflen, "[1 event record]"); else snprintf(buf, buflen, "[%d event records]", eap->ea_nrecords); } break; default: snprintf(buf, buflen, "Error: unexpected type: %s", pmTypeStr_r(type, strbuf, sizeof(strbuf))); } return buf; } /* * To avoid alignment problems, avp _must_ be aligned appropriately * for a pmAtomValue pointer by the caller. */ const char * pmAtomStr(const pmAtomValue *avp, int type) { static char abuf[80]; pmAtomStr_r(avp, type, abuf, sizeof(abuf)); return abuf; } /* * must be in agreement with ordinal values for PM_TYPE_* #defines */ static const char *typename[] = { "32", "U32", "64", "U64", "FLOAT", "DOUBLE", "STRING", "AGGREGATE", "AGGREGATE_STATIC", "EVENT" }; /* PM_TYPE_* -> string, max length is 20 bytes */ char * pmTypeStr_r(int type, char *buf, int buflen) { if (type >= 0 && type < sizeof(typename)/sizeof(typename[0])) snprintf(buf, buflen, "%s", typename[type]); else if (type == PM_TYPE_NOSUPPORT) snprintf(buf, buflen, "%s", "Not Supported"); else if (type == PM_TYPE_UNKNOWN) snprintf(buf, buflen, "%s", "Unknown"); else snprintf(buf, buflen, "Illegal type=%d", type); return buf; } const char * pmTypeStr(int type) { static char tbuf[20]; pmTypeStr_r(type, tbuf, sizeof(tbuf)); return tbuf; } /* scale+units -> string, max length is 60 bytes */ char * pmUnitsStr_r(const pmUnits *pu, char *buf, int buflen) { char *spacestr = NULL; char *timestr = NULL; char *countstr = NULL; char *p; char sbuf[20]; char tbuf[20]; char cbuf[20]; buf[0] = '\0'; if (pu->dimSpace) { switch (pu->scaleSpace) { case PM_SPACE_BYTE: spacestr = "byte"; break; case PM_SPACE_KBYTE: spacestr = "Kbyte"; break; case PM_SPACE_MBYTE: spacestr = "Mbyte"; break; case PM_SPACE_GBYTE: spacestr = "Gbyte"; break; case PM_SPACE_TBYTE: spacestr = "Tbyte"; break; case PM_SPACE_PBYTE: spacestr = "Pbyte"; break; case PM_SPACE_EBYTE: spacestr = "Ebyte"; break; default: snprintf(sbuf, sizeof(sbuf), "space-%d", pu->scaleSpace); spacestr = sbuf; break; } } if (pu->dimTime) { switch (pu->scaleTime) { case PM_TIME_NSEC: timestr = "nanosec"; break; case PM_TIME_USEC: timestr = "microsec"; break; case PM_TIME_MSEC: timestr = "millisec"; break; case PM_TIME_SEC: timestr = "sec"; break; case PM_TIME_MIN: timestr = "min"; break; case PM_TIME_HOUR: timestr = "hour"; break; default: snprintf(tbuf, sizeof(tbuf), "time-%d", pu->scaleTime); timestr = tbuf; break; } } if (pu->dimCount) { switch (pu->scaleCount) { case 0: countstr = "count"; break; case 1: snprintf(cbuf, sizeof(cbuf), "count x 10"); countstr = cbuf; break; default: snprintf(cbuf, sizeof(cbuf), "count x 10^%d", pu->scaleCount); countstr = cbuf; break; } } p = buf; if (pu->dimSpace > 0) { if (pu->dimSpace == 1) snprintf(p, buflen, "%s", spacestr); else snprintf(p, buflen, "%s^%d", spacestr, pu->dimSpace); while (*p) p++; *p++ = ' '; } if (pu->dimTime > 0) { if (pu->dimTime == 1) snprintf(p, buflen - (p - buf), "%s", timestr); else snprintf(p, buflen - (p - buf), "%s^%d", timestr, pu->dimTime); while (*p) p++; *p++ = ' '; } if (pu->dimCount > 0) { if (pu->dimCount == 1) snprintf(p, buflen - (p - buf), "%s", countstr); else snprintf(p, buflen - (p - buf), "%s^%d", countstr, pu->dimCount); while (*p) p++; *p++ = ' '; } if (pu->dimSpace < 0 || pu->dimTime < 0 || pu->dimCount < 0) { *p++ = '/'; *p++ = ' '; if (pu->dimSpace < 0) { if (pu->dimSpace == -1) snprintf(p, buflen - (p - buf), "%s", spacestr); else snprintf(p, buflen - (p - buf), "%s^%d", spacestr, -pu->dimSpace); while (*p) p++; *p++ = ' '; } if (pu->dimTime < 0) { if (pu->dimTime == -1) snprintf(p, buflen - (p - buf), "%s", timestr); else snprintf(p, buflen - (p - buf), "%s^%d", timestr, -pu->dimTime); while (*p) p++; *p++ = ' '; } if (pu->dimCount < 0) { if (pu->dimCount == -1) snprintf(p, buflen - (p - buf), "%s", countstr); else snprintf(p, buflen - (p - buf), "%s^%d", countstr, -pu->dimCount); while (*p) p++; *p++ = ' '; } } if (buf[0] == '\0') { /* * dimension is all 0, but scale maybe specified ... small * anomaly here as we would expect dimCount to be 1 not * 0 for these cases, but support maintained for historical * behaviour */ if (pu->scaleCount == 1) snprintf(buf, buflen, "x 10"); else if (pu->scaleCount != 0) snprintf(buf, buflen, "x 10^%d", pu->scaleCount); } else { p--; *p = '\0'; } return buf; } const char * pmUnitsStr(const pmUnits *pu) { static char ubuf[60]; pmUnitsStr_r(pu, ubuf, sizeof(ubuf)); return ubuf; } /* Scale conversion, based on value format, value type and scale */ int pmConvScale(int type, const pmAtomValue *ival, const pmUnits *iunit, pmAtomValue *oval, const pmUnits *ounit) { int sts; int k; __int64_t div, mult; __int64_t d, m; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_VALUE) { char strbuf[80]; fprintf(stderr, "pmConvScale: %s", pmAtomStr_r(ival, type, strbuf, sizeof(strbuf))); fprintf(stderr, " [%s]", pmUnitsStr_r(iunit, strbuf, sizeof(strbuf))); } #endif if (iunit->dimSpace != ounit->dimSpace || iunit->dimTime != ounit->dimTime || iunit->dimCount != ounit->dimCount) { sts = PM_ERR_CONV; goto bad; } div = mult = 1; if (iunit->dimSpace) { d = 1; m = 1; switch (iunit->scaleSpace) { case PM_SPACE_BYTE: d = 1024 * 1024; break; case PM_SPACE_KBYTE: d = 1024; break; case PM_SPACE_MBYTE: /* the canonical unit */ break; case PM_SPACE_GBYTE: m = 1024; break; case PM_SPACE_TBYTE: m = 1024 * 1024; break; case PM_SPACE_PBYTE: m = 1024 * 1024 * 1024; break; case PM_SPACE_EBYTE: m = (__int64_t)1024 * 1024 * 1024 * 1024; break; default: sts = PM_ERR_UNIT; goto bad; } switch (ounit->scaleSpace) { case PM_SPACE_BYTE: m *= 1024 * 1024; break; case PM_SPACE_KBYTE: m *= 1024; break; case PM_SPACE_MBYTE: /* the canonical unit */ break; case PM_SPACE_GBYTE: d *= 1024; break; case PM_SPACE_TBYTE: d *= 1024 * 1024; break; case PM_SPACE_PBYTE: d *= 1024 * 1024 * 1024; break; case PM_SPACE_EBYTE: d *= (__int64_t)1024 * 1024 * 1024 * 1024; break; default: sts = PM_ERR_UNIT; goto bad; } if (iunit->dimSpace > 0) { for (k = 0; k < iunit->dimSpace; k++) { div *= d; mult *= m; } } else { for (k = iunit->dimSpace; k < 0; k++) { mult *= d; div *= m; } } } if (iunit->dimTime) { d = 1; m = 1; switch (iunit->scaleTime) { case PM_TIME_NSEC: d = 1000000000; break; case PM_TIME_USEC: d = 1000000; break; case PM_TIME_MSEC: d = 1000; break; case PM_TIME_SEC: /* the canonical unit */ break; case PM_TIME_MIN: m = 60; break; case PM_TIME_HOUR: m = 3600; break; default: sts = PM_ERR_UNIT; goto bad; } switch (ounit->scaleTime) { case PM_TIME_NSEC: m *= 1000000000; break; case PM_TIME_USEC: m *= 1000000; break; case PM_TIME_MSEC: m *= 1000; break; case PM_TIME_SEC: /* the canonical unit */ break; case PM_TIME_MIN: d *= 60; break; case PM_TIME_HOUR: d *= 3600; break; default: sts = PM_ERR_UNIT; goto bad; } if (iunit->dimTime > 0) { for (k = 0; k < iunit->dimTime; k++) { div *= d; mult *= m; } } else { for (k = iunit->dimTime; k < 0; k++) { mult *= d; div *= m; } } } if (iunit->dimCount || (iunit->dimSpace == 0 && iunit->dimTime == 0)) { d = 1; m = 1; if (iunit->scaleCount < 0) { for (k = iunit->scaleCount; k < 0; k++) d *= 10; } else if (iunit->scaleCount > 0) { for (k = 0; k < iunit->scaleCount; k++) m *= 10; } if (ounit->scaleCount < 0) { for (k = ounit->scaleCount; k < 0; k++) m *= 10; } else if (ounit->scaleCount > 0) { for (k = 0; k < ounit->scaleCount; k++) d *= 10; } if (iunit->dimCount > 0) { for (k = 0; k < iunit->dimCount; k++) { div *= d; mult *= m; } } else if (iunit->dimCount < 0) { for (k = iunit->dimCount; k < 0; k++) { mult *= d; div *= m; } } else { mult = m; div = d; } } if (mult % div == 0) { mult /= div; div = 1; } switch (type) { case PM_TYPE_32: oval->l = (__int32_t)((ival->l * mult + div/2) / div); break; case PM_TYPE_U32: oval->ul = (__uint32_t)((ival->ul * mult + div/2) / div); break; case PM_TYPE_64: oval->ll = (ival->ll * mult + div/2) / div; break; case PM_TYPE_U64: oval->ull = (ival->ull * mult + div/2) / div; break; case PM_TYPE_FLOAT: oval->f = ival->f * ((float)mult / (float)div); break; case PM_TYPE_DOUBLE: oval->d = ival->d * ((double)mult / (double)div); break; default: sts = PM_ERR_CONV; goto bad; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_VALUE) { char strbuf[80]; fprintf(stderr, " -> %s", pmAtomStr_r(oval, type, strbuf, sizeof(strbuf))); fprintf(stderr, " [%s]\n", pmUnitsStr_r(ounit, strbuf, sizeof(strbuf))); } #endif return 0; bad: #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_VALUE) { char strbuf[60]; char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, " -> Error: %s", pmErrStr_r(sts, errmsg, sizeof(errmsg))); fprintf(stderr, " [%s]\n", pmUnitsStr_r(ounit, strbuf, sizeof(strbuf))); } #endif return sts; } /* Value extract from pmValue and type conversion */ int pmExtractValue(int valfmt, const pmValue *ival, int itype, pmAtomValue *oval, int otype) { void *avp; pmAtomValue av; int sts = 0; int len; const char *vp; char buf[80]; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_VALUE) { fprintf(stderr, "pmExtractValue: "); vp = "???"; } #endif oval->ll = 0; if (valfmt == PM_VAL_INSITU) { av.l = ival->value.lval; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_VALUE) { char strbuf[80]; vp = pmAtomStr_r(&av, itype, strbuf, sizeof(strbuf)); } #endif switch (itype) { case PM_TYPE_32: case PM_TYPE_UNKNOWN: switch (otype) { case PM_TYPE_32: oval->l = av.l; break; case PM_TYPE_U32: if (av.l < 0) sts = PM_ERR_SIGN; else oval->ul = (__uint32_t)av.l; break; case PM_TYPE_64: oval->ll = (__int64_t)av.l; break; case PM_TYPE_U64: if (av.l < 0) sts = PM_ERR_SIGN; else oval->ull = (__uint64_t)av.l; break; case PM_TYPE_FLOAT: oval->f = (float)av.l; break; case PM_TYPE_DOUBLE: oval->d = (double)av.l; break; default: sts = PM_ERR_CONV; } break; case PM_TYPE_U32: switch (otype) { case PM_TYPE_32: if (av.ul > 0x7fffffff) sts = PM_ERR_TRUNC; else oval->l = (__int32_t)av.ul; break; case PM_TYPE_U32: oval->ul = (__uint32_t)av.ul; break; case PM_TYPE_64: oval->ll = (__int64_t)av.ul; break; case PM_TYPE_U64: oval->ull = (__uint64_t)av.ul; break; case PM_TYPE_FLOAT: oval->f = (float)av.ul; break; case PM_TYPE_DOUBLE: oval->d = (double)av.ul; break; default: sts = PM_ERR_CONV; } break; /* * Notes on conversion to FLOAT ... because of the limited * precision of the mantissa, more than one integer value * maps to the same floating point value ... hence the * >= (float)max-int-value style of tests */ case PM_TYPE_FLOAT: /* old style insitu encoding */ switch (otype) { case PM_TYPE_32: if ((float)ABS(av.f) >= (float)0x7fffffff) sts = PM_ERR_TRUNC; else oval->l = (__int32_t)av.f; break; case PM_TYPE_U32: if (av.f >= (float)((unsigned)0xffffffff)) sts = PM_ERR_TRUNC; else if (av.f < 0) sts = PM_ERR_SIGN; else oval->ul = (__uint32_t)av.f; break; case PM_TYPE_64: #if defined(HAVE_CONST_LONGLONG) if (av.f >= (float)0x7fffffffffffffffLL) sts = PM_ERR_TRUNC; #else if (av.f >= (float)0x7fffffffffffffff) sts = PM_ERR_TRUNC; #endif else oval->ll = (__int64_t)av.f; break; case PM_TYPE_U64: #if defined(HAVE_CONST_LONGLONG) if (av.f >= (float)((__uint64_t)0xffffffffffffffffLL)) sts = PM_ERR_TRUNC; #else if (av.f >= (float)((__uint64_t)0xffffffffffffffff)) sts = PM_ERR_TRUNC; #endif else if (av.f < 0) sts = PM_ERR_SIGN; else oval->ull = (__uint64_t)av.f; break; case PM_TYPE_FLOAT: oval->f = av.f; break; case PM_TYPE_DOUBLE: oval->d = (double)av.f; break; default: sts = PM_ERR_CONV; } break; case PM_TYPE_64: case PM_TYPE_U64: case PM_TYPE_DOUBLE: case PM_TYPE_STRING: case PM_TYPE_AGGREGATE: case PM_TYPE_EVENT: default: sts = PM_ERR_CONV; } } else if (valfmt == PM_VAL_DPTR || valfmt == PM_VAL_SPTR) { __int64_t src; __uint64_t usrc; double dsrc; float fsrc; switch (itype) { case PM_TYPE_64: if (ival->value.pval->vlen != PM_VAL_HDR_SIZE + sizeof(__int64_t) || (ival->value.pval->vtype != PM_TYPE_64 && ival->value.pval->vtype != 0)) { sts = PM_ERR_CONV; break; } avp = (void *)&ival->value.pval->vbuf; memcpy((void *)&av.ll, avp, sizeof(av.ll)); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_VALUE) { char strbuf[80]; vp = pmAtomStr_r(&av, itype, strbuf, sizeof(strbuf)); } #endif src = av.ll; switch (otype) { case PM_TYPE_32: if (src > 0x7fffffff) sts = PM_ERR_TRUNC; else oval->l = (__int32_t)src; break; case PM_TYPE_U32: if (src > (unsigned)0xffffffff) sts = PM_ERR_TRUNC; else if (src < 0) sts = PM_ERR_SIGN; else oval->ul = (__uint32_t)src; break; case PM_TYPE_64: oval->ll = src; break; case PM_TYPE_U64: if (src < 0) sts = PM_ERR_SIGN; else oval->ull = (__uint64_t)src; break; case PM_TYPE_FLOAT: oval->f = (float)src; break; case PM_TYPE_DOUBLE: oval->d = (double)src; break; default: sts = PM_ERR_CONV; } break; case PM_TYPE_U64: if (ival->value.pval->vlen != PM_VAL_HDR_SIZE + sizeof(__uint64_t) || (ival->value.pval->vtype != PM_TYPE_U64 && ival->value.pval->vtype != 0)) { sts = PM_ERR_CONV; break; } avp = (void *)&ival->value.pval->vbuf; memcpy((void *)&av.ull, avp, sizeof(av.ull)); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_VALUE) { char strbuf[80]; vp = pmAtomStr_r(&av, itype, strbuf, sizeof(strbuf)); } #endif usrc = av.ull; switch (otype) { case PM_TYPE_32: if (usrc > 0x7fffffff) sts = PM_ERR_TRUNC; else oval->l = (__int32_t)usrc; break; case PM_TYPE_U32: if (usrc > (unsigned)0xffffffff) sts = PM_ERR_TRUNC; else oval->ul = (__uint32_t)usrc; break; case PM_TYPE_64: #if defined(HAVE_CONST_LONGLONG) if (usrc > (__int64_t)0x7fffffffffffffffLL) sts = PM_ERR_TRUNC; #else if (usrc > (__int64_t)0x7fffffffffffffff) sts = PM_ERR_TRUNC; #endif else oval->ll = (__int64_t)usrc; break; case PM_TYPE_U64: oval->ull = usrc; break; case PM_TYPE_FLOAT: #if !defined(HAVE_CAST_U64_DOUBLE) if (SIGN_64_MASK & usrc) oval->f = (float)(__int64_t)(usrc & (~SIGN_64_MASK)) + (__uint64_t)SIGN_64_MASK; else oval->f = (float)(__int64_t)usrc; #else oval->f = (float)usrc; #endif break; case PM_TYPE_DOUBLE: #if !defined(HAVE_CAST_U64_DOUBLE) if (SIGN_64_MASK & usrc) oval->d = (double)(__int64_t)(usrc & (~SIGN_64_MASK)) + (__uint64_t)SIGN_64_MASK; else oval->d = (double)(__int64_t)usrc; #else oval->d = (double)usrc; #endif break; default: sts = PM_ERR_CONV; } break; case PM_TYPE_DOUBLE: if (ival->value.pval->vlen != PM_VAL_HDR_SIZE + sizeof(double) || (ival->value.pval->vtype != PM_TYPE_DOUBLE && ival->value.pval->vtype != 0)) { sts = PM_ERR_CONV; break; } avp = (void *)&ival->value.pval->vbuf; memcpy((void *)&av.d, avp, sizeof(av.d)); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_VALUE) { char strbuf[80]; vp = pmAtomStr_r(&av, itype, strbuf, sizeof(strbuf)); } #endif dsrc = av.d; switch (otype) { case PM_TYPE_32: if (ABS(dsrc) >= (double)0x7fffffff) sts = PM_ERR_TRUNC; else oval->l = (__int32_t)dsrc; break; case PM_TYPE_U32: if (dsrc >= (double)((unsigned)0xffffffff)) sts = PM_ERR_TRUNC; else if (dsrc < 0) sts = PM_ERR_SIGN; else oval->ul = (__uint32_t)dsrc; break; case PM_TYPE_64: #if defined(HAVE_CONST_LONGLONG) if (dsrc >= (double)0x7fffffffffffffffLL) sts = PM_ERR_TRUNC; #else if (dsrc >= (double)0x7fffffffffffffff) sts = PM_ERR_TRUNC; #endif else oval->ll = (__int64_t)dsrc; break; case PM_TYPE_U64: #if defined(HAVE_CONST_LONGLONG) if (dsrc >= (double)((__uint64_t)0xffffffffffffffffLL)) sts = PM_ERR_TRUNC; #else if (dsrc >= (double)((__uint64_t)0xffffffffffffffff)) sts = PM_ERR_TRUNC; #endif else if (dsrc < 0) sts = PM_ERR_SIGN; else oval->ull = (__uint64_t)dsrc; break; case PM_TYPE_FLOAT: oval->f = (float)dsrc; break; case PM_TYPE_DOUBLE: oval->d = dsrc; break; default: sts = PM_ERR_CONV; } break; case PM_TYPE_FLOAT: /* new style pmValueBlock encoding */ if (ival->value.pval->vlen != PM_VAL_HDR_SIZE + sizeof(float) || (ival->value.pval->vtype != PM_TYPE_FLOAT && ival->value.pval->vtype != 0)) { sts = PM_ERR_CONV; break; } avp = (void *)&ival->value.pval->vbuf; memcpy((void *)&av.f, avp, sizeof(av.f)); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_VALUE) { char strbuf[80]; vp = pmAtomStr_r(&av, itype, strbuf, sizeof(strbuf)); } #endif fsrc = av.f; switch (otype) { case PM_TYPE_32: if ((float)ABS(fsrc) >= (float)0x7fffffff) sts = PM_ERR_TRUNC; else oval->l = (__int32_t)fsrc; break; case PM_TYPE_U32: if (fsrc >= (float)((unsigned)0xffffffff)) sts = PM_ERR_TRUNC; else if (fsrc < 0) sts = PM_ERR_SIGN; else oval->ul = (__uint32_t)fsrc; break; case PM_TYPE_64: #if defined(HAVE_CONST_LONGLONG) if (fsrc >= (float)0x7fffffffffffffffLL) sts = PM_ERR_TRUNC; #else if (fsrc >= (float)0x7fffffffffffffff) sts = PM_ERR_TRUNC; #endif else oval->ll = (__int64_t)fsrc; break; case PM_TYPE_U64: #if defined(HAVE_CONST_LONGLONG) if (fsrc >= (float)((__uint64_t)0xffffffffffffffffLL)) sts = PM_ERR_TRUNC; #else if (fsrc >= (float)((__uint64_t)0xffffffffffffffff)) sts = PM_ERR_TRUNC; #endif else if (fsrc < 0) sts = PM_ERR_SIGN; else oval->ull = (__uint64_t)fsrc; break; case PM_TYPE_FLOAT: oval->f = fsrc; break; case PM_TYPE_DOUBLE: oval->d = (float)fsrc; break; default: sts = PM_ERR_CONV; } break; case PM_TYPE_STRING: if (ival->value.pval->vtype != PM_TYPE_STRING && ival->value.pval->vtype != 0) { sts = PM_ERR_CONV; break; } len = ival->value.pval->vlen - PM_VAL_HDR_SIZE; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_VALUE) { if (ival->value.pval->vbuf[0] == '\0') vp = ""; else { int i; i = (int)strlen(ival->value.pval->vbuf); if (i < 38) snprintf(buf, sizeof(buf), "\"%s\"", ival->value.pval->vbuf); else snprintf(buf, sizeof(buf), "\"%34.34s...\"", ival->value.pval->vbuf); vp = buf; } } #endif if (otype != PM_TYPE_STRING) { sts = PM_ERR_CONV; break; } if ((oval->cp = (char *)malloc(len + 1)) == NULL) { __pmNoMem("pmExtractValue.string", len + 1, PM_FATAL_ERR); } memcpy(oval->cp, ival->value.pval->vbuf, len); oval->cp[len] = '\0'; break; case PM_TYPE_AGGREGATE: if (ival->value.pval->vtype != PM_TYPE_AGGREGATE && ival->value.pval->vtype != 0) { sts = PM_ERR_CONV; break; } len = ival->value.pval->vlen; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_VALUE) { int vlen; int i; vlen = ival->value.pval->vlen - PM_VAL_HDR_SIZE; if (vlen == 0) snprintf(buf, sizeof(buf), "[len=%d]", vlen); else { char *cp; char *bp; snprintf(buf, sizeof(buf), "[len=%d]", vlen); cp = (char *)ival->value.pval->vbuf; for (i = 0; i < vlen && i < 12; i++) { bp = &buf[strlen(buf)]; if ((i % 4) == 0) snprintf(bp, sizeof(buf) - (bp-buf), " %02x", *cp & 0xff); else snprintf(bp, sizeof(buf) - (bp-buf), "%02x", *cp & 0xff); cp++; } if (vlen > 12) { bp = &buf[strlen(buf)]; snprintf(bp, sizeof(buf) - (bp-buf), " ..."); } } vp = buf; } #endif if (otype != PM_TYPE_AGGREGATE) { sts = PM_ERR_CONV; break; } if ((oval->vbp = (pmValueBlock *)malloc(len)) == NULL) { __pmNoMem("pmExtractValue.aggr", len, PM_FATAL_ERR); } memcpy(oval->vbp, ival->value.pval, len); break; case PM_TYPE_32: case PM_TYPE_U32: case PM_TYPE_EVENT: default: sts = PM_ERR_CONV; } } else sts = PM_ERR_CONV; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_VALUE) { char strbuf[80]; char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, " %s", vp); fprintf(stderr, " [%s]", pmTypeStr_r(itype, strbuf, sizeof(strbuf))); if (sts == 0) fprintf(stderr, " -> %s", pmAtomStr_r(oval, otype, strbuf, sizeof(strbuf))); else fprintf(stderr, " -> Error: %s", pmErrStr_r(sts, errmsg, sizeof(errmsg))); fprintf(stderr, " [%s]\n", pmTypeStr_r(otype, strbuf, sizeof(strbuf))); } #endif return sts; } pcp-3.8.12ubuntu1/src/libpcp/src/p_result.c0000664000000000000000000003726712272262501015451 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2000 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe note * * Because __pmFindPDUBuf() returns with a pinned pdu buffer, the * buffer passed back from __pmEncodeResult() must also remain pinned * (otherwise another thread could clobber the buffer after returning * from __pmEncodeResult()) ... it is the caller of __pmEncodeResult() * who is responsible for (a) not pinning the buffer again, and (b) * ensuring _someone_ will unpin the buffer when it is safe to do so. * * Similarly, __pmDecodeResult() accepts a pinned buffer and returns * a pmResult that (on 64-bit pointer platforms) may contain pointers * into a second underlying pinned buffer. The input buffer remains * pinned, the second buffer will be pinned if it is used. The caller * will typically call pmFreeResult(), but also needs to call * __pmUnpinPDUBuf() for the input PDU buffer. When the result contains * pointers back into the input PDU buffer, this will be pinned _twice_ * so the pmFreeResult() and __pmUnpinPDUBuf() calls will still be * required. */ #include #include "pmapi.h" #include "impl.h" #include "internal.h" /* * PDU for pmResult (PDU_RESULT) */ typedef struct { pmID pmid; int numval; /* no. of vlist els to follow, or error */ int valfmt; /* insitu or pointer */ __pmValue_PDU vlist[1]; /* zero or more */ } vlist_t; typedef struct { __pmPDUHdr hdr; __pmTimeval timestamp; /* when returned */ int numpmid; /* no. of PMIDs to follow */ __pmPDU data[1]; /* zero or more */ } result_t; int __pmEncodeResult(int targetfd, const pmResult *result, __pmPDU **pdubuf) { int i; int j; size_t need; /* bytes for the PDU */ size_t vneed; /* additional bytes for the pmValueBlocks on the end */ __pmPDU *_pdubuf; __pmPDU *vbp; result_t *pp; vlist_t *vlp; /* to start with, need space for result_t with no data (__pmPDU) */ need = sizeof(result_t) - sizeof(__pmPDU); vneed = 0; /* now add space for each vlist_t (data in result_t) */ for (i = 0; i < result->numpmid; i++) { pmValueSet *vsp = result->vset[i]; /* need space for PMID and count of values (defer valfmt until * we know numval > 0, which means there should be a valfmt) */ need += sizeof(pmID) + sizeof(int); for (j = 0; j < vsp->numval; j++) { /* plus value, instance pair */ need += sizeof(__pmValue_PDU); if (vsp->valfmt != PM_VAL_INSITU) { /* plus pmValueBlock */ vneed += PM_PDU_SIZE_BYTES(vsp->vlist[j].value.pval->vlen); } } if (j) /* optional value format, if any values present */ need += sizeof(int); } if ((_pdubuf = __pmFindPDUBuf((int)(need+vneed))) == NULL) return -oserror(); pp = (result_t *)_pdubuf; pp->hdr.len = (int)(need+vneed); pp->hdr.type = PDU_RESULT; pp->timestamp.tv_sec = htonl((__int32_t)(result->timestamp.tv_sec)); pp->timestamp.tv_usec = htonl((__int32_t)(result->timestamp.tv_usec)); pp->numpmid = htonl(result->numpmid); vlp = (vlist_t *)pp->data; /* * Note: vbp, and hence offset in sent PDU is in units of __pmPDU */ vbp = _pdubuf + need/sizeof(__pmPDU); for (i = 0; i < result->numpmid; i++) { pmValueSet *vsp = result->vset[i]; vlp->pmid = __htonpmID(vsp->pmid); if (vsp->numval > 0) vlp->valfmt = htonl(vsp->valfmt); for (j = 0; j < vsp->numval; j++) { vlp->vlist[j].inst = htonl(vsp->vlist[j].inst); if (vsp->valfmt == PM_VAL_INSITU) vlp->vlist[j].value.lval = htonl(vsp->vlist[j].value.lval); else { /* * pmValueBlocks are harder! * -- need to copy the len field (len) + len bytes (vbuf) */ int nb; nb = vsp->vlist[j].value.pval->vlen; memcpy((void *)vbp, (void *)vsp->vlist[j].value.pval, nb); #ifdef PCP_DEBUG if ((nb % sizeof(__pmPDU)) != 0) { /* for Purify */ int pad; char *padp = (char *)vbp + nb; for (pad = sizeof(__pmPDU) - 1; pad >= (nb % sizeof(__pmPDU)); pad--) *padp++ = '~'; /* buffer end */ } #endif __htonpmValueBlock((pmValueBlock *)vbp); /* point to the value block at the end of the PDU */ vlp->vlist[j].value.lval = htonl((int)(vbp - _pdubuf)); vbp += PM_PDU_SIZE(nb); } } vlp->numval = htonl(vsp->numval); if (j > 0) vlp = (vlist_t *)((__psint_t)vlp + sizeof(*vlp) + (j-1)*sizeof(vlp->vlist[0])); else vlp = (vlist_t *)((__psint_t)vlp + sizeof(vlp->pmid) + sizeof(vlp->numval)); } *pdubuf = _pdubuf; /* Note _pdubuf remains pinned ... see thread-safe comments above */ return 0; } int __pmSendResult(int fd, int from, const pmResult *result) { int sts; __pmPDU *pdubuf; result_t *pp; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) __pmDumpResult(stderr, result); #endif if ((sts = __pmEncodeResult(fd, result, &pdubuf)) < 0) return sts; pp = (result_t *)pdubuf; pp->hdr.from = from; sts = __pmXmitPDU(fd, pdubuf); __pmUnpinPDUBuf(pdubuf); return sts; } /* * enter here with pdubuf already pinned ... result may point into * _another_ pdu buffer that is pinned on exit */ int __pmDecodeResult(__pmPDU *pdubuf, pmResult **result) { int numpmid; /* number of metrics */ int i; /* range of metrics */ int j; /* range over values */ int index; int vsize; /* size of vlist_t's in PDU buffer */ char *pduend; /* end pointer for incoming buffer */ char *vsplit; /* vlist/valueblock division point */ result_t *pp; vlist_t *vlp; pmResult *pr; #if defined(HAVE_64BIT_PTR) char *newbuf; int valfmt; int numval; int need; /* * Note: all sizes are in units of bytes ... beware that pp->data is in * units of __pmPDU */ int nvsize; /* size of pmValue's after decode */ int offset; /* differences in sizes */ int vbsize; /* size of pmValueBlocks */ pmValueSet *nvsp; #elif defined(HAVE_32BIT_PTR) pmValueSet *vsp; /* vlist_t == pmValueSet */ #else Bozo - unexpected sizeof pointer!! #endif pp = (result_t *)pdubuf; pduend = (char *)pdubuf + pp->hdr.len; if (pduend - (char *)pdubuf < sizeof(result_t) - sizeof(__pmPDU)) return PM_ERR_IPC; numpmid = ntohl(pp->numpmid); if (numpmid < 0 || numpmid > pp->hdr.len) return PM_ERR_IPC; if (numpmid >= (INT_MAX - sizeof(pmResult)) / sizeof(pmValueSet *)) return PM_ERR_IPC; if ((pr = (pmResult *)malloc(sizeof(pmResult) + (numpmid - 1) * sizeof(pmValueSet *))) == NULL) { return -oserror(); } pr->numpmid = numpmid; pr->timestamp.tv_sec = ntohl(pp->timestamp.tv_sec); pr->timestamp.tv_usec = ntohl(pp->timestamp.tv_usec); #if defined(HAVE_64BIT_PTR) vsplit = pduend; /* smallest observed value block pointer */ nvsize = vsize = vbsize = 0; for (i = 0; i < numpmid; i++) { vlp = (vlist_t *)&pp->data[vsize/sizeof(__pmPDU)]; if (sizeof(*vlp) - sizeof(vlp->vlist) - sizeof(int) > (pduend - (char *)vlp)) goto corrupt; vsize += sizeof(vlp->pmid) + sizeof(vlp->numval); nvsize += sizeof(pmValueSet); numval = ntohl(vlp->numval); valfmt = ntohl(vlp->valfmt); #ifdef DESPERATE { pmID pmid = __ntohpmID(vlp->pmid); char strbuf[20]; fprintf(stderr, "vlist[%d] pmid: %s numval: %d", i, pmIDStr_r(pmid, strbuf, sizeof(strbuf)), numval); } #endif /* numval may be negative - it holds an error code in that case */ if (numval > pp->hdr.len) goto corrupt; if (numval > 0) { if (sizeof(*vlp) - sizeof(vlp->vlist) > (pduend - (char *)vlp)) goto corrupt; if (numval >= (INT_MAX - sizeof(*vlp)) / sizeof(__pmValue_PDU)) goto corrupt; vsize += sizeof(vlp->valfmt) + numval * sizeof(__pmValue_PDU); nvsize += (numval - 1) * sizeof(pmValue); #ifdef DESPERATE fprintf(stderr, " valfmt: %s", valfmt == PM_VAL_INSITU ? "insitu" : "ptr"); #endif if (valfmt != PM_VAL_INSITU) { for (j = 0; j < numval; j++) { __pmValue_PDU *pduvp; pmValueBlock *pduvbp; pduvp = &vlp->vlist[j]; if (sizeof(__pmValue_PDU) > (size_t)(pduend - (char *)pduvp)) goto corrupt; index = ntohl(pduvp->value.lval); if (index < 0 || index > pp->hdr.len) goto corrupt; pduvbp = (pmValueBlock *)&pdubuf[index]; if (vsplit > (char *)pduvbp) vsplit = (char *)pduvbp; if (sizeof(unsigned int) > (size_t)(pduend - (char *)pduvbp)) goto corrupt; __ntohpmValueBlock(pduvbp); if (pduvbp->vlen < PM_VAL_HDR_SIZE || pduvbp->vlen > pp->hdr.len) goto corrupt; if (pduvbp->vlen > (size_t)(pduend - (char *)pduvbp)) goto corrupt; vbsize += PM_PDU_SIZE_BYTES(pduvbp->vlen); #ifdef DESPERATE fprintf(stderr, " len: %d type: %d", pduvbp->vlen - PM_VAL_HDR_SIZE, pduvbp->vtype); #endif } } } #ifdef DESPERATE fputc('\n', stderr); #endif } #ifdef DESPERATE fprintf(stderr, "vsize: %d nvsize: %d vbsize: %d\n", vsize, nvsize, vbsize); #endif need = nvsize + vbsize; offset = sizeof(result_t) - sizeof(__pmPDU) + vsize; if (need < 0 || vsize > INT_MAX / sizeof(__pmPDU) || vbsize > INT_MAX / sizeof(pmValueBlock) || offset != pp->hdr.len - (pduend - vsplit) || offset + vbsize != pduend - (char *)pdubuf) goto corrupt; /* the original pdubuf is already pinned so we won't allocate that again */ if ((newbuf = (char *)__pmFindPDUBuf(need)) == NULL) { free(pr); return -oserror(); } /* * At this point, we have verified the contents of the incoming PDU and * the following is set up ... * * From the original PDU buffer ... * :-----:---------:-----------:----------------:---------------------: * : Hdr : timestamp : numpmid : ... vlists ... : .. pmValueBlocks .. : * :-----:---------:-----------:----------------:---------------------: * <--- vsize ---> <---- vbsize ----> * bytes bytes * * and in the new PDU buffer we are going to build ... * :---------------------:---------------------: * : ... pmValueSets ... : .. pmValueBlocks .. : * :---------------------:---------------------: * <--- nvsize ---> <---- vbsize ----> * bytes bytes */ if (vbsize) { /* pmValueBlocks (if any) are copied across "as is" */ index = vsize / sizeof(__pmPDU); memcpy((void *)&newbuf[nvsize], (void *)&pp->data[index], vbsize); } /* * offset is a bit tricky ... _add_ the expansion due to the * different sizes of the vlist_t and pmValueSet, and _subtract_ * the PDU header and pmResult fields ... */ offset = nvsize - vsize - (int)sizeof(pp->hdr) - (int)sizeof(pp->timestamp) - (int)sizeof(pp->numpmid); nvsize = vsize = 0; for (i = 0; i < numpmid; i++) { vlp = (vlist_t *)&pp->data[vsize/sizeof(__pmPDU)]; nvsp = (pmValueSet *)&newbuf[nvsize]; pr->vset[i] = nvsp; nvsp->pmid = __ntohpmID(vlp->pmid); nvsp->numval = ntohl(vlp->numval); #ifdef DESPERATE { char strbuf[20]; fprintf(stderr, "new vlist[%d] pmid: %s numval: %d", i, pmIDStr_r(nvsp->pmid, strbuf, sizeof(strbuf)), nvsp->numval); } #endif vsize += sizeof(nvsp->pmid) + sizeof(nvsp->numval); nvsize += sizeof(pmValueSet); if (nvsp->numval > 0) { nvsp->valfmt = ntohl(vlp->valfmt); #ifdef DESPERATE fprintf(stderr, " valfmt: %s", nvsp->valfmt == PM_VAL_INSITU ? "insitu" : "ptr"); #endif vsize += sizeof(nvsp->valfmt) + nvsp->numval * sizeof(__pmValue_PDU); nvsize += (nvsp->numval - 1) * sizeof(pmValue); for (j = 0; j < nvsp->numval; j++) { __pmValue_PDU *vp = &vlp->vlist[j]; pmValue *nvp = &nvsp->vlist[j]; nvp->inst = ntohl(vp->inst); if (nvsp->valfmt == PM_VAL_INSITU) { nvp->value.lval = ntohl(vp->value.lval); #ifdef DESPERATE fprintf(stderr, " value: %d", nvp->value.lval); #endif } else { /* * in the input PDU buffer, pval is an index to the * start of the pmValueBlock, in units of __pmPDU */ index = sizeof(__pmPDU) * ntohl(vp->value.pval) + offset; nvp->value.pval = (pmValueBlock *)&newbuf[index]; #ifdef DESPERATE { int k, len; len = nvp->value.pval->vlen - PM_VAL_HDR_SIZE; fprintf(stderr, " len: %d type: %dvalue: 0x", len, nvp->value.pval->vtype; for (k = 0; k < len; k++) fprintf(stderr, "%02x", nvp->value.pval->vbuf[k]); } #endif } } } #ifdef DESPERATE fputc('\n', stderr); #endif } if (numpmid == 0) __pmUnpinPDUBuf(newbuf); #elif defined(HAVE_32BIT_PTR) pr->timestamp.tv_sec = ntohl(pp->timestamp.tv_sec); pr->timestamp.tv_usec = ntohl(pp->timestamp.tv_usec); vlp = (vlist_t *)pp->data; vsplit = pduend; vsize = 0; /* * Now fix up any pointers in pmValueBlocks (currently offsets into * the PDU buffer) by adding the base address of the PDU buffer. */ for (i = 0; i < numpmid; i++) { if (sizeof(*vlp) - sizeof(vlp->vlist) - sizeof(int) > (pduend - (char *)vlp)) goto corrupt; vsp = pr->vset[i] = (pmValueSet *)vlp; vsp->pmid = __ntohpmID(vsp->pmid); vsp->numval = ntohl(vsp->numval); /* numval may be negative - it holds an error code in that case */ if (vsp->numval > pp->hdr.len) goto corrupt; vsize += sizeof(vsp->pmid) + sizeof(vsp->numval); if (vsp->numval > 0) { if (sizeof(*vlp) - sizeof(vlp->vlist) > (pduend - (char *)vlp)) goto corrupt; if (vsp->numval >= (INT_MAX - sizeof(*vlp)) / sizeof(__pmValue_PDU)) goto corrupt; vsp->valfmt = ntohl(vsp->valfmt); vsize += sizeof(vsp->valfmt) + vsp->numval * sizeof(__pmValue_PDU); for (j = 0; j < vsp->numval; j++) { __pmValue_PDU *pduvp; pmValueBlock *pduvbp; pduvp = &vsp->vlist[j]; if (sizeof(__pmValue_PDU) > (size_t)(pduend - (char *)pduvp)) goto corrupt; pduvp->inst = ntohl(pduvp->inst); if (vsp->valfmt == PM_VAL_INSITU) { pduvp->value.lval = ntohl(pduvp->value.lval); } else { /* salvage pmValueBlocks from end of PDU */ index = ntohl(pduvp->value.lval); if (index < 0 || index > pp->hdr.len) goto corrupt; pduvbp = (pmValueBlock *)&pdubuf[index]; if (vsplit > (char *)pduvbp) vsplit = (char *)pduvbp; if (sizeof(unsigned int) > (size_t)(pduend - (char *)pduvbp)) goto corrupt; __ntohpmValueBlock(pduvbp); if (pduvbp->vlen < PM_VAL_HDR_SIZE || pduvbp->vlen > pp->hdr.len) goto corrupt; if (pduvbp->vlen > (size_t)(pduend - (char *)pduvbp)) goto corrupt; pduvp->value.pval = pduvbp; } } vlp = (vlist_t *)((__psint_t)vlp + sizeof(*vlp) + (vsp->numval-1)*sizeof(vlp->vlist[0])); } else { vlp = (vlist_t *)((__psint_t)vlp + sizeof(vlp->pmid) + sizeof(vlp->numval)); } } if (numpmid > 0) { if (sizeof(result_t) - sizeof(__pmPDU) + vsize != pp->hdr.len - (pduend - vsplit)) goto corrupt; /* * PDU buffer already pinned on entry, pin again so that * the caller can safely call _both_ pmFreeResult() and * __pmUnpinPDUBuf() ... refer to thread-safe notes above. */ __pmPinPDUBuf(pdubuf); } #endif #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) __pmDumpResult(stderr, pr); #endif /* * Note we return with the input buffer (pdubuf) still pinned and * for the 64-bit pointer case the new buffer (newbuf) also pinned - * if numpmid != 0 see the thread-safe comments above */ *result = pr; return 0; corrupt: free(pr); return PM_ERR_IPC; } pcp-3.8.12ubuntu1/src/libpcp/src/p_instance.c0000664000000000000000000001742712272262501015733 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include "pmapi.h" #include "impl.h" #include "internal.h" /* * PDU for pm*InDom request (PDU_INSTANCE_REQ) */ typedef struct { __pmPDUHdr hdr; pmInDom indom; __pmTimeval when; /* desired time */ int inst; /* may be PM_IN_NULL */ int namelen; /* chars in name[], may be 0 */ char name[sizeof(int)]; /* may be missing */ } instance_req_t; int __pmSendInstanceReq(int fd, int from, const __pmTimeval *when, pmInDom indom, int inst, const char *name) { instance_req_t *pp; int need; int sts; need = sizeof(instance_req_t) - sizeof(int); if (name != NULL) need += PM_PDU_SIZE_BYTES(strlen(name)); if ((pp = (instance_req_t *)__pmFindPDUBuf(sizeof(need))) == NULL) return -oserror(); pp->hdr.len = need; pp->hdr.type = PDU_INSTANCE_REQ; pp->hdr.from = from; pp->when.tv_sec = htonl((__int32_t)when->tv_sec); pp->when.tv_usec = htonl((__int32_t)when->tv_usec); pp->indom = __htonpmInDom(indom); pp->inst = htonl(inst); if (name == NULL) pp->namelen = 0; else { pp->namelen = (int)strlen(name); memcpy((void *)pp->name, (void *)name, pp->namelen); #ifdef PCP_DEBUG if ((pp->namelen % sizeof(__pmPDU)) != 0) { /* for Purify */ int pad; char *padp = pp->name + pp->namelen; for (pad = sizeof(__pmPDU) - 1; pad >= (pp->namelen % sizeof(__pmPDU)); pad--) *padp++ = '~'; /* buffer end */ } #endif pp->namelen = htonl(pp->namelen); } sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmDecodeInstanceReq(__pmPDU *pdubuf, __pmTimeval *when, pmInDom *indom, int *inst, char **name) { instance_req_t *pp; char *pdu_end; int namelen; pp = (instance_req_t *)pdubuf; pdu_end = (char *)pdubuf + pp->hdr.len; if (pdu_end - (char *)pp < sizeof(instance_req_t) - sizeof(pp->name)) return PM_ERR_IPC; when->tv_sec = ntohl(pp->when.tv_sec); when->tv_usec = ntohl(pp->when.tv_usec); *indom = __ntohpmInDom(pp->indom); *inst = ntohl(pp->inst); namelen = ntohl(pp->namelen); if (namelen > 0) { if (namelen >= INT_MAX - 1 || namelen > pp->hdr.len) return PM_ERR_IPC; if (pdu_end - (char *)pp < sizeof(instance_req_t) - sizeof(pp->name) + namelen) return PM_ERR_IPC; if ((*name = (char *)malloc(namelen+1)) == NULL) return -oserror(); strncpy(*name, pp->name, namelen); (*name)[namelen] = '\0'; } else if (namelen < 0) { return PM_ERR_IPC; } else { *name = NULL; } return 0; } /* * PDU for pm*InDom result (PDU_INSTANCE) */ typedef struct { int inst; /* internal instance id */ int namelen; /* chars in name[], may be 0 */ char name[sizeof(int)]; /* may be missing */ } instlist_t; typedef struct { __pmPDUHdr hdr; pmInDom indom; int numinst; /* no. of elts to follow */ __pmPDU rest[1]; /* array of instlist_t */ } instance_t; int __pmSendInstance(int fd, int from, __pmInResult *result) { instance_t *rp; instlist_t *ip; int need; int i; int j; int sts; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INDOM) __pmDumpInResult(stderr, result); #endif need = sizeof(*rp) - sizeof(rp->rest); /* instlist_t + name rounded up to a __pmPDU boundary */ for (i = 0; i < result->numinst; i++) { need += sizeof(*ip) - sizeof(ip->name); if (result->namelist != NULL) need += PM_PDU_SIZE_BYTES(strlen(result->namelist[i])); } if ((rp = (instance_t *)__pmFindPDUBuf(need)) == NULL) return -oserror(); rp->hdr.len = need; rp->hdr.type = PDU_INSTANCE; rp->hdr.from = from; rp->indom = __htonpmInDom(result->indom); rp->numinst = htonl(result->numinst); for (i = j = 0; i < result->numinst; i++) { ip = (instlist_t *)&rp->rest[j/sizeof(__pmPDU)]; if (result->instlist != NULL) ip->inst = htonl(result->instlist[i]); else /* weird, but this is going to be ignored at the other end */ ip->inst = htonl(PM_IN_NULL); if (result->namelist != NULL) { ip->namelen = (int)strlen(result->namelist[i]); memcpy((void *)ip->name, (void *)result->namelist[i], ip->namelen); #ifdef PCP_DEBUG if ((ip->namelen % sizeof(__pmPDU)) != 0) { /* for Purify */ int pad; char *padp = ip->name + ip->namelen; for (pad = sizeof(__pmPDU) - 1; pad >= (ip->namelen % sizeof(__pmPDU)); pad--) *padp++ = '~'; /* buffer end */ } #endif j += sizeof(*ip) - sizeof(ip->name) + PM_PDU_SIZE_BYTES(ip->namelen); ip->namelen = htonl(ip->namelen); } else { ip->namelen = 0; j += sizeof(*ip) - sizeof(ip->name); } } sts = __pmXmitPDU(fd, (__pmPDU *)rp); __pmUnpinPDUBuf(rp); return sts; } int __pmDecodeInstance(__pmPDU *pdubuf, __pmInResult **result) { int i; int j; instance_t *rp; instlist_t *ip; __pmInResult *res; int sts; char *p; char *pdu_end; int keep_instlist; int keep_namelist; rp = (instance_t *)pdubuf; pdu_end = (char *)pdubuf + rp->hdr.len; if (pdu_end - (char *)pdubuf < sizeof(instance_t) - sizeof(__pmPDU)) return PM_ERR_IPC; if ((res = (__pmInResult *)malloc(sizeof(*res))) == NULL) return -oserror(); res->instlist = NULL; res->namelist = NULL; res->indom = __ntohpmInDom(rp->indom); res->numinst = ntohl(rp->numinst); if (res->numinst >= (INT_MAX / sizeof(res->instlist[0])) || res->numinst >= (INT_MAX / sizeof(res->namelist[0])) || res->numinst >= rp->hdr.len) { sts = PM_ERR_IPC; goto badsts; } if ((res->instlist = (int *)malloc(res->numinst * sizeof(res->instlist[0]))) == NULL) { sts = -oserror(); goto badsts; } if ((res->namelist = (char **)malloc(res->numinst * sizeof(res->namelist[0]))) == NULL) { sts = -oserror(); goto badsts; } /* required for __pmFreeInResult() in the event of a later error */ memset(res->namelist, 0, res->numinst * sizeof(res->namelist[0])); if (res->numinst == 1) keep_instlist = keep_namelist = 0; else keep_instlist = keep_namelist = 1; for (i = j = 0; i < res->numinst; i++) { ip = (instlist_t *)&rp->rest[j/sizeof(__pmPDU)]; if (sizeof(instlist_t) - sizeof(ip->name) > (size_t)(pdu_end - (char *)ip)) { sts = PM_ERR_IPC; goto badsts; } res->instlist[i] = ntohl(ip->inst); if (res->instlist[i] != PM_IN_NULL) keep_instlist = 1; ip->namelen = ntohl(ip->namelen); if (ip->namelen > 0) keep_namelist = 1; if (ip->namelen < 0) { sts = PM_ERR_IPC; goto badsts; } if (sizeof(instlist_t) - sizeof(int) + ip->namelen > (size_t)(pdu_end - (char *)ip)) { sts = PM_ERR_IPC; goto badsts; } if ((p = (char *)malloc(ip->namelen + 1)) == NULL) { sts = -oserror(); goto badsts; } memcpy((void *)p, (void *)ip->name, ip->namelen); p[ip->namelen] = '\0'; res->namelist[i] = p; j += sizeof(*ip) - sizeof(ip->name) + PM_PDU_SIZE_BYTES(ip->namelen); } if (keep_instlist == 0) { free(res->instlist); res->instlist = NULL; } if (keep_namelist == 0) { free(res->namelist[0]); free(res->namelist); res->namelist = NULL; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_INDOM) __pmDumpInResult(stderr, res); #endif *result = res; return 0; badsts: __pmFreeInResult(res); return sts; } pcp-3.8.12ubuntu1/src/libpcp/src/pdu.c0000664000000000000000000004001212272262501014362 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2005 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Thread-safe notes: * * maxsize - monotonic increasing and rarely changes, so use global * mutex to protect updates, but allow reads without locking * as seeing an unexpected newly updated value is benign * * On success, the result parameter from __pmGetPDU() points into a PDU * buffer that is pinned from the call to __pmFindPDUBuf(). It is the * responsibility of the __pmGetPDU() caller to unpin the buffer when * it is safe to do so. * * __pmPDUCntIn[] and __pmPDUCntOut[] are diagnostic counters that are * maintained with non-atomic updates ... we've decided that it is * acceptable for their values to be subject to possible (but unlikely) * missed updates */ #include "pmapi.h" #include "impl.h" #include "internal.h" INTERN int pmDebug; /* the real McCoy */ /* * Performance Instrumentation * ... counts binary PDUs received and sent by low 4 bits of PDU type */ static unsigned int inctrs[PDU_MAX+1]; static unsigned int outctrs[PDU_MAX+1]; INTERN unsigned int *__pmPDUCntIn = inctrs; INTERN unsigned int *__pmPDUCntOut = outctrs; #ifdef PCP_DEBUG static int mypid = -1; #endif static int ceiling = PDU_CHUNK * 64; static struct timeval def_wait = { 10, 0 }; static double def_timeout = 10.0; #define HEADER -1 #define BODY 0 const struct timeval * __pmDefaultRequestTimeout(void) { static int done_default = 0; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (!done_default) { char *timeout_str; char *end_ptr; if ((timeout_str = getenv("PMCD_REQUEST_TIMEOUT")) != NULL) { def_timeout = strtod(timeout_str, &end_ptr); if (*end_ptr != '\0' || def_timeout < 0.0) { __pmNotifyErr(LOG_WARNING, "ignored bad PMCD_REQUEST_TIMEOUT = '%s'\n", timeout_str); } else { def_wait.tv_sec = (int)def_timeout; /* truncate -> secs */ if (def_timeout > (double)def_wait.tv_sec) def_wait.tv_usec = (long)((def_timeout - (double)def_wait.tv_sec) * 1000000); else def_wait.tv_usec = 0; } } done_default = 1; } PM_UNLOCK(__pmLock_libpcp); return (&def_wait); } static int pduread(int fd, char *buf, int len, int part, int timeout) { int socketipc = __pmSocketIPC(fd); int status = 0; int have = 0; int onetrip = 1; struct timeval dead_hand; struct timeval now; if (timeout == TIMEOUT_ASYNC) return -EOPNOTSUPP; /* * Handle short reads that may split a PDU ... * * The original logic here assumed that recv() would only split a * PDU at a word (__pmPDU) boundary ... with the introduction of * secure connections, SSL and possibly compression all lurking * below the socket covers, this is no longer a safe assumption. * * So, we keep nibbling at the input stream until we have all that * we have requested, or we timeout, or error. */ while (len) { struct timeval wait; #if defined(IS_MINGW) /* cannot select on a pipe on Win32 - yay! */ if (!__pmSocketIPC(fd)) { COMMTIMEOUTS cwait = { 0 }; if (timeout != TIMEOUT_NEVER) cwait.ReadTotalTimeoutConstant = timeout * 1000.0; else cwait.ReadTotalTimeoutConstant = def_timeout * 1000.0; SetCommTimeouts((HANDLE)_get_osfhandle(fd), &cwait); } else #endif /* * either never timeout (i.e. block forever), or timeout */ if (timeout != TIMEOUT_NEVER) { if (timeout > 0) { wait.tv_sec = timeout; wait.tv_usec = 0; } else wait = def_wait; if (onetrip) { /* * Need all parts of the PDU to be received by dead_hand * This enforces a low overall timeout for the whole PDU * (as opposed to just a timeout for individual calls to * recv). A more invasive alternative (better) approach * would see all I/O performed in the main event loop, * and I/O routines transformed to continuation-passing * style. */ gettimeofday(&dead_hand, NULL); dead_hand.tv_sec += wait.tv_sec; dead_hand.tv_usec += wait.tv_usec; while (dead_hand.tv_usec >= 1000000) { dead_hand.tv_usec -= 1000000; dead_hand.tv_sec++; } onetrip = 0; } status = __pmSocketReady(fd, &wait); if (status > 0) { gettimeofday(&now, NULL); if (now.tv_sec > dead_hand.tv_sec || (now.tv_sec == dead_hand.tv_sec && now.tv_usec > dead_hand.tv_usec)) status = 0; } if (status == 0) { if (__pmGetInternalState() != PM_STATE_APPL) { /* special for PMCD and friends * Note, on Linux select would return 'time remaining' * in timeout value, so report the expected timeout */ int tosec, tomsec; if ( timeout != TIMEOUT_NEVER && timeout > 0 ) { tosec = (int)timeout; tomsec = 0; } else { tosec = (int)def_wait.tv_sec; tomsec = 1000*(int)def_wait.tv_usec; } __pmNotifyErr(LOG_WARNING, "pduread: timeout (after %d.%03d " "sec) while attempting to read %d " "bytes out of %d in %s on fd=%d", tosec, tomsec, len - have, len, part == HEADER ? "HDR" : "BODY", fd); } return PM_ERR_TIMEOUT; } else if (status < 0) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "pduread: select() on fd=%d: %s", fd, netstrerror_r(errmsg, sizeof(errmsg))); setoserror(neterror()); return status; } } if (socketipc) { status = __pmRecv(fd, buf, len, 0); setoserror(neterror()); } else { status = read(fd, buf, len); } __pmOverrideLastFd(fd); if (status < 0) /* error */ return status; else if (status == 0) /* return what we have, or nothing */ break; have += status; buf += status; len -= status; #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_PDU) && (pmDebug & DBG_TRACE_DESPERATE)) { fprintf(stderr, "pduread(%d, ...): have %d, last read %d, still need %d\n", fd, have, status, len); } #endif } return have; } char * __pmPDUTypeStr_r(int type, char *buf, int buflen) { char *res = NULL; if (type == PDU_ERROR) res = "ERROR"; else if (type == PDU_RESULT) res = "RESULT"; else if (type == PDU_PROFILE) res = "PROFILE"; else if (type == PDU_FETCH) res = "FETCH"; else if (type == PDU_DESC_REQ) res = "DESC_REQ"; else if (type == PDU_DESC) res = "DESC"; else if (type == PDU_INSTANCE_REQ) res = "INSTANCE_REQ"; else if (type == PDU_INSTANCE) res = "INSTANCE"; else if (type == PDU_TEXT_REQ) res = "TEXT_REQ"; else if (type == PDU_TEXT) res = "TEXT"; else if (type == PDU_CONTROL_REQ) res = "CONTROL_REQ"; else if (type == PDU_CREDS) res = "CREDS"; else if (type == PDU_PMNS_IDS) res = "PMNS_IDS"; else if (type == PDU_PMNS_NAMES) res = "PMNS_NAMES"; else if (type == PDU_PMNS_CHILD) res = "PMNS_CHILD"; else if (type == PDU_PMNS_TRAVERSE) res = "PMNS_TRAVERSE"; else if (type == PDU_LOG_CONTROL) res = "LOG_CONTROL"; else if (type == PDU_LOG_STATUS) res = "LOG_STATUS"; else if (type == PDU_LOG_REQUEST) res = "LOG_REQUEST"; else if (type == PDU_AUTH) res = "AUTH"; if (res == NULL) snprintf(buf, buflen, "TYPE-%d?", type); else snprintf(buf, buflen, "%s", res); return buf; } const char * __pmPDUTypeStr(int type) { static char tbuf[20]; __pmPDUTypeStr_r(type, tbuf, sizeof(tbuf)); return tbuf; } #if defined(HAVE_SIGPIPE) /* * Because the default handler for SIGPIPE is to exit, we always want a handler * installed to override that so that the write() just returns an error. The * problem is that the user might have installed one prior to the first write() * or may install one at some later stage. This doesn't matter. As long as a * handler other than SIG_DFL is there, all will be well. The first time that * __pmXmitPDU is called, install SIG_IGN as the handler for SIGPIPE. If the * user had already changed the handler from SIG_DFL, put back what was there * before. */ static int sigpipe_done = 0; /* First time check for installation of non-default SIGPIPE handler */ static void setup_sigpipe() { if (!sigpipe_done) { /* Make sure SIGPIPE is handled */ SIG_PF user_onpipe; user_onpipe = signal(SIGPIPE, SIG_IGN); if (user_onpipe != SIG_DFL) /* Put user handler back */ signal(SIGPIPE, user_onpipe); sigpipe_done = 1; } } #else static void setup_sigpipe() { } #endif int __pmXmitPDU(int fd, __pmPDU *pdubuf) { int socketipc = __pmSocketIPC(fd); int off = 0; int len; __pmPDUHdr *php = (__pmPDUHdr *)pdubuf; setup_sigpipe(); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) { int j; char *p; int jend = PM_PDU_SIZE(php->len); char strbuf[20]; /* for Purify ... */ p = (char *)pdubuf + php->len; while (p < (char *)pdubuf + jend*sizeof(__pmPDU)) *p++ = '~'; /* buffer end */ if (mypid == -1) mypid = (int)getpid(); fprintf(stderr, "[%d]pmXmitPDU: %s fd=%d len=%d", mypid, __pmPDUTypeStr_r(php->type, strbuf, sizeof(strbuf)), fd, php->len); for (j = 0; j < jend; j++) { if ((j % 8) == 0) fprintf(stderr, "\n%03d: ", j); fprintf(stderr, "%8x ", pdubuf[j]); } putc('\n', stderr); } #endif len = php->len; php->len = htonl(php->len); php->from = htonl(php->from); php->type = htonl(php->type); while (off < len) { char *p = (char *)pdubuf; int n; p += off; n = socketipc ? __pmSend(fd, p, len-off, 0) : write(fd, p, len-off); if (n < 0) break; off += n; } php->len = ntohl(php->len); php->from = ntohl(php->from); php->type = ntohl(php->type); if (off != len) { if (socketipc) { if (__pmSocketClosed()) return PM_ERR_IPC; return neterror() ? -neterror() : PM_ERR_IPC; } return oserror() ? -oserror() : PM_ERR_IPC; } __pmOverrideLastFd(fd); if (php->type >= PDU_START && php->type <= PDU_FINISH) __pmPDUCntOut[php->type-PDU_START]++; return off; } /* result is pinned on successful return */ int __pmGetPDU(int fd, int mode, int timeout, __pmPDU **result) { int need; int len; static int maxsize = PDU_CHUNK; char *handle; __pmPDU *pdubuf; __pmPDU *pdubuf_prev; __pmPDUHdr *php; if ((pdubuf = __pmFindPDUBuf(maxsize)) == NULL) return -oserror(); /* First read - try to read the header */ len = pduread(fd, (void *)pdubuf, sizeof(__pmPDUHdr), HEADER, timeout); php = (__pmPDUHdr *)pdubuf; if (len < (int)sizeof(__pmPDUHdr)) { if (len == -1) { if (__pmSocketClosed()) { len = 0; } else { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d hdr read: len=%d: %s", fd, len, pmErrStr_r(-oserror(), errmsg, sizeof(errmsg))); } } else if (len >= (int)sizeof(php->len)) { /* * Have part of a PDU header. Enough for the "len" * field to be valid, but not yet all of it - save * what we have received and try to read some more. * Note this can only happen once per PDU, so the * ntohl() below will _only_ be done once per PDU. */ goto check_read_len; /* continue, do not return */ } else if (len == PM_ERR_TIMEOUT) { __pmUnpinPDUBuf(pdubuf); return PM_ERR_TIMEOUT; } else if (len < 0) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d hdr read: len=%d: %s", fd, len, pmErrStr_r(len, errmsg, sizeof(errmsg))); __pmUnpinPDUBuf(pdubuf); return PM_ERR_IPC; } else if (len > 0) { __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d hdr read: bad len=%d", fd, len); __pmUnpinPDUBuf(pdubuf); return PM_ERR_IPC; } /* * end-of-file with no data */ __pmUnpinPDUBuf(pdubuf); return 0; } check_read_len: php->len = ntohl(php->len); if (php->len < (int)sizeof(__pmPDUHdr)) { /* * PDU length indicates insufficient bytes for a PDU header * ... looks like DOS attack like PV 935490 */ __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d illegal PDU len=%d in hdr", fd, php->len); __pmUnpinPDUBuf(pdubuf); return PM_ERR_IPC; } else if (mode == LIMIT_SIZE && php->len > ceiling) { /* * Guard against denial of service attack ... don't accept PDUs * from clients that are larger than 64 Kbytes (ceiling) * (note, pmcd and pmdas have to be able to _send_ large PDUs, * e.g. for a pmResult or instance domain enquiry) */ __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d bad PDU len=%d in hdr exceeds maximum client PDU size (%d)", fd, php->len, ceiling); __pmUnpinPDUBuf(pdubuf); return PM_ERR_TOOBIG; } if (len < php->len) { /* * need to read more ... */ int tmpsize; int have = len; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (php->len > maxsize) { tmpsize = PDU_CHUNK * ( 1 + php->len / PDU_CHUNK); maxsize = tmpsize; } else tmpsize = maxsize; PM_UNLOCK(__pmLock_libpcp); pdubuf_prev = pdubuf; if ((pdubuf = __pmFindPDUBuf(tmpsize)) == NULL) { __pmUnpinPDUBuf(pdubuf_prev); return -oserror(); } memmove((void *)pdubuf, (void *)php, len); __pmUnpinPDUBuf(pdubuf_prev); php = (__pmPDUHdr *)pdubuf; need = php->len - have; handle = (char *)pdubuf; /* block until all of the PDU is received this time */ len = pduread(fd, (void *)&handle[len], need, BODY, timeout); if (len != need) { if (len == PM_ERR_TIMEOUT) { __pmUnpinPDUBuf(pdubuf); return PM_ERR_TIMEOUT; } else if (len < 0) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d data read: len=%d: %s", fd, len, pmErrStr_r(-oserror(), errmsg, sizeof(errmsg))); } else __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d data read: have %d, want %d, got %d", fd, have, need, len); /* * only report header fields if you've read enough bytes */ if (len > 0) have += len; if (have >= (int)(sizeof(php->len)+sizeof(php->type)+sizeof(php->from))) __pmNotifyErr(LOG_ERR, "__pmGetPDU: PDU hdr: len=0x%x type=0x%x from=0x%x", php->len, (unsigned)ntohl(php->type), (unsigned)ntohl(php->from)); else if (have >= (int)(sizeof(php->len)+sizeof(php->type))) __pmNotifyErr(LOG_ERR, "__pmGetPDU: PDU hdr: len=0x%x type=0x%x", php->len, (unsigned)ntohl(php->type)); __pmUnpinPDUBuf(pdubuf); return PM_ERR_IPC; } } *result = (__pmPDU *)php; php->type = ntohl((unsigned int)php->type); if (php->type < 0) { /* * PDU type is bad ... could be a possible mem leak attack like * https://bugzilla.redhat.com/show_bug.cgi?id=841319 */ __pmNotifyErr(LOG_ERR, "__pmGetPDU: fd=%d illegal PDU type=%d in hdr", fd, php->type); __pmUnpinPDUBuf(pdubuf); return PM_ERR_IPC; } php->from = ntohl((unsigned int)php->from); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDU) { int j; char *p; int jend = PM_PDU_SIZE(php->len); char strbuf[20]; /* for Purify ... */ p = (char *)*result + php->len; while (p < (char *)*result + jend*sizeof(__pmPDU)) *p++ = '~'; /* buffer end */ if (mypid == -1) mypid = (int)getpid(); fprintf(stderr, "[%d]pmGetPDU: %s fd=%d len=%d from=%d", mypid, __pmPDUTypeStr_r(php->type, strbuf, sizeof(strbuf)), fd, php->len, php->from); for (j = 0; j < jend; j++) { if ((j % 8) == 0) fprintf(stderr, "\n%03d: ", j); fprintf(stderr, "%8x ", (*result)[j]); } putc('\n', stderr); } #endif if (php->type >= PDU_START && php->type <= PDU_FINISH) __pmPDUCntIn[php->type-PDU_START]++; /* * Note php points into the PDU buffer pdubuf that remains pinned * and php is returned via the result parameter ... see the * thread-safe comments above */ return php->type; } int __pmGetPDUCeiling(void) { return ceiling; } int __pmSetPDUCeiling(int newceiling) { if (newceiling > 0) return (ceiling = newceiling); return ceiling; } void __pmSetPDUCntBuf(unsigned *in, unsigned *out) { __pmPDUCntIn = in; __pmPDUCntOut = out; } pcp-3.8.12ubuntu1/src/libpcp/src/ipc.c0000664000000000000000000001516312272262501014356 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995,2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #ifdef HAVE_VALUES_H #include #endif #ifdef HAVE_SYS_CONFIG_H #include #endif /* * We keep a table of connection state for each interesting file descriptor here. * The version field holds the version of the software at the other end of the * connection end point (0 is unknown, 1 or 2 are also valid). * The socket field is used to tell whether this is a socket or pipe (or a file) * connection, which is most important for the Windows port, as socket interfaces * are "special" and do not use the usual file descriptor read/write/close calls, * but must rather use recv/send/closesocket. * * The table entries are of fixed length, but the actual size depends on compile * time options used (in particular, the secure sockets setting requires further * space allocated to hold the additional security metadata for each socket). */ typedef struct { int version; /* one or two */ int socket; /* true or false */ char data[0]; /* opaque data (optional) */ } __pmIPC; static int __pmLastUsedFd = -INT_MAX; static __pmIPC *__pmIPCTable; static int ipctablecount; static int ipcentrysize; static inline __pmIPC * __pmIPCTablePtr(int fd) { char *entry = (char *)__pmIPCTable; return (__pmIPC *)(entry + fd * ipcentrysize); } /* * always called with __pmLock_libpcp held */ static int __pmResizeIPC(int fd) { size_t size; int oldcount; if (__pmIPCTable == NULL || fd >= ipctablecount) { if (ipcentrysize == 0) ipcentrysize = sizeof(__pmIPC) + __pmDataIPCSize(); oldcount = ipctablecount; if (ipctablecount == 0) ipctablecount = 4; while (fd >= ipctablecount) ipctablecount *= 2; size = ipcentrysize * ipctablecount; __pmIPCTable = (__pmIPC *)realloc(__pmIPCTable, size); if (__pmIPCTable == NULL) return -oserror(); size -= ipcentrysize * oldcount; memset(__pmIPCTablePtr(oldcount), 0, size); } return 0; } int __pmSetVersionIPC(int fd, int version) { int sts; if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmSetVersionIPC: fd=%d version=%d\n", fd, version); PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if ((sts = __pmResizeIPC(fd)) < 0) { PM_UNLOCK(__pmLock_libpcp); return sts; } __pmIPCTablePtr(fd)->version = version; __pmLastUsedFd = fd; if (pmDebug & DBG_TRACE_CONTEXT) __pmPrintIPC(); PM_UNLOCK(__pmLock_libpcp); return sts; } int __pmSetSocketIPC(int fd) { int sts; if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmSetSocketIPC: fd=%d\n", fd); PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if ((sts = __pmResizeIPC(fd)) < 0) { PM_UNLOCK(__pmLock_libpcp); return sts; } __pmIPCTablePtr(fd)->socket = 1; __pmLastUsedFd = fd; if (pmDebug & DBG_TRACE_CONTEXT) __pmPrintIPC(); PM_UNLOCK(__pmLock_libpcp); return sts; } int __pmVersionIPC(int fd) { int sts; if (fd == PDU_OVERRIDE2) return PDU_VERSION2; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (__pmIPCTable == NULL || fd < 0 || fd >= ipctablecount) { if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "IPC protocol botch: table->" PRINTF_P_PFX "%p fd=%d sz=%d\n", __pmIPCTable, fd, ipctablecount); PM_UNLOCK(__pmLock_libpcp); return UNKNOWN_VERSION; } sts = __pmIPCTablePtr(fd)->version; PM_UNLOCK(__pmLock_libpcp); return sts; } int __pmLastVersionIPC() { int sts; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); sts = __pmVersionIPC(__pmLastUsedFd); PM_UNLOCK(__pmLock_libpcp); return sts; } int __pmSocketIPC(int fd) { int sts; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (__pmIPCTable == NULL || fd < 0 || fd >= ipctablecount) { PM_UNLOCK(__pmLock_libpcp); return 0; } sts = __pmIPCTablePtr(fd)->socket; PM_UNLOCK(__pmLock_libpcp); return sts; } int __pmSetDataIPC(int fd, void *data) { char *dest; int sts; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if ((sts = __pmResizeIPC(fd)) < 0) { PM_UNLOCK(__pmLock_libpcp); return sts; } if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "__pmSetDataIPC: fd=%d data=%p(sz=%d)\n", fd, data, (int)(ipcentrysize - sizeof(__pmIPC))); dest = ((char *)__pmIPCTablePtr(fd)) + sizeof(__pmIPC); memcpy(dest, data, ipcentrysize - sizeof(__pmIPC)); __pmLastUsedFd = fd; if (pmDebug & DBG_TRACE_CONTEXT) __pmPrintIPC(); PM_UNLOCK(__pmLock_libpcp); return sts; } int __pmDataIPC(int fd, void *data) { char *source; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (fd < 0 || fd >= ipctablecount || __pmIPCTable == NULL || ipcentrysize == sizeof(__pmIPC)) { PM_UNLOCK(__pmLock_libpcp); return -ESRCH; } source = ((char *)__pmIPCTablePtr(fd)) + sizeof(__pmIPC); if ((pmDebug & DBG_TRACE_CONTEXT) && (pmDebug & DBG_TRACE_DESPERATE)) fprintf(stderr, "__pmDataIPC: fd=%d, data=%p(sz=%d)\n", fd, source, (int)(ipcentrysize - sizeof(__pmIPC))); memcpy(data, source, ipcentrysize - sizeof(__pmIPC)); PM_UNLOCK(__pmLock_libpcp); return 0; } /* * Called by log readers who need version info for result decode, * but don't have a socket fd (have a FILE* & fileno though). * Also at start of version exchange before version is known * (when __pmDecodeError is called before knowing version). */ void __pmOverrideLastFd(int fd) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); __pmLastUsedFd = fd; PM_UNLOCK(__pmLock_libpcp); } void __pmResetIPC(int fd) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (__pmIPCTable && fd >= 0 && fd < ipctablecount) memset(__pmIPCTablePtr(fd), 0, ipcentrysize); PM_UNLOCK(__pmLock_libpcp); } void __pmPrintIPC(void) { int i; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); fprintf(stderr, "IPC table fd(PDU version):"); for (i = 0; i < ipctablecount; i++) { if (__pmIPCTablePtr(i)->version != UNKNOWN_VERSION) fprintf(stderr, " %d(%d,%d)", i, __pmIPCTablePtr(i)->version, __pmIPCTablePtr(i)->socket); } fputc('\n', stderr); PM_UNLOCK(__pmLock_libpcp); } pcp-3.8.12ubuntu1/src/libpcp/src/derive.h0000664000000000000000000000554512272262501015071 0ustar /* * Copyright (c) 2009 Ken McDonell. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #ifndef _DERIVE_H #define _DERIVE_H /* * Derived Metrics support */ typedef struct { /* one value in the expression tree */ int inst; pmAtomValue value; int vlen; /* from vlen of pmValueBlock for string and aggregates */ } val_t; typedef struct { /* dynamic information for an expression node */ pmID pmid; int numval; /* length of ivlist[] */ int mul_scale; /* scale multiplier */ int div_scale; /* scale divisor */ val_t *ivlist; /* instance-value pairs */ int last_numval; /* length of last_ivlist[] */ val_t *last_ivlist; /* values from previous fetch for delta() */ } info_t; typedef struct node { /* expression tree node */ int type; pmDesc desc; int save_last; struct node *left; struct node *right; char *value; info_t *info; } node_t; typedef struct { /* one derived metric */ char *name; pmID pmid; node_t *expr; } dm_t; /* * Control structure for a set of derived metrics. * This is used for the static definitions (registered) and the dynamic * tree of expressions maintained per context. */ typedef struct { __pmMutex mutex; int nmetric; /* derived metrics */ dm_t *mlist; int fetch_has_dm; /* ==1 if pmResult rewrite needed */ int numpmid; /* from pmFetch before rewrite */ } ctl_t; /* lexical types */ #define L_ERROR -2 #define L_EOF -1 #define L_UNDEF 0 #define L_NUMBER 1 #define L_NAME 2 #define L_PLUS 3 #define L_MINUS 4 #define L_STAR 5 #define L_SLASH 6 #define L_LPAREN 7 #define L_RPAREN 8 #define L_AVG 9 #define L_COUNT 10 #define L_DELTA 11 #define L_MAX 12 #define L_MIN 13 #define L_SUM 14 #define L_ANON 15 extern int __dmtraverse(const char *, char ***) _PCP_HIDDEN; extern int __dmchildren(const char *, char ***, int **) _PCP_HIDDEN; extern int __dmgetpmid(const char *, pmID *) _PCP_HIDDEN; extern int __dmgetname(pmID, char **) _PCP_HIDDEN; extern void __dmopencontext(__pmContext *) _PCP_HIDDEN; extern void __dmclosecontext(__pmContext *) _PCP_HIDDEN; extern int __dmdesc(__pmContext *, pmID, pmDesc *) _PCP_HIDDEN; extern int __dmprefetch(__pmContext *, int, const pmID *, pmID **) _PCP_HIDDEN; extern void __dmpostfetch(__pmContext *, pmResult **) _PCP_HIDDEN; extern void __dmdumpexpr(node_t *, int) _PCP_HIDDEN; #endif /* _DERIVE_H */ pcp-3.8.12ubuntu1/src/libpcp/src/auxserver.c0000664000000000000000000004612212272262501015626 0ustar /* * Copyright (c) 2013 Red Hat. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include "pmapi.h" #include "impl.h" #define SOCKET_INTERNAL #include "internal.h" #if defined(HAVE_GETPEERUCRED) #include #endif #include "avahi.h" /* * Info about a request port that clients may connect to a server on */ enum { INET_FD = 0, IPV6_FD, FAMILIES }; typedef struct { int fds[FAMILIES]; /* Inet and IPv6 File descriptors */ int port; /* Listening port */ const char *address; /* Network address string (or NULL) */ __pmServerPresence *presence; /* For advertising server presence on the network. */ } ReqPortInfo; static unsigned nReqPorts; /* number of ports */ static unsigned szReqPorts; /* capacity of ports array */ static ReqPortInfo *reqPorts; /* ports array */ /* * Interfaces we're willing to listen for clients on, from -i */ static int nintf; static char **intflist; /* * Ports we're willing to listen for clients on, from -p (or env) */ static int nport; static int *portlist; /* * The unix domain socket we're willing to listen for clients on, from -s (or env) */ static const char *localSocketPath; static int localSocketFd = -EPROTO; static const char *serviceSpec; int __pmServerAddInterface(const char *address) { size_t size = (nintf+1) * sizeof(char *); /* one (of possibly several) IP addresses for client requests */ intflist = (char **)realloc(intflist, nintf * sizeof(char *)); if (intflist == NULL) __pmNoMem("AddInterface: cannot grow interface list", size, PM_FATAL_ERR); intflist[nintf++] = strdup(address); return nintf; } int __pmServerAddPorts(const char *ports) { char *endptr, *p = (char *)ports; /* * one (of possibly several) ports for client requests * ... accept a comma separated list of ports here */ for ( ; ; ) { size_t size = (nport + 1) * sizeof(int); int port = (int)strtol(p, &endptr, 0); if ((*endptr != '\0' && *endptr != ',') || port < 0) return -EINVAL; if ((portlist = (int *)realloc(portlist, size)) == NULL) __pmNoMem("AddPorts: cannot grow port list", size, PM_FATAL_ERR); portlist[nport++] = port; if (*endptr == '\0') break; p = &endptr[1]; } return nport; } void __pmServerSetLocalSocket(const char *path) { if (path != NULL && *path != '\0') localSocketPath = strdup(path); else localSocketPath = __pmPMCDLocalSocketDefault(); } void __pmServerSetServiceSpec(const char *spec) { if (spec != NULL && *spec != '\0') serviceSpec = strdup(spec); else serviceSpec = PM_SERVER_SERVICE_SPEC; } void __pmCheckAcceptedAddress(__pmSockAddr *addr) { #if defined(HAVE_STRUCT_SOCKADDR_UN) /* * accept(3) doesn't set the peer address for unix domain sockets. * We need to do it ourselves. The address family * is set, so we can use it to test. There is only one unix domain socket * open, so we know its path. */ if (__pmSockAddrGetFamily(addr) == AF_UNIX) __pmSockAddrSetPath(addr, localSocketPath); #endif } /* Increase the capacity of the reqPorts array (maintain the contents) */ static void GrowRequestPorts(void) { size_t need; szReqPorts += 4; need = szReqPorts * sizeof(ReqPortInfo); reqPorts = (ReqPortInfo*)realloc(reqPorts, need); if (reqPorts == NULL) { __pmNoMem("GrowRequestPorts: can't grow request port array", need, PM_FATAL_ERR); } } /* Add a request port to the reqPorts array */ static int AddRequestPort(const char *address, int port) { ReqPortInfo *rp; if (address == NULL) address = "INADDR_ANY"; if (nReqPorts == szReqPorts) GrowRequestPorts(); rp = &reqPorts[nReqPorts]; rp->fds[INET_FD] = -1; rp->fds[IPV6_FD] = -1; rp->address = address; rp->port = port; rp->presence = NULL; nReqPorts++; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "AddRequestPort: %s port %d\n", rp->address, rp->port); #endif return nReqPorts; /* success */ } static int SetupRequestPorts(void) { int i, n; /* check for duplicate ports, remove duplicates */ for (i = 0; i < nport; i++) { for (n = i + 1; n < nport; n++) { if (portlist[i] == portlist[n]) break; } if (n < nport) { __pmNotifyErr(LOG_WARNING, "%s: duplicate client request port (%d) will be ignored\n", pmProgname, portlist[n]); portlist[n] = -1; } } if (nintf == 0) { /* no interface options specified, allow connections on any address */ for (n = 0; n < nport; n++) { if (portlist[n] != -1) AddRequestPort(NULL, portlist[n]); } } else { for (i = 0; i < nintf; i++) { for (n = 0; n < nport; n++) { if (portlist[n] == -1 || intflist[i] == NULL) continue; AddRequestPort(intflist[i], portlist[n]); } } } return 0; } static const char * AddressFamily(int family) { if (family == AF_INET) return "inet"; if (family == AF_INET6) return "ipv6"; #if defined(HAVE_STRUCT_SOCKADDR_UN) if (family == AF_UNIX) return "unix"; #endif return "unknown"; } /* * Create socket for incoming connections and bind to it an address for * clients to use. Returns -1 on failure. * * If '*family' is AF_UNIX and unix domain sockets are supported: * 'port' is ignored and 'address' is the path to the socket file in the filesystem. * * Otherwise: * address is a string representing the Inet/IPv6 address that the port * is advertised for. To allow connections to all this host's internet * addresses from clients use address = "INADDR_ANY". * On input, 'family' is a pointer to the address family to use (AF_INET, * AF_INET6) if the address specified is empty. If the spec is not * empty then family is ignored and is set to the actual address family * used. 'family' must be initialized to AF_UNSPEC, in this case. */ static int OpenRequestSocket(int port, const char *address, int *family, int backlog, __pmFdSet *fdset, int *maximum) { int fd = -1; int one, sts; __pmSockAddr *myAddr; int isUnix = 0; /* * Using this flag will eliminate the need for more conditional * compilation below, hopefully making the code easier to read and maintain. */ #if defined(HAVE_STRUCT_SOCKADDR_UN) if (*family == AF_UNIX) isUnix = 1; #endif if (isUnix) { if ((myAddr = __pmSockAddrAlloc()) == NULL) { __pmNoMem("OpenRequestSocket: can't allocate socket address", sizeof(*myAddr), PM_FATAL_ERR); } /* Initialize the address. */ __pmSockAddrSetFamily(myAddr, *family); __pmSockAddrSetPath(myAddr, address); /* Create the socket. */ fd = __pmCreateUnixSocket(); } else { if ((myAddr = __pmStringToSockAddr(address)) == NULL) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s) invalid address\n", port, address); goto fail; } /* * If the address is unspecified, then use the address family we * have been given, otherwise the family will be determined by * __pmStringToSockAddr. */ if (address == NULL || strcmp(address, "INADDR_ANY") == 0) __pmSockAddrSetFamily(myAddr, *family); else *family = __pmSockAddrGetFamily(myAddr); __pmSockAddrSetPort(myAddr, port); /* Create the socket. */ if (*family == AF_INET) fd = __pmCreateSocket(); else if (*family == AF_INET6) fd = __pmCreateIPv6Socket(); else { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s) invalid address family: %d\n", port, address, *family); goto fail; } } if (fd < 0) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmCreateSocket: %s\n", port, address, AddressFamily(*family), netstrerror()); goto fail; } /* Ignore dead client connections. */ one = 1; #ifndef IS_MINGW if (__pmSetSockOpt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, (__pmSockLen)sizeof(one)) < 0) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmSetSockOpt(SO_REUSEADDR): %s\n", port, address, AddressFamily(*family), netstrerror()); goto fail; } #else if (__pmSetSockOpt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *)&one, (__pmSockLen)sizeof(one)) < 0) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmSetSockOpt(EXCLUSIVEADDRUSE): %s\n", port, address, AddressFamily(*family), netstrerror()); goto fail; } #endif /* and keep alive please - bad networks eat fds */ if (__pmSetSockOpt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, (__pmSockLen)sizeof(one)) < 0) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmSetSockOpt(SO_KEEPALIVE): %s\n", port, address, AddressFamily(*family), netstrerror()); goto fail; } sts = __pmBind(fd, (void *)myAddr, __pmSockAddrSize()); __pmSockAddrFree(myAddr); myAddr = NULL; if (sts < 0) { sts = neterror(); __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmBind: %s\n", port, address, AddressFamily(*family), netstrerror()); if (sts == EADDRINUSE) __pmNotifyErr(LOG_ERR, "%s may already be running\n", pmProgname); goto fail; } if (isUnix) { /* * For unix domain sockets, grant rw access to the socket for all, * otherwise, on linux platforms, connection will not be possible. * This must be done AFTER binding the address. See Unix(7) for details. */ sts = chmod(address, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); if (sts != 0) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) chmod(%s): %s\n", port, address, AddressFamily(*family), address, strerror(errno)); goto fail; } } sts = __pmListen(fd, backlog); /* Max. pending connection requests */ if (sts < 0) { __pmNotifyErr(LOG_ERR, "OpenRequestSocket(%d, %s, %s) __pmListen: %s\n", port, address, AddressFamily(*family), netstrerror()); goto fail; } if (fd > *maximum) *maximum = fd; __pmFD_SET(fd, fdset); return fd; fail: if (fd != -1) { __pmCloseSocket(fd); /* We must unlink the socket file. */ if (isUnix) unlink(address); } if (myAddr) __pmSockAddrFree(myAddr); return -1; } /* * Open request ports for client connections. * For each request port, open an inet and IPv6 (if supported) socket * for clients. Also open a local unix domain socket, if it has been * specified */ static int OpenRequestPorts(__pmFdSet *fdset, int backlog) { int i, fd, family, success = 0, maximum = -1; int with_ipv6 = strcmp(__pmGetAPIConfig("ipv6"), "true") == 0; for (i = 0; i < nReqPorts; i++) { ReqPortInfo *rp = &reqPorts[i]; int portsOpened = 0;; /* * If the spec is NULL or "INADDR_ANY", then we open one socket * for each address family (inet, IPv6). Otherwise, the address * family will be determined by OpenRequestSocket. Reporting of * all errors is left to OpenRequestSocket to avoid doubling up. */ if (rp->address == NULL || strcmp(rp->address, "INADDR_ANY") == 0) { family = AF_INET; if ((fd = OpenRequestSocket(rp->port, rp->address, &family, backlog, fdset, &maximum)) >= 0) { rp->fds[INET_FD] = fd; ++portsOpened; success = 1; } if (with_ipv6) { family = AF_INET6; if ((fd = OpenRequestSocket(rp->port, rp->address, &family, backlog, fdset, &maximum)) >= 0) { rp->fds[IPV6_FD] = fd; ++portsOpened; success = 1; } } else rp->fds[IPV6_FD] = -EPROTO; } else { family = AF_UNSPEC; if ((fd = OpenRequestSocket(rp->port, rp->address, &family, backlog, fdset, &maximum)) >= 0) { if (family == AF_INET) { rp->fds[INET_FD] = fd; ++portsOpened; success = 1; } else if (family == AF_INET6) { rp->fds[IPV6_FD] = fd; ++portsOpened; success = 1; } } } if (portsOpened > 0) { /* Advertise our presence on the network, if requested. */ if (serviceSpec != NULL) { rp->presence = __pmServerAdvertisePresence(serviceSpec, rp->port); } } } /* Open a local unix domain socket, if specified, and supported. */ if (localSocketPath != NULL) { #if defined(HAVE_STRUCT_SOCKADDR_UN) family = AF_UNIX; if ((localSocketFd = OpenRequestSocket(0, localSocketPath, &family, backlog, fdset, &maximum)) >= 0) { __pmServerSetFeature(PM_SERVER_FEATURE_UNIX_DOMAIN); success = 1; } #else __pmNotifyErr(LOG_ERR, "%s: unix domain sockets are not supported\n", pmProgname); #endif } if (success) return maximum; __pmNotifyErr(LOG_ERR, "%s: can't open any request ports, exiting\n", pmProgname); return -1; } int __pmServerOpenRequestPorts(__pmFdSet *fdset, int backlog) { int sts; if ((sts = SetupRequestPorts()) < 0) return sts; return OpenRequestPorts(fdset, backlog); } void __pmServerCloseRequestPorts(void) { int i, fd; for (i = 0; i < nReqPorts; i++) { /* No longer advertise our presence on the network. */ if (reqPorts[i].presence != NULL) __pmServerUnadvertisePresence(reqPorts[i].presence); if ((fd = reqPorts[i].fds[INET_FD]) >= 0) __pmCloseSocket(fd); if ((fd = reqPorts[i].fds[IPV6_FD]) >= 0) __pmCloseSocket(fd); } if (localSocketFd >= 0) { __pmCloseSocket(localSocketFd); localSocketFd = -EPROTO; /* We must remove the socket file. */ if (unlink(localSocketPath) != 0 && oserror() != ENOENT) { char errmsg[PM_MAXERRMSGLEN]; __pmNotifyErr(LOG_ERR, "%s: can't unlink %s (uid=%d,euid=%d): %s", pmProgname, localSocketPath, getuid(), geteuid(), osstrerror_r(errmsg, sizeof(errmsg))); } } } /* * Accept any new client connections */ void __pmServerAddNewClients(__pmFdSet *fdset, __pmServerCallback NewClient) { int i, fd; #if defined(HAVE_STRUCT_SOCKADDR_UN) /* Check the local unix domain fd. */ if (localSocketFd >= 0) NewClient(fdset, localSocketFd, AF_UNIX); #endif for (i = 0; i < nReqPorts; i++) { /* Check the inet and ipv6 fds. */ if ((fd = reqPorts[i].fds[INET_FD]) >= 0) NewClient(fdset, fd, AF_INET); if ((fd = reqPorts[i].fds[IPV6_FD]) >= 0) NewClient(fdset, fd, AF_INET6); } } static int SetCredentialAttrs(__pmHashCtl *attrs, unsigned int pid, unsigned int uid, unsigned int gid) { char name[32], *namep; snprintf(name, sizeof(name), "%u", uid); name[sizeof(name)-1] = '\0'; if ((namep = strdup(name)) != NULL) __pmHashAdd(PCP_ATTR_USERID, namep, attrs); snprintf(name, sizeof(name), "%u", gid); name[sizeof(name)-1] = '\0'; if ((namep = strdup(name)) != NULL) __pmHashAdd(PCP_ATTR_GROUPID, namep, attrs); if (!pid) /* not available on all platforms */ return 0; snprintf(name, sizeof(name), "%u", pid); name[sizeof(name)-1] = '\0'; if ((namep = strdup(name)) != NULL) __pmHashAdd(PCP_ATTR_PROCESSID, namep, attrs); return 0; } /* * Set local connection credentials into given hash structure */ int __pmServerSetLocalCreds(int fd, __pmHashCtl *attrs) { #if defined(HAVE_STRUCT_UCRED) /* Linux */ struct ucred ucred; __pmSockLen length = sizeof(ucred); if (__pmGetSockOpt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &length) < 0) return -oserror(); return SetCredentialAttrs(attrs, ucred.pid, ucred.uid, ucred.gid); #elif defined(HAVE_GETPEEREID) /* MacOSX */ uid_t uid; gid_t gid; if (getpeereid(__pmFD(fd), &uid, &gid) < 0) return -oserror(); return SetCredentialAttrs(attrs, 0, uid, gid); #elif defined(HAVE_GETPEERUCRED) /* Solaris */ unsigned int uid, gid, pid; ucred_t *ucred = NULL; if (getpeerucred(__pmFD(fd), &ucred) < 0) return -oserror(); pid = ucred_getpid(ucred); uid = ucred_geteuid(ucred); gid = ucred_getegid(ucred); ucred_free(ucred); return SetCredentialAttrs(attrs, pid, uid, gid); #else return -EOPNOTSUPP; #endif } static const char * RequestFamilyString(int index) { if (index == INET_FD) return "inet"; if (index == IPV6_FD) return "ipv6"; return "unknown"; } void __pmServerDumpRequestPorts(FILE *stream) { int i, j; fprintf(stream, "%s request port(s):\n" " sts fd port family address\n" " === ==== ===== ====== =======\n", pmProgname); if (localSocketFd != -EPROTO) fprintf(stderr, " %-3s %4d %5s %-6s %s\n", (localSocketFd != -1) ? "ok" : "err", localSocketFd, "", "unix", localSocketPath); for (i = 0; i < nReqPorts; i++) { ReqPortInfo *rp = &reqPorts[i]; for (j = 0; j < FAMILIES; j++) { if (rp->fds[j] != -EPROTO) fprintf(stderr, " %-3s %4d %5d %-6s %s\n", (rp->fds[j] != -1) ? "ok" : "err", rp->fds[j], rp->port, RequestFamilyString(j), rp->address ? rp->address : "(any address)"); } } } char * __pmServerRequestPortString(int fd, char *buffer, size_t sz) { int i, j; if (fd == localSocketFd) { snprintf(buffer, sz, "%s unix request socket %s", pmProgname, localSocketPath); return buffer; } for (i = 0; i < nReqPorts; i++) { ReqPortInfo *rp = &reqPorts[i]; for (j = 0; j < FAMILIES; j++) { if (fd == rp->fds[j]) { snprintf(buffer, sz, "%s %s request socket %s", pmProgname, RequestFamilyString(j), rp->address); return buffer; } } } return NULL; } #if !defined(HAVE_SECURE_SOCKETS) int __pmSecureServerSetup(const char *db, const char *passwd) { (void)db; (void)passwd; return 0; } int __pmSecureServerIPCFlags(int fd, int flags) { (void)fd; (void)flags; return -EOPNOTSUPP; } void __pmSecureServerShutdown(void) { /* nothing to do here */ } int __pmSecureServerHandshake(int fd, int flags, __pmHashCtl *attrs) { (void)fd; (void)flags; (void)attrs; return -EOPNOTSUPP; } int __pmSecureServerHasFeature(__pmServerFeature query) { (void)query; return 0; } int __pmSecureServerSetFeature(__pmServerFeature wanted) { (void)wanted; return 0; } int __pmSecureServerClearFeature(__pmServerFeature clear) { (void)clear; return 0; } #endif /* !HAVE_SECURE_SOCKETS */ static unsigned int server_features; int __pmServerClearFeature(__pmServerFeature clear) { if (clear == PM_SERVER_FEATURE_DISCOVERY) { server_features &= ~(1<c_lock. We should not unlock the context, that is the * responsibility of our callers. * * derive_errmsg needs to be thread-private */ #include #include #include #include "pmapi.h" #include "impl.h" #include "internal.h" #include "fault.h" #ifdef IS_MINGW extern const char *strerror_r(int, char *, size_t); #endif static int need_init = 1; static ctl_t registered = { #ifdef PM_MULTI_THREAD #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, #else PTHREAD_MUTEX_INITIALIZER, #endif #endif 0, NULL, 0, 0 }; /* parser and lexer variables */ static char *tokbuf = NULL; static int tokbuflen; static const char *this; /* start of current lexicon */ static int lexpeek = 0; static const char *string; #ifdef PM_MULTI_THREAD #ifdef HAVE___THREAD /* using a gcc construct here to make derive_errmsg thread-private */ static __thread char *derive_errmsg; #endif #else static char *derive_errmsg; #endif static const char *type_dbg[] = { "ERROR", "EOF", "UNDEF", "NUMBER", "NAME", "PLUS", "MINUS", "STAR", "SLASH", "LPAREN", "RPAREN", "AVG", "COUNT", "DELTA", "MAX", "MIN", "SUM", "ANON" }; static const char type_c[] = { '\0', '\0', '\0', '\0', '\0', '+', '-', '*', '/', '(', ')', '\0' }; /* function table for lexer */ static const struct { int f_type; char *f_name; } func[] = { { L_AVG, "avg" }, { L_COUNT, "count" }, { L_DELTA, "delta" }, { L_MAX, "max" }, { L_MIN, "min" }, { L_SUM, "sum" }, { L_ANON, "anon" }, { L_UNDEF, NULL } }; /* parser states */ #define P_INIT 0 #define P_LEAF 1 #define P_LEAF_PAREN 2 #define P_BINOP 3 #define P_FUNC_OP 4 #define P_FUNC_END 5 #define P_END 99 static const char *state_dbg[] = { "INIT", "LEAF", "LEAF_PAREN", "BINOP", "FUNC_OP", "FUNC_END" }; #ifdef PM_MULTI_THREAD #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP static void initialize_mutex(void) { static pthread_mutex_t init = PTHREAD_MUTEX_INITIALIZER; static int done = 0; int psts; char errmsg[PM_MAXERRMSGLEN]; if ((psts = pthread_mutex_lock(&init)) != 0) { strerror_r(psts, errmsg, sizeof(errmsg)); fprintf(stderr, "initializ_mutex: pthread_mutex_lock failed: %s", errmsg); exit(4); } if (!done) { /* * Unable to initialize at compile time, need to do it here in * a one trip for all threads run-time initialization. */ pthread_mutexattr_t attr; if ((psts = pthread_mutexattr_init(&attr)) != 0) { strerror_r(psts, errmsg, sizeof(errmsg)); fprintf(stderr, "initialize_mutex: pthread_mutexattr_init failed: %s", errmsg); exit(4); } if ((psts = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) != 0) { strerror_r(psts, errmsg, sizeof(errmsg)); fprintf(stderr, "initialize_mutex: pthread_mutexattr_settype failed: %s", errmsg); exit(4); } if ((psts = pthread_mutex_init(®istered.mutex, &attr)) != 0) { strerror_r(psts, errmsg, sizeof(errmsg)); fprintf(stderr, "initialize_mutex: pthread_mutex_init failed: %s", errmsg); exit(4); } done = 1; } if ((psts = pthread_mutex_unlock(&init)) != 0) { strerror_r(psts, errmsg, sizeof(errmsg)); fprintf(stderr, "initialize_mutex: pthread_mutex_unlock failed: %s", errmsg); exit(4); } } #endif #endif /* Register an anonymous metric */ int __pmRegisterAnon(const char *name, int type) { char *msg; char buf[21]; /* anon(PM_TYPE_XXXXXX) */ PM_FAULT_CHECK(PM_FAULT_PMAPI); switch (type) { case PM_TYPE_32: snprintf(buf, sizeof(buf), "anon(PM_TYPE_32)"); break; case PM_TYPE_U32: snprintf(buf, sizeof(buf), "anon(PM_TYPE_U32)"); break; case PM_TYPE_64: snprintf(buf, sizeof(buf), "anon(PM_TYPE_64)"); break; case PM_TYPE_U64: snprintf(buf, sizeof(buf), "anon(PM_TYPE_U64)"); break; case PM_TYPE_FLOAT: snprintf(buf, sizeof(buf), "anon(PM_TYPE_FLOAT)"); break; case PM_TYPE_DOUBLE: snprintf(buf, sizeof(buf), "anon(PM_TYPE_DOUBLE)"); break; default: return PM_ERR_TYPE; } if ((msg = pmRegisterDerived(name, buf)) != NULL) { pmprintf("__pmRegisterAnon(%s, %d): @ \"%s\" Error: %s\n", name, type, msg, pmDerivedErrStr()); pmflush(); return PM_ERR_GENERIC; } return 0; } static void init(void) { if (need_init) { char *configpath; if ((configpath = getenv("PCP_DERIVED_CONFIG")) != NULL) { int sts; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { fprintf(stderr, "Derived metric initialization from $PCP_DERIVED_CONFIG\n"); } #endif sts = pmLoadDerivedConfig(configpath); #ifdef PCP_DEBUG if (sts < 0 && (pmDebug & DBG_TRACE_DERIVE)) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "pmLoadDerivedConfig -> %s\n", pmErrStr_r(sts, errmsg, sizeof(errmsg))); } #endif } need_init = 0; } } static void unget(int c) { lexpeek = c; } static int get() { int c; if (lexpeek != 0) { c = lexpeek; lexpeek = 0; return c; } c = *string; if (c == '\0') { return L_EOF; } string++; return c; } static int lex(void) { int c; char *p = tokbuf; int ltype = L_UNDEF; int i; int firstch = 1; for ( ; ; ) { c = get(); if (firstch) { if (isspace((int)c)) continue; this = &string[-1]; firstch = 0; } if (c == L_EOF) { if (ltype != L_UNDEF) { /* force end of last token */ c = 0; } else { /* really the end of the input */ return L_EOF; } } if (p == NULL) { tokbuflen = 128; if ((p = tokbuf = (char *)malloc(tokbuflen)) == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("pmRegisterDerived: alloc tokbuf", tokbuflen, PM_FATAL_ERR); /*NOTREACHED*/ } } else if (p >= &tokbuf[tokbuflen]) { int x = p - tokbuf; tokbuflen *= 2; if ((tokbuf = (char *)realloc(tokbuf, tokbuflen)) == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("pmRegisterDerived: realloc tokbuf", tokbuflen, PM_FATAL_ERR); /*NOTREACHED*/ } p = &tokbuf[x]; } *p++ = (char)c; if (ltype == L_UNDEF) { if (isdigit((int)c)) ltype = L_NUMBER; else if (isalpha((int)c)) ltype = L_NAME; else { switch (c) { case '+': *p = '\0'; return L_PLUS; break; case '-': *p = '\0'; return L_MINUS; break; case '*': *p = '\0'; return L_STAR; break; case '/': *p = '\0'; return L_SLASH; break; case '(': *p = '\0'; return L_LPAREN; break; case ')': *p = '\0'; return L_RPAREN; break; default: return L_ERROR; break; } } } else { if (ltype == L_NUMBER) { if (!isdigit((int)c)) { unget(c); p[-1] = '\0'; return L_NUMBER; } } else if (ltype == L_NAME) { if (isalpha((int)c) || isdigit((int)c) || c == '_' || c == '.') continue; if (c == '(') { /* check for functions ... */ int namelen = p - tokbuf - 1; for (i = 0; func[i].f_name != NULL; i++) { if (namelen == strlen(func[i].f_name) && strncmp(tokbuf, func[i].f_name, namelen) == 0) { *p = '\0'; return func[i].f_type; } } } /* current character is end of name */ unget(c); p[-1] = '\0'; return L_NAME; } } } } static node_t * newnode(int type) { node_t *np; np = (node_t *)malloc(sizeof(node_t)); if (np == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("pmRegisterDerived: newnode", sizeof(node_t), PM_FATAL_ERR); /*NOTREACHED*/ } np->type = type; np->save_last = 0; np->left = NULL; np->right = NULL; np->value = NULL; np->info = NULL; return np; } static void free_expr(node_t *np) { if (np == NULL) return; if (np->left != NULL) free_expr(np->left); if (np->right != NULL) free_expr(np->right); /* value is only allocated once for the static nodes */ if (np->info == NULL && np->value != NULL) free(np->value); if (np->info != NULL) free(np->info); free(np); } /* * copy a static expression tree to make the dynamic per context * expression tree and initialize the info block */ static node_t * bind_expr(int n, node_t *np) { node_t *new; assert(np != NULL); new = newnode(np->type); if (np->left != NULL) { if ((new->left = bind_expr(n, np->left)) == NULL) { /* error, reported deeper in the recursion, clean up */ free(new); return(NULL); } } if (np->right != NULL) { if ((new->right = bind_expr(n, np->right)) == NULL) { /* error, reported deeper in the recursion, clean up */ free(new); return(NULL); } } if ((new->info = (info_t *)malloc(sizeof(info_t))) == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("bind_expr: info block", sizeof(info_t), PM_FATAL_ERR); /*NOTREACHED*/ } new->info->pmid = PM_ID_NULL; new->info->numval = 0; new->info->mul_scale = new->info->div_scale = 1; new->info->ivlist = NULL; new->info->last_numval = 0; new->info->last_ivlist = NULL; /* need info to be non-null to protect copy of value in free_expr */ new->value = np->value; new->save_last = np->save_last; if (new->type == L_NAME) { int sts; sts = pmLookupName(1, &new->value, &new->info->pmid); if (sts < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "bind_expr: error: derived metric %s: operand: %s: %s\n", registered.mlist[n].name, new->value, pmErrStr_r(sts, errmsg, sizeof(errmsg))); } #endif free(new->info); free(new); return NULL; } sts = pmLookupDesc(new->info->pmid, &new->desc); if (sts < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { char strbuf[20]; char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "bind_expr: error: derived metric %s: operand (%s [%s]): %s\n", registered.mlist[n].name, new->value, pmIDStr_r(new->info->pmid, strbuf, sizeof(strbuf)), pmErrStr_r(sts, errmsg, sizeof(errmsg))); } #endif free(new->info); free(new); return NULL; } } else if (new->type == L_NUMBER) { new->desc = np->desc; } return new; } static void report_sem_error(char *name, node_t *np) { pmprintf("Semantic error: derived metric %s: ", name); switch (np->type) { case L_PLUS: case L_MINUS: case L_STAR: case L_SLASH: if (np->left->type == L_NUMBER || np->left->type == L_NAME) pmprintf("%s ", np->left->value); else pmprintf(" "); pmprintf("%c ", type_c[np->type+2]); if (np->right->type == L_NUMBER || np->right->type == L_NAME) pmprintf("%s", np->right->value); else pmprintf(""); break; case L_AVG: case L_COUNT: case L_DELTA: case L_MAX: case L_MIN: case L_SUM: case L_ANON: pmprintf("%s(%s)", type_dbg[np->type+2], np->left->value); break; default: /* should never get here ... */ if (np->type+2 >= 0 && np->type+2 < sizeof(type_dbg)/sizeof(type_dbg[0])) pmprintf("botch @ node type %s?", type_dbg[np->type+2]); else pmprintf("botch @ node type #%d?", np->type); break; } pmprintf(": %s\n", PM_TPD(derive_errmsg)); pmflush(); PM_TPD(derive_errmsg) = NULL; } /* type promotion */ static const int promote[6][6] = { { PM_TYPE_32, PM_TYPE_U32, PM_TYPE_64, PM_TYPE_U64, PM_TYPE_FLOAT, PM_TYPE_DOUBLE }, { PM_TYPE_U32, PM_TYPE_U32, PM_TYPE_64, PM_TYPE_U64, PM_TYPE_FLOAT, PM_TYPE_DOUBLE }, { PM_TYPE_64, PM_TYPE_64, PM_TYPE_64, PM_TYPE_U64, PM_TYPE_FLOAT, PM_TYPE_DOUBLE }, { PM_TYPE_U64, PM_TYPE_U64, PM_TYPE_U64, PM_TYPE_U64, PM_TYPE_FLOAT, PM_TYPE_DOUBLE }, { PM_TYPE_FLOAT, PM_TYPE_FLOAT, PM_TYPE_FLOAT, PM_TYPE_FLOAT, PM_TYPE_FLOAT, PM_TYPE_DOUBLE }, { PM_TYPE_DOUBLE, PM_TYPE_DOUBLE, PM_TYPE_DOUBLE, PM_TYPE_DOUBLE, PM_TYPE_DOUBLE, PM_TYPE_DOUBLE } }; /* time scale conversion factors */ static const int timefactor[] = { 1000, /* NSEC -> USEC */ 1000, /* USEC -> MSEC */ 1000, /* MSEC -> SEC */ 60, /* SEC -> MIN */ 60, /* MIN -> HOUR */ }; /* * mapping pmUnits for the result, and refining pmDesc as we go ... * we start with the pmDesc from the left operand and adjust as * necessary * * scale conversion rules ... * Count - choose larger, divide/multiply smaller by 10^(difference) * Time - choose larger, divide/multiply smaller by appropriate scale * Space - choose larger, divide/multiply smaller by 1024^(difference) * and result is of type PM_TYPE_DOUBLE * * Need inverted logic to deal with numerator (dimension > 0) and * denominator (dimension < 0) cases. */ static void map_units(node_t *np) { pmDesc *right = &np->right->desc; pmDesc *left = &np->left->desc; int diff; int i; if (left->units.dimCount != 0 && right->units.dimCount != 0) { diff = left->units.scaleCount - right->units.scaleCount; if (diff > 0) { /* use the left scaleCount, scale the right operand */ for (i = 0; i < diff; i++) { if (right->units.dimCount > 0) np->right->info->div_scale *= 10; else np->right->info->mul_scale *= 10; } np->desc.type = PM_TYPE_DOUBLE; } else if (diff < 0) { /* use the right scaleCount, scale the left operand */ np->desc.units.scaleCount = right->units.scaleCount; for (i = diff; i < 0; i++) { if (left->units.dimCount > 0) np->left->info->div_scale *= 10; else np->left->info->mul_scale *= 10; } np->desc.type = PM_TYPE_DOUBLE; } } if (left->units.dimTime != 0 && right->units.dimTime != 0) { diff = left->units.scaleTime - right->units.scaleTime; if (diff > 0) { /* use the left scaleTime, scale the right operand */ for (i = right->units.scaleTime; i < left->units.scaleTime; i++) { if (right->units.dimTime > 0) np->right->info->div_scale *= timefactor[i]; else np->right->info->mul_scale *= timefactor[i]; } np->desc.type = PM_TYPE_DOUBLE; } else if (diff < 0) { /* use the right scaleTime, scale the left operand */ np->desc.units.scaleTime = right->units.scaleTime; for (i = left->units.scaleTime; i < right->units.scaleTime; i++) { if (right->units.dimTime > 0) np->left->info->div_scale *= timefactor[i]; else np->left->info->mul_scale *= timefactor[i]; } np->desc.type = PM_TYPE_DOUBLE; } } if (left->units.dimSpace != 0 && right->units.dimSpace != 0) { diff = left->units.scaleSpace - right->units.scaleSpace; if (diff > 0) { /* use the left scaleSpace, scale the right operand */ for (i = 0; i < diff; i++) { if (right->units.dimSpace > 0) np->right->info->div_scale *= 1024; else np->right->info->mul_scale *= 1024; } np->desc.type = PM_TYPE_DOUBLE; } else if (diff < 0) { /* use the right scaleSpace, scale the left operand */ np->desc.units.scaleSpace = right->units.scaleSpace; for (i = diff; i < 0; i++) { if (right->units.dimSpace > 0) np->left->info->div_scale *= 1024; else np->left->info->mul_scale *= 1024; } np->desc.type = PM_TYPE_DOUBLE; } } if (np->type == L_STAR) { np->desc.units.dimCount = left->units.dimCount + right->units.dimCount; np->desc.units.dimTime = left->units.dimTime + right->units.dimTime; np->desc.units.dimSpace = left->units.dimSpace + right->units.dimSpace; } else if (np->type == L_SLASH) { np->desc.units.dimCount = left->units.dimCount - right->units.dimCount; np->desc.units.dimTime = left->units.dimTime - right->units.dimTime; np->desc.units.dimSpace = left->units.dimSpace - right->units.dimSpace; } /* * for division and multiplication, dimension may have come from * right operand, need to pick up scale from there also */ if (np->desc.units.dimCount != 0 && left->units.dimCount == 0) np->desc.units.scaleCount = right->units.scaleCount; if (np->desc.units.dimTime != 0 && left->units.dimTime == 0) np->desc.units.scaleTime = right->units.scaleTime; if (np->desc.units.dimSpace != 0 && left->units.dimSpace == 0) np->desc.units.scaleSpace = right->units.scaleSpace; } static int map_desc(int n, node_t *np) { /* * pmDesc mapping for binary operators ... * * semantics acceptable operators * counter, counter + - * non-counter, non-counter + - * / * counter, non-counter * / * non-counter, counter * * * in the non-counter and non-counter case, the semantics for the * result are PM_SEM_INSTANT, unless both operands are * PM_SEM_DISCRETE in which case the result is also PM_SEM_DISCRETE * * type promotion (similar to ANSI C) * PM_TYPE_STRING, PM_TYPE_AGGREGATE, PM_TYPE_AGGREGATE_STATIC * and PM_TYPE_EVENT are illegal operands except for renaming * (where no operator is involved) * for all operands, division => PM_TYPE_DOUBLE * else PM_TYPE_DOUBLE & any type => PM_TYPE_DOUBLE * else PM_TYPE_FLOAT & any type => PM_TYPE_FLOAT * else PM_TYPE_U64 & any type => PM_TYPE_U64 * else PM_TYPE_64 & any type => PM_TYPE_64 * else PM_TYPE_U32 & any type => PM_TYPE_U32 * else PM_TYPE_32 & any type => PM_TYPE_32 * * units mapping * operator checks * +, - same dimension * *, / if only one is a counter, non-counter must * have pmUnits of "none" */ pmDesc *right = &np->right->desc; pmDesc *left = &np->left->desc; if (left->sem == PM_SEM_COUNTER) { if (right->sem == PM_SEM_COUNTER) { if (np->type != L_PLUS && np->type != L_MINUS) { PM_TPD(derive_errmsg) = "Illegal operator for counters"; goto bad; } } else { if (np->type != L_STAR && np->type != L_SLASH) { PM_TPD(derive_errmsg) = "Illegal operator for counter and non-counter"; goto bad; } } } else { if (right->sem == PM_SEM_COUNTER) { if (np->type != L_STAR) { PM_TPD(derive_errmsg) = "Illegal operator for non-counter and counter"; goto bad; } } else { if (np->type != L_PLUS && np->type != L_MINUS && np->type != L_STAR && np->type != L_SLASH) { /* * this is not possible at the present since only * arithmetic operators are supported and all are * acceptable here ... check added for completeness */ PM_TPD(derive_errmsg) = "Illegal operator for non-counters"; goto bad; } } } /* * Choose candidate descriptor ... prefer metric or expression * over constant */ if (np->left->type != L_NUMBER) np->desc = *left; /* struct copy */ else np->desc = *right; /* struct copy */ /* * most non-counter expressions produce PM_SEM_INSTANT results */ if (left->sem != PM_SEM_COUNTER && right->sem != PM_SEM_COUNTER) { if (left->sem == PM_SEM_DISCRETE && right->sem == PM_SEM_DISCRETE) np->desc.sem = PM_SEM_DISCRETE; else np->desc.sem = PM_SEM_INSTANT; } /* * type checking and promotion */ switch (left->type) { case PM_TYPE_32: case PM_TYPE_U32: case PM_TYPE_64: case PM_TYPE_U64: case PM_TYPE_FLOAT: case PM_TYPE_DOUBLE: break; default: PM_TPD(derive_errmsg) = "Non-arithmetic type for left operand"; goto bad; } switch (right->type) { case PM_TYPE_32: case PM_TYPE_U32: case PM_TYPE_64: case PM_TYPE_U64: case PM_TYPE_FLOAT: case PM_TYPE_DOUBLE: break; default: PM_TPD(derive_errmsg) = "Non-arithmetic type for right operand"; goto bad; } np->desc.type = promote[left->type][right->type]; if (np->type == L_SLASH) { /* for division result is real number */ np->desc.type = PM_TYPE_DOUBLE; } if (np->type == L_PLUS || np->type == L_MINUS) { /* * unit dimensions have to be identical */ if (left->units.dimCount != right->units.dimCount || left->units.dimTime != right->units.dimTime || left->units.dimSpace != right->units.dimSpace) { PM_TPD(derive_errmsg) = "Dimensions are not the same"; goto bad; } map_units(np); } if (np->type == L_STAR || np->type == L_SLASH) { /* * if multiply or divide and operands are a counter and a non-counter, * then non-counter needs to be dimensionless */ if (left->sem == PM_SEM_COUNTER && right->sem != PM_SEM_COUNTER) { if (right->units.dimCount != 0 || right->units.dimTime != 0 || right->units.dimSpace != 0) { PM_TPD(derive_errmsg) = "Non-counter and not dimensionless for right operand"; goto bad; } } if (left->sem != PM_SEM_COUNTER && right->sem == PM_SEM_COUNTER) { if (left->units.dimCount != 0 || left->units.dimTime != 0 || left->units.dimSpace != 0) { PM_TPD(derive_errmsg) = "Non-counter and not dimensionless for left operand"; goto bad; } } map_units(np); } /* * if not both singular, then both operands must have the same * instance domain */ if (left->indom != PM_INDOM_NULL && right->indom != PM_INDOM_NULL && left->indom != right->indom) { PM_TPD(derive_errmsg) = "Operands should have the same instance domain"; goto bad; } return 0; bad: report_sem_error(registered.mlist[n].name, np); return -1; } static int check_expr(int n, node_t *np) { int sts; assert(np != NULL); if (np->type == L_NUMBER || np->type == L_NAME) return 0; /* otherwise, np->left is never NULL ... */ assert(np->left != NULL); if ((sts = check_expr(n, np->left)) < 0) return sts; if (np->right != NULL) { if ((sts = check_expr(n, np->right)) < 0) return sts; /* build pmDesc from pmDesc of both operands */ if ((sts = map_desc(n, np)) < 0) return sts; } else { np->desc = np->left->desc; /* struct copy */ /* * special cases for functions ... * delta expect numeric operand, result is instantaneous * aggr funcs most expect numeric operand, result is instantaneous * and singular */ if (np->type == L_AVG || np->type == L_COUNT || np->type == L_DELTA || np->type == L_MAX || np->type == L_MIN || np->type == L_SUM) { if (np->type == L_COUNT) { /* count() has its own type and units */ np->desc.type = PM_TYPE_U32; memset((void *)&np->desc.units, 0, sizeof(np->desc.units)); np->desc.units.dimCount = 1; np->desc.units.scaleCount = PM_COUNT_ONE; } else { /* others inherit, but need arithmetic operand */ switch (np->left->desc.type) { case PM_TYPE_32: case PM_TYPE_U32: case PM_TYPE_64: case PM_TYPE_U64: case PM_TYPE_FLOAT: case PM_TYPE_DOUBLE: break; default: PM_TPD(derive_errmsg) = "Non-arithmetic operand for function"; report_sem_error(registered.mlist[n].name, np); return -1; } } np->desc.sem = PM_SEM_INSTANT; if (np->type != L_DELTA) /* all the others are aggregate funcs with a singular value */ np->desc.indom = PM_INDOM_NULL; if (np->type == L_AVG) { /* avg() returns float result */ np->desc.type = PM_TYPE_FLOAT; } } else if (np->type == L_ANON) { /* do nothing, pmDesc inherited "as is" from left node */ ; } } return 0; } static void dump_value(int type, pmAtomValue *avp) { switch (type) { case PM_TYPE_32: fprintf(stderr, "%i", avp->l); break; case PM_TYPE_U32: fprintf(stderr, "%u", avp->ul); break; case PM_TYPE_64: fprintf(stderr, "%" PRId64, avp->ll); break; case PM_TYPE_U64: fprintf(stderr, "%" PRIu64, avp->ull); break; case PM_TYPE_FLOAT: fprintf(stderr, "%g", (double)avp->f); break; case PM_TYPE_DOUBLE: fprintf(stderr, "%g", avp->d); break; case PM_TYPE_STRING: fprintf(stderr, "%s", avp->cp); break; case PM_TYPE_AGGREGATE: case PM_TYPE_AGGREGATE_STATIC: case PM_TYPE_EVENT: case PM_TYPE_UNKNOWN: fprintf(stderr, "[blob]"); break; case PM_TYPE_NOSUPPORT: fprintf(stderr, "dump_value: bogus value, metric Not Supported\n"); break; default: fprintf(stderr, "dump_value: unknown value type=%d\n", type); } } void __dmdumpexpr(node_t *np, int level) { char strbuf[20]; if (level == 0) fprintf(stderr, "Derived metric expr dump from " PRINTF_P_PFX "%p...\n", np); if (np == NULL) return; fprintf(stderr, "expr node " PRINTF_P_PFX "%p type=%s left=" PRINTF_P_PFX "%p right=" PRINTF_P_PFX "%p save_last=%d", np, type_dbg[np->type+2], np->left, np->right, np->save_last); if (np->type == L_NAME || np->type == L_NUMBER) fprintf(stderr, " [%s] master=%d", np->value, np->info == NULL ? 1 : 0); fputc('\n', stderr); if (np->info) { fprintf(stderr, " PMID: %s ", pmIDStr_r(np->info->pmid, strbuf, sizeof(strbuf))); fprintf(stderr, "(%s from pmDesc) numval: %d", pmIDStr_r(np->desc.pmid, strbuf, sizeof(strbuf)), np->info->numval); if (np->info->div_scale != 1) fprintf(stderr, " div_scale: %d", np->info->div_scale); if (np->info->mul_scale != 1) fprintf(stderr, " mul_scale: %d", np->info->mul_scale); fputc('\n', stderr); __pmPrintDesc(stderr, &np->desc); if (np->info->ivlist) { int j; int max; max = np->info->numval > np->info->last_numval ? np->info->numval : np->info->last_numval; for (j = 0; j < max; j++) { fprintf(stderr, "[%d]", j); if (j < np->info->numval) { fprintf(stderr, " inst=%d, val=", np->info->ivlist[j].inst); dump_value(np->desc.type, &np->info->ivlist[j].value); } if (j < np->info->last_numval) { fprintf(stderr, " (last inst=%d, val=", np->info->last_ivlist[j].inst); dump_value(np->desc.type, &np->info->last_ivlist[j].value); fputc(')', stderr); } fputc('\n', stderr); } } } if (np->left != NULL) __dmdumpexpr(np->left, level+1); if (np->right != NULL) __dmdumpexpr(np->right, level+1); } /* * Parser FSA * state lex new state * P_INIT L_NAME or P_LEAF * L_NUMBER * P_INIT L_ P_FUNC_OP * P_INIT L_LPAREN if parse() != NULL then P_LEAF * P_LEAF L_PLUS or P_BINOP * L_MINUS or * L_STAR or * L_SLASH * P_BINOP L_NAME or P_LEAF * L_NUMBER * P_BINOP L_LPAREN if parse() != NULL then P_LEAF * P_BINOP L_ P_FUNC_OP * P_LEAF_PAREN same as P_LEAF, but no precedence rules at next operator * P_FUNC_OP L_NAME P_FUNC_END * P_FUNC_END L_RPAREN P_LEAF */ static node_t * parse(int level) { int state = P_INIT; int type; node_t *expr = NULL; node_t *curr = NULL; node_t *np; for ( ; ; ) { type = lex(); #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL0)) { fprintf(stderr, "parse(%d) state=P_%s type=L_%s \"%s\"\n", level, state_dbg[state], type_dbg[type+2], type == L_EOF ? "" : tokbuf); } #endif /* handle lexicons that terminate the parsing */ switch (type) { case L_ERROR: PM_TPD(derive_errmsg) = "Illegal character"; free_expr(expr); return NULL; break; case L_EOF: if (level == 1 && (state == P_LEAF || state == P_LEAF_PAREN)) return expr; PM_TPD(derive_errmsg) = "End of input"; free_expr(expr); return NULL; break; case L_RPAREN: if (state == P_FUNC_END) { state = P_LEAF; continue; } if ((level > 1 && state == P_LEAF_PAREN) || state == P_LEAF) return expr; PM_TPD(derive_errmsg) = "Unexpected ')'"; free_expr(expr); return NULL; break; } switch (state) { case P_INIT: /* * Only come here at the start of parsing an expression. * The assert() is designed to stop Coverity flagging a * memory leak if we should come here after expr and/or * curr have already been assigned values either directly * from calling newnode() or via an assignment to np that * was previously assigned a value from newnode() */ assert(expr == NULL && curr == NULL); if (type == L_NAME || type == L_NUMBER) { expr = curr = newnode(type); if ((curr->value = strdup(tokbuf)) == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("pmRegisterDerived: leaf node", strlen(tokbuf)+1, PM_FATAL_ERR); /*NOTREACHED*/ } if (type == L_NUMBER) { char *endptr; __uint64_t check; check = strtoull(tokbuf, &endptr, 10); if (*endptr != '\0' || check > 0xffffffffUL) { PM_TPD(derive_errmsg) = "Constant value too large"; free_expr(expr); return NULL; } curr->desc.pmid = PM_ID_NULL; curr->desc.type = PM_TYPE_U32; curr->desc.indom = PM_INDOM_NULL; curr->desc.sem = PM_SEM_DISCRETE; memset(&curr->desc.units, 0, sizeof(pmUnits)); } state = P_LEAF; } else if (type == L_LPAREN) { expr = curr = parse(level+1); if (expr == NULL) return NULL; state = P_LEAF_PAREN; } else if (type == L_AVG || type == L_COUNT || type == L_DELTA || type == L_MAX || type == L_MIN || type == L_SUM || type == L_ANON) { expr = curr = newnode(type); state = P_FUNC_OP; } else { free_expr(expr); return NULL; } break; case P_LEAF_PAREN: /* fall through */ case P_LEAF: if (type == L_PLUS || type == L_MINUS || type == L_STAR || type == L_SLASH) { np = newnode(type); if (state == P_LEAF_PAREN || curr->type == L_NAME || curr->type == L_NUMBER || curr->type == L_AVG || curr->type == L_COUNT || curr->type == L_DELTA || curr->type == L_MAX || curr->type == L_MIN || curr->type == L_SUM || curr->type == L_ANON || type == L_PLUS || type == L_MINUS) { /* * first operator or equal or lower precedence * make new root of tree and push previous * expr down left descendent branch */ np->left = curr; expr = curr = np; } else { /* * push previous right branch down one level */ np->left = curr->right; curr->right = np; curr = np; } state = P_BINOP; } else { free_expr(expr); return NULL; } break; case P_BINOP: if (type == L_NAME || type == L_NUMBER) { np = newnode(type); if ((np->value = strdup(tokbuf)) == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("pmRegisterDerived: leaf node", strlen(tokbuf)+1, PM_FATAL_ERR); /*NOTREACHED*/ } if (type == L_NUMBER) { np->desc.pmid = PM_ID_NULL; np->desc.type = PM_TYPE_U32; np->desc.indom = PM_INDOM_NULL; np->desc.sem = PM_SEM_DISCRETE; memset(&np->desc.units, 0, sizeof(pmUnits)); } curr->right = np; curr = expr; state = P_LEAF; } else if (type == L_LPAREN) { np = parse(level+1); if (np == NULL) return NULL; curr->right = np; state = P_LEAF_PAREN; } else if (type == L_AVG || type == L_COUNT || type == L_DELTA || type == L_MAX || type == L_MIN || type == L_SUM || type == L_ANON) { np = newnode(type); curr->right = np; curr = np; state = P_FUNC_OP; } else { free_expr(expr); return NULL; } break; case P_FUNC_OP: if (type == L_NAME) { np = newnode(type); if ((np->value = strdup(tokbuf)) == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("pmRegisterDerived: func op node", strlen(tokbuf)+1, PM_FATAL_ERR); /*NOTREACHED*/ } np->save_last = 1; if (curr->type == L_ANON) { /* * anon(PM_TYPE_...) is a special case ... the * argument defines the metric type, the remainder * of the metadata is fixed and there are never any * values available. So we build the pmDesc and then * clobber the "left" node and prevent any attempt to * contact a PMDA for metadata or values */ if (strcmp(np->value, "PM_TYPE_32") == 0) np->desc.type = PM_TYPE_32; else if (strcmp(np->value, "PM_TYPE_U32") == 0) np->desc.type = PM_TYPE_U32; else if (strcmp(np->value, "PM_TYPE_64") == 0) np->desc.type = PM_TYPE_64; else if (strcmp(np->value, "PM_TYPE_U64") == 0) np->desc.type = PM_TYPE_U64; else if (strcmp(np->value, "PM_TYPE_FLOAT") == 0) np->desc.type = PM_TYPE_FLOAT; else if (strcmp(np->value, "PM_TYPE_DOUBLE") == 0) np->desc.type = PM_TYPE_DOUBLE; else { fprintf(stderr, "Error: type=%s not allowed for anon()\n", np->value); free_expr(np); return NULL; } np->desc.pmid = PM_ID_NULL; np->desc.indom = PM_INDOM_NULL; np->desc.sem = PM_SEM_DISCRETE; memset((void *)&np->desc.units, 0, sizeof(np->desc.units)); np->type = L_NUMBER; } curr->left = np; curr = expr; state = P_FUNC_END; } else { free_expr(expr); return NULL; } break; default: free_expr(expr); return NULL; } } } static int checkname(char *p) { int firstch = 1; for ( ; *p; p++) { if (firstch) { firstch = 0; if (isalpha((int)*p)) continue; return -1; } else { if (isalpha((int)*p) || isdigit((int)*p) || *p == '_') continue; if (*p == '.') { firstch = 1; continue; } return -1; } } return 0; } char * pmRegisterDerived(const char *name, const char *expr) { node_t *np; static __pmID_int pmid; int i; PM_INIT_LOCKS(); #ifdef PM_MULTI_THREAD #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP initialize_mutex(); #endif #endif PM_LOCK(registered.mutex); #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL0)) { fprintf(stderr, "pmRegisterDerived: name=\"%s\" expr=\"%s\"\n", name, expr); } #endif for (i = 0; i < registered.nmetric; i++) { if (strcmp(name, registered.mlist[i].name) == 0) { /* oops, duplicate name ... */ PM_TPD(derive_errmsg) = "Duplicate derived metric name"; PM_UNLOCK(registered.mutex); return (char *)expr; } } PM_TPD(derive_errmsg) = NULL; string = expr; np = parse(1); if (np == NULL) { /* parser error */ char *sts = (char *)this; PM_UNLOCK(registered.mutex); return sts; } registered.nmetric++; registered.mlist = (dm_t *)realloc(registered.mlist, registered.nmetric*sizeof(dm_t)); if (registered.mlist == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("pmRegisterDerived: registered mlist", registered.nmetric*sizeof(dm_t), PM_FATAL_ERR); /*NOTREACHED*/ } if (registered.nmetric == 1) { pmid.flag = 0; pmid.domain = DYNAMIC_PMID; pmid.cluster = 0; } registered.mlist[registered.nmetric-1].name = strdup(name); pmid.item = registered.nmetric; registered.mlist[registered.nmetric-1].pmid = *((pmID *)&pmid); registered.mlist[registered.nmetric-1].expr = np; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { fprintf(stderr, "pmRegisterDerived: register metric[%d] %s = %s\n", registered.nmetric-1, name, expr); if (pmDebug & DBG_TRACE_APPL0) __dmdumpexpr(np, 0); } #endif PM_UNLOCK(registered.mutex); return NULL; } int pmLoadDerivedConfig(const char *fname) { FILE *fp; int buflen; char *buf; char *p; int c; int sts = 0; int eq = -1; int lineno = 1; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { fprintf(stderr, "pmLoadDerivedConfig(\"%s\")\n", fname); } #endif if ((fp = fopen(fname, "r")) == NULL) { return -oserror(); } buflen = 128; if ((buf = (char *)malloc(buflen)) == NULL) { /* registered.mutex not locked in this case */ __pmNoMem("pmLoadDerivedConfig: alloc buf", buflen, PM_FATAL_ERR); /*NOTREACHED*/ } p = buf; while ((c = fgetc(fp)) != EOF) { if (p == &buf[buflen]) { if ((buf = (char *)realloc(buf, 2*buflen)) == NULL) { /* registered.mutex not locked in this case */ __pmNoMem("pmLoadDerivedConfig: expand buf", 2*buflen, PM_FATAL_ERR); /*NOTREACHED*/ } p = &buf[buflen]; buflen *= 2; } if (c == '=' && eq == -1) { /* * mark first = in line ... metric name to the left and * expression to the right */ eq = p - buf; } if (c == '\n') { if (p == buf || buf[0] == '#') { /* comment or empty line, skip it ... */ goto next_line; } *p = '\0'; if (eq != -1) { char *np; /* copy of name */ char *ep; /* start of expression */ char *q; char *errp; buf[eq] = '\0'; if ((np = strdup(buf)) == NULL) { /* registered.mutex not locked in this case */ __pmNoMem("pmLoadDerivedConfig: dupname", strlen(buf), PM_FATAL_ERR); /*NOTREACHED*/ } /* trim white space from tail of metric name */ q = &np[eq-1]; while (q >= np && isspace((int)*q)) *q-- = '\0'; /* trim white space from head of metric name */ q = np; while (*q && isspace((int)*q)) q++; if (*q == '\0') { buf[eq] = '='; pmprintf("[%s:%d] Error: pmLoadDerivedConfig: derived metric name missing\n%s\n", fname, lineno, buf); pmflush(); free(np); goto next_line; } if (checkname(q) < 0) { pmprintf("[%s:%d] Error: pmLoadDerivedConfig: illegal derived metric name (%s)\n", fname, lineno, q); pmflush(); free(np); goto next_line; } ep = &buf[eq+1]; while (*ep != '\0' && isspace((int)*ep)) ep++; if (*ep == '\0') { buf[eq] = '='; pmprintf("[%s:%d] Error: pmLoadDerivedConfig: expression missing\n%s\n", fname, lineno, buf); pmflush(); free(np); goto next_line; } errp = pmRegisterDerived(q, ep); if (errp != NULL) { pmprintf("[%s:%d] Error: pmRegisterDerived(%s, ...) syntax error\n", fname, lineno, q); pmprintf("%s\n", &buf[eq+1]); for (q = &buf[eq+1]; *q; q++) { if (q == errp) *q = '^'; else if (!isspace((int)*q)) *q = ' '; } pmprintf("%s\n", &buf[eq+1]); q = pmDerivedErrStr(); if (q != NULL) pmprintf("%s\n", q); pmflush(); } else sts++; free(np); } else { /* * error ... no = in the line, so no derived metric name */ pmprintf("[%s:%d] Error: pmLoadDerivedConfig: missing ``='' after derived metric name\n%s\n", fname, lineno, buf); pmflush(); } next_line: lineno++; p = buf; eq = -1; } else *p++ = c; } fclose(fp); free(buf); return sts; } char * pmDerivedErrStr(void) { PM_INIT_LOCKS(); return PM_TPD(derive_errmsg); } /* * callbacks */ int __dmtraverse(const char *name, char ***namelist) { int sts = 0; int i; char **list = NULL; int matchlen = strlen(name); #ifdef PM_MULTI_THREAD #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP initialize_mutex(); #endif #endif PM_LOCK(registered.mutex); init(); for (i = 0; i < registered.nmetric; i++) { /* * prefix match ... if name is "", then all names match */ if (matchlen == 0 || (strncmp(name, registered.mlist[i].name, matchlen) == 0 && (registered.mlist[i].name[matchlen] == '.' || registered.mlist[i].name[matchlen] == '\0'))) { sts++; if ((list = (char **)realloc(list, sts*sizeof(list[0]))) == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("__dmtraverse: list", sts*sizeof(list[0]), PM_FATAL_ERR); /*NOTREACHED*/ } list[sts-1] = registered.mlist[i].name; } } *namelist = list; PM_UNLOCK(registered.mutex); return sts; } int __dmchildren(const char *name, char ***offspring, int **statuslist) { int sts = 0; int i; int j; char **children = NULL; int *status = NULL; int matchlen = strlen(name); int start; int len; #ifdef PM_MULTI_THREAD #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP initialize_mutex(); #endif #endif PM_LOCK(registered.mutex); init(); for (i = 0; i < registered.nmetric; i++) { /* * prefix match ... pick off the unique next level names on match */ if (name[0] == '\0' || (strncmp(name, registered.mlist[i].name, matchlen) == 0 && (registered.mlist[i].name[matchlen] == '.' || registered.mlist[i].name[matchlen] == '\0'))) { if (registered.mlist[i].name[matchlen] == '\0') { /* * leaf node * assert is for coverity, name uniqueness means we * should only ever come here after zero passes through * the block below where sts is incremented and children[] * and status[] are realloc'd */ assert(sts == 0 && children == NULL && status == NULL); PM_UNLOCK(registered.mutex); return 0; } start = matchlen > 0 ? matchlen + 1 : 0; for (j = 0; j < sts; j++) { len = strlen(children[j]); if (strncmp(®istered.mlist[i].name[start], children[j], len) == 0 && registered.mlist[i].name[start+len] == '.') break; } if (j == sts) { /* first time for this one */ sts++; if ((children = (char **)realloc(children, sts*sizeof(children[0]))) == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("__dmchildren: children", sts*sizeof(children[0]), PM_FATAL_ERR); /*NOTREACHED*/ } for (len = 0; registered.mlist[i].name[start+len] != '\0' && registered.mlist[i].name[start+len] != '.'; len++) ; if ((children[sts-1] = (char *)malloc(len+1)) == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("__dmchildren: name", len+1, PM_FATAL_ERR); /*NOTREACHED*/ } strncpy(children[sts-1], ®istered.mlist[i].name[start], len); children[sts-1][len] = '\0'; #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL1)) { fprintf(stderr, "__dmchildren: offspring[%d] %s", sts-1, children[sts-1]); } #endif if (statuslist != NULL) { if ((status = (int *)realloc(status, sts*sizeof(status[0]))) == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("__dmchildren: statrus", sts*sizeof(status[0]), PM_FATAL_ERR); /*NOTREACHED*/ } status[sts-1] = registered.mlist[i].name[start+len] == '\0' ? PMNS_LEAF_STATUS : PMNS_NONLEAF_STATUS; #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL1)) { fprintf(stderr, " (status=%d)", status[sts-1]); } #endif } #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL1)) { fputc('\n', stderr); } #endif } } } if (sts == 0) { PM_UNLOCK(registered.mutex); return PM_ERR_NAME; } *offspring = children; if (statuslist != NULL) *statuslist = status; PM_UNLOCK(registered.mutex); return sts; } int __dmgetpmid(const char *name, pmID *dp) { int i; #ifdef PM_MULTI_THREAD #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP initialize_mutex(); #endif #endif PM_LOCK(registered.mutex); init(); for (i = 0; i < registered.nmetric; i++) { if (strcmp(name, registered.mlist[i].name) == 0) { *dp = registered.mlist[i].pmid; PM_UNLOCK(registered.mutex); return 0; } } PM_UNLOCK(registered.mutex); return PM_ERR_NAME; } int __dmgetname(pmID pmid, char ** name) { int i; #ifdef PM_MULTI_THREAD #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP initialize_mutex(); #endif #endif PM_LOCK(registered.mutex); init(); for (i = 0; i < registered.nmetric; i++) { if (pmid == registered.mlist[i].pmid) { *name = strdup(registered.mlist[i].name); if (*name == NULL) { PM_UNLOCK(registered.mutex); return -oserror(); } else { PM_UNLOCK(registered.mutex); return 0; } } } PM_UNLOCK(registered.mutex); return PM_ERR_PMID; } void __dmopencontext(__pmContext *ctxp) { int i; int sts; ctl_t *cp; #ifdef PM_MULTI_THREAD #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP initialize_mutex(); #endif #endif PM_LOCK(registered.mutex); init(); #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL1)) { fprintf(stderr, "__dmopencontext(->ctx %d) called\n", __pmPtrToHandle(ctxp)); } #endif if (registered.nmetric == 0) { ctxp->c_dm = NULL; PM_UNLOCK(registered.mutex); return; } if ((cp = (void *)malloc(sizeof(ctl_t))) == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("pmNewContext: derived metrics (ctl)", sizeof(ctl_t), PM_FATAL_ERR); /* NOTREACHED */ } ctxp->c_dm = (void *)cp; cp->nmetric = registered.nmetric; if ((cp->mlist = (dm_t *)malloc(cp->nmetric*sizeof(dm_t))) == NULL) { PM_UNLOCK(registered.mutex); __pmNoMem("pmNewContext: derived metrics (mlist)", cp->nmetric*sizeof(dm_t), PM_FATAL_ERR); /* NOTREACHED */ } for (i = 0; i < cp->nmetric; i++) { cp->mlist[i].name = registered.mlist[i].name; cp->mlist[i].pmid = registered.mlist[i].pmid; assert(registered.mlist[i].expr != NULL); /* failures must be reported in bind_expr() or below */ cp->mlist[i].expr = bind_expr(i, registered.mlist[i].expr); if (cp->mlist[i].expr != NULL) { /* failures must be reported in check_expr() or below */ sts = check_expr(i, cp->mlist[i].expr); if (sts < 0) { free_expr(cp->mlist[i].expr); cp->mlist[i].expr = NULL; } else { /* set correct PMID in pmDesc at the top level */ cp->mlist[i].expr->desc.pmid = cp->mlist[i].pmid; } } #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && cp->mlist[i].expr != NULL) { fprintf(stderr, "__dmopencontext: bind metric[%d] %s\n", i, registered.mlist[i].name); if (pmDebug & DBG_TRACE_APPL1) __dmdumpexpr(cp->mlist[i].expr, 0); } #endif } PM_UNLOCK(registered.mutex); } void __dmclosecontext(__pmContext *ctxp) { int i; ctl_t *cp = (ctl_t *)ctxp->c_dm; /* if needed, init() called in __dmopencontext beforehand */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { fprintf(stderr, "__dmclosecontext(->ctx %d) called dm->" PRINTF_P_PFX "%p %d metrics\n", __pmPtrToHandle(ctxp), cp, cp == NULL ? -1 : cp->nmetric); } #endif if (cp == NULL) return; for (i = 0; i < cp->nmetric; i++) { free_expr(cp->mlist[i].expr); } free(cp->mlist); free(cp); ctxp->c_dm = NULL; } int __dmdesc(__pmContext *ctxp, pmID pmid, pmDesc *desc) { int i; ctl_t *cp = (ctl_t *)ctxp->c_dm; /* if needed, init() called in __dmopencontext beforehand */ if (cp == NULL) return PM_ERR_PMID; for (i = 0; i < cp->nmetric; i++) { if (cp->mlist[i].pmid == pmid) { if (cp->mlist[i].expr == NULL) /* bind failed for some reason, reported earlier */ return PM_ERR_NAME; *desc = cp->mlist[i].expr->desc; return 0; } } return PM_ERR_PMID; } #ifdef PM_MULTI_THREAD #ifdef PM_MULTI_THREAD_DEBUG /* * return true if lock == registered.mutex ... no locking here to avoid * recursion ad nauseum */ int __pmIsDeriveLock(void *lock) { return lock == (void *)®istered.mutex; } #endif #endif pcp-3.8.12ubuntu1/src/libpcp/src/check-statics0000775000000000000000000003774712272262501016126 0ustar #!/bin/sh # # Check symbols for static variables against list of exceptions # that are known to be thread-safe # sts=0 tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1 trap "rm -rf $tmp; exit \$sts" 0 1 2 3 15 # Note # Really want to make this run on as many platforms as possible ... eval `grep PCP_PLATFORM= ../../include/pcp.conf` case "$PCP_PLATFORM" in linux|darwin) # only works for some architectures ... and in particular not # Power PC! # arch=`uname -m 2>/dev/null` [ "$arch" = "i686" -o "$arch" = "x86_64" ] || exit 0 ;; netbsd) ;; *) echo "Warning: check-statics skipped for PCP_PLATFORM=$PCP_PLATFORM" exit 0 ;; esac obj='' cat <$tmp/ctl # Format for the control file ... # All text after a # is treated as a comment # # Lines containing one word are assumed to be the name of an # object file ... if any object file is found in the current # directory that is not named in the control file, this is an # error. Object file names beginning with '?' are optional, # otherwise the object file is expected to exist. # # Following the name of an object file follows zero or more # lines defining static data symbols from that object file that is # known to be thread-safe ... these lines contain the symbol's type # as reported by nm(1) (this may be a regular expression for a set of # types as in [...] for cases where different compilers map the symbol # to different types), the symbol and by convention an comment # explaining why the symbol is thread-safe. The symbol may be # preceded by a '?' character to indicate the symbol may or may not # be in the object file, otherwise a symbol named here that is not # in the object file produces a warning. access.o b all_ops # single-threaded PM_SCOPE_ACL b gotmyhostid # single-threaded PM_SCOPE_ACL b grouplist # single-threaded PM_SCOPE_ACL b hostlist # single-threaded PM_SCOPE_ACL b myhostid # single-threaded PM_SCOPE_ACL b myhostname # single-threaded PM_SCOPE_ACL b nhosts # single-threaded PM_SCOPE_ACL b ngroups # single-threaded PM_SCOPE_ACL b nusers # single-threaded PM_SCOPE_ACL b oldgrouplist # single-threaded PM_SCOPE_ACL b oldhostlist # single-threaded PM_SCOPE_ACL b olduserlist # single-threaded PM_SCOPE_ACL b oldngroups # single-threaded PM_SCOPE_ACL b oldnhosts # single-threaded PM_SCOPE_ACL b oldnusers # single-threaded PM_SCOPE_ACL b oldszgrouplist # single-threaded PM_SCOPE_ACL b oldszhostlist # single-threaded PM_SCOPE_ACL b oldszuserlist # single-threaded PM_SCOPE_ACL b saved # single-threaded PM_SCOPE_ACL b szhostlist # single-threaded PM_SCOPE_ACL b szgrouplist # single-threaded PM_SCOPE_ACL b szuserlist # single-threaded PM_SCOPE_ACL b userlist # single-threaded PM_SCOPE_ACL accounts.o AF.o d afid # single-threaded PM_SCOPE_AF b block # single-threaded PM_SCOPE_AF b root # single-threaded PM_SCOPE_AF b ?afblock # guarded by __pmLock_libpcp mutex b ?afsetup # guarded by __pmLock_libpcp mutex b ?aftimer # guarded by __pmLock_libpcp mutex auxconnect.o d canwait # guarded by __pmLock_libpcp mutex d first_time.[0-9]* # guarded by __pmLock_libpcp mutex b pmcd_port.[0-9]* # guarded by __pmLock_libpcp mutex b pmcd_socket.[0-9]* # guarded by __pmLock_libpcp mutex auxserver.o b nport # single-threaded server scope b portlist # single-threaded server scope b nintf # single-threaded server scope b intflist # single-threaded server scope b nReqPorts # single-threaded server scope b szReqPorts # single-threaded server scope b reqPorts # single-threaded server scope b localSocketPath # single-threaded server scope b serviceSpec # single-threaded server scope d localSocketFd # single-threaded server scope b server_features # single-threaded server scope discovery.o ?avahi.o b nActiveServices # single-threaded server scope b szActiveServices # single-threaded server scope b activeServices # single-threaded server scope b threadedPoll # single-threaded server scope b client # single-threaded server scope b group # single-threaded server scope b done_default # guarded by __pmLock_libpcp mutex b def_timeout # guarded by __pmLock_libpcp mutex checksum.o config.o [SDR] ?__pmNativeConfig # const b state.[0-9]* # guarded by __pmLock_libpcp mutex [sd] ?features # const connectlocal.o b atexit_installed.[0-9]* # guarded by __pmLock_libpcp mutex b buffer.[0-9]* # assert safe, see notes in connectlocal.c b dsotab # assert safe, see notes in connectlocal.c d numdso # assert safe, see notes in connectlocal.c connect.o b global_nports # guarded by __pmLock_libpcp mutex b global_portlist # guarded by __pmLock_libpcp mutex d default_portlist # guarded by __pmLock_libpcp mutex d first_time.[0-9]* # guarded by __pmLock_libpcp mutex b proxy.[0-9]* # guarded by __pmLock_libpcp mutex b proxy_port.[0-9]* # guarded by __pmLock_libpcp mutex context.o [ds] _mode # const d def_backoff # guarded by __pmLock_libpcp mutex b backoff # guarded by __pmLock_libpcp mutex b n_backoff # guarded by __pmLock_libpcp mutex b contexts # guarded by __pmLock_libpcp mutex b contexts_len # guarded by __pmLock_libpcp mutex b hostbuf.[0-9]* # single-threaded d ?curcontext # thread private r ?__emutls_t.curcontext # thread private (MinGW) d ?__emutls_v.curcontext # thread private (MinGW) derive_fetch.o derive.o [ds] ?func # const [bd] ?init.[0-9]* # local initialize_mutex mutex b ?done.[0-9]* # guarded by local initialize_mutex mutex [ds] type_dbg # const s ?type_c # const [ds] state_dbg # const s ?promote # const s ?timefactor # const d need_init # guarded by registered.mutex b tokbuf # guarded by registered.mutex b tokbuflen # guarded by registered.mutex b string # guarded by registered.mutex b lexpeek # guarded by registered.mutex b this # guarded by registered.mutex [bd] ?registered # guarded by registered.mutex b pmid.[0-9]* # guarded by registered.mutex b ?derive_errmsg # thread private d ?__emutls_v.derive_errmsg # thread private (MinGW) r ?func # const (MinGW) r ?promote # const (MinGW) r ?timefactor # const (MinGW) r ?type_c # const (MinGW) desc.o endian.o err.o [dsr] ?errtab # const d ?first.[0-9]* # guarded by __pmLock_libpcp mutex [bd] unknown.[0-9]* # guarded by __pmLock_libpcp mutex or const (MinGW) b errmsg.[0-9]* # pmErrStr deprecated by pmErrStr_r events.o d first.[0-9]* # guarded by __pmLock_libpcp mutex d name_flags.[0-9]* # guarded by __pmLock_libpcp mutex d name_missed.[0-9]* # guarded by __pmLock_libpcp mutex b pmid_flags.[0-9]* # no unsafe side-effects b pmid_missed.[0-9]* # no unsafe side-effects fault.o fetchlocal.o b splitlist.[0-9]* # single-threaded PM_SCOPE_DSO_PMDA b splitmax.[0-9]* # single-threaded PM_SCOPE_DSO_PMDA fetch.o freeresult.o hash.o help.o instance.o interp.o d dowrap.[0-9]* # guarded by __pmLock_libpcp mutex d round_robin.[0-9]* # guarded by __pmLock_libpcp mutex b nr # diag counters, no atomic updates b nr_cache # diag counters, no atomic updates b cache # guarded by __pmLock_libpcp mutex ipc.o b __pmIPCTable # guarded by __pmLock_libpcp mutex d __pmLastUsedFd # guarded by __pmLock_libpcp mutex b ipcentrysize # guarded by __pmLock_libpcp mutex b ipctablecount # guarded by __pmLock_libpcp mutex lock.o [DC] __pmLock_libpcp # the global libpcp mutex [bd] ?init.[0-9]* # local __pmInitLocks mutex b ?done.[0-9]* # guarded by local __pmInitLocks mutex [CD] ?__pmTPDKey # one-trip initialization then read-only b ?multi_init # guarded by __pmLock_libpcp mutex b ?multi_seen # guarded by __pmLock_libpcp mutex b ?hashctl.[0-9]* # for lock debug tracing B ?__pmTPDKey # if don't have __thread support logconnect.o b done_default.[0-9]* # guarded by __pmLock_libpcp mutex b timeout.[0-9]* # guarded by __pmLock_libpcp mutex logcontrol.o logmeta.o logportmap.o b nlogports # single-threaded PM_SCOPE_LOGPORT b szlogport # single-threaded PM_SCOPE_LOGPORT b logport # single-threaded PM_SCOPE_LOGPORT b match # single-threaded PM_SCOPE_LOGPORT logutil.o b tbuf.[0-9]* # __pmLogName deprecated by __pmLogName_r [dsr] compress_ctl # const [sr] ?ncompress # const [BD] __pmLogReads # diag counter, no atomic updates b pc_hc # guarded by __pmLock_libpcp mutex secureserver.o b secure_server # guarded by __pmLock_libpcp mutex secureconnect.o b ?nsprFds # guarded by __pmLock_libpcp mutex d common_callbacks # const optfetch.o d optcost # guarded by __pmLock_libpcp mutex p_auth.o p_creds.o p_desc.o pdubuf.o b buf_free # guarded by __pmLock_libpcp mutex b buf_pin # guarded by __pmLock_libpcp mutex b buf_pin_tail # guarded by __pmLock_libpcp mutex pdu.o b done_default.[0-9]* # guarded by __pmLock_libpcp mutex d def_timeout # guarded by __pmLock_libpcp mutex d def_wait # guarded by __pmLock_libpcp mutex [CD] pmDebug # set-once in main(), read-only elsewhere d ceiling # no unsafe side-effects b ?sigpipe_done # no unsafe side-effects d mypid # no unsafe side-effects b tbuf.[0-9]* # __pmPDUTypeStr deprecated by __pmPDUTypeStr_r D __pmPDUCntIn # pointer to diag counters, no atomic updates D __pmPDUCntOut # pointer to diag counters, no atomic updates b inctrs # diag counters, no atomic updates b outctrs # diag counters, no atomic updates d maxsize.[0-9]* # guarded by __pmLock_libpcp mutex p_error.o p_profile.o p_result.o profile.o p_text.o p_fetch.o p_instance.o p_lcontrol.o p_lrequest.o p_lstatus.o pmns.o b lineno # guarded by __pmLock_libpcp mutex b export # guarded by __pmLock_libpcp mutex b fin.[0-9]* # guarded by __pmLock_libpcp mutex d first.[0-9]* # guarded by __pmLock_libpcp mutex b fname # guarded by __pmLock_libpcp mutex b havePmLoadCall # guarded by __pmLock_libpcp mutex b last_mtim # guarded by __pmLock_libpcp mutex d last_pmns_location.[0-9]* # guarded by __pmLock_libpcp mutex b linebuf # guarded by __pmLock_libpcp mutex b linep # guarded by __pmLock_libpcp mutex b lp.[0-9]* # guarded by __pmLock_libpcp mutex b seen # guarded by __pmLock_libpcp mutex b seenpmid # guarded by __pmLock_libpcp mutex b tokbuf # guarded by __pmLock_libpcp mutex b tokpmid # guarded by __pmLock_libpcp mutex b useExtPMNS # guarded by __pmLock_libpcp mutex b repname.[0-9]* # guarded by __pmLock_libpcp mutex b main_pmns # guarded by __pmLock_libpcp mutex b curr_pmns # guarded by __pmLock_libpcp mutex b locerr.[0-9]* # no unsafe side-effects, see notes in pmns.c p_pmns.o p_profile.o p_result.o profile.o p_text.o rtime.o s ?wdays # const s ?months # const s ?ampm # const [dsr] int_tab # const struct {...} int_tab[] = {...} [sr] ?numint # const r ?ampm # const (MinGW) r ?months # const (MinGW) r ?wdays # const (MinGW) sortinst.o spec.o store.o stuffvalue.o tv.o tz.o d curzone # guarded by __pmLock_libpcp mutex b envtz # guarded by __pmLock_libpcp mutex b envtzlen # guarded by __pmLock_libpcp mutex b zone # guarded by __pmLock_libpcp mutex b nzone # guarded by __pmLock_libpcp mutex b savetz # guarded by __pmLock_libpcp mutex b savetzp # guarded by __pmLock_libpcp mutex b tzbuffer.[0-9]* # guarded by __pmLock_libpcp mutex r ?wildabbr.[0-9]* # const (MinGW) units.o [ds] typename # const b abuf.[0-9]* # pmAtomStr deprecated by pmAtomStr_r b tbuf.[0-9]* # pmTypeStr deprecated by pmTypeStr_r b ubuf.[0-9]* # pmUnitsStr deprecated by pmUnitsStr_r util.o b idbuf.[0-9]* # pmIDStr deprecated by pmIDStr_r b indombuf.[0-9]* # pmInDomStr deprecated by pmInDomStr_r b ebuf.[0-9]* # pmEventFlagsStr deprecated by pmEventFlagsStr_r b nbuf.[0-9]* # pmNumberStr deprecated by pmNumberStr_r [sd] ?unknownVal.[0-9]* # const, variable may be optimized away by gcc [sd] debug_map # const [rsd] ?num_debug # const b pmState # no unsafe side-effects, see notes in util.c D pmProgname # no unsafe side-effects, see notes in util.c b filelog # guarded by __pmLock_libpcp mutex b nfilelog # guarded by __pmLock_libpcp mutex b dosyslog # guarded by __pmLock_libpcp mutex b done_exit # guarded by __pmLock_libpcp mutex b ferr # guarded by __pmLock_libpcp mutex d errtype.[0-9]* # guarded by __pmLock_libpcp mutex b fptr # guarded by __pmLock_libpcp mutex b fname # guarded by __pmLock_libpcp mutex b msgsize # guarded by __pmLock_libpcp mutex b ?base.[0-9]* # no unsafe side-effects, see notes in util.c d first.[0-9]* # __pmEventType deprecated by __pmEventType_r b last.[0-9]* # __pmEventType deprecated by __pmEventType_r b sum.[0-9]* # __pmEventType deprecated by __pmEventType_r r ?bp # const r ?dp_h # const r ?dp_l # const ?win32.o END # this is magic, DO NOT DELETE THIS LINE End-of-File for file in *.o do if grep "^?*$file\$" $tmp/ctl >/dev/null 2>&1 then : else echo "$file: Error: object file not mentioned in control file" touch $tmp/fail fi done skip_file=false cat $tmp/ctl \ | while read type name do if [ -z "$name" ] then # one word on a line, this is the name of a new object code file if [ -n "$obj" ] then if [ -s $tmp/out ] then # extras from the last object code file sed <$tmp/out \ -e 's/^[^ ]* //' \ -e "s/^\(.\) \(.*\)/$obj: \1 \2 : Error: additional symbol/" touch $tmp/fail fi fi if [ "$type" != END ] then if [ -f $type ] then # Need some nm special case logic ... # for darwin # + const data and text symbols both appear as "S", but # the latter have .eh appended to the name # + static arrays and some debug (?) symbols appear as # "s", but the latter have _.NNN appended, or start # with LC, or have .eh appended, or start with EH_ # + older versions insert get_pc_thunk symbols in all # object files # for MinGW # + strip .bss and .data lines # + strip .rdata and .eh_frame lines # + external symbols tend to have "C" lines # skip_file=false nm $type \ | sed -n >$tmp/out \ -e '/ S ___i686.get_pc_thunk.[bc]x/d' \ -e '/ [sS] .*\.eh$/d' \ -e '/ s .*_\.[0-9][0-9]*$/d' \ -e '/ s LC[0-9][0-9]*$/d' \ -e '/ s EH_/d' \ -e '/ b \.bss/d' \ -e '/ d \.data/d' \ -e '/ r \.rdata/d' \ -e '/ r \.eh_frame/d' \ -e '/ r __PRETTY_FUNCTION__.[0-9][0-9]*$/d' \ -e '/ r \.LC[0-9][0-9]*$/d' \ -e '/ C ___pmLogReads/d' \ -e '/ C ___pmNativeConfig/d' \ -e '/ C ___pmPDUCntIn/d' \ -e '/ C ___pmPDUCntOut/d' \ -e '/ C _pmDebug/d' \ -e '/ C _pmProgname/d' \ -e '/ [dDbBCsSrR] /p' obj=$type else case "$type" in secure*.o) echo "$type: Info: security object file skipped, not configured" skip_file=true ;; \?*) skip_file=true ;; *) echo "$type: Error: object file in control file but not found" touch $tmp/fail esac fi fi continue fi $skip_file && continue opt=`echo $name | sed -n -e 's/?.*/?/p'` name=`echo $name | sed -e 's/?//'` #debug# echo "obj=$obj type=$type name=$name opt=$opt" # Note some nm output prefixes the name with _, hence the two # sed lines below # sed <$tmp/out >$tmp/tmp \ -e "/ $type $name\$/d" \ -e "/ $type _$name\$/d" if cmp -s $tmp/out $tmp/tmp then if [ "$opt" != "?" ] then echo "$obj: $name: Warning: exceptioned symbol (type=$type) no longer present" fi else mv $tmp/tmp $tmp/out fi done [ -f $tmp/fail ] && sts=1 pcp-3.8.12ubuntu1/src/libpcp/src/instance.c0000664000000000000000000002220512272262501015402 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1995-2006 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "internal.h" int pmLookupInDom(pmInDom indom, const char *name) { int n; __pmInResult *result; __pmContext *ctxp; if (indom == PM_INDOM_NULL) return PM_ERR_INDOM; if ((n = pmWhichContext()) >= 0) { int ctx = n; ctxp = __pmHandleToPtr(ctx); if (ctxp == NULL) return PM_ERR_NOCONTEXT; if (ctxp->c_type == PM_CONTEXT_HOST) { PM_LOCK(ctxp->c_pmcd->pc_lock); n = __pmSendInstanceReq(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), &ctxp->c_origin, indom, PM_IN_NULL, name); if (n < 0) n = __pmMapErrno(n); else { __pmPDU *pb; int pinpdu; pinpdu = n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, ctxp->c_pmcd->pc_tout_sec, &pb); if (n == PDU_INSTANCE) { __pmInResult *result; if ((n = __pmDecodeInstance(pb, &result)) >= 0) { n = result->instlist[0]; __pmFreeInResult(result); } } else if (n == PDU_ERROR) __pmDecodeError(pb, &n); else if (n != PM_ERR_TIMEOUT) n = PM_ERR_IPC; if (pinpdu > 0) __pmUnpinPDUBuf(pb); } PM_UNLOCK(ctxp->c_pmcd->pc_lock); } else if (ctxp->c_type == PM_CONTEXT_LOCAL) { __pmDSO *dp; if (PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) /* Local context requires single-threaded applications */ n = PM_ERR_THREAD; else if ((dp = __pmLookupDSO(((__pmInDom_int *)&indom)->domain)) == NULL) n = PM_ERR_NOAGENT; else { /* We can safely cast away const here */ if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; n = dp->dispatch.version.any.instance(indom, PM_IN_NULL, (char *)name, &result, dp->dispatch.version.any.ext); } if (n >= 0) { n = result->instlist[0]; __pmFreeInResult(result); } } else { /* assume PM_CONTEXT_ARCHIVE */ n = __pmLogLookupInDom(ctxp->c_archctl->ac_log, indom, &ctxp->c_origin, name); } PM_UNLOCK(ctxp->c_lock); } return n; } int pmNameInDom(pmInDom indom, int inst, char **name) { int n; __pmInResult *result; __pmContext *ctxp; if (indom == PM_INDOM_NULL) return PM_ERR_INDOM; if ((n = pmWhichContext()) >= 0) { int ctx = n; ctxp = __pmHandleToPtr(ctx); if (ctxp == NULL) return PM_ERR_NOCONTEXT; if (ctxp->c_type == PM_CONTEXT_HOST) { PM_LOCK(ctxp->c_pmcd->pc_lock); n = __pmSendInstanceReq(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), &ctxp->c_origin, indom, inst, NULL); if (n < 0) n = __pmMapErrno(n); else { __pmPDU *pb; int pinpdu; pinpdu = n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, ctxp->c_pmcd->pc_tout_sec, &pb); if (n == PDU_INSTANCE) { __pmInResult *result; if ((n = __pmDecodeInstance(pb, &result)) >= 0) { if ((*name = strdup(result->namelist[0])) == NULL) n = -oserror(); __pmFreeInResult(result); } } else if (n == PDU_ERROR) __pmDecodeError(pb, &n); else if (n != PM_ERR_TIMEOUT) n = PM_ERR_IPC; if (pinpdu > 0) __pmUnpinPDUBuf(pb); } PM_UNLOCK(ctxp->c_pmcd->pc_lock); } else if (ctxp->c_type == PM_CONTEXT_LOCAL) { __pmDSO *dp; if (PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) /* Local context requires single-threaded applications */ n = PM_ERR_THREAD; else if ((dp = __pmLookupDSO(((__pmInDom_int *)&indom)->domain)) == NULL) n = PM_ERR_NOAGENT; else { if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; n = dp->dispatch.version.any.instance(indom, inst, NULL, &result, dp->dispatch.version.any.ext); } if (n >= 0) { if ((*name = strdup(result->namelist[0])) == NULL) n = -oserror(); __pmFreeInResult(result); } } else { /* assume PM_CONTEXT_ARCHIVE */ char *tmp; if ((n = __pmLogNameInDom(ctxp->c_archctl->ac_log, indom, &ctxp->c_origin, inst, &tmp)) >= 0) { if ((*name = strdup(tmp)) == NULL) n = -oserror(); } } PM_UNLOCK(ctxp->c_lock); } return n; } static int inresult_to_lists(__pmInResult *result, int **instlist, char ***namelist) { int n, i, sts, need; char *p; int *ilist; char **nlist; if (result->numinst == 0) { __pmFreeInResult(result); return 0; } need = 0; for (i = 0; i < result->numinst; i++) { need += sizeof(**namelist) + strlen(result->namelist[i]) + 1; } ilist = (int *)malloc(result->numinst * sizeof(result->instlist[0])); if (ilist == NULL) { sts = -oserror(); __pmFreeInResult(result); return sts; } if ((nlist = (char **)malloc(need)) == NULL) { sts = -oserror(); free(ilist); __pmFreeInResult(result); return sts; } *instlist = ilist; *namelist = nlist; p = (char *)&nlist[result->numinst]; for (i = 0; i < result->numinst; i++) { ilist[i] = result->instlist[i]; strcpy(p, result->namelist[i]); nlist[i] = p; p += strlen(result->namelist[i]) + 1; } n = result->numinst; __pmFreeInResult(result); return n; } int pmGetInDom(pmInDom indom, int **instlist, char ***namelist) { int n; int i; __pmInResult *result; __pmContext *ctxp; char *p; int need; int *ilist; char **nlist; if (indom == PM_INDOM_NULL) return PM_ERR_INDOM; if ((n = pmWhichContext()) >= 0) { int ctx = n; ctxp = __pmHandleToPtr(ctx); if (ctxp == NULL) return PM_ERR_NOCONTEXT; if (ctxp->c_type == PM_CONTEXT_HOST) { PM_LOCK(ctxp->c_pmcd->pc_lock); n = __pmSendInstanceReq(ctxp->c_pmcd->pc_fd, __pmPtrToHandle(ctxp), &ctxp->c_origin, indom, PM_IN_NULL, NULL); if (n < 0) n = __pmMapErrno(n); else { __pmPDU *pb; int pinpdu; pinpdu = n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE, ctxp->c_pmcd->pc_tout_sec, &pb); if (n == PDU_INSTANCE) { __pmInResult *result; if ((n = __pmDecodeInstance(pb, &result)) < 0) { if (pinpdu > 0) __pmUnpinPDUBuf(pb); PM_UNLOCK(ctxp->c_pmcd->pc_lock); return n; } n = inresult_to_lists(result, instlist, namelist); } else if (n == PDU_ERROR) __pmDecodeError(pb, &n); else if (n != PM_ERR_TIMEOUT) n = PM_ERR_IPC; if (pinpdu > 0) __pmUnpinPDUBuf(pb); } PM_UNLOCK(ctxp->c_pmcd->pc_lock); } else if (ctxp->c_type == PM_CONTEXT_LOCAL) { __pmDSO *dp; if (PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) /* Local context requires single-threaded applications */ n = PM_ERR_THREAD; else if ((dp = __pmLookupDSO(((__pmInDom_int *)&indom)->domain)) == NULL) n = PM_ERR_NOAGENT; else { if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; n = dp->dispatch.version.any.instance(indom, PM_IN_NULL, NULL, &result, dp->dispatch.version.any.ext); } if (n >= 0) n = inresult_to_lists(result, instlist, namelist); } else { /* assume PM_CONTEXT_ARCHIVE */ int *insttmp; char **nametmp; if ((n = __pmLogGetInDom(ctxp->c_archctl->ac_log, indom, &ctxp->c_origin, &insttmp, &nametmp)) >= 0) { need = 0; for (i = 0; i < n; i++) need += sizeof(char *) + strlen(nametmp[i]) + 1; if ((ilist = (int *)malloc(n * sizeof(insttmp[0]))) == NULL) { PM_UNLOCK(ctxp->c_lock); return -oserror(); } if ((nlist = (char **)malloc(need)) == NULL) { free(ilist); PM_UNLOCK(ctxp->c_lock); return -oserror(); } *instlist = ilist; *namelist = nlist; p = (char *)&nlist[n]; for (i = 0; i < n; i++) { ilist[i] = insttmp[i]; strcpy(p, nametmp[i]); nlist[i] = p; p += strlen(nametmp[i]) + 1; } } } PM_UNLOCK(ctxp->c_lock); } if (n == 0) { /* avoid ambiguity when no instances or errors */ *instlist = NULL; *namelist = NULL; } return n; } #ifdef PCP_DEBUG void __pmDumpInResult(FILE *f, const __pmInResult *irp) { int i; char strbuf[20]; fprintf(f,"pmInResult dump from " PRINTF_P_PFX "%p for InDom %s (0x%x), numinst=%d\n", irp, pmInDomStr_r(irp->indom, strbuf, sizeof(strbuf)), irp->indom, irp->numinst); for (i = 0; i < irp->numinst; i++) { fprintf(f, " [%d]", i); if (irp->instlist != NULL) fprintf(f, " inst=%d", irp->instlist[i]); if (irp->namelist != NULL) fprintf(f, " name=\"%s\"", irp->namelist[i]); fputc('\n', f); } return; } #endif void __pmFreeInResult(__pmInResult *res) { int i; if (res->namelist != NULL) { for (i = 0; i < res->numinst; i++) { if (res->namelist[i] != NULL) { free(res->namelist[i]); } } free(res->namelist); } if (res->instlist != NULL) free(res->instlist); free(res); } pcp-3.8.12ubuntu1/src/libpcp/src/secureserver.c0000664000000000000000000004551512272262501016324 0ustar /* * Copyright (c) 2012-2013 Red Hat. * * Server side security features - via Network Security Services (NSS) and * the Simple Authentication and Security Layer (SASL). * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #define SOCKET_INTERNAL #include "internal.h" #include #include #include #include #define MAX_NSSDB_PASSWORD_LENGTH 256 static struct { /* NSS certificate management */ CERTCertificate *certificate; SECKEYPrivateKey *private_key; const char *password_file; SSLKEAType certificate_KEA; char database_path[MAXPATHLEN]; /* status flags (bitfields) */ unsigned int certificate_verified : 1; /* NSS */ unsigned int ssl_session_cache_setup : 1; /* NSS */ } secure_server; int __pmSecureServerSetFeature(__pmServerFeature wanted) { (void)wanted; return 0; /* nothing dynamically enabled at this stage */ } int __pmSecureServerClearFeature(__pmServerFeature clear) { (void)clear; return 0; /* nothing dynamically disabled at this stage */ } int __pmSecureServerHasFeature(__pmServerFeature query) { int sts = 0; switch (query) { case PM_SERVER_FEATURE_SECURE: sts = secure_server.certificate_verified; break; case PM_SERVER_FEATURE_COMPRESS: case PM_SERVER_FEATURE_AUTH: sts = 1; break; default: break; } return sts; } static int secure_file_contents(const char *filename, char **passwd, size_t *length) { struct stat stat; size_t size = *length; char *pass = NULL; FILE *file = NULL; int sts; if ((file = fopen(filename, "r")) == NULL) goto fail; if (fstat(fileno(file), &stat) < 0) goto fail; if (stat.st_size > size) { setoserror(E2BIG); goto fail; } if ((pass = (char *)PORT_Alloc(stat.st_size)) == NULL) { setoserror(ENOMEM); goto fail; } sts = fread(pass, 1, stat.st_size, file); if (sts < 1) { setoserror(EINVAL); goto fail; } while (sts > 0 && (pass[sts-1] == '\r' || pass[sts-1] == '\n')) pass[--sts] = '\0'; *passwd = pass; *length = sts; fclose(file); return 0; fail: sts = -oserror(); if (file) fclose(file); if (pass) PORT_Free(pass); return sts; } static char * certificate_database_password(PK11SlotInfo *info, PRBool retry, void *arg) { size_t length = MAX_NSSDB_PASSWORD_LENGTH; char *password = NULL; char passfile[MAXPATHLEN]; int sts; (void)arg; (void)info; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); passfile[0] = '\0'; if (secure_server.password_file) strncpy(passfile, secure_server.password_file, MAXPATHLEN-1); passfile[MAXPATHLEN-1] = '\0'; PM_UNLOCK(__pmLock_libpcp); if (passfile[0] == '\0') { __pmNotifyErr(LOG_ERR, "Password sought but no password file given"); return NULL; } if (retry) { __pmNotifyErr(LOG_ERR, "Retry attempted during password extraction"); return NULL; /* no soup^Wretries for you */ } sts = secure_file_contents(passfile, &password, &length); if (sts < 0) { __pmNotifyErr(LOG_ERR, "Cannot read password file \"%s\": %s", passfile, pmErrStr(sts)); return NULL; } return password; } static int __pmCertificateTimestamp(SECItem *vtime, char *buffer, size_t size) { PRExplodedTime exploded; SECStatus secsts; int64 itime; switch (vtime->type) { case siUTCTime: secsts = DER_UTCTimeToTime(&itime, vtime); break; case siGeneralizedTime: secsts = DER_GeneralizedTimeToTime(&itime, vtime); break; default: return -EINVAL; } if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); /* Convert to local time */ PR_ExplodeTime(itime, PR_GMTParameters, &exploded); if (!PR_FormatTime(buffer, size, "%a %b %d %H:%M:%S %Y", &exploded)) return __pmSecureSocketsError(PR_GetError()); return 0; } static void __pmDumpCertificate(FILE *fp, const char *nickname, CERTCertificate *cert) { CERTValidity *valid = &cert->validity; char tbuf[256]; fprintf(fp, "Certificate: %s", nickname); if (__pmCertificateTimestamp(&valid->notBefore, tbuf, sizeof(tbuf)) == 0) fprintf(fp, " Not Valid Before: %s UTC", tbuf); if (__pmCertificateTimestamp(&valid->notAfter, tbuf, sizeof(tbuf)) == 0) fprintf(fp, " Not Valid After: %s UTC", tbuf); } static int __pmValidCertificate(CERTCertDBHandle *db, CERTCertificate *cert, PRTime stamp) { SECCertificateUsage usage = certificateUsageSSLServer; SECStatus secsts = CERT_VerifyCertificate(db, cert, PR_TRUE, usage, stamp, NULL, NULL, &usage); return (secsts == SECSuccess); } static char * serverdb(char *path, size_t size, char *db_method) { int sep = __pmPathSeparator(); char *nss_method = getenv("PCP_SECURE_DB_METHOD"); if (nss_method == NULL) nss_method = db_method; /* * Fill in a buffer with the server NSS database specification. * Return a pointer to the filesystem path component - without * the :-prefix - for other routines to work with. */ snprintf(path, size, "%s" "%c" "etc" "%c" "pki" "%c" "nssdb", nss_method, sep, sep, sep); return path + strlen(nss_method); } int __pmSecureServerSetup(const char *db, const char *passwd) { const char *nickname = SECURE_SERVER_CERTIFICATE; SECStatus secsts; int sts; sts = __pmInitAuthServer(); if (sts < 0) { __pmNotifyErr(LOG_ERR, "Failed to start authenticating server"); return sts; } PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); /* Configure optional (cmdline) password file in case DB locked */ secure_server.password_file = passwd; PK11_SetPasswordFunc(certificate_database_password); /* * Configure location of the NSS database with a sane default. * For servers, we default to the shared (sql) system-wide database. * If command line db specified, pass it directly through - allowing * any old database format, at the users discretion. */ sts = -EINVAL; if (!db) { char *path = serverdb(secure_server.database_path, MAXPATHLEN, "sql:"); /* this is the default case on some platforms, so no log spam */ if (access(path, R_OK|X_OK) < 0) { if (pmDebug & DBG_TRACE_CONTEXT) __pmNotifyErr(LOG_INFO, "Cannot access system security database: %s", secure_server.database_path); sts = 0; /* not fatal - just no secure connections */ goto done; } } else { /* shortened-buffer-size (-2) guarantees null-termination */ strncpy(secure_server.database_path, db, MAXPATHLEN-2); } secsts = NSS_Init(secure_server.database_path); if (secsts != SECSuccess && !db) { /* fallback, older versions of NSS do not support sql: */ serverdb(secure_server.database_path, MAXPATHLEN, ""); secsts = NSS_Init(secure_server.database_path); } if (secsts != SECSuccess) { __pmNotifyErr(LOG_ERR, "Cannot setup certificate DB (%s): %s", secure_server.database_path, pmErrStr(__pmSecureSocketsError(PR_GetError()))); goto done; } /* Some NSS versions don't do this correctly in NSS_SetDomesticPolicy. */ do { const PRUint16 *cipher; for (cipher = SSL_ImplementedCiphers; *cipher != 0; ++cipher) SSL_CipherPolicySet(*cipher, SSL_ALLOWED); } while (0); /* Configure SSL session cache for multi-process server, using defaults */ secsts = SSL_ConfigMPServerSIDCache(0, 0, 0, NULL); if (secsts != SECSuccess) { __pmNotifyErr(LOG_ERR, "Unable to configure SSL session ID cache: %s", pmErrStr(__pmSecureSocketsError(PR_GetError()))); goto done; } else { secure_server.ssl_session_cache_setup = 1; } /* * Iterate over any/all PCP Collector nickname certificates, * seeking one valid certificate. No-such-nickname is not an * error (not configured by admin at all) but anything else is. */ CERTCertList *certlist; CERTCertDBHandle *nssdb = CERT_GetDefaultCertDB(); CERTCertificate *dbcert = PK11_FindCertFromNickname(nickname, NULL); if (dbcert) { PRTime now = PR_Now(); SECItem *name = &dbcert->derSubject; CERTCertListNode *node; certlist = CERT_CreateSubjectCertList(NULL, nssdb, name, now, PR_FALSE); if (certlist) { for (node = CERT_LIST_HEAD(certlist); !CERT_LIST_END(node, certlist); node = CERT_LIST_NEXT (node)) { if (pmDebug & DBG_TRACE_CONTEXT) __pmDumpCertificate(stderr, nickname, node->cert); if (!__pmValidCertificate(nssdb, node->cert, now)) continue; secure_server.certificate_verified = 1; break; } CERT_DestroyCertList(certlist); } if (secure_server.certificate_verified) { secure_server.certificate_KEA = NSS_FindCertKEAType(dbcert); secure_server.private_key = PK11_FindKeyByAnyCert(dbcert, NULL); if (!secure_server.private_key) { __pmNotifyErr(LOG_ERR, "Unable to extract %s private key", nickname); CERT_DestroyCertificate(dbcert); secure_server.certificate_verified = 0; goto done; } } else { __pmNotifyErr(LOG_ERR, "Unable to find a valid %s", nickname); CERT_DestroyCertificate(dbcert); goto done; } } if (secure_server.certificate_verified) { secure_server.certificate = dbcert; } else if (pmDebug & DBG_TRACE_CONTEXT) { __pmNotifyErr(LOG_INFO, "No valid %s in security database: %s", nickname, secure_server.database_path); } sts = 0; done: PM_UNLOCK(__pmLock_libpcp); return sts; } void __pmSecureServerShutdown(void) { PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); if (secure_server.certificate) { CERT_DestroyCertificate(secure_server.certificate); secure_server.certificate = NULL; } if (secure_server.private_key) { SECKEY_DestroyPrivateKey(secure_server.private_key); secure_server.private_key = NULL; } if (secure_server.ssl_session_cache_setup) { SSL_ShutdownServerSessionIDCache(); secure_server.ssl_session_cache_setup = 0; } PM_UNLOCK(__pmLock_libpcp); NSS_Shutdown(); } static int __pmSecureServerNegotiation(int fd, int *strength) { PRIntervalTime timer; PRFileDesc *sslsocket; SECStatus secsts; int enabled, keysize; int msec; sslsocket = (PRFileDesc *)__pmGetSecureSocket(fd); if (!sslsocket) return PM_ERR_IPC; PM_INIT_LOCKS(); PM_LOCK(__pmLock_libpcp); secsts = SSL_ConfigSecureServer(sslsocket, secure_server.certificate, secure_server.private_key, secure_server.certificate_KEA); PM_UNLOCK(__pmLock_libpcp); if (secsts != SECSuccess) { __pmNotifyErr(LOG_ERR, "Unable to configure secure server: %s", pmErrStr(__pmSecureSocketsError(PR_GetError()))); return PM_ERR_IPC; } secsts = SSL_ResetHandshake(sslsocket, PR_TRUE /*server*/); if (secsts != SECSuccess) { __pmNotifyErr(LOG_ERR, "Unable to reset secure handshake: %s", pmErrStr(__pmSecureSocketsError(PR_GetError()))); return PM_ERR_IPC; } /* Server initiates handshake now to get early visibility of errors */ msec = __pmConvertTimeout(TIMEOUT_DEFAULT); timer = PR_MillisecondsToInterval(msec); secsts = SSL_ForceHandshakeWithTimeout(sslsocket, timer); if (secsts != SECSuccess) { __pmNotifyErr(LOG_ERR, "Unable to force secure handshake: %s", pmErrStr(__pmSecureSocketsError(PR_GetError()))); return PM_ERR_IPC; } secsts = SSL_SecurityStatus(sslsocket, &enabled, NULL, &keysize, NULL, NULL, NULL); if (secsts != SECSuccess) return __pmSecureSocketsError(PR_GetError()); *strength = (enabled > 0) ? keysize : DEFAULT_SECURITY_STRENGTH; return 0; } static int __pmSetUserGroupAttributes(const char *username, __pmHashCtl *attrs) { char name[32]; char *namep; uid_t uid; gid_t gid; if (__pmGetUserIdentity(username, &uid, &gid, PM_RECOV_ERR) == 0) { snprintf(name, sizeof(name), "%u", uid); name[sizeof(name)-1] = '\0'; if ((namep = strdup(name)) != NULL) __pmHashAdd(PCP_ATTR_USERID, namep, attrs); else return -ENOMEM; snprintf(name, sizeof(name), "%u", gid); name[sizeof(name)-1] = '\0'; if ((namep = strdup(name)) != NULL) __pmHashAdd(PCP_ATTR_GROUPID, namep, attrs); else return -ENOMEM; return 0; } __pmNotifyErr(LOG_ERR, "Authenticated user %s not found\n", username); return -ESRCH; } static int __pmAuthServerSetAttributes(sasl_conn_t *conn, __pmHashCtl *attrs) { const void *property = NULL; char *username; int sts; sts = sasl_getprop(conn, SASL_USERNAME, &property); username = (char *)property; if (sts == SASL_OK && username) { __pmNotifyErr(LOG_INFO, "Successful authentication for user \"%s\"\n", username); if ((username = strdup(username)) == NULL) { __pmNoMem("__pmAuthServerSetAttributes", strlen(username), PM_RECOV_ERR); return -ENOMEM; } } else { __pmNotifyErr(LOG_ERR, "Authentication complete, but no username\n"); return -ESRCH; } if ((sts = __pmHashAdd(PCP_ATTR_USERNAME, username, attrs)) < 0) return sts; return __pmSetUserGroupAttributes(username, attrs); } static int __pmAuthServerSetProperties(sasl_conn_t *conn, int ssf) { int saslsts; sasl_security_properties_t props; /* set external security strength factor */ saslsts = sasl_setprop(conn, SASL_SSF_EXTERNAL, &ssf); if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) { __pmNotifyErr(LOG_ERR, "SASL setting external SSF to %d: %s", ssf, sasl_errstring(saslsts, NULL, NULL)); return __pmSecureSocketsError(saslsts); } /* set general security properties */ memset(&props, 0, sizeof(props)); props.maxbufsize = LIMIT_AUTH_PDU; props.max_ssf = UINT_MAX; saslsts = sasl_setprop(conn, SASL_SEC_PROPS, &props); if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) { __pmNotifyErr(LOG_ERR, "SASL setting security properties: %s", sasl_errstring(saslsts, NULL, NULL)); return __pmSecureSocketsError(saslsts); } return 0; } static int __pmAuthServerNegotiation(int fd, int ssf, __pmHashCtl *attrs) { int sts, saslsts; int pinned, length, count; char *payload, *offset; sasl_conn_t *sasl_conn; __pmPDU *pb; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "__pmAuthServerNegotiation(fd=%d, ssf=%d)\n", fd, ssf); if ((sasl_conn = (sasl_conn_t *)__pmGetUserAuthData(fd)) == NULL) return -EINVAL; /* setup all the security properties for this connection */ if ((sts = __pmAuthServerSetProperties(sasl_conn, ssf)) < 0) return sts; saslsts = sasl_listmech(sasl_conn, NULL, NULL, " ", NULL, (const char **)&payload, (unsigned int *)&length, &count); if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) { __pmNotifyErr(LOG_ERR, "Generating client mechanism list: %s", sasl_errstring(saslsts, NULL, NULL)); return __pmSecureSocketsError(saslsts); } if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "__pmAuthServerNegotiation - sending mechanism list " "(%d items, %d bytes): \"%s\"\n", count, length, payload); if ((sts = __pmSendAuth(fd, FROM_ANON, 0, payload, length)) < 0) return sts; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "__pmAuthServerNegotiation - wait for mechanism\n"); sts = pinned = __pmGetPDU(fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb); if (sts == PDU_AUTH) { sts = __pmDecodeAuth(pb, &count, &payload, &length); if (sts >= 0) { for (count = 0; count < length; count++) { if (payload[count] == '\0') break; } if (count < length) { /* found an initial response */ length = length - count - 1; offset = payload + count + 1; } else { length = 0; offset = NULL; } saslsts = sasl_server_start(sasl_conn, payload, offset, length, (const char **)&payload, (unsigned int *)&length); if (saslsts != SASL_OK && saslsts != SASL_CONTINUE) { sts = __pmSecureSocketsError(saslsts); if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "sasl_server_start failed: %d (%s)\n", saslsts, pmErrStr(sts)); } else { if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "sasl_server_start success: sts=%s\n", saslsts == SASL_CONTINUE ? "continue" : "ok"); } } } else if (sts == PDU_ERROR) { __pmDecodeError(pb, &sts); } else if (sts != PM_ERR_TIMEOUT) { sts = PM_ERR_IPC; } if (pinned) __pmUnpinPDUBuf(pb); if (sts < 0) return sts; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "__pmAuthServerNegotiation method negotiated\n"); while (saslsts == SASL_CONTINUE) { if (!payload) { __pmNotifyErr(LOG_ERR, "No SASL data to send"); sts = -EINVAL; break; } if ((sts = __pmSendAuth(fd, FROM_ANON, 0, payload, length)) < 0) break; if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "__pmAuthServerNegotiation awaiting response\n"); sts = pinned = __pmGetPDU(fd, ANY_SIZE, TIMEOUT_DEFAULT, &pb); if (sts == PDU_AUTH) { sts = __pmDecodeAuth(pb, &count, &payload, &length); if (sts >= 0) { sts = saslsts = sasl_server_step(sasl_conn, payload, length, (const char **)&payload, (unsigned int *)&length); if (sts != SASL_OK && sts != SASL_CONTINUE) { sts = __pmSecureSocketsError(sts); break; } if (pmDebug & DBG_TRACE_AUTH) { fprintf(stderr, "__pmAuthServerNegotiation" " step recv (%d bytes)\n", length); } } } else if (sts == PDU_ERROR) { __pmDecodeError(pb, &sts); } else if (sts != PM_ERR_TIMEOUT) { sts = PM_ERR_IPC; } if (pinned) __pmUnpinPDUBuf(pb); if (sts < 0) break; } if (sts < 0) { if (pmDebug & DBG_TRACE_AUTH) fprintf(stderr, "__pmAuthServerNegotiation loop failed: %d\n", sts); return sts; } return __pmAuthServerSetAttributes(sasl_conn, attrs); } int __pmSecureServerHandshake(int fd, int flags, __pmHashCtl *attrs) { int sts, ssf = DEFAULT_SECURITY_STRENGTH; /* protect from unsupported requests from future/oddball clients */ if ((flags & ~(PDU_FLAG_SECURE | PDU_FLAG_COMPRESS | PDU_FLAG_AUTH | PDU_FLAG_CREDS_REQD)) != 0) return PM_ERR_IPC; if (flags & PDU_FLAG_CREDS_REQD) { if (__pmHashSearch(PCP_ATTR_USERID, attrs) != NULL) return 0; /* unix domain socket */ else flags |= PDU_FLAG_AUTH; /* force authentication */ } if ((sts = __pmSecureServerIPCFlags(fd, flags)) < 0) return sts; if (((flags & PDU_FLAG_SECURE) != 0) && ((sts = __pmSecureServerNegotiation(fd, &ssf)) < 0)) return sts; if (((flags & PDU_FLAG_AUTH) != 0) && ((sts = __pmAuthServerNegotiation(fd, ssf, attrs)) < 0)) return sts; return 0; } pcp-3.8.12ubuntu1/src/libpcp/src/freeresult.c0000664000000000000000000000437612272262501015767 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" /* Free result buffer routines */ void __pmFreeResultValues(pmResult *result) { register pmValueSet *pvs; register pmValueSet **ppvs; register pmValueSet **ppvsend; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDUBUF) { fprintf(stderr, "__pmFreeResultValues(" PRINTF_P_PFX "%p) numpmid=%d\n", result, result->numpmid); } #endif if (result->numpmid == 0) return; ppvsend = &result->vset[result->numpmid]; /* if _any_ vset[] -> an address within a pdubuf, we are done */ for (ppvs = result->vset; ppvs < ppvsend; ppvs++) { if (__pmUnpinPDUBuf((void *)*ppvs)) return; } /* not created from a pdubuf, really free the memory */ for (ppvs = result->vset; ppvs < ppvsend; ppvs++) { pvs = *ppvs; if (pvs->numval > 0 && pvs->valfmt == PM_VAL_DPTR) { /* pmValueBlocks may be malloc'd as well */ int j; for (j = 0; j < pvs->numval; j++) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDUBUF) { char strbuf[20]; fprintf(stderr, "free(" PRINTF_P_PFX "%p) pmValueBlock pmid=%s inst=%d\n", pvs->vlist[j].value.pval, pmIDStr_r(pvs->pmid, strbuf, sizeof(strbuf)), pvs->vlist[j].inst); } #endif free(pvs->vlist[j].value.pval); } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDUBUF) { char strbuf[20]; fprintf(stderr, "free(" PRINTF_P_PFX "%p) vset pmid=%s\n", pvs, pmIDStr_r(pvs->pmid, strbuf, sizeof(strbuf))); } #endif free(pvs); } } void pmFreeResult(pmResult *result) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_PDUBUF) { fprintf(stderr, "pmFreeResult(" PRINTF_P_PFX "%p)\n", result); } #endif __pmFreeResultValues(result); free(result); } pcp-3.8.12ubuntu1/src/libpcp/src/internal.h0000664000000000000000000002052712272262501015424 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #ifndef _INTERNAL_H #define _INTERNAL_H /* * Routines and data structures used within libpcp source files, * but which we do not want to expose via impl.h or pmapi.h. */ #if defined(__GNUC__) && (__GNUC__ >= 4) # define _PCP_HIDDEN __attribute__ ((visibility ("hidden"))) #else # define _PCP_HIDDEN #endif #include "derive.h" extern int __pmConvertTimeout(int) _PCP_HIDDEN; extern const struct timeval *__pmConnectTimeout(void) _PCP_HIDDEN; extern const struct timeval * __pmDefaultRequestTimeout(void) _PCP_HIDDEN; extern int __pmPtrToHandle(__pmContext *) _PCP_HIDDEN; extern int __pmFetchLocal(__pmContext *, int, pmID *, pmResult **) _PCP_HIDDEN; extern int __pmGetFileStatusFlags(int) _PCP_HIDDEN; extern int __pmSetFileStatusFlags(int, int) _PCP_HIDDEN; extern int __pmGetFileDescriptorFlags(int) _PCP_HIDDEN; extern int __pmSetFileDescriptorFlags(int, int) _PCP_HIDDEN; #ifdef HAVE_NETWORK_BYTEORDER /* * no-ops if already in network byte order but * the value may be used in an expression. */ #define __htonpmUnits(a) (a) #define __ntohpmUnits(a) (a) #define __htonpmID(a) (a) #define __ntohpmID(a) (a) #define __htonpmInDom(a) (a) #define __ntohpmInDom(a) (a) #define __htonpmPDUInfo(a) (a) #define __ntohpmPDUInfo(a) (a) #define __htonpmCred(a) (a) #define __ntohpmCred(a) (a) /* * For network byte order, the following are noops, * but otherwise the function is void, so they are * defined as comments to catch code that tries to * use them in an expression or assignment. */ #define __htonpmValueBlock(a) /* noop */ #define __ntohpmValueBlock(a) /* noop */ #define __htonf(a) /* noop */ #define __ntohf(a) /* noop */ #define __htond(a) /* noop */ #define __ntohd(a) /* noop */ #define __htonll(a) /* noop */ #define __ntohll(a) /* noop */ #else /* * Functions to convert to/from network byte order * for little-endian platforms (e.g. Intel). */ #define __htonpmID(a) htonl(a) #define __ntohpmID(a) ntohl(a) #define __htonpmInDom(a) htonl(a) #define __ntohpmInDom(a) ntohl(a) extern pmUnits __htonpmUnits(pmUnits) _PCP_HIDDEN; extern pmUnits __ntohpmUnits(pmUnits) _PCP_HIDDEN; extern __pmPDUInfo __htonpmPDUInfo(__pmPDUInfo) _PCP_HIDDEN; extern __pmPDUInfo __ntohpmPDUInfo(__pmPDUInfo) _PCP_HIDDEN; extern __pmCred __htonpmCred(__pmCred) _PCP_HIDDEN; extern __pmCred __ntohpmCred(__pmCred) _PCP_HIDDEN; /* insitu swab for these */ extern void __htonpmValueBlock(pmValueBlock * const) _PCP_HIDDEN; extern void __ntohpmValueBlock(pmValueBlock * const) _PCP_HIDDEN; extern void __htonf(char *) _PCP_HIDDEN; /* float */ #define __ntohf(v) __htonf(v) #define __htond(v) __htonll(v) /* double */ #define __ntohd(v) __ntohll(v) extern void __htonll(char *) _PCP_HIDDEN; /* 64bit int */ #define __ntohll(v) __htonll(v) #endif /* HAVE_NETWORK_BYTEORDER */ #ifdef PM_MULTI_THREAD #ifdef HAVE___THREAD /* * C compiler is probably gcc and supports __thread declarations */ #define PM_TPD(x) x #else /* * Roll-your-own Thread Private Data support */ extern pthread_key_t __pmTPDKey _PCP_HIDDEN; typedef struct { int curcontext; /* current context */ char *derive_errmsg; /* derived metric parser error message */ } __pmTPD; static inline __pmTPD * __pmTPDGet(void) { return (__pmTPD *)pthread_getspecific(__pmTPDKey); } #define PM_TPD(x) __pmTPDGet()->x #endif #else /* !PM_MULTI_THREAD */ /* No threads - just access global variables as-is */ #define PM_TPD(x) x #endif #ifdef PM_MULTI_THREAD_DEBUG extern void __pmDebugLock(int, void *, const char *, int) _PCP_HIDDEN; extern int __pmIsContextLock(void *) _PCP_HIDDEN; extern int __pmIsChannelLock(void *) _PCP_HIDDEN; extern int __pmIsDeriveLock(void *) _PCP_HIDDEN; #endif /* AF_UNIX socket family internals */ #define PM_HOST_SPEC_NPORTS_LOCAL (-1) #define PM_HOST_SPEC_NPORTS_UNIX (-2) extern const char *__pmPMCDLocalSocketDefault(void) _PCP_HIDDEN; extern void __pmCheckAcceptedAddress(__pmSockAddr *) _PCP_HIDDEN; #ifdef SOCKET_INTERNAL #ifdef HAVE_SECURE_SOCKETS #include #include #include #include #include #include #define SECURE_SERVER_CERTIFICATE "PCP Collector certificate" #define SECURE_USERDB_DEFAULT_KEY "\n" struct __pmSockAddr { PRNetAddr sockaddr; }; typedef PRAddrInfo __pmAddrInfo; /* internal NSS/NSPR/SSL/SASL implementation details */ extern int __pmSecureSocketsError(int) _PCP_HIDDEN; #else /* native sockets only */ #if defined(HAVE_SYS_UN_H) #include #endif struct __pmSockAddr { union { struct sockaddr raw; struct sockaddr_in inet; struct sockaddr_in6 ipv6; #if defined(HAVE_STRUCT_SOCKADDR_UN) struct sockaddr_un local; #endif } sockaddr; }; typedef struct addrinfo __pmAddrInfo; #endif struct __pmHostEnt { char *name; __pmAddrInfo *addresses; }; #endif extern int __pmInitSecureSockets(void) _PCP_HIDDEN; extern int __pmInitCertificates(void) _PCP_HIDDEN; extern int __pmInitSocket(int, int) _PCP_HIDDEN; extern int __pmSocketReady(int, struct timeval *) _PCP_HIDDEN; extern int __pmSocketClosed(void) _PCP_HIDDEN; extern int __pmConnectCheckError(int) _PCP_HIDDEN; extern void *__pmGetSecureSocket(int) _PCP_HIDDEN; extern void *__pmGetUserAuthData(int) _PCP_HIDDEN; extern int __pmSecureServerIPCFlags(int, int) _PCP_HIDDEN; extern int __pmSecureServerHasFeature(__pmServerFeature) _PCP_HIDDEN; extern int __pmSecureServerSetFeature(__pmServerFeature) _PCP_HIDDEN; extern int __pmSecureServerClearFeature(__pmServerFeature) _PCP_HIDDEN; extern int __pmShutdownLocal(void) _PCP_HIDDEN; extern int __pmShutdownCertificates(void) _PCP_HIDDEN; extern int __pmShutdownSecureSockets(void) _PCP_HIDDEN; #define SECURE_SERVER_SASL_SERVICE "PCP Collector" #define LIMIT_AUTH_PDU 2048 /* maximum size of a SASL transfer (in bytes) */ #define LIMIT_CLIENT_CALLBACKS 8 /* maximum size of callback array */ #define DEFAULT_SECURITY_STRENGTH 0 /* SASL security strength factor */ typedef int (*sasl_callback_func)(void); extern int __pmInitAuthClients(void) _PCP_HIDDEN; extern int __pmInitAuthServer(void) _PCP_HIDDEN; /* * Platform independent user/group account manipulation */ extern int __pmValidUserID(__pmUserID) _PCP_HIDDEN; extern int __pmValidGroupID(__pmGroupID) _PCP_HIDDEN; extern int __pmEqualUserIDs(__pmUserID, __pmUserID) _PCP_HIDDEN; extern int __pmEqualGroupIDs(__pmGroupID, __pmGroupID) _PCP_HIDDEN; extern void __pmUserIDFromString(const char *, __pmUserID *) _PCP_HIDDEN; extern void __pmGroupIDFromString(const char *, __pmGroupID *) _PCP_HIDDEN; extern char *__pmUserIDToString(__pmUserID, char *, size_t) _PCP_HIDDEN; extern char *__pmGroupIDToString(__pmGroupID, char *, size_t) _PCP_HIDDEN; extern int __pmUsernameToID(const char *, __pmUserID *) _PCP_HIDDEN; extern int __pmGroupnameToID(const char *, __pmGroupID *) _PCP_HIDDEN; extern char *__pmUsernameFromID(__pmUserID, char *, size_t) _PCP_HIDDEN; extern char *__pmGroupnameFromID(__pmGroupID, char *, size_t) _PCP_HIDDEN; extern int __pmUsersGroupIDs(const char *, __pmGroupID **, unsigned int *) _PCP_HIDDEN; extern int __pmGroupsUserIDs(const char *, __pmUserID **, unsigned int *) _PCP_HIDDEN; extern int __pmGetUserIdentity(const char *, __pmUserID *, __pmGroupID *, int) _PCP_HIDDEN; extern int __pmStringListAdd(char *, int, char ***) _PCP_HIDDEN; extern char *__pmStringListFind(const char *, int, char **) _PCP_HIDDEN; /* * Representations of server presence on the network. */ typedef struct __pmServerAvahiPresence __pmServerAvahiPresence; struct __pmServerPresence { /* Common data. */ char *serviceSpec; int port; /* API-specific data. */ __pmServerAvahiPresence *avahi; }; /* Service discovery internals. */ typedef struct { const char *spec; __pmSockAddr *address; } __pmServiceInfo; extern int __pmAddDiscoveredService(__pmServiceInfo *, int, char ***) _PCP_HIDDEN; #endif /* _INTERNAL_H */ pcp-3.8.12ubuntu1/src/libpcp/src/p_creds.c0000664000000000000000000000544012272262501015217 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "internal.h" #define LIMIT_CREDS 1024 /* * PDU for process credentials (PDU_CREDS) */ typedef struct { __pmPDUHdr hdr; int numcreds; __pmCred credlist[1]; } creds_t; int __pmSendCreds(int fd, int from, int credcount, const __pmCred *credlist) { size_t need; creds_t *pp; int i; int sts; if (credcount <= 0 || credcount > LIMIT_CREDS || credlist == NULL) return PM_ERR_IPC; need = sizeof(creds_t) + ((credcount-1) * sizeof(__pmCred)); if ((pp = (creds_t *)__pmFindPDUBuf((int)need)) == NULL) return -oserror(); pp->hdr.len = (int)need; pp->hdr.type = PDU_CREDS; pp->hdr.from = from; pp->numcreds = htonl(credcount); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) for (i = 0; i < credcount; i++) fprintf(stderr, "__pmSendCreds: #%d = %x\n", i, *(unsigned int*)&(credlist[i])); #endif /* swab and fix bitfield order */ for (i = 0; i < credcount; i++) pp->credlist[i] = __htonpmCred(credlist[i]); sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; } int __pmDecodeCreds(__pmPDU *pdubuf, int *sender, int *credcount, __pmCred **credlist) { creds_t *pp; int i; int len; int need; int numcred; __pmCred *list; pp = (creds_t *)pdubuf; len = pp->hdr.len; /* ntohl() converted already in __pmGetPDU() */ numcred = ntohl(pp->numcreds); if (numcred < 0 || numcred > LIMIT_CREDS) return PM_ERR_IPC; need = sizeof(creds_t) + ((numcred-1) * sizeof(__pmCred)); if (need != len) return PM_ERR_IPC; *sender = pp->hdr.from; /* ntohl() converted already in __pmGetPDU() */ if ((list = (__pmCred *)malloc(sizeof(__pmCred) * numcred)) == NULL) return -oserror(); /* swab and fix bitfield order */ for (i = 0; i < numcred; i++) { list[i] = __ntohpmCred(pp->credlist[i]); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) for (i = 0; i < numcred; i++) fprintf(stderr, "__pmDecodeCreds: #%d = { type=0x%x a=0x%x b=0x%x c=0x%x }\n", i, list[i].c_type, list[i].c_vala, list[i].c_valb, list[i].c_valc); #endif *credlist = list; *credcount = numcred; return 0; } pcp-3.8.12ubuntu1/src/libpcp/GNUmakefile0000664000000000000000000000147012272262501014716 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs LSRCFILES = GNUlocaldefs.32 SUBDIRS = src $(PCP_ALTLIBS) default install : $(SUBDIRS) $(SUBDIRS_MAKERULE) include $(BUILDRULES) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/libpcp_trace/0000775000000000000000000000000012272262617014030 5ustar pcp-3.8.12ubuntu1/src/libpcp_trace/src/0000775000000000000000000000000012272262617014617 5ustar pcp-3.8.12ubuntu1/src/libpcp_trace/src/ftrace.c0000664000000000000000000000544012272262501016222 0ustar /* * ftrace.c - Fortran front-end to the libpcp_trace entry points * * Copyright (c) 1997-2000 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "trace.h" #include "trace_dev.h" int pmtracebegin_(const char *tag, int tag_len) { char *tmp = NULL; int sts; if ((tmp = malloc(tag_len + 1)) == NULL) return -oserror(); strncpy(tmp, tag, tag_len); tmp[tag_len] = '\0'; sts = pmtracebegin(tmp); free(tmp); return sts; } int pmtraceend_(const char *tag, int tag_len) { char *tmp = NULL; int sts; if ((tmp = malloc(tag_len + 1)) == NULL) return -oserror(); strncpy(tmp, tag, tag_len); tmp[tag_len] = '\0'; sts = pmtraceend(tmp); free(tmp); return sts; } int pmtraceabort_(const char *tag, int tag_len) { char *tmp = NULL; int sts; if ((tmp = malloc(tag_len + 1)) == NULL) return -oserror(); strncpy(tmp, tag, tag_len); tmp[tag_len] = '\0'; sts = pmtraceabort(tmp); free(tmp); return sts; } int pmtracepoint_(const char *tag, int tag_len) { char *tmp = NULL; int sts; if ((tmp = malloc(tag_len + 1)) == NULL) return -oserror(); strncpy(tmp, tag, tag_len); tmp[tag_len] = '\0'; sts = pmtracepoint(tmp); free(tmp); return sts; } int pmtracecounter_(const char *tag, double *value, int tag_len) { char *tmp = NULL; int sts; if ((tmp = malloc(tag_len + 1)) == NULL) return -oserror(); strncpy(tmp, tag, tag_len); tmp[tag_len] = '\0'; sts = pmtracecounter(tmp, *value); free(tmp); return sts; } int #ifdef __GNUC__ pmtraceobs_(const char *tag, int tag_len, double *value) #else pmtraceobs_(const char *tag, double *value, int tag_len) #endif { char *tmp = NULL; int sts; if ((tmp = malloc(tag_len + 1)) == NULL) return -oserror(); strncpy(tmp, tag, tag_len); tmp[tag_len] = '\0'; sts = pmtraceobs(tmp, *value); free(tmp); return sts; } void pmtraceerrstr_(int *code, char *msg, int msg_len) { char *tmp; int len; tmp = pmtraceerrstr(*code); len = (int)strlen(tmp); len = (len < msg_len ? len : msg_len); strncpy(msg, tmp, len); for (; len < msg_len; len++) /* blank fill */ msg[len-1] = ' '; } int pmtracestate_(int *code) { return pmtracestate(*code); } pcp-3.8.12ubuntu1/src/libpcp_trace/src/trace.c0000664000000000000000000005526412272262501016065 0ustar /* * trace.c - client-side interface for trace PMDA * * Copyright (c) 1997-2004 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include "pmapi.h" #include "impl.h" #if defined(HAVE_PTHREAD_H) #include #elif defined(HAVE_ABI_MUTEX_H) #include #elif !defined(IS_MINGW) #error !bozo! #endif #include "hash.h" #include "trace.h" #include "trace_dev.h" static int _pmtimedout = 1; static time_t _pmttimeout = 0; static int _pmtraceconnect(int); static int _pmtracereconnect(void); static int _pmauxtraceconnect(void); static void _pmtraceupdatewait(void); static int _pmtracegetack(int, int); static int _pmtraceremaperr(int); static __uint64_t _pmtraceid(void); int __pmstate = PMTRACE_STATE_NONE; static double __pmtracetvsub(const struct timeval *a, const struct timeval *b) { return (double)(a->tv_sec - b->tv_sec + (double)(a->tv_usec - b->tv_usec)/1000000.0); } /* transaction data unit */ typedef struct { __uint64_t id; char *tag; unsigned int tracetype : 7; unsigned int inprogress : 1; unsigned int taglength : 8; unsigned int pad : 16; struct timeval start; /* transaction started timestamp */ double data; /* time interval / -1 / user-defined */ } _pmTraceLibdata; static int _pmlibcmp(void *a, void *b) { _pmTraceLibdata *aa = (_pmTraceLibdata *)a; _pmTraceLibdata *bb = (_pmTraceLibdata *)b; if (!aa || !bb || (aa->id != bb->id)) return 0; if (aa->tracetype != bb->tracetype) return 0; if (aa->id != bb->id) return 0; return !strcmp(aa->tag, bb->tag); } static void _pmlibdel(void *entry) { _pmTraceLibdata *data = (_pmTraceLibdata *)entry; if (data->tag) free(data->tag); if (data) free(data); } static int __pmfd; static __pmHashTable _pmtable; #if defined(HAVE_PTHREAD_MUTEX_T) /* use portable pthreads for mutex */ static pthread_mutex_t _pmtracelock; #define TRACE_LOCK_INIT pthread_mutex_init(&_pmtracelock, NULL) #define TRACE_LOCK pthread_mutex_lock(&_pmtracelock) #define TRACE_UNLOCK pthread_mutex_unlock(&_pmtracelock) #elif defined(HAVE_ABI_MUTEX_H) /* use an SGI spinlock for mutex */ static abilock_t _pmtracelock; #define TRACE_LOCK_INIT init_lock(&_pmtracelock) #define TRACE_LOCK spin_lock(&_pmtracelock) #define TRACE_UNLOCK release_lock(&_pmtracelock) #elif defined(IS_MINGW) /* use native Win32 primitives */ static HANDLE _pmtracelock; #define TRACE_LOCK_INIT (_pmtracelock = CreateMutex(NULL, FALSE, NULL), 0) #define TRACE_LOCK WaitForSingleObject(_pmtracelock, INFINITE) #define TRACE_UNLOCK ReleaseMutex(_pmtracelock) #else #error !bozo! #endif int pmtracebegin(const char *tag) { static int first = 1; _pmTraceLibdata *hptr; _pmTraceLibdata hash; int len, a_sts = 0, b_sts = 0, protocol; if (tag == NULL || *tag == '\0') return PMTRACE_ERR_TAGNAME; if ((len = strlen(tag)+1) >= MAXTAGNAMELEN) return PMTRACE_ERR_TAGLENGTH; hash.tag = (char *)tag; hash.taglength = len; hash.id = _pmtraceid(); hash.tracetype = TRACE_TYPE_TRANSACT; /* * We need to do both the connect and hash table manipulation, * otherwise the reconnect isn't reliable and the hash table * (potentially) becomes completely wrong, and we reject some * transact calls which actually were in a valid call sequence. */ protocol = __pmtraceprotocol(TRACE_PROTOCOL_QUERY); if (_pmtimedout && (a_sts = _pmtraceconnect(1)) < 0) { if (first || protocol == TRACE_PROTOCOL_ASYNC) return a_sts; /* exception to the rule */ a_sts = _pmtraceremaperr(a_sts); if (a_sts == PMTRACE_ERR_IPC && protocol == TRACE_PROTOCOL_SYNC) { _pmtimedout = 1; /* try reconnect */ a_sts = 0; } } if (a_sts >= 0) first = 0; /* lock hash table for search and subsequent insert/update */ TRACE_LOCK; if ((hptr = __pmhashlookup(&_pmtable, tag, &hash)) == NULL) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtracebegin: new transaction '%s' " "(id=0x%" PRIx64 ")\n", tag, hash.id); #endif hash.pad = 0; if ((hash.tag = strdup(tag)) == NULL) b_sts = -oserror(); __pmtimevalNow(&hash.start); if (b_sts >= 0) { hash.inprogress = 1; b_sts = __pmhashinsert(&_pmtable, tag, &hash); } if (b_sts < 0 && hash.tag != NULL) free(hash.tag); } else if (hptr->inprogress == 1) b_sts = PMTRACE_ERR_INPROGRESS; else if (hptr->tracetype != TRACE_TYPE_TRANSACT) b_sts = PMTRACE_ERR_TAGTYPE; else { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtracebegin: updating transaction '%s' " "(id=0x%" PRIx64 ")\n", tag, hash.id); #endif __pmtimevalNow(&hptr->start); hptr->inprogress = 1; } /* unlock hash table */ if (TRACE_UNLOCK != 0) b_sts = -oserror(); if (a_sts < 0) return a_sts; return b_sts; } int pmtraceend(const char *tag) { _pmTraceLibdata hash; _pmTraceLibdata *hptr; struct timeval now; int len, protocol, sts = 0; if (tag == NULL || *tag == '\0') return PMTRACE_ERR_TAGNAME; if ((len = strlen(tag)+1) >= MAXTAGNAMELEN) return PMTRACE_ERR_TAGLENGTH; __pmtimevalNow(&now); /* give just enough info for comparison routine */ hash.tag = (char *)tag; hash.taglength = len; hash.id = _pmtraceid(); hash.tracetype = TRACE_TYPE_TRANSACT; /* lock hash table for search and update then send data */ TRACE_LOCK; if ((hptr = __pmhashlookup(&_pmtable, tag, &hash)) == NULL) sts = PMTRACE_ERR_NOSUCHTAG; else if (hptr->inprogress != 1) sts = PMTRACE_ERR_NOPROGRESS; else if (hptr->tracetype != TRACE_TYPE_TRANSACT) sts = PMTRACE_ERR_TAGTYPE; else { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtraceend: sending transaction data '%s' " "(id=0x%" PRIx64 ")\n", tag, hash.id); #endif hptr->inprogress = 0; hptr->data = __pmtracetvsub(&now, &hptr->start); if (sts >= 0 && _pmtimedout) { sts = _pmtracereconnect(); sts = _pmtraceremaperr(sts); } if (sts >= 0) { sts = __pmtracesenddata(__pmfd, hptr->tag, hptr->taglength, TRACE_TYPE_TRANSACT, hptr->data); sts = _pmtraceremaperr(sts); } protocol = __pmtraceprotocol(TRACE_PROTOCOL_QUERY); if (sts >= 0 && protocol == TRACE_PROTOCOL_SYNC) sts = _pmtracegetack(sts, TRACE_TYPE_TRANSACT); if (sts == PMTRACE_ERR_IPC && protocol == TRACE_PROTOCOL_SYNC) { _pmtimedout = 1; /* try reconnect */ sts = 0; } } if (TRACE_UNLOCK != 0) return -oserror(); return sts; } int pmtraceabort(const char *tag) { _pmTraceLibdata hash; _pmTraceLibdata *hptr; int len, sts = 0; if (tag == NULL || *tag == '\0') return PMTRACE_ERR_TAGNAME; if ((len = strlen(tag)+1) >= MAXTAGNAMELEN) return PMTRACE_ERR_TAGLENGTH; hash.tag = (char *)tag; hash.taglength = len; hash.id = _pmtraceid(); hash.tracetype = TRACE_TYPE_TRANSACT; /* lock hash table for search and update */ TRACE_LOCK; if ((hptr = __pmhashlookup(&_pmtable, tag, &hash)) == NULL) sts = PMTRACE_ERR_NOSUCHTAG; else if (hptr->inprogress != 1) sts = PMTRACE_ERR_NOPROGRESS; else if (hptr->tracetype != TRACE_TYPE_TRANSACT) sts = PMTRACE_ERR_TAGTYPE; else { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtraceabort: aborting transaction '%s' " "(id=0x%" PRIx64 ")\n", tag, hash.id); #endif hptr->inprogress = 0; } if (TRACE_UNLOCK != 0) return -oserror(); return sts; } static int _pmtracecommon(const char *label, double value, int type) { static int first = 1; int taglength; int protocol; int sts = 0; if (label == NULL || *label == '\0') return PMTRACE_ERR_TAGNAME; taglength = (unsigned int)strlen(label)+1; if (taglength >= MAXTAGNAMELEN) return PMTRACE_ERR_TAGLENGTH; #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "_pmtracecommon: trace tag '%s' (type=%d,value=%f)\n", label, type, value); #endif protocol = __pmtraceprotocol(TRACE_PROTOCOL_QUERY); if (_pmtimedout && (sts = _pmtraceconnect(1)) < 0) { if (first || protocol == TRACE_PROTOCOL_ASYNC) return sts; sts = _pmtraceremaperr(sts); if (sts == PMTRACE_ERR_IPC && protocol == TRACE_PROTOCOL_SYNC) { _pmtimedout = 1; /* try reconnect */ sts = 0; } return sts; } first = 0; TRACE_LOCK; if (sts >= 0 && _pmtimedout) { sts = _pmtracereconnect(); sts = _pmtraceremaperr(sts); } if (sts >= 0) { sts = __pmtracesenddata(__pmfd, (char *)label, (int)strlen(label)+1, type, value); sts = _pmtraceremaperr(sts); } protocol = __pmtraceprotocol(TRACE_PROTOCOL_QUERY); if (sts >= 0 && protocol == TRACE_PROTOCOL_SYNC) sts = _pmtracegetack(sts, type); if (sts == PMTRACE_ERR_IPC && protocol == TRACE_PROTOCOL_SYNC) { _pmtimedout = 1; sts = 0; } if (TRACE_UNLOCK != 0) return -oserror(); return sts; } int pmtracepoint(const char *label) { return _pmtracecommon(label, -1, TRACE_TYPE_POINT); } int pmtracecounter(const char *label, double value) { return _pmtracecommon(label, value, TRACE_TYPE_COUNTER); } int pmtraceobs(const char *label, double value) { return _pmtracecommon(label, value, TRACE_TYPE_OBSERVE); } char * pmtraceerrstr(int code) { static const struct { int code; char *msg; } errtab[] = { { PMTRACE_ERR_TAGNAME, "Invalid tag name - tag names cannot be NULL" }, { PMTRACE_ERR_INPROGRESS, "Transaction is already in progress - cannot begin" }, { PMTRACE_ERR_NOPROGRESS, "Transaction is not currently in progress - cannot end" }, { PMTRACE_ERR_NOSUCHTAG, "Transaction tag was not successfully initialised" }, { PMTRACE_ERR_TAGTYPE, "Tag is already in use for a different type of tracing" }, { PMTRACE_ERR_TAGLENGTH, "Tag name is too long (maximum 256 characters)" }, { PMTRACE_ERR_IPC, "IPC protocol failure" }, { PMTRACE_ERR_ENVFORMAT, "Unrecognised environment variable format" }, { PMTRACE_ERR_TIMEOUT, "Application timed out connecting to the PMDA" }, { PMTRACE_ERR_VERSION, "Incompatible versions between application and PMDA" }, { PMTRACE_ERR_PERMISSION, "Cannot connect to PMDA - permission denied" }, { PMTRACE_ERR_CONNLIMIT, "Cannot connect to PMDA - connection limit reached" }, { 0, "" } }; if ((code < 0) && (code > -PMTRACE_ERR_BASE)) /* intro(2) errors */ return strerror(-code); else if (code == 0) return "No error."; else { int i; for (i=0; errtab[i].code; i++) { if (errtab[i].code == code) return errtab[i].msg; } } return "Unknown error code."; } static int _pmtraceremaperr(int sts) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceremaperr: status %d remapped to %d\n", sts, (sts == -EBADF || sts == -EPIPE || sts == -ETIMEDOUT || sts == -ECONNRESET || sts == -ECONNREFUSED)? PMTRACE_ERR_IPC : sts); #endif if (sts == -EBADF || sts == -EPIPE || sts == -ETIMEDOUT || sts == -ECONNRESET || sts == -ECONNREFUSED) { _pmtimedout = 1; return PMTRACE_ERR_IPC; } return sts; } static __uint64_t _pmtraceid(void) { __uint64_t myid = 0; myid |= getpid(); return myid; } /* * gets an ack from the PMDA, based on expected ACK type. * if type is zero, expects and returns the version, otherwise * ACK is for a sent data PDU. */ static int _pmtracegetack(int sts, int type) { if (sts >= 0) { __pmTracePDU *ack; int status, acktype; #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_NOAGENT) { fprintf(stderr, "_pmtracegetack: awaiting ack (skipped)\n"); return 0; } else if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtracegetack: awaiting ack ...\n"); #endif status = __pmtracegetPDU(__pmfd, TRACE_TIMEOUT_DEFAULT, &ack); if (status < 0) { if ((status = _pmtraceremaperr(status)) == PMTRACE_ERR_IPC) return 0; /* hide this - try reconnect later */ return status; } else if (status == 0) { _pmtimedout = 1; return PMTRACE_ERR_IPC; } else if (status == TRACE_PDU_ACK) { if ((status = __pmtracedecodeack(ack, &acktype)) < 0) return _pmtraceremaperr(status); else if (type != 0 && acktype == type) return 0; /* alls well */ else if (acktype < 0) return _pmtraceremaperr(acktype); else if (type == 0) /* acktype contains PDU version if needed (not currently) */ return acktype; return PMTRACE_ERR_IPC; } else { fprintf(stderr, "_pmtracegetack: unknown PDU type (0x%x)\n", status); return PMTRACE_ERR_IPC; } } return _pmtraceremaperr(sts); } static void _pmtraceupdatewait(void) { static int defbackoff[] = {5, 10, 20, 40, 80}; static int *backoff = NULL; static int n_backoff = 0; char *q; #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceupdatewait: updating reconnect back-off\n"); #endif if (n_backoff == 0) { /* compute backoff before trying again */ if ((q = getenv(TRACE_ENV_RECTIMEOUT)) != NULL) { char *pend, *p; int val; for (p=q; *p != '\0'; ) { val = (int)strtol(p, &pend, 10); if (val <= 0 || (*pend != ',' && *pend != '\0')) { n_backoff = 0; if (backoff != NULL) free(backoff); #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceupdatewait: bad reconnect " "format in %s.\n", TRACE_ENV_RECTIMEOUT); #endif break; } if ((backoff = (int *)realloc(backoff, n_backoff * sizeof(backoff[0]))) == NULL) break; backoff[n_backoff++] = val; if (*pend == '\0') break; p = &pend[1]; } } if (n_backoff == 0) { /* use defaults */ n_backoff = 5; backoff = defbackoff; } } if (_pmtimedout == 0) _pmtimedout = 1; else if (_pmtimedout < n_backoff) _pmtimedout++; _pmttimeout = time(NULL) + backoff[_pmtimedout-1]; #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceupdatewait: next attempt after %d seconds\n", backoff[_pmtimedout-1]); #endif } static int _pmtracereconnect(void) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_NOAGENT) { fprintf(stderr, "_pmtracereconnect: reconnect attempt (skipped)\n"); return 0; } else if (__pmstate & PMTRACE_STATE_COMMS) { fprintf(stderr, "_pmtracereconnect: attempting PMDA reconnection\n"); } #endif if (_pmtimedout && time(NULL) < _pmttimeout) { /* too soon to retry */ #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtracereconnect: too soon to retry " "(%d seconds remain)\n", (int)(_pmttimeout - time(NULL))); #endif return -ETIMEDOUT; } if (__pmfd >= 0) { __pmtracenomoreinput(__pmfd); close(__pmfd); __pmfd = -1; } if (_pmtraceconnect(1) < 0) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtracereconnect: failed to reconnect\n"); #endif _pmtraceupdatewait(); return -ETIMEDOUT; } else { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtracereconnect: reconnect succeeded!\n"); #endif _pmtimedout = 0; } return 0; } #ifndef IS_MINGW static struct itimerval _pmmyitimer, off_itimer; static void _pmtracealarm(int dummy) { } static void _pmtraceinit(void) { } #else static void _pmtraceinit(void) { WORD wVersionRequested = MAKEWORD(2, 2); WSADATA wsaData; WSAStartup(wVersionRequested, &wsaData); _fmode = O_BINARY; } #endif static int _pmtraceconnect(int doit) { static int first = 1; int sts = 0; if (!_pmtimedout) return 0; else if (first) { /* once-off, not to be done on reconnect */ _pmtraceinit(); if (TRACE_LOCK_INIT < 0) return -oserror(); first = 0; TRACE_LOCK; sts = __pmhashinit(&_pmtable, 0, sizeof(_pmTraceLibdata), _pmlibcmp, _pmlibdel); if (TRACE_UNLOCK != 0) return -oserror(); } else if (__pmtraceprotocol(TRACE_PROTOCOL_QUERY) == TRACE_PROTOCOL_ASYNC) return PMTRACE_ERR_IPC; if (sts >= 0 && doit) sts = _pmauxtraceconnect(); if (sts >= 0) __pmtraceprotocol(TRACE_PROTOCOL_FINAL); return sts; } static int _pmauxtraceconnect(void) { int port = TRACE_PORT; char hostname[MAXHOSTNAMELEN]; struct timeval timeout = { 3, 0 }; /* default 3 secs */ struct sockaddr_in myaddr; struct hostent *servinfo; struct linger nolinger = {1, 0}; #ifndef IS_MINGW struct itimerval _pmolditimer; void (*old_handler)(int foo); #endif int rc, sts = 0; int flags; int nodelay=1; char *sptr, *endptr, *endnum; #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_NOAGENT) { fprintf(stderr, "_pmtraceconnect: connecting to PMDA (skipped)\n"); return 0; } else if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceconnect: connecting to PMDA ...\n"); #endif /* * get optional stuff from environment ... * PCP_TRACE_HOST, PCP_TRACE_PORT, PCP_TRACE_TIMEOUT, and * PCP_TRACE_NOAGENT */ if ((sptr = getenv(TRACE_ENV_HOST)) != NULL) strcpy(hostname, sptr); else { (void)gethostname(hostname, MAXHOSTNAMELEN); hostname[MAXHOSTNAMELEN-1] = '\0'; } if ((sptr = getenv(TRACE_ENV_PORT)) != NULL) { port = (int)strtol(sptr, &endnum, 0); if (*endnum != '\0' || port < 0) { fprintf(stderr, "trace warning: bad PCP_TRACE_PORT ignored."); port = TRACE_PORT; } } if ((sptr = getenv(TRACE_ENV_TIMEOUT)) != NULL) { double timesec = strtod(sptr, &endptr); if (*endptr != '\0' || timesec < 0.0) fprintf(stderr, "trace warning: bogus PCP_TRACE_TIMEOUT."); else { timeout.tv_sec = (time_t)timesec; timeout.tv_usec = (int)((timesec - (double)timeout.tv_sec)*1000000); } } if (getenv(TRACE_ENV_NOAGENT) != NULL) __pmstate |= PMTRACE_STATE_NOAGENT; if ((servinfo = gethostbyname(hostname)) == NULL) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceconnect(gethostbyname(hostname=%s): " "hosterror=%d, ``%s''\n", hostname, hosterror(), hoststrerror()); #endif return -EHOSTUNREACH; } /* Create socket and attempt to connect to the local PMDA */ if ((__pmfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceconnect(socket failed): %s\n", netstrerror()); #endif return -neterror(); } /* avoid 200 ms delay */ if (setsockopt(__pmfd, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, (__pmSockLen)sizeof(nodelay)) < 0) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceconnect(setsockopt1 failed): %s\n", netstrerror()); #endif return -neterror(); } /* don't linger on close */ if (setsockopt(__pmfd, SOL_SOCKET, SO_LINGER, (char *)&nolinger, (__pmSockLen)sizeof(nolinger)) < 0) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceconnect(setsockopt2 failed): %s\n", netstrerror()); #endif return -neterror(); } memset(&myaddr, 0, sizeof(myaddr)); myaddr.sin_family = AF_INET; memcpy(&myaddr.sin_addr, servinfo->h_addr, servinfo->h_length); myaddr.sin_port = htons(port); #ifndef IS_MINGW /* arm interval timer */ _pmmyitimer.it_value.tv_sec = timeout.tv_sec; _pmmyitimer.it_value.tv_usec = timeout.tv_usec; _pmmyitimer.it_interval.tv_sec = 0; _pmmyitimer.it_interval.tv_usec = 0; old_handler = signal(SIGALRM, _pmtracealarm); setitimer(ITIMER_REAL, &_pmmyitimer, &_pmolditimer); #endif #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) { fprintf(stderr, "_pmtraceconnect: PMDA host=%s port=%d timeout=%d" "secs\n", servinfo->h_name, port, (int)timeout.tv_sec); } #endif if ((rc = connect(__pmfd, (struct sockaddr*) &myaddr, sizeof(myaddr))) < 0) return -neterror(); #ifndef IS_MINGW /* re-arm interval timer */ setitimer(ITIMER_REAL, &off_itimer, &_pmmyitimer); signal(SIGALRM, old_handler); if (_pmolditimer.it_value.tv_sec != 0 && _pmolditimer.it_value.tv_usec != 0) { _pmolditimer.it_value.tv_usec -= timeout.tv_usec - _pmmyitimer.it_value.tv_usec; while (_pmolditimer.it_value.tv_usec < 0) { _pmolditimer.it_value.tv_usec += 1000000; _pmolditimer.it_value.tv_sec--; } while (_pmolditimer.it_value.tv_usec > 1000000) { _pmolditimer.it_value.tv_usec -= 1000000; _pmolditimer.it_value.tv_sec++; } _pmolditimer.it_value.tv_sec -= timeout.tv_sec - _pmmyitimer.it_value.tv_sec; if (_pmolditimer.it_value.tv_sec < 0) { /* missed the user's itimer, pretend there is 1 msec to go! */ _pmolditimer.it_value.tv_sec = 0; _pmolditimer.it_value.tv_usec = 1000; } setitimer(ITIMER_REAL, &_pmolditimer, &_pmmyitimer); } #endif _pmtimedout = 0; /* make sure this file descriptor is closed if exec() is called */ if ((flags = fcntl(__pmfd, F_GETFD)) != -1) sts = fcntl(__pmfd, F_SETFD, flags | FD_CLOEXEC); else sts = -1; if (sts == -1) return -oserror(); if (__pmtraceprotocol(TRACE_PROTOCOL_QUERY) == TRACE_PROTOCOL_ASYNC) { /* in the asynchronoous protocol - ensure no delay after close */ if ((flags = fcntl(__pmfd, F_GETFL)) != -1) sts = fcntl(__pmfd, F_SETFL, flags | FNDELAY); else sts = -1; if (sts == -1) return -oserror(); #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceconnect: async protocol setup complete\n"); #endif } else #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_COMMS) fprintf(stderr, "_pmtraceconnect: sync protocol setup complete\n"); #endif /* trace PMDA sends an ACK on successful connect */ sts = _pmtracegetack(sts, 0); return sts; } /* this is used internally to maintain connection state */ int __pmtraceprotocol(int update) { static int fixedinstone = 0; static int protocol = TRACE_PROTOCOL_SYNC; if (update == TRACE_PROTOCOL_QUERY) /* just a state request */ return protocol; else if (update == TRACE_PROTOCOL_FINAL) /* no more changes allowed */ fixedinstone = 1; else if (!fixedinstone && update == TRACE_PROTOCOL_ASYNC) { __pmstate |= PMTRACE_STATE_ASYNC; protocol = update; } return protocol; } int pmtracestate(int code) { int old = __pmstate; if (code & PMTRACE_STATE_ASYNC) { if (__pmtraceprotocol(TRACE_PROTOCOL_ASYNC) != TRACE_PROTOCOL_ASYNC) /* only can do this before connection established */ return -EINVAL; } __pmstate = code; return old; } pcp-3.8.12ubuntu1/src/libpcp_trace/src/hash.c0000664000000000000000000000751512272262501015706 0ustar /* * hash.c - hash table used by trace pmda and libpcp_trace * * Copyright (c) 1997-2000 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "hash.h" static unsigned int hashindex(const char *key, size_t tablesize) { unsigned int hash, i; char *p = (char *)key; /* use first few chars for hash table distribution */ for (i=0, hash=0; i < 5 && *p; i++) hash = (hash << PM_HASH_SHFT) - hash + *p++; #ifdef DESPERATE fprintf(stderr, "Generated hash number: %d (%s)\n", hash % tablesize, key); #endif return hash % (unsigned int)tablesize; } int __pmhashinit(__pmHashTable *t, size_t tsize, size_t esize, __pmHashCmpFunc cmp, __pmHashDelFunc del) { size_t blocksize; t->tsize = tsize; t->esize = esize; t->entries = 0; t->cmp = cmp; t->del = del; if (t->tsize <= 0) /* use default */ t->tsize = PM_HASH_SIZE; blocksize = sizeof(__pmHashEnt *) * t->tsize; if ((t->rows = (__pmHashEnt **)malloc(blocksize)) == NULL) return -oserror(); memset((void *)t->rows, 0, blocksize); return 0; } static int hashalloc(__pmHashTable *t, __pmHashEnt **entry) { int e; if ((*entry = (__pmHashEnt *)malloc(sizeof(__pmHashEnt))) == NULL) return -oserror(); if (((*entry)->ent = malloc(t->esize)) == NULL) { e = -oserror(); free(*entry); *entry = NULL; return e; } (*entry)->next = NULL; return 0; } void __pmhashtrunc(__pmHashTable *t) { if (t == NULL || t->rows == NULL || t->entries <= 0) return; else { __pmHashEnt *tmp, *e; int i; for (i = 0; i < PM_HASH_SIZE; i++) { e = t->rows[i]; while (e != NULL) { tmp = e; e = e->next; if (tmp->ent != NULL) { t->del(tmp->ent); tmp->ent = NULL; } if (tmp) { free(tmp); tmp = NULL; } } t->rows[i] = NULL; } memset((void *)t->rows, 0, sizeof(__pmHashEnt *)*t->tsize); t->entries = 0; } } void * __pmhashlookup(__pmHashTable *t, const char *key, void *result) { __pmHashEnt *e; int index; if (t->entries == 0) return NULL; index = hashindex(key, t->tsize); e = t->rows[index]; while (e != NULL) { if (t->cmp(e->ent, result)) break; e = e->next; } if (e == NULL) return NULL; return e->ent; } int __pmhashinsert(__pmHashTable *t, const char *key, void *entry) { __pmHashEnt *hash = NULL; int index, sts; if ((sts = hashalloc(t, &hash)) < 0) return sts; index = hashindex(key, t->tsize); /* stick at head of list (locality of reference) */ memcpy(hash->ent, entry, t->esize); if (t->rows[index]) { hash->next = t->rows[index]->next; t->rows[index]->next = hash; } else { t->rows[index] = hash; t->rows[index]->next = NULL; } t->entries++; #ifdef DESPERATE fprintf(stderr, "Insert: %s at 0x%x (key=%d entry=%d)\n", key, &t->rows[index], index, t->entries); #endif return 0; } void __pmhashtraverse(__pmHashTable *t, __pmHashIterFunc func) { __pmHashEnt *e = NULL; unsigned int i, hits; if (t == NULL || func == NULL) return; for (i = 0, hits = 0; i < PM_HASH_SIZE && hits < t->entries; i++) { e = t->rows[i]; while (e != NULL && hits < t->entries) { hits++; if (e->ent != NULL) func(t, e->ent); e = e->next; } } #ifdef DESPERATE fprintf(stderr, "Traverse: looped %d times\n", i); #endif } pcp-3.8.12ubuntu1/src/libpcp_trace/src/p_ack.c0000664000000000000000000000346712272262501016042 0ustar /* * Copyright (c) 1997-2000 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "trace.h" #include "trace_dev.h" /* * PDU for general receive acknowledgement (TRACE_PDU_ACK) */ typedef struct { __pmTracePDUHdr hdr; __int32_t data; /* ack for specific PDU type / error code */ } ack_t; int __pmtracesendack(int fd, __int32_t data) { ack_t *pp; if (__pmstate & PMTRACE_STATE_NOAGENT) { fprintf(stderr, "__pmtracesendack: sending acka (skipped)\n"); return 0; } if ((pp = (ack_t *)__pmtracefindPDUbuf(sizeof(ack_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(ack_t); pp->hdr.type = TRACE_PDU_ACK; pp->data = htonl(data); #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_PDU) fprintf(stderr, "__pmtracesendack(data=%d)\n", (int)pp->data); #endif return __pmtracexmitPDU(fd, (__pmTracePDU *)pp); } int __pmtracedecodeack(__pmTracePDU *pdubuf, __int32_t *data) { ack_t *pp; char *pduend; pp = (ack_t *)pdubuf; pduend = (char *)pdubuf + pp->hdr.len; if (pduend - (char*)pp != sizeof(ack_t)) return PMTRACE_ERR_IPC; *data = ntohl(pp->data); #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_PDU) fprintf(stderr, "__pmtracedecodeack -> data=%d\n", (int)*data); #endif return 0; } pcp-3.8.12ubuntu1/src/libpcp_trace/src/exports0000664000000000000000000000151112272262501016234 0ustar PCP_TRACE_2.0 { global: /* C and Fortran calling interfaces */ pmtraceabort; pmtraceabort_; pmtracebegin; pmtracebegin_; pmtracecounter; pmtracecounter_; pmtraceend; pmtraceend_; pmtraceobs; pmtraceobs_; pmtracepoint; pmtracepoint_; pmtracestate; pmtracestate_; pmtraceerrstr; pmtraceerrstr_; /* Internals shared between pmdatrace and libpcp_trace */ __pmhashinit; __pmhashinsert; __pmhashlookup; __pmhashtraverse; __pmhashtrunc; __pmstate; __pmtracedecodeack; __pmtracedecodedata; __pmtracefindPDUbuf; __pmtracegetPDU; __pmtracemoreinput; __pmtracenomoreinput; __pmtracepinPDUbuf; __pmtraceprotocol; __pmtracesendack; __pmtracesenddata; __pmtraceunpinPDUbuf; __pmtracexmitPDU; local: *; }; pcp-3.8.12ubuntu1/src/libpcp_trace/src/pdubuf.c0000664000000000000000000001032012272262501016234 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include #include #include #include "trace.h" #include "trace_dev.h" typedef struct bufctl { struct bufctl *bc_next; int bc_size; int bc_pincnt; char *bc_buf; char *bc_bufend; } bufctl_t; static bufctl_t *buf_free; static bufctl_t *buf_pin; static bufctl_t *buf_pin_tail; #ifdef PMTRACE_DEBUG static void pdubufdump(void) { bufctl_t *pcp; if (buf_free != NULL) { fprintf(stderr, " free pdubuf[size]:"); for (pcp = buf_free; pcp != NULL; pcp = pcp->bc_next) fprintf(stderr, " 0x%p[%d]", pcp->bc_buf, pcp->bc_size); fputc('\n', stderr); } if (buf_pin != NULL) { fprintf(stderr, " pinned pdubuf[pincnt]:"); for (pcp = buf_pin; pcp != NULL; pcp = pcp->bc_next) fprintf(stderr, " 0x%p[%d]", pcp->bc_buf, pcp->bc_pincnt); fputc('\n', stderr); } } #endif __pmTracePDU * __pmtracefindPDUbuf(int need) { bufctl_t *pcp; for (pcp = buf_free; pcp != NULL; pcp = pcp->bc_next) { if (pcp->bc_size >= need) break; } if (pcp == NULL) { if ((pcp = (bufctl_t *)malloc(sizeof(*pcp))) == NULL) return NULL; pcp->bc_pincnt = 0; pcp->bc_size = TRACE_PDU_CHUNK * (1 + need/TRACE_PDU_CHUNK); if ((pcp->bc_buf = (char *)valloc(pcp->bc_size)) == NULL) { free(pcp); return NULL; } pcp->bc_next = buf_free; pcp->bc_bufend = &pcp->bc_buf[pcp->bc_size]; buf_free = pcp; } #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_PDUBUF) { fprintf(stderr, "__pmtracefindPDUbuf(%d) -> 0x%p\n", need, pcp->bc_buf); pdubufdump(); } #endif return (__pmTracePDU *)pcp->bc_buf; } void __pmtracepinPDUbuf(void *handle) { bufctl_t *pcp; bufctl_t *prior = NULL; for (pcp = buf_free; pcp != NULL; pcp = pcp->bc_next) { if (pcp->bc_buf <= (char *)handle && (char *)handle < pcp->bc_bufend) break; prior = pcp; } if (pcp != NULL) { /* first pin for this buffer, move between lists */ if (prior == NULL) buf_free = pcp->bc_next; else prior->bc_next = pcp->bc_next; pcp->bc_next = NULL; if (buf_pin_tail != NULL) buf_pin_tail->bc_next = pcp; buf_pin_tail = pcp; if (buf_pin == NULL) buf_pin = pcp; pcp->bc_pincnt = 1; } else { for (pcp = buf_pin; pcp != NULL; pcp = pcp->bc_next) { if (pcp->bc_buf <= (char *)handle && (char *)handle < pcp->bc_bufend) break; } if (pcp != NULL) pcp->bc_pincnt++; else { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_PDUBUF) { fprintf(stderr, "__pmtracepinPDUbuf: 0x%p not in pool!", handle); pdubufdump(); } #endif return; } } #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_PDUBUF) fprintf(stderr, "__pmtracepinPDUbuf(0x%p) -> pdubuf=0x%p, cnt=%d\n", handle, pcp->bc_buf, pcp->bc_pincnt); #endif return; } int __pmtraceunpinPDUbuf(void *handle) { bufctl_t *pcp; bufctl_t *prior = NULL; for (pcp = buf_pin; pcp != NULL; pcp = pcp->bc_next) { if (pcp->bc_buf <= (char *)handle && (char *)handle < &pcp->bc_buf[pcp->bc_size]) break; prior = pcp; } if (pcp == NULL) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_PDUBUF) { fprintf(stderr, "__pmtraceunpinPDUbuf(0x%p) -> fails\n", handle); pdubufdump(); } #endif return 0; } if (--pcp->bc_pincnt == 0) { if (prior == NULL) buf_pin = pcp->bc_next; else prior->bc_next = pcp->bc_next; if (buf_pin_tail == pcp) buf_pin_tail = prior; pcp->bc_next = buf_free; buf_free = pcp; } #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_PDUBUF) fprintf(stderr, "__pmtraceunpinPDUbuf(0x%p) -> pdubuf=0x%p, pincnt=%d\n", handle, pcp->bc_buf, pcp->bc_pincnt); #endif return 1; } pcp-3.8.12ubuntu1/src/libpcp_trace/src/GNUmakefile0000664000000000000000000000347712272262501016674 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs HFILES = hash.h CFILES = trace.c hash.c pdu.c pdubuf.c p_ack.c p_data.c ftrace.c VERSION_SCRIPT = exports LCFLAGS = -DPMTRACE_DEBUG LLDLIBS = $(LIB_FOR_PTHREADS) -lpcp LSRCFILES = $(VERSION_SCRIPT) STATICLIBTARGET = libpcp_trace.a DSOVERSION = 2 LIBTARGET = libpcp_trace.$(DSOSUFFIX).$(DSOVERSION) SYMTARGET = libpcp_trace.$(DSOSUFFIX) ifeq "$(TARGET_OS)" "darwin" LIBTARGET = libpcp_trace.$(DSOVERSION).$(DSOSUFFIX) endif ifeq "$(TARGET_OS)" "mingw" STATICLIBTARGET = LIBTARGET = libpcp_trace.$(DSOSUFFIX) SYMTARGET = endif ifeq "$(ENABLE_SHARED)" "no" LIBTARGET = SYMTARGET = endif LDIRT = $(SYMTARGET) base default: $(LIBTARGET) $(SYMTARGET) $(STATICLIBTARGET) ifneq ($(SYMTARGET),) $(SYMTARGET): $(LN_S) -f $(LIBTARGET) $(SYMTARGET) endif include $(BUILDRULES) install : default ifneq ($(LIBTARGET),) $(INSTALL) -m 755 $(LIBTARGET) $(PCP_LIB_DIR)/$(LIBTARGET) endif ifneq ($(SYMTARGET),) $(INSTALL) -S $(LIBTARGET) $(PCP_LIB_DIR)/$(SYMTARGET) endif ifneq ($(STATICLIBTARGET),) $(INSTALL) -m 755 $(STATICLIBTARGET) $(PCP_LIB_DIR)/$(STATICLIBTARGET) endif default_pcp : default install_pcp : install ifneq ($(LIBTARGET),) $(LIBTARGET): $(VERSION_SCRIPT) endif pcp-3.8.12ubuntu1/src/libpcp_trace/src/hash.h0000664000000000000000000000306712272262501015711 0ustar /* * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _TRACE_HASH_H #define _TRACE_HASH_H typedef int (*__pmHashCmpFunc)(void *, void *); typedef int (*__pmHashKeyCmpFunc)(void *, const char *); typedef void (*__pmHashDelFunc)(void *); struct __pmHashEl { void *ent; struct __pmHashEl *next; }; typedef struct __pmHashEl __pmHashEnt; struct __pmHashTab { size_t tsize; size_t esize; unsigned int entries; __pmHashCmpFunc cmp; __pmHashDelFunc del; __pmHashEnt **rows; }; typedef struct __pmHashTab __pmHashTable; extern int __pmhashinit(__pmHashTable *, size_t, size_t, __pmHashCmpFunc, __pmHashDelFunc); extern void __pmhashtrunc(__pmHashTable *); extern int __pmhashinsert(__pmHashTable *, const char *, void *); extern void *__pmhashlookup(__pmHashTable *, const char *, void *); typedef void (*__pmHashIterFunc)(__pmHashTable *, void *); extern void __pmhashtraverse(__pmHashTable *, __pmHashIterFunc); #ifndef PM_HASH_TUNE #define PM_HASH_SHFT 5 #define PM_HASH_SIZE 31 #endif #endif /* _TRACE_HASH_H */ pcp-3.8.12ubuntu1/src/libpcp_trace/src/p_data.c0000664000000000000000000001137712272262501016214 0ustar /* * Copyright (c) 1997-2002 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * Assumptions: * 1. "double" is 64-bits * 2. "double" is IEEE format and needs endian conversion (like a * 64-bit integer, but no other format conversion */ #include "pmapi.h" #include "impl.h" #include "trace.h" #include "trace_dev.h" /* * PDU for all trace data updates (TRACE_PDU_DATA) * * note "taglen" includes the null-byte terminator */ typedef struct { __pmTracePDUHdr hdr; struct { #ifdef HAVE_BITFIELDS_LTOR unsigned int version : 8; unsigned int taglen : 8; unsigned int tagtype : 8; unsigned int protocol : 1; unsigned int pad : 7; #else unsigned int pad : 7; unsigned int protocol : 1; unsigned int tagtype : 8; unsigned int taglen : 8; unsigned int version : 8; #endif } bits; /* * avoid struct padding traps! * * what really follows is a double (data) and then the tag */ } tracedata_t; #ifdef HAVE_NETWORK_BYTEORDER #define trace_htonll(a) do { } while (0) /* noop */ #define trace_ntohll(a) do { } while (0) /* noop */ #else static void trace_htonll(char *p) { char c; int i; for (i = 0; i < 4; i++) { c = p[i]; p[i] = p[7-i]; p[7-i] = c; } } #define trace_ntohll(v) trace_htonll(v) #endif int __pmtracesenddata(int fd, char *tag, int taglen, int tagtype, double data) { tracedata_t *pp = NULL; size_t need = 0; char *cp; int *ip; if (taglen <= 0) return PMTRACE_ERR_IPC; else if (__pmstate & PMTRACE_STATE_NOAGENT) { fprintf(stderr, "__pmtracesenddata: sending data (skipped)\n"); return 0; } /* * pad to the next __pmTracePDU boundary */ need = sizeof(tracedata_t) + sizeof(double) + sizeof(__pmTracePDU)*((taglen - 1 + sizeof(__pmTracePDU))/sizeof(__pmTracePDU)); if ((pp = (tracedata_t *)__pmtracefindPDUbuf((int)need)) == NULL) return -oserror(); pp->hdr.len = (int)need; pp->hdr.type = TRACE_PDU_DATA; pp->bits.taglen = taglen; pp->bits.tagtype = tagtype; pp->bits.version = TRACE_PDU_VERSION; if (__pmtraceprotocol(TRACE_PROTOCOL_QUERY) == TRACE_PROTOCOL_SYNC) pp->bits.protocol = 1; else pp->bits.protocol = 0; pp->bits.pad = 0; ip = (int *)&pp->bits; *ip = htonl(*ip); cp = (char *)pp; cp += sizeof(tracedata_t); memcpy((void *)cp, (void *)&data, sizeof(double)); trace_htonll(cp); /* send in network byte order */ cp += sizeof(double); strcpy(cp, tag); #ifdef PCP_DEBUG if ((taglen % sizeof(__pmTracePDU)) != 0) { /* for Purify */ int pad; char *padp = cp + taglen; for (pad = sizeof(__pmTracePDU) - 1; pad >= (taglen % sizeof(__pmTracePDU)); pad--) *padp++ = '~'; /* buffer end */ } #endif #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_PDU) fprintf(stderr, "__pmtracesenddata(tag=\"%s\", data=%f)\n", tag, data); #endif return __pmtracexmitPDU(fd, (__pmTracePDU *)pp); } int __pmtracedecodedata(__pmTracePDU *pdubuf, char **tag, int *taglenp, int *tagtype, int *protocol, double *data) { tracedata_t *pp; int *ip; char *cp; char *pduend; int taglen; if (pdubuf == NULL) return PMTRACE_ERR_IPC; pp = (tracedata_t *)pdubuf; pduend = (char *)pdubuf + pp->hdr.len; if (pduend - (char*)pp < sizeof(tracedata_t) + sizeof(double)) return PMTRACE_ERR_IPC; ip = (int *)&pp->bits; *ip = ntohl(*ip); taglen = pp->bits.taglen; if (pp->bits.version != TRACE_PDU_VERSION) return PMTRACE_ERR_VERSION; if (taglen <= 0 || taglen >= CHAR_MAX - 1 || taglen > pp->hdr.len) return PMTRACE_ERR_IPC; if (pduend - (char *)pp < sizeof(tracedata_t) + sizeof(double) + taglen) return PMTRACE_ERR_IPC; *taglenp = taglen; *tagtype = pp->bits.tagtype; *protocol = pp->bits.protocol; cp = (char *)pp; cp += sizeof(tracedata_t); memcpy((void *)data, (void *)cp, sizeof(double)); trace_ntohll((char *)data); /* receive in network byte order */ cp += sizeof(double); if ((*tag = (char *)malloc(taglen+1)) == NULL) return -oserror(); strncpy(*tag, cp, taglen); (*tag)[taglen] = '\0'; #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_PDU) fprintf(stderr, "__pmtracedecodedata -> tag=\"%s\" data=%f\n", *tag, *data); #endif return 0; } pcp-3.8.12ubuntu1/src/libpcp_trace/src/pdu.c0000664000000000000000000002666212272262501015557 0ustar /* * Copyright (c) 1997-2000,2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2012 Red Hat. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include #include "pmapi.h" #include "impl.h" #include "trace.h" #include "trace_dev.h" typedef struct { __pmTracePDU *pdubuf; int len; } more_ctl; static more_ctl *more; static int maxfd = -1; static char * pdutypestr(int type) { if (type == TRACE_PDU_ACK) return "ACK"; else if (type == TRACE_PDU_DATA) return "DATA"; else { static char buf[20]; snprintf(buf, sizeof(buf), "TYPE-%d?", type); return buf; } } static void moreinput(int fd, __pmTracePDU *pdubuf, int len) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_PDU) { __pmTracePDUHdr *php = (__pmTracePDUHdr *)pdubuf; __pmTracePDU *p; int j, jend; char *q; jend = (php->len+(int)sizeof(__pmTracePDU)-1)/(int)sizeof(__pmTracePDU); fprintf(stderr, "moreinput: fd=%d pdubuf=0x%p len=%d\n", fd, pdubuf, len); fprintf(stderr, "Piggy-back PDU: %s addr=0x%p len=%d from=%d", pdutypestr(php->type), php, php->len, php->from); fprintf(stderr, "%03d: ", 0); p = (__pmTracePDU *)php; /* for Purify ... */ q = (char *)p + php->len; while (q < (char *)p + jend*sizeof(__pmTracePDU)) *q++ = '~'; /* buffer end */ for (j = 0; j < jend; j++) { if ((j % 8) == 0) fprintf(stderr, "\n%03d: ", j); fprintf(stderr, "%8x ", p[j]); } putc('\n', stderr); } #endif if (fd > maxfd) { int next = maxfd + 1; if ((more = (more_ctl *)realloc(more, (fd+1)*sizeof(more[0]))) == NULL) { fprintf(stderr, "realloc failed (%d bytes): %s\n", (fd+1)*(int)sizeof(more[0]), osstrerror()); return; } maxfd = fd; while (next <= maxfd) { more[next].pdubuf = NULL; next++; } } __pmtracepinPDUbuf(pdubuf); more[fd].pdubuf = pdubuf; more[fd].len = len; } int __pmtracemoreinput(int fd) { if (fd < 0 || fd > maxfd) return 0; return more[fd].pdubuf == NULL ? 0 : 1; } void __pmtracenomoreinput(int fd) { if (fd < 0 || fd > maxfd) return; if (more[fd].pdubuf != NULL) { __pmtraceunpinPDUbuf(more[fd].pdubuf); more[fd].pdubuf = NULL; } } static int pduread(int fd, char *buf, int len, int mode, int timeout) { /* * handle short reads that may split a PDU ... */ int status = 0; int have = 0; __pmFdSet onefd; static int done_default = 0; static struct timeval def_wait = { 10, 0 }; if (timeout == TRACE_TIMEOUT_DEFAULT) { if (!done_default) { double def_timeout; char *timeout_str; char *end_ptr; if ((timeout_str = getenv(TRACE_ENV_REQTIMEOUT)) != NULL) { def_timeout = strtod(timeout_str, &end_ptr); if (*end_ptr != '\0' || def_timeout < 0.0) { status = PMTRACE_ERR_ENVFORMAT; return status; } else { def_wait.tv_sec = (int)def_timeout; /* truncate -> secs */ if (def_timeout > (double)def_wait.tv_sec) def_wait.tv_usec = (long)((def_timeout - (double)def_wait.tv_sec) * 1000000); else def_wait.tv_usec = 0; } } done_default = 1; } } while (len) { struct timeval wait; /* * either never timeout (i.e. block forever), or timeout */ if (timeout != TRACE_TIMEOUT_NEVER) { if (timeout > 0) { wait.tv_sec = timeout; wait.tv_usec = 0; } else wait = def_wait; __pmFD_ZERO(&onefd); __pmFD_SET(fd, &onefd); status = __pmSelectRead(fd+1, &onefd, &wait); if (status == 0) return PMTRACE_ERR_TIMEOUT; else if (status < 0) { setoserror(neterror()); return status; } } status = (int)__pmRead(fd, buf, len); if (status <= 0) { /* EOF or error */ setoserror(neterror()); return status; } if (mode == -1) /* special case, see __pmtracegetPDU */ return status; have += status; buf += status; len -= status; } return have; } /* * Because the default handler for SIGPIPE is to exit, we always want a handler * installed to override that so that the write() just returns an error. The * problem is that the user might have installed one prior to the first write() * or may install one at some later stage. This doesn't matter. As long as a * handler other than SIG_DFL is there, all will be well. The first time that * __pmtracexmitPDU is called, install SIG_IGN as the handler for SIGPIPE. * If the user had already changed the handler from SIG_DFL, put back what was * there before. */ int __pmtracexmitPDU(int fd, __pmTracePDU *pdubuf) { int n, len; __pmTracePDUHdr *php = (__pmTracePDUHdr *)pdubuf; #if defined(HAVE_SIGPIPE) SIG_PF user_onpipe; user_onpipe = signal(SIGPIPE, SIG_IGN); if (user_onpipe != SIG_DFL) /* put user handler back */ signal(SIGPIPE, user_onpipe); #endif php->from = (__int32_t)getpid(); #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_PDU) { int j; int jend = (php->len+(int)sizeof(__pmTracePDU)-1)/(int)sizeof(__pmTracePDU); char *p; /* for Purify ... */ p = (char *)pdubuf + php->len; while (p < (char *)pdubuf + jend*sizeof(__pmTracePDU)) *p++ = '~'; /* buffer end */ fprintf(stderr, "[%d]__pmtracexmitPDU: %s fd=%d len=%d", php->from, pdutypestr(php->type), fd, php->len); for (j = 0; j < jend; j++) { if ((j % 8) == 0) fprintf(stderr, "\n%03d: ", j); fprintf(stderr, "%8x ", pdubuf[j]); } putc('\n', stderr); } #endif len = php->len; php->len = htonl(php->len); php->from = htonl(php->from); php->type = htonl(php->type); n = (int)__pmWrite(fd, pdubuf, len); php->len = ntohl(php->len); php->from = ntohl(php->from); php->type = ntohl(php->type); if (n != len) return -oserror(); return n; } int __pmtracegetPDU(int fd, int timeout, __pmTracePDU **result) { int need, len; char *handle; static int maxsize = TRACE_PDU_CHUNK; __pmTracePDU *pdubuf; __pmTracePDU *pdubuf_prev; __pmTracePDUHdr *php; /* * This stuff is a little tricky. What we try to do is read() * an amount of data equal to the largest PDU we have (or are * likely to have) seen thus far. In the majority of cases * this returns exactly one PDU's worth, i.e. read() returns * a length equal to php->len. * * For this to work, we have a special "mode" of -1 * to pduread() which means read, but return after the * first read(), rather than trying to read up to the request * length with multiple read()s, which would of course "hang" * after the first PDU arrived. * * We need to handle the following tricky cases: * 1. We get _more_ than we need for a single PDU -- happens * when PDU's arrive together. This requires "moreinput" * to handle leftovers here (it gets even uglier if we * have part, but not all of the second PDU). * 2. We get _less_ than we need for a single PDU -- this * requires at least another read(), and possibly acquiring * another pdubuf and doing a memcpy() for the partial PDU * from the earlier call. */ if (__pmtracemoreinput(fd)) { /* some leftover from last time ... handle -> start of PDU */ pdubuf = more[fd].pdubuf; len = more[fd].len; __pmtracenomoreinput(fd); } else { if ((pdubuf = __pmtracefindPDUbuf(maxsize)) == NULL) return -oserror(); len = pduread(fd, (void *)pdubuf, maxsize, -1, timeout); } php = (__pmTracePDUHdr *)pdubuf; if (len < (int)sizeof(__pmTracePDUHdr)) { if (len == -1) { if (oserror() == ECONNRESET|| oserror() == ETIMEDOUT || oserror() == ENETDOWN || oserror() == ENETUNREACH || oserror() == EHOSTDOWN || oserror() == EHOSTUNREACH || oserror() == ECONNREFUSED) /* * failed as a result of pmdatrace exiting and the * connection being reset, or as a result of the kernel * ripping down the connection (most likely because the * host at the other end just took a dive) * * treat this like end of file on input * * from irix/kern/fs/nfs/bds.c seems like all of the * following are peers here: * ECONNRESET (pmdatrace terminated?) * ETIMEDOUT ENETDOWN ENETUNREACH EHOSTDOWN EHOSTUNREACH * ECONNREFUSED * peers for bds but not here: * ENETRESET ENONET ESHUTDOWN (cache_fs only?) * ECONNABORTED (accept, user req only?) * ENOTCONN (udp?) * EPIPE EAGAIN (nfs, bds & ..., but not ip or tcp?) */ len = 0; else fprintf(stderr, "__pmtracegetPDU: fd=%d hdr: %s", fd, osstrerror()); } else if (len > 0) fprintf(stderr, "__pmtracegetPDU: fd=%d hdr: len=%d, not %d?", fd, len, (int)sizeof(__pmTracePDUHdr)); else if (len == PMTRACE_ERR_TIMEOUT) return PMTRACE_ERR_TIMEOUT; else if (len < 0) fprintf(stderr, "__pmtracegetPDU: fd=%d hdr: %s", fd, pmtraceerrstr(len)); return len ? PMTRACE_ERR_IPC : 0; } php->len = ntohl(php->len); if (php->len < 0) { fprintf(stderr, "__pmtracegetPDU: fd=%d illegal len=%d in hdr\n", fd, php->len); return PMTRACE_ERR_IPC; } if (len == php->len) /* return below */ ; else if (len > php->len) { /* * read more than we need for this one, save it up for next time */ handle = (char *)pdubuf; moreinput(fd, (__pmTracePDU *)&handle[php->len], len - php->len); } else { int tmpsize; /* * need to read more ... */ __pmtracepinPDUbuf(pdubuf); pdubuf_prev = pdubuf; if (php->len > maxsize) tmpsize = TRACE_PDU_CHUNK * ( 1 + php->len / TRACE_PDU_CHUNK); else tmpsize = maxsize; if ((pdubuf = __pmtracefindPDUbuf(tmpsize)) == NULL) { __pmtraceunpinPDUbuf(pdubuf_prev); return -oserror(); } if (php->len > maxsize) maxsize = tmpsize; memmove((void *)pdubuf, (void *)php, len); __pmtraceunpinPDUbuf(pdubuf_prev); php = (__pmTracePDUHdr *)pdubuf; need = php->len - len; handle = (char *)pdubuf; /* block until all of the PDU is received this time */ len = pduread(fd, (void *)&handle[len], need, 0, timeout); if (len != need) { if (len == PMTRACE_ERR_TIMEOUT) return PMTRACE_ERR_TIMEOUT; if (len < 0) fprintf(stderr, "__pmtracegetPDU: error (%d) fd=%d: %s\n", (int)oserror(), fd, osstrerror()); else fprintf(stderr, "__pmtracegetPDU: len=%d, not %d? (fd=%d)\n", len, need, fd); fprintf(stderr, "hdr: len=0x%08x type=0x%08x from=0x%08x\n", php->len, (int)ntohl(php->type), (int)ntohl(php->from)); return PMTRACE_ERR_IPC; } } *result = (__pmTracePDU *)php; php->type = ntohl(php->type); php->from = ntohl(php->from); #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_PDU) { int j; int jend = (int)(php->len+(int)sizeof(__pmTracePDU)-1)/(int)sizeof(__pmTracePDU); char *p; /* for Purify ... */ p = (char *)*result + php->len; while (p < (char *)*result + jend*sizeof(__pmTracePDU)) *p++ = '~'; /* buffer end */ fprintf(stderr, "[%" FMT_PID "]__pmtracegetPDU: %s fd=%d len=%d from=%d", getpid(), pdutypestr(php->type), fd, php->len, php->from); for (j = 0; j < jend; j++) { if ((j % 8) == 0) fprintf(stderr, "\n%03d: ", j); fprintf(stderr, "%8x ", (*result)[j]); } putc('\n', stderr); } #endif return php->type; } pcp-3.8.12ubuntu1/src/libpcp_trace/GNUmakefile0000664000000000000000000000142212272262501016071 0ustar #!gmake # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs SUBDIRS = src default install : $(SUBDIRS) $(SUBDIRS_MAKERULE) include $(BUILDRULES) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmlogsummary/0000775000000000000000000000000012272262620014127 5ustar pcp-3.8.12ubuntu1/src/pmlogsummary/pmwtf.sh0000775000000000000000000001337312272262501015630 0ustar #!/bin/sh # # Copyright (c) 2008-2010 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Compare two PCP archives and report significant differences # tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1 sts=0 trap "rm -rf $tmp; exit \$sts" 0 1 2 3 15 _usage() { echo "Usage: $0 [options] archive1 [archive2]" echo echo "Options:" echo " -d debug, keep temp files" echo " -p digits number of digits to display after the decimal point" echo " -q thres change interesting threshold to be > thres or < 1/thres" echo " [default 2]" echo " -S start start time, see PCPIntro(1)" echo " -T end end time, see PCPIntro(1)" echo " -B start start time, second archive (optional)" echo " -E end end time, second archive (optional)" echo " -x metric egrep(1) pattern of metric(s) to be excluded" echo " -X file file containing egrep(1) patterns to exclude" echo " -z use local timezone, see PCPIntro(1)" echo " -Z zone set reporting timezone" sts=1 exit $sts } _fix() { sed -e 's/ *\([0-9][0-9.]*\)\([^"]*\)$/|\1/' \ | egrep -v -f $tmp/exclude \ | sort -t\| -k1,1 } cat <<'End-of-File' >$tmp/exclude ^pmcd.pmlogger.port End-of-File thres=2 opts="" start1="" start2="" finish1="" finish2="" precision=3 while getopts dp:q:S:T:B:E:x:X:zZ:? c do case $c in d) trap "exit \$sts" 0 1 2 3 15 otmp="$tmp" tmp=`pwd`/tmp if [ -d $tmp ] then : else mkdir $tmp || exit 1 fi mv $otmp/exclude $tmp/exclude rmdir $otmp ;; p) precision="$OPTARG" opts="$opts -p $precision" ;; q) thres="$OPTARG" ;; S) start1="$OPTARG" ;; T) finish1="$OPTARG" ;; B) start2="$OPTARG" ;; E) finish2="$OPTARG" ;; x) echo "$OPTARG" >>$tmp/exclude ;; X) cat "$OPTARG" >>$tmp/exclude ;; z) opts="$opts -z" ;; Z) opts="$opts -Z $OPTARG" ;; ?) _usage # NOTREACHED ;; esac done shift `expr $OPTIND - 1` if [ $# -lt 1 -o $# -gt 2 ] then _usage # NOTREACHED elif [ $# -eq 2 ] then arch1=$1 arch2=$2 else arch1=$1 arch2=$1 fi echo "Directory: `pwd`" echo "Excluded metrics:" sed -e 's/^/ /' <$tmp/exclude echo options="$opts" if [ "X$start1" != X ]; then options="$options -S $start1" fi if [ "X$finish1" != X ]; then options="$options -T $finish1" fi pmlogsummary -N $options $arch1 2>$tmp/err | _fix >$tmp/1 if [ -s $tmp/err ] then echo "Warnings from pmlogsummary ... $arch1" cat $tmp/err echo fi options="$opts" if [ "X$start2" != X ]; then options="$options -S $start2" elif [ "X$start1" != X ]; then options="$options -S $start1" fi if [ "X$finish2" != X ]; then options="$options -T $finish2" elif [ "X$finish1" != X ]; then options="$options -T $finish1" fi pmlogsummary -N $options $arch2 2>$tmp/err | _fix >$tmp/2 if [ -s $tmp/err ] then echo "Warnings from pmlogsummary ... $arch2" cat $tmp/err echo fi if [ -z "$start1" ] then window1="start" else window1="$start1" fi if [ -z "$finish1" ] then window1="$window1-end" else window1="$window1-$finish1" fi if [ -z "$start2" ] then window2="start" else window2="$start2" fi if [ -z "$finish2" ] then window2="$window2-end" else window2="$window2-$finish2" fi join -t\| -v 2 $tmp/1 $tmp/2 >$tmp/tmp if [ -s $tmp/tmp ] then echo "Missing from $arch1 $window1 (not compared) ..." sed <$tmp/tmp -e 's/|.*//' -e 's/^/ /' echo fi join -t\| -v 1 $tmp/1 $tmp/2 >$tmp/tmp if [ -s $tmp/tmp ] then echo "Missing from $arch2 $window2 (not compared) ..." sed <$tmp/tmp -e 's/|.*//' -e 's/^/ /' echo fi a1=`basename "$arch1"` a2=`basename "$arch2"` echo "$thres" | awk ' { printf "Ratio Threshold: > %.2f or < %.3f\n",'"$thres"',1/'"$thres"' printf "%15s %15s Ratio Metric-Instance\n","'"$a1"'","'"$a2"'" }' if [ -z "$start1" ] then window1="start" else window1="$start1" fi if [ -z "$finish1" ] then window1="$window1-end" else window1="$window1-$finish1" fi if [ -z "$start2" ] then window2="start" else window2="$start2" fi if [ -z "$finish2" ] then window2="$window2-end" else window2="$window2-$finish2" fi printf '%15s %15s\n' "$window1" "$window2" join -t\| $tmp/1 $tmp/2 \ | awk -F\| ' function doval(v) { precision='"$precision"' if (precision < 3 || precision > 15) precision=3 extra=precision-3 if (v > 99999999) printf "%*.*f%*s",15+extra,0,v,1," " else if (v > 999) printf "%*.*f%*s",11,0,v,2+precision," " else if (v > 99) printf "%*.*f%*s",13+extra,1+extra,v,3," " else if (v > 9) printf "%*.*f%*s",14+extra,2+extra,v,2," " else printf "%*.*f%*s",15+extra,precision,v,1," " } $3+0 == 0 || $2+0 == 0 { if ($3 == $2) next doval($2) doval($3) printf " " if ($3+0 == 0) printf "|-| %s\n",$1 else if ($2+0 == 0) printf "|+| %s\n",$1 next } $2 / $3 > '"$thres"' || $3 / $2 > '"$thres"' { doval($2) doval($3) printf " " r = $3/$2 if (r < 0.001) printf " 0.001-" else if (r < 0.01) printf "%6.3f ",r else if (r > 100) printf " 100+ " else printf "%5.2f ",r printf " %s\n",$1 }' \ | sort -nr -k 3,3 \ | sed -e 's/100+/>100/' -e 's/ 0.001-/<0.001 /' pcp-3.8.12ubuntu1/src/pmlogsummary/GNUmakefile0000664000000000000000000000224512272262501016202 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmlogcheck.c pmlogsummary.c TARGETS = pmlogcheck$(EXECSUFFIX) pmlogsummary$(EXECSUFFIX) LSRCFILES = pmwtf.sh LLDLIBS = $(PCPLIB) $(LIB_FOR_MATH) LDIRT += $(TARGETS) default: $(TARGETS) pmlogcheck$(EXECSUFFIX): pmlogcheck.o $(CCF) -o $@ $(LDFLAGS) pmlogcheck.o $(LDLIBS) pmlogsummary$(EXECSUFFIX): pmlogsummary.o $(CCF) -o $@ $(LDFLAGS) pmlogsummary.o $(LDLIBS) include $(BUILDRULES) install: $(TARGETS) $(INSTALL) -m 755 $(TARGETS) $(PCP_BIN_DIR) $(INSTALL) -m 755 pmwtf.sh $(PCP_BINADM_DIR)/pmwtf default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmlogsummary/pmlogcheck.c0000664000000000000000000004144612272262501016416 0ustar /* * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "pmapi.h" #include "impl.h" static void usage(void) { fprintf(stderr, "Usage: %s [options] archive\n\n\ Options:\n\ -l print the archive label\n\ -n pmnsfile use an alternative PMNS\n\ -S starttime start of the time window\n\ -T endtime end of the time window\n\ -Z timezone set reporting timezone\n\ -z set reporting timezone to local time of metrics source\n", pmProgname); } typedef struct { int inst; double lastval; /* value from previous sample */ struct timeval lasttime; /* time of previous sample */ } instData; typedef struct { pmDesc desc; double scale; instData **instlist; unsigned int listsize; } checkData; /* * Hash control for statistics about each metric */ static __pmHashCtl hashlist; /* time stuff */ static int sflag = 0; static int tflag = 0; static struct timeval logstart = {0, 0}; static struct timeval logend = {0, 0}; static struct timeval windowstart = {0, 0}; static struct timeval windowend = {0, 0}; static int dayflag = 0; static char timebuf[32]; /* for pmCtime result + .xxx */ /* time manipulation */ static int tsub(struct timeval *a, struct timeval *b) { if ((a == NULL) || (b == NULL)) return -1; a->tv_usec -= b->tv_usec; if (a->tv_usec < 0) { a->tv_usec += 1000000; a->tv_sec--; } a->tv_sec -= b->tv_sec; return 0; } static double tosec(struct timeval t) { return t.tv_sec + (t.tv_usec / 1000000.0); } static char * typeStr(int pmtype) { switch (pmtype) { case PM_TYPE_32: return "signed 32-bit"; case PM_TYPE_U32: return "unsigned 32-bit"; case PM_TYPE_64: return "signed 64-bit"; case PM_TYPE_U64: return "unsigned 64-bit"; } return "unknown type"; } static void print_metric(FILE *f, pmID pmid) { char *name = NULL; if (pmNameID(pmid, &name) < 0) fprintf(f, "%s", pmIDStr(pmid)); else { fprintf(f, "%s", name); free(name); } } static void print_stamp(FILE *f, struct timeval *stamp) { if (dayflag) { char *ddmm; char *yr; ddmm = pmCtime(&stamp->tv_sec, timebuf); ddmm[10] = ' '; ddmm[11] = '\0'; yr = &ddmm[20]; fprintf(f, "%s", ddmm); __pmPrintStamp(f, stamp); fprintf(f, " %4.4s", yr); } else __pmPrintStamp(f, stamp); } static double unwrap(double current, struct timeval *curtime, checkData *checkdata, int index) { double outval = current; int wrapflag = 0; char *str = NULL; if ((current - checkdata->instlist[index]->lastval) < 0.0) { switch (checkdata->desc.type) { case PM_TYPE_32: case PM_TYPE_U32: outval += (double)UINT_MAX+1; wrapflag = 1; break; case PM_TYPE_64: case PM_TYPE_U64: outval += (double)ULONGLONG_MAX+1; wrapflag = 1; break; default: wrapflag = 0; } } if (wrapflag) { printf("["); print_stamp(stdout, curtime); printf("]: "); print_metric(stdout, checkdata->desc.pmid); if (pmNameInDom(checkdata->desc.indom, checkdata->instlist[index]->inst, &str) < 0) printf(": %s wrap", typeStr(checkdata->desc.type)); else { printf("[%s]: %s wrap", str, typeStr(checkdata->desc.type)); free(str); } printf("\n\tvalue %.0f at ", checkdata->instlist[index]->lastval); print_stamp(stdout, &checkdata->instlist[index]->lasttime); printf("\n\tvalue %.0f at ", current); print_stamp(stdout, curtime); putchar('\n'); } return outval; } static void newHashInst(pmValue *vp, checkData *checkdata, /* updated by this function */ int valfmt, struct timeval *timestamp, /* timestamp for this sample */ int pos) /* position of this inst in instlist */ { int sts; size_t size; pmAtomValue av; if ((sts = pmExtractValue(valfmt, vp, checkdata->desc.type, &av, PM_TYPE_DOUBLE)) < 0) { printf("["); print_stamp(stdout, timestamp); printf("] "); print_metric(stdout, checkdata->desc.pmid); printf(": pmExtractValue failed: %s\n", pmErrStr(sts)); fprintf(stderr, "%s: possibly corrupt archive?\n", pmProgname); exit(1); } size = (pos+1)*sizeof(instData*); checkdata->instlist = (instData**) realloc(checkdata->instlist, size); if (!checkdata->instlist) __pmNoMem("newHashInst.instlist", size, PM_FATAL_ERR); size = sizeof(instData); checkdata->instlist[pos] = (instData*) malloc(size); if (!checkdata->instlist[pos]) __pmNoMem("newHashInst.instlist[pos]", size, PM_FATAL_ERR); checkdata->instlist[pos]->inst = vp->inst; checkdata->instlist[pos]->lastval = av.d; checkdata->instlist[pos]->lasttime = *timestamp; checkdata->listsize++; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { char *name; printf("["); print_stamp(stdout, timestamp); printf("] "); print_metric(stdout, checkdata->desc.pmid); if (vp->inst == PM_INDOM_NULL) printf(": new singular metric\n"); else { printf(": new metric-instance pair "); if (pmNameInDom(checkdata->desc.indom, vp->inst, &name) < 0) printf("%d\n", vp->inst); else { printf("\"%s\"\n", name); free(name); } } } #endif } static void newHashItem(pmValueSet *vsp, pmDesc *desc, checkData *checkdata, /* output from this function */ struct timeval *timestamp) /* timestamp for this sample */ { int j; checkdata->desc = *desc; checkdata->scale = 0.0; /* convert counter metric units to rate units & get time scale */ if (checkdata->desc.sem == PM_SEM_COUNTER) { if (checkdata->desc.units.dimTime == 0) checkdata->scale = 1.0; else { if (checkdata->desc.units.scaleTime > PM_TIME_SEC) checkdata->scale = pow(60.0, (double)(PM_TIME_SEC - checkdata->desc.units.scaleTime)); else checkdata->scale = pow(1000.0, (double)(PM_TIME_SEC - checkdata->desc.units.scaleTime)); } if (checkdata->desc.units.dimTime == 0) checkdata->desc.units.scaleTime = PM_TIME_SEC; checkdata->desc.units.dimTime--; } checkdata->listsize = 0; checkdata->instlist = NULL; for (j = 0; j < vsp->numval; j++) { newHashInst(&vsp->vlist[j], checkdata, vsp->valfmt, timestamp, j); } } static void docheck(pmResult *result) { int i, j, k; int sts; pmDesc desc; pmAtomValue av; pmValue *vp; pmValueSet *vsp; __pmHashNode *hptr = NULL; checkData *checkdata = NULL; double diff; struct timeval timediff; for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { if (vsp->numval == 0) { printf("["); print_stamp(stdout, &result->timestamp); printf("] "); print_metric(stdout, vsp->pmid); printf(": No values returned\n"); continue; } else if (vsp->numval < 0) { printf("["); print_stamp(stdout, &result->timestamp); printf("] "); print_metric(stdout, vsp->pmid); printf(": Error from numval: %s\n", pmErrStr(vsp->numval)); continue; } } #endif /* check if pmid already in hash list */ if ((hptr = __pmHashSearch(vsp->pmid, &hashlist)) == NULL) { if ((sts = pmLookupDesc(vsp->pmid, &desc)) < 0) { printf("["); print_stamp(stdout, &result->timestamp); printf("] "); print_metric(stdout, vsp->pmid); printf(": pmLookupDesc failed: %s\n", pmErrStr(sts)); continue; } if (desc.type != PM_TYPE_32 && desc.type != PM_TYPE_U32 && desc.type != PM_TYPE_64 && desc.type != PM_TYPE_U64 && desc.type != PM_TYPE_FLOAT && desc.type != PM_TYPE_DOUBLE) { continue; /* no checks for non-numeric metrics */ } /* create a new one & add to list */ checkdata = (checkData*) malloc(sizeof(checkData)); newHashItem(vsp, &desc, checkdata, &result->timestamp); if (__pmHashAdd(checkdata->desc.pmid, (void*)checkdata, &hashlist) < 0) { printf("["); print_stamp(stdout, &result->timestamp); printf("] "); print_metric(stdout, vsp->pmid); printf(": __pmHashAdd failed (internal pmlogcheck error)\n"); /* free memory allocated above on insert failure */ for (j = 0; j < vsp->numval; j++) { if (checkdata->instlist[j] != NULL) free(checkdata->instlist[j]); } if (checkdata->instlist != NULL) free(checkdata->instlist); continue; } } else { /* pmid exists - update statistics */ checkdata = (checkData *)hptr->data; for (j = 0; j < vsp->numval; j++) { /* iterate thro result values */ vp = &vsp->vlist[j]; k = j; /* index into stored inst list, result may differ */ if ((vsp->numval > 1) || (checkdata->desc.indom != PM_INDOM_NULL)) { /* must store values using correct inst - probably in correct order already */ if ((k < checkdata->listsize) && (checkdata->instlist[k]->inst != vp->inst)) { for (k = 0; k < checkdata->listsize; k++) { if (vp->inst == checkdata->instlist[k]->inst) { break; /* k now correct */ } } if (k == checkdata->listsize) { /* no matching inst was found */ newHashInst(vp, checkdata, vsp->valfmt, &result->timestamp, k); continue; } } else if (k >= checkdata->listsize) { k = checkdata->listsize; newHashInst(vp, checkdata, vsp->valfmt, &result->timestamp, k); continue; } } timediff = result->timestamp; tsub(&timediff, &(checkdata->instlist[k]->lasttime)); if (timediff.tv_sec < 0) { /* clip negative values at zero */ timediff.tv_sec = 0; timediff.tv_usec = 0; } diff = tosec(timediff); if ((sts = pmExtractValue(vsp->valfmt, vp, checkdata->desc.type, &av, PM_TYPE_DOUBLE)) < 0) { printf("["); print_stamp(stdout, &result->timestamp); printf("] "); print_metric(stdout, vsp->pmid); printf(": pmExtractValue failed: %s\n", pmErrStr(sts)); continue; } if (checkdata->desc.sem == PM_SEM_COUNTER) { if (diff == 0.0) continue; diff *= checkdata->scale; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { printf("["); print_stamp(stdout, &result->timestamp); printf("] "); print_metric(stdout, checkdata->desc.pmid); printf(": current counter value is %.0f\n", av.d); } #endif unwrap(av.d, &(result->timestamp), checkdata, k); } checkdata->instlist[k]->lastval = av.d; checkdata->instlist[k]->lasttime = result->timestamp; } } } } int main(int argc, char *argv[]) { int c, sts; char *pmnsfile = PM_NS_DEFAULT; char *startstr = NULL; char *endstr = NULL; char *msg = NULL; int errflag = 0; int lflag = 0; /* no label by default */ pmResult *result; pmLogLabel label; struct timeval unused = {0, 0}; struct timeval timespan = {0, 0}; struct timeval last_stamp; struct timeval delta_stamp; int zflag = 0; /* for -z */ char *tz = NULL; /* for -Z timezone */ __pmSetProgname(argv[0]); while ((c = getopt(argc, argv, "D:ln:S:T:zZ:?")) != EOF) { switch (c) { case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case 'l': /* display label */ lflag = 1; break; case 'n': /* alternative name space file */ pmnsfile = optarg; break; case 'S': startstr = optarg; sflag = 1; break; case 'T': endstr = optarg; tflag = 1; break; case 'z': /* timezone from host */ if (tz != NULL) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); errflag++; } zflag++; break; case 'Z': /* $TZ timezone */ if (zflag) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); errflag++; } tz = optarg; break; case '?': default: errflag++; break; } } if (errflag || optind >= argc) { usage(); exit(1); } if ((sts = pmNewContext(PM_CONTEXT_ARCHIVE, argv[optind])) < 0) { fprintf(stderr, "%s: Cannot open archive \"%s\": %s\n", pmProgname, argv[optind], pmErrStr(sts)); exit(1); } optind++; if (pmnsfile != PM_NS_DEFAULT) { if ((sts = pmLoadNameSpace(pmnsfile)) < 0) { fprintf(stderr, "%s: Cannot load namespace from \"%s\": %s\n", pmProgname, pmnsfile, pmErrStr(sts)); exit(1); } } if ((sts = pmTrimNameSpace()) < 0) { fprintf(stderr, "%s: pmTrimNamespace failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } if ((sts = pmGetArchiveLabel(&label)) < 0) { fprintf(stderr, "%s: Cannot get archive label record: %s\n", pmProgname, pmErrStr(sts)); exit(1); } else { logstart = label.ll_start; last_stamp = logstart; } if (zflag) { if ((sts = pmNewContextZone()) < 0) { fprintf(stderr, "%s: Cannot set context timezone: %s\n", pmProgname, pmErrStr(sts)); exit(1); } printf("Note: timezone set to local timezone of host \"%s\" from archive\n\n", label.ll_hostname); } else if (tz != NULL) { if ((sts = pmNewZone(tz)) < 0) { fprintf(stderr, "%s: Cannot set timezone to \"%s\": %s\n", pmProgname, tz, pmErrStr(sts)); exit(1); } printf("Note: timezone set to \"TZ=%s\"\n\n", tz); } if ((sts = pmGetArchiveEnd(&logend)) < 0) { fprintf(stderr, "%s: Cannot locate end of archive: %s\n", pmProgname, pmErrStr(sts)); exit(1); } if (tflag || sflag) { if (pmParseTimeWindow(startstr, endstr, NULL, NULL, &logstart, &logend, &windowstart, &windowend, &unused, &msg) < 0) { fprintf(stderr, "%s: Invalid time window specified: %s\n", pmProgname, msg); exit(1); } #ifdef PCP_DEBUG else if (pmDebug & DBG_TRACE_APPL0) { printf("parseTimeWindow: \n " "Window start=%.0f end=%.0f sec\nArchive start=%.0f end=%.0f sec\n", tosec(windowstart), tosec(windowend), tosec(logstart), tosec(logend)); } #endif } else { /* time window covers whole log */ windowstart = logstart; windowend = logend; } if ((sts = pmSetMode(PM_MODE_FORW, &windowstart, 0)) < 0) { fprintf(stderr, "%s: pmSetMode failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } if (lflag == 1) { char *ddmm; char *yr; printf("Log Label (Log Format Version %d)\n", label.ll_magic & 0xff); printf("Performance metrics from host %s\n", label.ll_hostname); ddmm = pmCtime(&logstart.tv_sec, timebuf); ddmm[10] = '\0'; yr = &ddmm[20]; printf(" commencing %s ", ddmm); __pmPrintStamp(stdout, &logstart); printf(" %4.4s\n", yr); ddmm = pmCtime(&logend.tv_sec, timebuf); ddmm[10] = '\0'; yr = &ddmm[20]; printf(" ending %s ", ddmm); __pmPrintStamp(stdout, &logend); printf(" %4.4s\n", yr); } timespan = windowend; tsub(×pan, &windowstart); if (timespan.tv_sec > 86400) /* seconds per day: 60*60*24 */ dayflag = 1; sts = 0; for ( ; ; ) { if ((sts = pmFetchArchive(&result)) < 0) break; delta_stamp = result->timestamp; tsub(&delta_stamp, &last_stamp); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { int i; int sum_val = 0; int cnt_noval = 0; int cnt_err = 0; pmValueSet *vsp; printf("["); print_stamp(stdout, &result->timestamp); for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; if (vsp->numval > 0) sum_val += vsp->numval; else if (vsp->numval == 0) cnt_noval++; else cnt_err++; } printf("] delta(stamp)=%d.%03fsec", (int)delta_stamp.tv_sec, (double)(delta_stamp.tv_usec)/1000000); printf(" numpmid=%d sum(numval)=%d", result->numpmid, sum_val); if (cnt_noval > 0) printf(" count(numval=0)=%d", cnt_noval); if (cnt_err > 0) printf(" count(numval<0)=%d", cnt_err); fputc('\n', stdout); } #endif if (delta_stamp.tv_sec < 0) { /* time went backwards! */ printf("["); print_stamp(stdout, &result->timestamp); printf("]: timestamp went backwards, prior timestamp: "); print_stamp(stdout, &last_stamp); printf("\n"); } last_stamp = result->timestamp; if ((windowend.tv_sec > result->timestamp.tv_sec) || ((windowend.tv_sec == result->timestamp.tv_sec) && (windowend.tv_usec >= result->timestamp.tv_usec))) { docheck(result); pmFreeResult(result); } else { pmFreeResult(result); sts = PM_ERR_EOL; break; } } if (sts != PM_ERR_EOL) { printf("[after "); print_stamp(stdout, &last_stamp); printf("]: pmFetch: Error: %s\n", pmErrStr(sts)); exit(1); } return 0; } pcp-3.8.12ubuntu1/src/pmlogsummary/pmlogsummary.c0000664000000000000000000010756512272262501017043 0ustar /* * Copyright (c) 1995-2001,2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "pmapi.h" #include "impl.h" static void usage(void) { fprintf(stderr, "Usage: %s [options] archive [metricname ...]\n\n" "Options:\n" " -a print all information (equivalent to -blmMy)\n" " -b print both stochastic and time averages for counter metrics\n" " -B nbins print value distribution across a number of bins\n" " -f print using \"spreadsheet\" format (tab delimited fields)\n" " -F print using \"spreadsheet\" format (comma separated values)\n" " -i also print timestamp for minimum value\n" " -I also print timestamp for maximum value\n" " -l also print the archive label\n" " -m also print minimum values\n" " -M also print maximum values\n" " -n pmnsfile use an alternative PMNS\n" " -N suppress warnings from individual archive fetches [default]\n" " -p precision number of digits to display after the decimal point\n" " -S starttime start of the time window\n" " -T endtime end of the time window\n" " -v verbose, enable warnings from individual archive fetches\n" " -x print only stochastic averages for counter metrics\n" " -y print sample count for each metric\n" " -z set reporting timezone to local time of metrics source\n" " -Z timezone set reporting timezone\n", pmProgname); exit(1); } typedef struct { int inst; unsigned int count; double stocave; /* stochastic average */ double timeave; /* time average */ double min; /* minimum value */ double max; /* maximum value */ double sum; /* sum of all values */ double lastval; /* value from previous sample */ struct timeval firsttime; /* time of first sample */ struct timeval lasttime; /* time of previous sample */ struct timeval mintime; /* time of minimum sample */ struct timeval maxtime; /* time of maximum sample */ int markcount; /* num mark records seen */ int marked; /* seen since last "mark" record? */ unsigned int bintotal; /* copy of count for 2nd pass */ unsigned int *bin; /* bins for value distribution */ } instData; typedef struct { pmDesc desc; double scale; instData **instlist; unsigned int listsize; } aveData; /* * Hash control for statistics & errors related to each metric */ static __pmHashCtl hashlist; static __pmHashCtl errlist; /* output format flags */ static unsigned int stocaveflag; /* no stochastic counter ave */ static unsigned int timeaveflag = 1;/* use time counter ave */ static unsigned int maxflag; /* no maximum */ static unsigned int minflag; /* no minimum */ static unsigned int sumflag; /* no sum */ static unsigned int maxtimeflag; /* no timestamp for maximum */ static unsigned int mintimeflag; /* no timestamp for minimum */ static unsigned int countflag; /* no count */ static unsigned int warnflag; /* warnings are off by default */ static unsigned int delimiter = ' ';/* output field separator */ static unsigned int nbins; /* number of distribution bins */ static unsigned int precision = 3; /* number of digits after "." */ /* time window stuff */ static int sflag; static int tflag; static int dayflag; static struct timeval logstart; static struct timeval logend; static struct timeval windowstart; static struct timeval windowend; static char timebuf[32]; /* for pmCtime result + .xxx */ /* duration of log */ static double logspan; /* optional metric specification, optionally with instances */ pmMetricSpec *msp; /* time manipulation */ static int tsub(struct timeval *a, struct timeval *b) { if ((a == NULL) || (b == NULL)) return -1; a->tv_usec -= b->tv_usec; if (a->tv_usec < 0) { a->tv_usec += 1000000; a->tv_sec--; } a->tv_sec -= b->tv_sec; if (a->tv_sec < 0) { /* clip negative values at zero */ a->tv_sec = 0; a->tv_usec = 0; } return 0; } static int tadd(struct timeval *a, struct timeval *b) { if ((a == NULL) || (b == NULL)) return -1; a->tv_usec += b->tv_usec; if (a->tv_usec > 1000000) { a->tv_usec -= 1000000; a->tv_sec++; } a->tv_sec += b->tv_sec; return 0; } static double tosec(struct timeval t) { return t.tv_sec + (t.tv_usec / 1000000.0); } static void pmiderr(pmID pmid, const char *msg, ...) { if (warnflag && __pmHashSearch(pmid, &errlist) == NULL) { va_list arg; char *mname = NULL; static char *unknown = "(cannot find metric name) "; pmNameID(pmid, &mname); if (!mname) mname = unknown; fprintf(stderr, "%s: %s(%s) - ", pmProgname, mname, pmIDStr(pmid)); va_start(arg, msg); vfprintf(stderr, msg, arg); va_end(arg); __pmHashAdd(pmid, NULL, &errlist); if (mname && mname != unknown) free(mname); } } static void printstamp(struct timeval *stamp, int delimiter) { if (dayflag) { char *ddmm; char *yr; ddmm = pmCtime(&stamp->tv_sec, timebuf); ddmm[10] = ' '; ddmm[11] = '\0'; yr = &ddmm[20]; printf("%c'%s", delimiter, ddmm); __pmPrintStamp(stdout, stamp); printf(" %4.4s\'", yr); } else { printf("%c", delimiter); __pmPrintStamp(stdout, stamp); } } static void printheaders(void) { printf("metric"); if (stocaveflag) printf("%cstochastic_average", delimiter); if (timeaveflag) printf("%ctime_average", delimiter); if (sumflag) printf("%csum", delimiter); if (minflag) printf("%cminimum", delimiter); if (mintimeflag) printf("%cminimum_time", delimiter); if (maxflag) printf("%cmaximum", delimiter); if (maxtimeflag) printf("%cmaximum_time", delimiter); if (countflag) printf("%ccount", delimiter); if (nbins) printf("%cbins", delimiter); printf("%cunits\n", delimiter); } static void printsummary(const char *name) { int sts; int i, j; int star; pmID pmid; char *str = NULL; const char *u; __pmHashNode *hptr; aveData *avedata; instData *instdata; double metricspan = 0.0; struct timeval metrictimespan; /* cast away const, pmLookupName should never modify name */ if ((sts = pmLookupName(1, (char **)&name, &pmid)) < 0) { fprintf(stderr, "%s: failed to lookup metric name (pmid=%s): %s\n", pmProgname, name, pmErrStr(sts)); return; } /* lookup using pmid, print values according to set flags */ if ((hptr = __pmHashSearch(pmid, &hashlist)) != NULL) { avedata = (aveData*)hptr->data; for (i = 0; i < avedata->listsize; i++) { if ((instdata = avedata->instlist[i]) == NULL) break; if (avedata->desc.sem == PM_SEM_DISCRETE) { double val; struct timeval timediff; /* extend discrete metrics to the archive end */ timediff = logend; tsub(&timediff, &instdata->lasttime); val = instdata->lastval; instdata->stocave += val; instdata->timeave += val*tosec(timediff); instdata->lasttime = logend; instdata->count++; } metrictimespan = instdata->lasttime; tsub(&metrictimespan, &instdata->firsttime); metricspan = tosec(metrictimespan); /* counter metric doesn't cover 90% of log */ star = (avedata->desc.sem == PM_SEM_COUNTER && metricspan / logspan <= 0.1); if ((sts = pmNameInDom(avedata->desc.indom, instdata->inst, &str)) < 0) { if (msp && msp->ninst > 0 && avedata->desc.indom == PM_INDOM_NULL) break; if (star) putchar('*'); if (avedata->desc.indom == PM_INDOM_NULL) printf("%s%c", name, delimiter); else printf("%s%c[%u]", name, delimiter, instdata->inst); } else { /* part of an instance domain */ if (msp && msp->ninst > 0) { for (j = 0; j < msp->ninst; j++) if (strcmp(msp->inst[j], str) == 0) break; if (j == msp->ninst) continue; } if (star) putchar('*'); printf("%s%c[\"%s\"]", name, delimiter, str); } if (str) free(str); str = NULL; /* complete the calculations, count is number of intervals */ if (avedata->desc.sem == PM_SEM_COUNTER) { if (metricspan <= 0) { printf("%c- insufficient archive data.\n", delimiter); continue; } instdata->stocave /= (double)instdata->count; instdata->timeave /= metricspan * avedata->scale; } else { /* non-counters, count is number of observations */ instdata->stocave /= (double)instdata->count; if (metricspan == 0) /* happens for instantaneous metrics */ metricspan = 1; /* only - just report the one value */ instdata->timeave /= metricspan; } if (stocaveflag) printf("%c%.*f", delimiter, (int)precision, instdata->stocave); if (timeaveflag) printf("%c%.*f", delimiter, (int)precision, instdata->timeave); if (sumflag) printf("%c%.*f", delimiter, (int)precision, instdata->sum); if (minflag) printf("%c%.*f", delimiter, (int)precision, instdata->min); if (mintimeflag) printstamp(&instdata->mintime, delimiter); if (maxflag) printf("%c%.*f", delimiter, (int)precision, instdata->max); if (maxtimeflag) printstamp(&instdata->maxtime, delimiter); if (avedata->desc.sem == PM_SEM_DISCRETE) /* all added marks + added endpoint above */ instdata->count = instdata->count - instdata->markcount - 1; if (countflag) printf("%c%u", delimiter, instdata->count); for (j=0; j < nbins; j++) { /* print value distribution summary */ if (j > 0 && instdata->min == instdata->max) /* all in 1st bin */ printf("%c[]%c%u", delimiter, delimiter, 0); else printf("%c[<=%.*f]%c%u", delimiter, (int)precision, ((instdata->max - instdata->min) / nbins * (j+1)) + instdata->min, delimiter, instdata->bin[j]); } u = pmUnitsStr(&avedata->desc.units); printf("%c%s\n", delimiter, *u == '\0' ? "none" : u); if (instdata) { if (instdata->bin) free(instdata->bin); free(instdata); } } if (avedata->instlist) free(avedata->instlist); __pmHashDel(avedata->desc.pmid, (void*)avedata, &hashlist); free(avedata); } } static double unwrap(double current, double previous, int pmtype) { double outval = current; static int dowrap = -1; if ((current - previous) < 0.0) { if (dowrap == -1) { /* PCP_COUNTER_WRAP in environment enables "counter wrap" logic */ if (getenv("PCP_COUNTER_WRAP") == NULL) dowrap = 0; else dowrap = 1; } if (dowrap) { switch (pmtype) { case PM_TYPE_32: case PM_TYPE_U32: outval += (double)UINT_MAX+1; break; case PM_TYPE_64: case PM_TYPE_U64: outval += (double)ULONGLONG_MAX+1; break; } } } return outval; } static void newHashInst(pmValue *vp, aveData *avedata, /* updated by this function */ int valfmt, struct timeval *timestamp, /* timestamp for this sample */ int pos) /* position of this inst in instlist */ { int sts; size_t size; instData *instdata; pmAtomValue av; if ((sts = pmExtractValue(valfmt, vp, avedata->desc.type, &av, PM_TYPE_DOUBLE)) < 0) { pmiderr(avedata->desc.pmid, "failed to extract value: %s\n", pmErrStr(sts)); fprintf(stderr, "%s: possibly corrupt archive?\n", pmProgname); exit(1); } size = (pos+1) * sizeof(instData *); avedata->instlist = (instData **) realloc(avedata->instlist, size); if (avedata->instlist == NULL) __pmNoMem("newHashInst.instlist", size, PM_FATAL_ERR); size = sizeof(instData); avedata->instlist[pos] = instdata = (instData *) malloc(size); if (instdata == NULL) __pmNoMem("newHashInst.instlist[inst]", size, PM_FATAL_ERR); if (nbins == 0) instdata->bin = NULL; else { /* we are doing binning ... make space for the bins */ size = nbins * sizeof(unsigned int); instdata->bin = (unsigned int *)malloc(size); if (instdata->bin == NULL) __pmNoMem("newHashInst.instlist[inst].bin", size, PM_FATAL_ERR); memset(instdata->bin, 0, size); } instdata->inst = vp->inst; if (avedata->desc.sem == PM_SEM_COUNTER) { instdata->min = 0.0; instdata->max = 0.0; instdata->sum = 0.0; instdata->mintime = *timestamp; instdata->maxtime = *timestamp; instdata->stocave = 0.0; instdata->timeave = 0.0; instdata->count = 0; } else { /* for the other semantics */ instdata->min = av.d; instdata->max = av.d; instdata->sum = av.d; instdata->mintime = *timestamp; instdata->maxtime = *timestamp; instdata->stocave = av.d; instdata->timeave = 0.0; instdata->count = 1; } instdata->marked = 0; instdata->bintotal = 0; instdata->markcount = 0; instdata->lastval = av.d; instdata->firsttime = *timestamp; instdata->lasttime = *timestamp; avedata->listsize++; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { char *name = NULL; pmNameID(avedata->desc.pmid, &name); fprintf(stderr, "%s Initially - min/max=%f/%f\n", name, instdata->min, instdata->max); if (name) free(name); } #endif } static void newHashItem(pmValueSet *vsp, pmDesc *desc, aveData *avedata, /* output from this function */ struct timeval *timestamp) /* timestamp for this sample */ { int j; avedata->desc = *desc; avedata->scale = 0.0; /* convert counter metric units to rate units & get time scale */ if (avedata->desc.sem == PM_SEM_COUNTER && !sumflag) { if (avedata->desc.units.dimTime == 0) avedata->scale = 1.0; else { if (avedata->desc.units.scaleTime > PM_TIME_SEC) avedata->scale = pow(60.0, (double)(PM_TIME_SEC - avedata->desc.units.scaleTime)); else avedata->scale = pow(1000.0, (double)(PM_TIME_SEC - avedata->desc.units.scaleTime)); } if (avedata->desc.units.dimTime == 0) avedata->desc.units.scaleTime = PM_TIME_SEC; avedata->desc.units.dimTime--; } else if (avedata->desc.sem == PM_SEM_COUNTER && sumflag) { avedata->scale = 1.0; } avedata->listsize = 0; avedata->instlist = NULL; for (j = 0; j < vsp->numval; j++) newHashInst(&vsp->vlist[j], avedata, vsp->valfmt, timestamp, j); } /* * find index to bin array for "val" */ unsigned int findbin(pmID pmid, double val, double min, double max) { unsigned int index; double bound, next; double binsize; binsize = (max - min) / (double)nbins; bound = min; for (index=0; index < nbins-1; index++) { next = bound + binsize; if (val >= bound && val <= next) break; bound = next; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { char *mname = NULL; pmNameID(pmid, &mname); fprintf(stderr, "%s selected bin %u/%u (val=%.*f, min=%.*f, max=%.*f)\n", mname, index, nbins, (int)precision, val, (int)precision, min, (int)precision, max); if (mname) free(mname); if (index >= nbins) exit(1); } #endif return index; } /* * must keep a note for every instance of every metric whenever a mark * record has been seen between now & the last fetch for that instance */ static void markrecord(pmResult *result) { int i, j; __pmHashNode *hptr; aveData *avedata; instData *instdata; double val; struct timeval timediff; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { printstamp(&result->timestamp, '\n'); printf(" - mark record\n\n"); } #endif for (i = 0; i < hashlist.hsize; i++) { for (hptr = hashlist.hash[i]; hptr != NULL; hptr = hptr->next) { avedata = (aveData *)hptr->data; for (j = 0; j < avedata->listsize; j++) { instdata = avedata->instlist[j]; if (avedata->desc.sem == PM_SEM_DISCRETE) { /* extend discrete metrics to the mark point */ timediff = result->timestamp; tsub(&timediff, &instdata->lasttime); val = instdata->lastval; instdata->stocave += val; instdata->timeave += val*tosec(timediff); instdata->lasttime = result->timestamp; instdata->count++; } instdata->marked = 1; instdata->markcount++; } } } } static void calcbinning(pmResult *result) { int i, j, k; int sts; int wrap; double val; pmAtomValue av; pmValue *vp; pmValueSet *vsp; __pmHashNode *hptr = NULL; aveData *avedata = NULL; instData *instdata; double diff; struct timeval timediff; if (result->numpmid == 0) /* mark record */ markrecord(result); for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; if (vsp->numval == 0) continue; else if (vsp->numval < 0) { pmiderr(vsp->pmid, "failed in 2nd pass archive fetch: %s\n", pmErrStr(vsp->numval)); continue; } if ((hptr = __pmHashSearch(vsp->pmid, &hashlist)) != NULL) { avedata = (aveData *)hptr->data; for (j = 0; j < vsp->numval; j++) { /* iterate thro result values */ int fp_bad; vp = &vsp->vlist[j]; k = j; /* index into stored inst list, result may differ */ if ((vsp->numval > 1) || (avedata->desc.indom != PM_INDOM_NULL)) { if ((k < avedata->listsize) && (avedata->instlist[k]->inst != vp->inst)) { for (k = 0; k < avedata->listsize; k++) { if (vp->inst == avedata->instlist[k]->inst) break; /* k now correct */ } if (k == avedata->listsize) { pmiderr(vsp->pmid, "ignoring new instance found on second pass\n"); continue; } } else if (k >= avedata->listsize) { k = avedata->listsize; pmiderr(vsp->pmid, "ignoring new instance found on second pass\n"); continue; } } instdata = avedata->instlist[k]; if ((sts = pmExtractValue(vsp->valfmt, vp, avedata->desc.type, &av, PM_TYPE_DOUBLE)) < 0) { pmiderr(avedata->desc.pmid, "failed to extract value: %s\n", pmErrStr(sts)); continue; } fp_bad = 0; #ifdef HAVE_FPCLASSIFY fp_bad = fpclassify(av.d) == FP_NAN; #else #ifdef HAVE_ISNAN fp_bad = isnan(av.d); #endif #endif if (fp_bad) continue; /* reset values from first pass needed in this second pass */ if (instdata->bintotal == 0) { /* 1st time instance seen on 2nd pass */ instdata->bintotal = instdata->count; instdata->lasttime = result->timestamp; instdata->firsttime = result->timestamp; instdata->lastval = av.d; if (avedata->desc.sem == PM_SEM_COUNTER) instdata->count = 0; else { unsigned int sts; instdata->count = 1; sts = findbin(avedata->desc.pmid, av.d, instdata->min, instdata->max); instdata->bin[sts]++; } continue; } timediff = result->timestamp; tsub(&timediff, &instdata->lasttime); diff = tosec(timediff); wrap = 0; if (avedata->desc.sem == PM_SEM_COUNTER) { diff *= avedata->scale; if (diff == 0.0) continue; if (instdata->marked) val = av.d; else val = unwrap(av.d, instdata->lastval, avedata->desc.type); if (instdata->marked || val < instdata->lastval) { /* mark or not first one & counter not monotonic increasing */ wrap = 1; instdata->marked = 0; tadd(&instdata->firsttime, &result->timestamp); tsub(&instdata->firsttime, &instdata->lasttime); } else { unsigned int sts; val = (val - instdata->lastval) / diff; sts = findbin(avedata->desc.pmid, val, instdata->min, instdata->max); instdata->bin[sts]++; } } else { /* for the other semantics */ unsigned int sts; val = av.d; sts = findbin(avedata->desc.pmid, val, instdata->min, instdata->max); instdata->bin[sts]++; } if (!wrap) { instdata->count++; } instdata->lastval = av.d; instdata->lasttime = result->timestamp; } } } } static void calcaverage(pmResult *result) { int i, j, k; int sts; int wrap; double val; pmDesc desc; pmAtomValue av; pmValue *vp; pmValueSet *vsp; __pmHashNode *hptr = NULL; aveData *avedata = NULL; instData *instdata; double diff; double rate = 0; struct timeval timediff; if (result->numpmid == 0) /* mark record */ markrecord(result); for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; if (vsp->numval == 0) continue; else if (vsp->numval < 0) { pmiderr(vsp->pmid, "failed in archive value fetch: %s\n", pmErrStr(vsp->numval)); continue; } /* check if pmid already in hash list */ if ((hptr = __pmHashSearch(vsp->pmid, &hashlist)) == NULL) { if ((sts = pmLookupDesc(vsp->pmid, &desc)) < 0) { pmiderr(vsp->pmid, "cannot find descriptor: %s\n", pmErrStr(sts)); continue; } if (desc.type != PM_TYPE_32 && desc.type != PM_TYPE_U32 && desc.type != PM_TYPE_64 && desc.type != PM_TYPE_U64 && desc.type != PM_TYPE_FLOAT && desc.type != PM_TYPE_DOUBLE) { continue; /* cannot average non-numeric metrics */ } /* create a new one & add to list */ avedata = (aveData*) malloc(sizeof(aveData)); newHashItem(vsp, &desc, avedata, &result->timestamp); if (__pmHashAdd(avedata->desc.pmid, (void*)avedata, &hashlist) < 0) { pmiderr(avedata->desc.pmid, "failed %s hash table insertion\n", pmProgname); /* free memory allocated above on insert failure */ for (j = 0; j < vsp->numval; j++) if (avedata->instlist[j]) free(avedata->instlist[j]); if (avedata->instlist) free(avedata->instlist); continue; } } else { /* pmid exists - update statistics */ avedata = (aveData*)hptr->data; for (j = 0; j < vsp->numval; j++) { /* iterate thro result values */ int fp_bad; vp = &vsp->vlist[j]; k = j; /* index into stored inst list, result may differ */ if ((vsp->numval > 1) || (avedata->desc.indom != PM_INDOM_NULL)) { /* must store values using correct inst - probably in correct order already */ if ((k < avedata->listsize) && (avedata->instlist[k]->inst != vp->inst)) { for (k = 0; k < avedata->listsize; k++) { if (vp->inst == avedata->instlist[k]->inst) { break; /* k now correct */ } } if (k == avedata->listsize) { /* no matching inst was found */ newHashInst(vp, avedata, vsp->valfmt, &result->timestamp, k); continue; } } else if (k >= avedata->listsize) { k = avedata->listsize; newHashInst(vp, avedata, vsp->valfmt, &result->timestamp, k); continue; } } instdata = avedata->instlist[k]; if ((sts = pmExtractValue(vsp->valfmt, vp, avedata->desc.type, &av, PM_TYPE_DOUBLE)) < 0) { pmiderr(avedata->desc.pmid, "failed to extract value: %s\n", pmErrStr(sts)); continue; } fp_bad = 0; #ifdef HAVE_FPCLASSIFY fp_bad = fpclassify(av.d) == FP_NAN; #else #ifdef HAVE_ISNAN fp_bad = isnan(av.d); #endif #endif if (fp_bad) continue; timediff = result->timestamp; tsub(&timediff, &instdata->lasttime); diff = tosec(timediff); wrap = 0; if (avedata->desc.sem == PM_SEM_COUNTER) { diff *= avedata->scale; if (diff == 0.0) continue; if (instdata->marked) val = av.d; else val = unwrap(av.d, instdata->lastval, avedata->desc.type); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { char *name = NULL; pmNameID(avedata->desc.pmid, &name); fprintf(stderr, "%s base value is %f, count %d\n", name, val, instdata->count+1); if (name) free(name); } #endif if (instdata->marked || val < instdata->lastval) { /* either previous record was a "mark", or this is not */ /* the first one, and counter not monotonic increasing */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { char *name = NULL; pmNameID(avedata->desc.pmid, &name); fprintf(stderr, "%s counter wrapped or \n", name); if (name) free(name); } #endif wrap = 1; instdata->marked = 0; tadd(&instdata->firsttime, &result->timestamp); tsub(&instdata->firsttime, &instdata->lasttime); } else { rate = (val - instdata->lastval) / diff; instdata->stocave += rate; if (!instdata->marked) instdata->timeave += (val - instdata->lastval); else { instdata->marked = 0; /* remove the timeslice in question from time-based calc */ tadd(&instdata->firsttime, &result->timestamp); tsub(&instdata->firsttime, &instdata->lasttime); } if (instdata->count == 0) { /* 1st time */ instdata->min = instdata->max = rate; instdata->sum = (val - instdata->lastval); } else { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { char *name = NULL; char *istr = NULL; pmNameID(avedata->desc.pmid, &name); if (pmNameInDom(avedata->desc.indom, instdata->inst, &istr) < 0) istr = NULL; if (rate < instdata->min) { fprintf(stderr, "new min value for %s " "(inst[%s]: %f) at ", name, (istr == NULL ? "":istr), rate); __pmPrintStamp(stderr, &result->timestamp); fprintf(stderr, "\n"); } if (rate > instdata->max) { fprintf(stderr, "new max value for %s " "(inst[%s]: %f) at ", name, (istr == NULL ? "":istr), rate); __pmPrintStamp(stderr, &result->timestamp); fprintf(stderr, "\n"); } if (name) free(name); if (istr) free(istr); } #endif if (rate < instdata->min) { instdata->min = rate; instdata->mintime = result->timestamp; } if (rate > instdata->max) { instdata->max = rate; instdata->maxtime = result->timestamp; } instdata->sum += (val - instdata->lastval); } } } else { /* for the other semantics - discrete & instantaneous */ val = av.d; instdata->sum += val; instdata->stocave += val; if (val < instdata->min) { instdata->min = val; instdata->mintime = result->timestamp; } if (val > instdata->max) { instdata->max = val; instdata->maxtime = result->timestamp; } if (!instdata->marked) instdata->timeave += instdata->lastval*diff; else { instdata->marked = 0; /* remove the timeslice in question from time-based calc */ tadd(&instdata->firsttime, &result->timestamp); tsub(&instdata->firsttime, &instdata->lasttime); } } if (!wrap) { instdata->count++; #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_APPL1) && (avedata->desc.sem != PM_SEM_COUNTER || instdata->count > 0)) { char *name = NULL; double metricspan = 0.0; struct timeval metrictimespan; metrictimespan = result->timestamp; tsub(&metrictimespan, &instdata->firsttime); metricspan = tosec(metrictimespan); pmNameID(avedata->desc.pmid, &name); if (avedata->desc.sem == PM_SEM_COUNTER) { fprintf(stderr, "++ %s timedelta=%f count=%d\n" "sum=%f min=%f max=%f stocsum=%f\n" "rate=%f timesum=%f (+%f) timespan=%f\n", name, diff, instdata->count, instdata->sum, instdata->min, instdata->max, instdata->stocave, rate, instdata->timeave, diff * (val - instdata->lastval) / 2, metricspan); } else { /* non-counters */ fprintf(stderr, "++ %s timedelta=%f count=%d\n" "sum=%f min=%f max=%f stocsum=%f\n" "lastval=%f timesum=%f (+%f) timespan=%f\n", name, diff, instdata->count, instdata->sum, instdata->min, instdata->max, instdata->stocave, instdata->lastval, instdata->timeave, instdata->lastval*diff, metricspan); } if (name) free(name); } #endif } instdata->lastval = av.d; instdata->lasttime = result->timestamp; } } } } int main(int argc, char *argv[]) { int c, i, sts, trip, exitstatus=0; char *pmnsfile = PM_NS_DEFAULT; char *startstr = NULL; char *endstr = NULL; char *endnum = NULL; char *msg = NULL; int errflag = 0; int lflag = 0; /* no label by default */ int Hflag = 0; /* no header by default */ pmResult *result; pmLogLabel label; /* get hostname for archives */ struct timeval timespan = {0, 0}; int zflag = 0; /* for -z */ char *tz = NULL; /* for -Z timezone */ char *archive; char timebuf[32]; /* for pmCtime result + .xxx */ __pmSetProgname(argv[0]); while ((c = getopt(argc, argv, "abB:D:fFHiIlmMNn:p:rsS:T:vxyzZ:?")) != EOF) { switch (c) { case 'a': /* provide all information */ stocaveflag = timeaveflag = lflag = countflag = minflag = maxflag = 1; sumflag = 0; break; case 'b': /* use both averages */ stocaveflag = 1; timeaveflag = 1; sumflag = 0; break; case 'B': /* number of distribution bins */ sts = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0' || sts < 0) { fprintf(stderr, "%s: -B requires positive numeric argument\n", pmProgname); errflag++; } else nbins = (unsigned int)sts; break; case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case 'f': /* spreadsheet format - use tab delimiters */ delimiter = '\t'; break; case 'F': /* spreadsheet format - use comma delimiters */ delimiter = ','; break; case 'H': /* print columns headings */ Hflag = 1; break; case 'i': /* print timestamp for minimum */ mintimeflag = 1; break; case 'I': /* print timestamp for maximum */ maxtimeflag = 1; break; case 'l': /* display label */ lflag = 1; break; case 'm': /* print minimums */ minflag = 1; break; case 'M': /* print maximums */ maxflag = 1; break; case 'N': /* suppress fetch warnings */ warnflag = 0; break; case 'n': /* alternative name space file */ pmnsfile = optarg; break; case 'p': /* number of digits after decimal point */ precision = (unsigned int)strtol(optarg, &endnum, 10); if (*endnum != '\0') { fprintf(stderr, "%s: -p requires numeric argument\n", pmProgname); errflag++; } break; case 's': /* print sums (and only sums) */ stocaveflag = timeaveflag = lflag = countflag = minflag = maxflag = 0; sumflag = 1; break; case 'S': startstr = optarg; sflag = 1; break; case 'T': endstr = optarg; tflag = 1; break; case 'v': /* verbose "fetch" warnings reported */ warnflag = 1; break; case 'x': /* use only stochastic counter averages */ stocaveflag = 1; timeaveflag = 0; sumflag = 0; break; case 'y': /* print sample count */ countflag = 1; break; case 'z': /* timezone from host */ if (tz != NULL) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); errflag++; } zflag++; break; case 'Z': /* $TZ timezone */ if (zflag) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); errflag++; } tz = optarg; break; case '?': default: errflag++; break; } } if (errflag || optind >= argc) usage(); archive = argv[optind]; if ((sts = pmNewContext(PM_CONTEXT_ARCHIVE, archive)) < 0) { fprintf(stderr, "%s: Cannot open archive \"%s\": %s\n", pmProgname, archive, pmErrStr(sts)); exit(1); } optind++; if (pmnsfile != PM_NS_DEFAULT) { if ((sts = pmLoadNameSpace(pmnsfile)) < 0) { fprintf(stderr, "%s: Cannot load namespace from \"%s\": %s\n", pmProgname, pmnsfile, pmErrStr(sts)); exit(1); } } if ((sts = pmTrimNameSpace()) < 0) { fprintf(stderr, "%s: pmTrimNamespace failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } if ((sts = pmGetArchiveLabel(&label)) < 0) { fprintf(stderr, "%s: Cannot get archive label record: %s\n", pmProgname, pmErrStr(sts)); exit(1); } else logstart = label.ll_start; if (zflag) { if ((sts = pmNewContextZone()) < 0) { fprintf(stderr, "%s: Cannot set context timezone: %s\n", pmProgname, pmErrStr(sts)); exit(1); } printf("Note: timezone set to local timezone of host \"%s\" from archive\n\n", label.ll_hostname); } else if (tz != NULL) { if ((sts = pmNewZone(tz)) < 0) { fprintf(stderr, "%s: Cannot set timezone to \"%s\": %s\n", pmProgname, tz, pmErrStr(sts)); exit(1); } printf("Note: timezone set to \"TZ=%s\"\n\n", tz); } if ((sts = pmGetArchiveEnd(&logend)) < 0) { logend.tv_sec = INT_MAX; logend.tv_usec = 0; fflush(stdout); fprintf(stderr, "%s: Cannot locate end of archive: %s\n", pmProgname, pmErrStr(sts)); fprintf(stderr, "\nWARNING: This archive is sufficiently damaged that it may not be possible to\n"); fprintf(stderr, " produce complete information. Continuing and hoping for the best.\n\n"); fflush(stderr); } if (tflag || sflag) { if (pmParseTimeWindow(startstr, endstr, NULL, NULL, &logstart, &logend, &windowstart, &windowend, ×pan, &msg) < 0) { fprintf(stderr, "%s: Invalid time window specified:\n%s\n", pmProgname, msg); exit(1); } #ifdef PCP_DEBUG else if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "parseTimeWindow: \n " "Window start=%.0f end=%.0f sec\nArchive start=%.0f end=%.0f sec\n", tosec(windowstart), tosec(windowend), tosec(logstart), tosec(logend)); fprintf(stderr, "\nWindow Start: "); __pmPrintStamp(stderr, &windowstart); fprintf(stderr, "\nWindow End: "); __pmPrintStamp(stderr, &windowend); fprintf(stderr, "\n\n"); } #endif } else { /* time window covers whole log */ windowstart = logstart; windowend = logend; } logspan = tosec(windowend) - tosec(windowstart); if ((sts = pmSetMode(PM_MODE_FORW, &windowstart, 0)) < 0) { fprintf(stderr, "%s: pmSetMode failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } if (lflag == 1) { char *ddmm; char *yr; printf("Log Label (Log Format Version %d)\n", label.ll_magic & 0xff); printf("Performance metrics from host %s\n", label.ll_hostname); ddmm = pmCtime(&windowstart.tv_sec, timebuf); ddmm[10] = '\0'; yr = &ddmm[20]; printf(" commencing %s ", ddmm); __pmPrintStamp(stdout, &windowstart); printf(" %4.4s\n", yr); ddmm = pmCtime(&windowend.tv_sec, timebuf); ddmm[10] = '\0'; yr = &ddmm[20]; printf(" ending %s ", ddmm); __pmPrintStamp(stdout, &windowend); printf(" %4.4s\n", yr); } /* check which timestamp print format we should be using */ timespan = windowend; tsub(×pan, &windowstart); if (timespan.tv_sec > 86400) /* seconds per day: 60*60*24 */ dayflag = 1; for (trip = 0; trip < 2; trip++) { /* two passes if binning */ for ( ; ; ) { if ((sts = pmFetchArchive(&result)) < 0) break; if (windowend.tv_sec > result->timestamp.tv_sec || (windowend.tv_sec == result->timestamp.tv_sec && windowend.tv_usec >= result->timestamp.tv_usec)) { if (trip == 0) calcaverage(result); else calcbinning(result); pmFreeResult(result); } else { pmFreeResult(result); sts = PM_ERR_EOL; break; } } if (trip == 0 && nbins > 0) { /* distribute values into bins */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "resetting for second iteration\n"); #endif if ((sts = pmSetMode(PM_MODE_FORW, &windowstart, 0)) < 0) { fprintf(stderr, "%s: pmSetMode reset failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } } else break; /* two passes only when doing binning */ } if (sts != PM_ERR_EOL) { fprintf(stderr, "%s: fetch failed: %s\n", pmProgname, pmErrStr(sts)); exitstatus = 1; } if (Hflag) printheaders(); if (optind >= argc) { /* print all results */ if ((sts = pmTraversePMNS("", printsummary)) < 0) { fprintf(stderr, "%s: PMNS traversal failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } } else { /* print only selected results */ for (i = optind; i < argc; i++) { char *msg; if (pmParseMetricSpec(argv[i], 1, archive, &msp, &msg) < 0) { fputs(msg, stderr); free(msg); continue; } if ((sts = pmTraversePMNS(msp->metric, printsummary)) < 0) fprintf(stderr, "%s: PMNS traversal failed for %s: %s\n", pmProgname, msp->metric, pmErrStr(sts)); pmFreeMetricSpec(msp); } } exit(exitstatus); } pcp-3.8.12ubuntu1/src/libpcp_import/0000775000000000000000000000000012272262617014244 5ustar pcp-3.8.12ubuntu1/src/libpcp_import/src/0000775000000000000000000000000012272262617015033 5ustar pcp-3.8.12ubuntu1/src/libpcp_import/src/exports0000664000000000000000000000053112272262501016451 0ustar PCP_IMPORT_1.0 { global: pmiStart; pmiSetHostname; pmiSetTimezone; pmiUseContext; pmiGetHandle; pmiDump; pmiEnd; pmiAddInstance; pmiAddMetric; pmiErrStr; pmiErrStr_r; pmiID; pmiInDom; pmiUnits; pmiPutResult; pmiPutValue; pmiPutValueHandle; pmiWrite; local: *; }; pcp-3.8.12ubuntu1/src/libpcp_import/src/private.h0000664000000000000000000000363112272262501016651 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 2010 Ken McDonell. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #ifndef _PRIVATE_H #define _PRIVATE_H typedef struct { char *name; pmID pmid; pmDesc desc; int meta_done; } pmi_metric; typedef struct { pmInDom indom; int ninstance; char **name; // list of external instance names int *inst; // list of internal instance identifiers int namebuflen; // names are packed in namebuf[] as char *namebuf; // required by __pmLogPutInDom() int meta_done; } pmi_indom; typedef struct { int midx; // index into metric[] int inst; // internal instance identifier } pmi_handle; typedef struct { int state; char *archive; char *hostname; char *timezone; __pmLogCtl logctl; pmResult *result; int nmetric; pmi_metric *metric; int nindom; pmi_indom *indom; int nhandle; pmi_handle *handle; int last_sts; struct timeval last_stamp; } pmi_context; #define CONTEXT_START 1 #define CONTEXT_ACTIVE 2 #define CONTEXT_END 3 #if defined(__GNUC__) && (__GNUC__ >= 4) # define _PMI_HIDDEN __attribute__ ((visibility ("hidden"))) #else # define _PMI_HIDDEN #endif extern int _pmi_stuff_value(pmi_context *, pmi_handle *, const char *) _PMI_HIDDEN; extern int _pmi_put_result(pmi_context *, pmResult *) _PMI_HIDDEN; extern int _pmi_end(pmi_context *) _PMI_HIDDEN; #endif /* _PRIVATE_H */ pcp-3.8.12ubuntu1/src/libpcp_import/src/GNUmakefile0000664000000000000000000000365512272262501017106 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2001,2009 Silicon Graphics, Inc. All Rights Reserved. # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs CFILES = import.c stuff.c archive.c HFILES = private.h VERSION_SCRIPT = exports STATICLIBTARGET = libpcp_import.a DSOVERSION = 1 LIBTARGET = libpcp_import.$(DSOSUFFIX).$(DSOVERSION) SYMTARGET = libpcp_import.$(DSOSUFFIX) ifeq "$(TARGET_OS)" "darwin" LIBTARGET = libpcp_import.$(DSOVERSION).$(DSOSUFFIX) endif ifeq "$(TARGET_OS)" "mingw" LIBTARGET = libpcp_import.$(DSOSUFFIX) SYMTARGET = STATICLIBTARGET = endif ifeq "$(ENABLE_SHARED)" "no" LIBTARGET = SYMTARGET = endif LCFLAGS = LLDLIBS = -lpcp LSRCFILES = $(VERSION_SCRIPT) LDIRT = $(SYMTARGET) domain.h DOMAIN = PMI_DOMAIN default: domain.h $(LIBTARGET) $(SYMTARGET) $(STATICLIBTARGET) $(OBJECTS): $(HFILES) include $(BUILDRULES) install: default ifneq ($(LIBTARGET),) $(INSTALL) -m 755 $(LIBTARGET) $(PCP_LIB_DIR)/$(LIBTARGET) endif ifneq ($(SYMTARGET),) for tt in $(SYMTARGET); do \ $(INSTALL) -S $(LIBTARGET) $(PCP_LIB_DIR)/$$tt || exit 1; \ done endif ifneq ($(STATICLIBTARGET),) $(INSTALL) -m 755 $(STATICLIBTARGET) $(PCP_LIB_DIR)/$(STATICLIBTARGET) endif default_pcp: default install_pcp: install ifneq ($(SYMTARGET),) $(SYMTARGET): $(LN_S) -f $(LIBTARGET) $@ endif ifneq ($(LIBTARGET),) $(LIBTARGET): $(VERSION_SCRIPT) endif domain.h: $(TOPDIR)/src/pmns/stdpmid $(DOMAIN_MAKERULE) pcp-3.8.12ubuntu1/src/libpcp_import/src/stuff.c0000664000000000000000000001166512272262501016327 0ustar /* * Copyright (c) 2010 Ken McDonell. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "import.h" #include "private.h" int _pmi_stuff_value(pmi_context *current, pmi_handle *hp, const char *value) { pmResult *rp; int i; pmID pmid; pmValueSet *vsp; pmValue *vp; pmi_metric *mp; char *end; int dsize; void *data; __int64_t ll; __uint64_t ull; float f; double d; mp = ¤t->metric[hp->midx]; if (current->result == NULL) { /* first time */ current->result = (pmResult *)malloc(sizeof(pmResult)); if (current->result == NULL) { __pmNoMem("_pmi_stuff_value: result malloc:", sizeof(pmResult), PM_FATAL_ERR); } current->result->numpmid = 0; current->result->timestamp.tv_sec = 0; current->result->timestamp.tv_usec = 0; } rp = current->result; pmid = current->metric[hp->midx].pmid; for (i = 0; i < rp->numpmid; i++) { if (pmid == rp->vset[i]->pmid) { if (mp->desc.indom == PM_INDOM_NULL) /* singular metric, cannot have more than one value */ return PMI_ERR_DUPVALUE; break; } } if (i == rp->numpmid) { rp->numpmid++; rp = current->result = (pmResult *)realloc(current->result, sizeof(pmResult) + (rp->numpmid - 1)*sizeof(pmValueSet *)); if (current->result == NULL) { __pmNoMem("_pmi_stuff_value: result realloc:", sizeof(pmResult) + (rp->numpmid - 1)*sizeof(pmValueSet *), PM_FATAL_ERR); } rp->vset[rp->numpmid-1] = (pmValueSet *)malloc(sizeof(pmValueSet)); if (rp->vset[rp->numpmid-1] == NULL) { __pmNoMem("_pmi_stuff_value: vset alloc:", sizeof(pmValueSet), PM_FATAL_ERR); } vsp = rp->vset[rp->numpmid-1]; vsp->pmid = pmid; vsp->numval = 1; } else { int j; for (j = 0; j < rp->vset[i]->numval; j++) { if (rp->vset[i]->vlist[j].inst == hp->inst) /* each metric-instance can appear at most once per pmResult */ return PMI_ERR_DUPVALUE; } rp->vset[i]->numval++; vsp = rp->vset[i] = (pmValueSet *)realloc(rp->vset[i], sizeof(pmValueSet) + (rp->vset[i]->numval-1)*sizeof(pmValue)); if (rp->vset[i] == NULL) { __pmNoMem("_pmi_stuff_value: vset realloc:", sizeof(pmValueSet) + (rp->vset[i]->numval-1)*sizeof(pmValue), PM_FATAL_ERR); } } vp = &vsp->vlist[vsp->numval-1]; vp->inst = hp->inst; dsize = -1; switch (mp->desc.type) { case PM_TYPE_32: if (vsp->numval == 1) vsp->valfmt = PM_VAL_INSITU; vp->value.lval = strtol(value, &end, 10); if (*end != '\0') { vsp->numval = PM_ERR_CONV; return PM_ERR_CONV; } break; case PM_TYPE_U32: if (vsp->numval == 1) vsp->valfmt = PM_VAL_INSITU; vp->value.lval = strtoul(value, &end, 10); if (*end != '\0') { vsp->numval = PM_ERR_CONV; return PM_ERR_CONV; } break; case PM_TYPE_64: if (vsp->numval == 1) vsp->valfmt = PM_VAL_DPTR; ll = strtoll(value, &end, 10); if (*end != '\0') { vsp->numval = PM_ERR_CONV; return PM_ERR_CONV; } dsize = sizeof(ll); data = (void *)≪ break; case PM_TYPE_U64: if (vsp->numval == 1) vsp->valfmt = PM_VAL_DPTR; ull = strtoull(value, &end, 10); if (*end != '\0') { vsp->numval = PM_ERR_CONV; return PM_ERR_CONV; } dsize = sizeof(ull); data = (void *)&ull; break; case PM_TYPE_FLOAT: if (vsp->numval == 1) vsp->valfmt = PM_VAL_DPTR; f = strtof(value, &end); if (*end != '\0') { vsp->numval = PM_ERR_CONV; return PM_ERR_CONV; } dsize = sizeof(f); data = (void *)&f; break; case PM_TYPE_DOUBLE: if (vsp->numval == 1) vsp->valfmt = PM_VAL_DPTR; d = strtod(value, &end); if (*end != '\0') { vsp->numval = PM_ERR_CONV; return PM_ERR_CONV; } dsize = sizeof(d); data = (void *)&d; break; case PM_TYPE_STRING: if (vsp->numval == 1) vsp->valfmt = PM_VAL_DPTR; dsize = strlen(value)+1; data = (void *)value; break; default: vsp->numval = PM_ERR_TYPE; return PM_ERR_TYPE; } if (dsize != -1) { /* logic copied from stuffvalue.c in libpcp */ int need = dsize + PM_VAL_HDR_SIZE; vp->value.pval = (pmValueBlock *)malloc(need < sizeof(pmValueBlock) ? sizeof(pmValueBlock) : need); if (vp->value.pval == NULL) { __pmNoMem("_pmi_stuff_value: pmValueBlock:", need < sizeof(pmValueBlock) ? sizeof(pmValueBlock) : need, PM_FATAL_ERR); } vp->value.pval->vlen = (int)need; vp->value.pval->vtype = mp->desc.type; memcpy((void *)vp->value.pval->vbuf, data, dsize); } return 0; } pcp-3.8.12ubuntu1/src/libpcp_import/src/archive.c0000664000000000000000000000766512272262501016626 0ustar /* * Copyright (c) 2010 Ken McDonell. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "import.h" #include "private.h" static __pmTimeval stamp; int _pmi_put_result(pmi_context *current, pmResult *result) { int sts; char *host; char myname[MAXHOSTNAMELEN]; __pmPDU *pb; __pmLogCtl *lcp = ¤t->logctl; int k; int i; int m; int needti; /* * some front-end tools use lazy discovery of instances and/or process * data in non-deterministic order ... it is simpler for everyone if * we sort the values into ascending instance order. */ pmSortInstances(result); stamp.tv_sec = result->timestamp.tv_sec; stamp.tv_usec = result->timestamp.tv_usec; if (current->state == CONTEXT_START) { if (current->hostname == NULL) { (void)gethostname(myname, MAXHOSTNAMELEN); myname[MAXHOSTNAMELEN-1] = '\0'; host = myname; } else host = current->hostname; sts = __pmLogCreate(host, current->archive, PM_LOG_VERS02, lcp); if (sts < 0) return sts; if (current->timezone == NULL) { char tzbuf[PM_TZ_MAXLEN]; strcpy(lcp->l_label.ill_tz, __pmTimezone_r(tzbuf, sizeof(tzbuf))); } else strcpy(lcp->l_label.ill_tz, current->timezone); pmNewZone(lcp->l_label.ill_tz); current->state = CONTEXT_ACTIVE; /* * do the label records (it is too late when __pmLogPutResult * is called as we've already output some metadata) ... this * code is stolen from __pmLogPutResult */ lcp->l_label.ill_start.tv_sec = stamp.tv_sec; lcp->l_label.ill_start.tv_usec = stamp.tv_usec; lcp->l_label.ill_vol = PM_LOG_VOL_TI; __pmLogWriteLabel(lcp->l_tifp, &lcp->l_label); lcp->l_label.ill_vol = PM_LOG_VOL_META; __pmLogWriteLabel(lcp->l_mdfp, &lcp->l_label); lcp->l_label.ill_vol = 0; __pmLogWriteLabel(lcp->l_mfp, &lcp->l_label); lcp->l_state = PM_LOG_STATE_INIT; __pmLogPutIndex(¤t->logctl, &stamp); } __pmOverrideLastFd(fileno(lcp->l_mfp)); if ((sts = __pmEncodeResult(fileno(lcp->l_mfp), result, &pb)) < 0) return sts; needti = 0; for (k = 0; k < result->numpmid; k++) { for (m = 0; m < current->nmetric; m++) { if (result->vset[k]->pmid != current->metric[m].pmid) continue; if (current->metric[m].meta_done == 0) { char **namelist = ¤t->metric[m].name; if ((sts = __pmLogPutDesc(lcp, ¤t->metric[m].desc, 1, namelist)) < 0) { __pmUnpinPDUBuf(pb); return sts; } current->metric[m].meta_done = 1; needti = 1; } if (current->metric[m].desc.indom != PM_INDOM_NULL) { for (i = 0; i < current->nindom; i++) { if (current->metric[m].desc.indom == current->indom[i].indom) { if (current->indom[i].meta_done == 0) { if ((sts = __pmLogPutInDom(lcp, current->indom[i].indom, &stamp, current->indom[i].ninstance, current->indom[i].inst, current->indom[i].name)) < 0) { __pmUnpinPDUBuf(pb); return sts; } current->indom[i].meta_done = 1; needti = 1; } } } } break; } } if (needti) { __pmLogPutIndex(lcp, &stamp); } if ((sts = __pmLogPutResult(lcp, pb)) < 0) { __pmUnpinPDUBuf(pb); return sts; } __pmUnpinPDUBuf(pb); return 0; } int _pmi_end(pmi_context *current) { /* Final temporal index update to finish the archive * ... same logic here as in run_done() for pmlogger */ __pmLogPutIndex(¤t->logctl, &stamp); current->state = CONTEXT_END; return 0; } pcp-3.8.12ubuntu1/src/libpcp_import/src/import.c0000664000000000000000000004712612272262501016513 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 2010 Ken McDonell. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #include "pmapi.h" #include "impl.h" #include "import.h" #include "domain.h" #include "private.h" #include static pmi_context *context_tab; static int ncontext; static pmi_context *current; static void printstamp(FILE *f, const struct timeval *tp) { struct tm tmp; time_t now; now = (time_t)tp->tv_sec; pmLocaltime(&now, &tmp); fprintf(f, "%4d-%02d-%02d %02d:%02d:%02d.%06d", 1900+tmp.tm_year, tmp.tm_mon, tmp.tm_mday, tmp.tm_hour, tmp.tm_min, tmp.tm_sec, (int)(tp->tv_usec)); } void pmiDump(void) { FILE *f = stderr; fprintf(f, "pmiDump: context %ld of %d", (long)(current - context_tab), ncontext); if (current == NULL) { fprintf(f, " Error: current context is not defined.\n"); return; } else { fprintf(f, " archive: %s\n", current->archive == NULL ? "" : current->archive); } fprintf(f, " state: %d ", current->state); switch (current->state) { case CONTEXT_START: fprintf(f, "(start)"); break; case CONTEXT_ACTIVE: fprintf(f, "(active)"); break; case CONTEXT_END: fprintf(f, "(end)"); break; default: fprintf(f, "(BAD)"); break; } fprintf(f, " hostname: %s timezone: %s\n", current->hostname == NULL ? "" : current->hostname, current->timezone == NULL ? "" : current->timezone); if (current->nmetric == 0) fprintf(f, " No metrics.\n"); else { int m; char strbuf[20]; for (m = 0; m < current->nmetric; m++) { fprintf(f, " metric[%d] name=%s pmid=%s\n", m, current->metric[m].name, pmIDStr_r(current->metric[m].pmid, strbuf, sizeof(strbuf))); __pmPrintDesc(f, ¤t->metric[m].desc); } } if (current->nindom == 0) fprintf(f, " No indoms.\n"); else { int i; char strbuf[20]; for (i = 0; i < current->nindom; i++) { fprintf(f, " indom[%d] indom=%s", i, pmInDomStr_r(current->indom[i].indom, strbuf, sizeof(strbuf))); if (current->indom[i].ninstance == 0) { fprintf(f, " No instances.\n"); } else { int j; fputc('\n', f); for (j = 0; j < current->indom[i].ninstance; j++) { fprintf(f, " instance[%d] %s (%d)\n", j, current->indom[i].name[j], current->indom[i].inst[j]); } } } } if (current->nhandle == 0) fprintf(f, " No handles.\n"); else { int h; char strbuf[20]; for (h = 0; h < current->nhandle; h++) { fprintf(f, " handle[%d] metric=%s (%s) instance=%d\n", h, current->metric[current->handle[h].midx].name, pmIDStr_r(current->metric[current->handle[h].midx].pmid, strbuf, sizeof(strbuf)), current->handle[h].inst); } } if (current->result == NULL) fprintf(f, " No pmResult.\n"); else __pmDumpResult(f, current->result); } pmUnits pmiUnits(int dimSpace, int dimTime, int dimCount, int scaleSpace, int scaleTime, int scaleCount) { static pmUnits units; units.dimSpace = dimSpace; units.dimTime = dimTime; units.dimCount = dimCount; units.scaleSpace = scaleSpace; units.scaleTime = scaleTime; units.scaleCount = scaleCount; return units; } pmID pmiID(int domain, int cluster, int item) { return pmid_build(domain, cluster, item); } pmInDom pmiInDom(int domain, int serial) { return pmInDom_build(domain, serial); } const char * pmiErrStr(int sts) { static char errmsg[PMI_MAXERRMSGLEN]; pmiErrStr_r(sts, errmsg, sizeof(errmsg)); return errmsg; } char * pmiErrStr_r(int code, char *buf, int buflen) { const char *msg; if (code == -1 && current != NULL) code = current->last_sts; switch (code) { case PMI_ERR_DUPMETRICNAME: msg = "Metric name already defined"; break; case PMI_ERR_DUPMETRICID: msg = "Metric pmID already defined"; break; case PMI_ERR_DUPINSTNAME: msg = "External instance name already defined"; break; case PMI_ERR_DUPINSTID: msg = "Internal instance identifer already defined"; break; case PMI_ERR_INSTNOTNULL: msg = "Null instance expected for a singular metric"; break; case PMI_ERR_INSTNULL: msg = "Null instance not allowed for a non-singular metric"; break; case PMI_ERR_BADHANDLE: msg = "Illegal handle"; break; case PMI_ERR_DUPVALUE: msg = "Value already assigned for this metric-instance"; break; case PMI_ERR_BADTYPE: msg = "Illegal metric type"; break; case PMI_ERR_BADSEM: msg = "Illegal metric semantics"; break; case PMI_ERR_NODATA: msg = "No data to output"; break; case PMI_ERR_BADMETRICNAME: msg = "Illegal metric name"; break; case PMI_ERR_BADTIMESTAMP: msg = "Illegal result timestamp"; break; default: return pmErrStr_r(code, buf, buflen); } strncpy(buf, msg, buflen); buf[buflen-1] = '\0'; return buf; } int pmiStart(const char *archive, int inherit) { pmi_context *old_current; char *np; int c = current - context_tab; ncontext++; context_tab = (pmi_context *)realloc(context_tab, ncontext*sizeof(context_tab[0])); if (context_tab == NULL) { __pmNoMem("pmiStart: context_tab", ncontext*sizeof(context_tab[0]), PM_FATAL_ERR); } old_current = &context_tab[c]; current = &context_tab[ncontext-1]; current->state = CONTEXT_START; current->archive = strdup(archive); if (current->archive == NULL) { __pmNoMem("pmiStart", strlen(archive)+1, PM_FATAL_ERR); } current->hostname = NULL; current->timezone = NULL; current->result = NULL; memset((void *)¤t->logctl, 0, sizeof(current->logctl)); if (inherit && old_current != NULL) { current->nmetric = old_current->nmetric; if (old_current->metric != NULL) { int m; current->metric = (pmi_metric *)malloc(current->nmetric*sizeof(pmi_metric)); if (current->metric == NULL) { __pmNoMem("pmiStart: pmi_metric", current->nmetric*sizeof(pmi_metric), PM_FATAL_ERR); } for (m = 0; m < current->nmetric; m++) { current->metric[m].name = old_current->metric[m].name; current->metric[m].pmid = old_current->metric[m].pmid; current->metric[m].desc = old_current->metric[m].desc; current->metric[m].meta_done = 0; } } else current->metric = NULL; current->nindom = old_current->nindom; if (old_current->indom != NULL) { int i; current->indom = (pmi_indom *)malloc(current->nindom*sizeof(pmi_indom)); if (current->indom == NULL) { __pmNoMem("pmiStart: pmi_indom", current->nindom*sizeof(pmi_indom), PM_FATAL_ERR); } for (i = 0; i < current->nindom; i++) { int j; current->indom[i].indom = old_current->indom[i].indom; current->indom[i].ninstance = old_current->indom[i].ninstance; current->indom[i].meta_done = 0; if (old_current->indom[i].ninstance > 0) { current->indom[i].name = (char **)malloc(current->indom[i].ninstance*sizeof(char *)); if (current->indom[i].name == NULL) { __pmNoMem("pmiStart: name", current->indom[i].ninstance*sizeof(char *), PM_FATAL_ERR); } current->indom[i].inst = (int *)malloc(current->indom[i].ninstance*sizeof(int)); if (current->indom[i].inst == NULL) { __pmNoMem("pmiStart: inst", current->indom[i].ninstance*sizeof(int), PM_FATAL_ERR); } current->indom[i].namebuflen = old_current->indom[i].namebuflen; current->indom[i].namebuf = (char *)malloc(old_current->indom[i].namebuflen); if (current->indom[i].namebuf == NULL) { __pmNoMem("pmiStart: namebuf", old_current->indom[i].namebuflen, PM_FATAL_ERR); } np = current->indom[i].namebuf; for (j = 0; j < current->indom[i].ninstance; j++) { strcpy(np, old_current->indom[i].name[j]); current->indom[i].name[j] = np; np += strlen(np)+1; current->indom[i].inst[j] = old_current->indom[i].inst[j]; } } else { current->indom[i].name = NULL; current->indom[i].inst = NULL; current->indom[i].namebuflen = 0; current->indom[i].namebuf = NULL; } } } else current->indom = NULL; current->nhandle = old_current->nhandle; if (old_current->handle != NULL) { int h; current->handle = (pmi_handle *)malloc(current->nhandle*sizeof(pmi_handle)); if (current->handle == NULL) { __pmNoMem("pmiStart: pmi_handle", current->nhandle*sizeof(pmi_handle), PM_FATAL_ERR); } for (h = 0; h < current->nhandle; h++) { current->handle[h].midx = old_current->handle[h].midx; current->handle[h].inst = old_current->handle[h].inst; } } else current->handle = NULL; current->last_stamp = old_current->last_stamp; } else { current->nmetric = 0; current->metric = NULL; current->nindom = 0; current->indom = NULL; current->nhandle = 0; current->handle = NULL; current->last_stamp.tv_sec = current->last_stamp.tv_usec = 0; } return ncontext; } int pmiUseContext(int context) { if (context < 1 || context > ncontext) { if (current != NULL) current->last_sts = PM_ERR_NOCONTEXT; return PM_ERR_NOCONTEXT; } current = &context_tab[context-1]; return current->last_sts = 0; } int pmiEnd(void) { if (current == NULL) return PM_ERR_NOCONTEXT; return current->last_sts = _pmi_end(current); } int pmiSetHostname(const char *value) { if (current == NULL) return PM_ERR_NOCONTEXT; current->hostname = strdup(value); if (current->hostname == NULL) { __pmNoMem("pmiSetHostname", strlen(value)+1, PM_FATAL_ERR); } return current->last_sts = 0; } int pmiSetTimezone(const char *value) { if (current == NULL) return PM_ERR_NOCONTEXT; current->timezone = strdup(value); if (current->timezone == NULL) { __pmNoMem("pmiSetTimezone", strlen(value)+1, PM_FATAL_ERR); } return current->last_sts = 0; } static int valid_pmns_name(const char *name) { const char *previous; /* * Ensure requested metric name conforms to the PMNS rules: * Should start with an alphabetic, then any combination of * alphanumerics or underscore. Dot separators are OK, but * ensure only one (no repeats). */ if (name == NULL) return 0; if (!isalpha((int)*name)) return 0; for (previous = name++; *name != '\0'; name++) { if (!isalnum((int)*name) && *name != '_' && *name != '.') return 0; if (*previous == '.') { if (!isalpha((int)*name)) /* non-alphabetic first */ return 0; if (*name == *previous) /* repeated . separator */ return 0; } previous = name; } if (*previous == '.') /* shouldn't end with separator */ return 0; return 1; } int pmiAddMetric(const char *name, pmID pmid, int type, pmInDom indom, int sem, pmUnits units) { int m; int item; int cluster; size_t size; pmi_metric *mp; if (current == NULL) return PM_ERR_NOCONTEXT; if (valid_pmns_name(name) == 0) return current->last_sts = PMI_ERR_BADMETRICNAME; for (m = 0; m < current->nmetric; m++) { if (strcmp(name, current->metric[m].name) == 0) { /* duplicate metric name is not good */ return current->last_sts = PMI_ERR_DUPMETRICNAME; } if (pmid == current->metric[m].pmid) { /* duplicate metric pmID is not good */ return current->last_sts = PMI_ERR_DUPMETRICID; } } /* * basic sanity check of metadata ... we do not check later so this * needs to be robust */ switch (type) { case PM_TYPE_32: case PM_TYPE_U32: case PM_TYPE_64: case PM_TYPE_U64: case PM_TYPE_FLOAT: case PM_TYPE_DOUBLE: case PM_TYPE_STRING: break; default: return current->last_sts = PMI_ERR_BADTYPE; } switch (sem) { case PM_SEM_INSTANT: case PM_SEM_COUNTER: case PM_SEM_DISCRETE: break; default: return current->last_sts = PMI_ERR_BADSEM; } current->nmetric++; size = current->nmetric * sizeof(pmi_metric); current->metric = (pmi_metric *)realloc(current->metric, size); if (current->metric == NULL) { __pmNoMem("pmiAddMetric: pmi_metric", size, PM_FATAL_ERR); } mp = ¤t->metric[current->nmetric-1]; if (pmid != PM_ID_NULL) { mp->pmid = pmid; } else { /* choose a PMID on behalf of the caller - check boundaries first */ item = cluster = current->nmetric; if (item >= (1<<22)) { /* enough room for unique item:cluster? */ current->nmetric--; return current->last_sts = PMI_ERR_DUPMETRICID; /* wrap */ } item %= (1<<10); cluster >>= 10; mp->pmid = pmid_build(PMI_DOMAIN, cluster, item); } mp->name = strdup(name); if (mp->name == NULL) { __pmNoMem("pmiAddMetric: name", strlen(name)+1, PM_FATAL_ERR); } mp->desc.pmid = mp->pmid; mp->desc.type = type; mp->desc.indom = indom; mp->desc.sem = sem; mp->desc.units = units; mp->meta_done = 0; return current->last_sts = 0; } int pmiAddInstance(pmInDom indom, const char *instance, int inst) { pmi_indom *idp; const char *p; char *np; int spaced; int i; int j; if (current == NULL) return PM_ERR_NOCONTEXT; for (i = 0; i < current->nindom; i++) { if (current->indom[i].indom == indom) break; } if (i == current->nindom) { /* extend indom table */ current->nindom++; current->indom = (pmi_indom *)realloc(current->indom, current->nindom*sizeof(pmi_indom)); if (current->indom == NULL) { __pmNoMem("pmiAddInstance: pmi_indom", current->nindom*sizeof(pmi_indom), PM_FATAL_ERR); } current->indom[i].indom = indom; current->indom[i].ninstance = 0; current->indom[i].name = NULL; current->indom[i].inst = NULL; current->indom[i].namebuflen = 0; current->indom[i].namebuf = NULL; } idp = ¤t->indom[i]; /* * duplicate external instance identifier would be bad, but need * to honour unique to first space rule ... * duplicate instance internal identifier is also not allowed */ for (p = instance; *p && *p != ' '; p++) ; spaced = (*p == ' ') ? p - instance + 1: 0; /* +1 => *must* compare the space too */ for (j = 0; j < idp->ninstance; j++) { if (spaced) { if (strncmp(instance, idp->name[j], spaced) == 0) return current->last_sts = PMI_ERR_DUPINSTNAME; } else { if (strcmp(instance, idp->name[j]) == 0) return current->last_sts = PMI_ERR_DUPINSTNAME; } if (inst == idp->inst[j]) { return current->last_sts = PMI_ERR_DUPINSTID; } } /* add instance marks whole indom as needing to be written */ idp->meta_done = 0; idp->ninstance++; idp->name = (char **)realloc(idp->name, idp->ninstance*sizeof(char *)); if (idp->name == NULL) { __pmNoMem("pmiAddInstance: name", idp->ninstance*sizeof(char *), PM_FATAL_ERR); } idp->inst = (int *)realloc(idp->inst, idp->ninstance*sizeof(int)); if (idp->inst == NULL) { __pmNoMem("pmiAddInstance: inst", idp->ninstance*sizeof(int), PM_FATAL_ERR); } idp->namebuf = (char *)realloc(idp->namebuf, idp->namebuflen+strlen(instance)+1); if (idp->namebuf == NULL) { __pmNoMem("pmiAddInstance: namebuf", idp->namebuflen+strlen(instance)+1, PM_FATAL_ERR); } strcpy(&idp->namebuf[idp->namebuflen], instance); idp->namebuflen += strlen(instance)+1; idp->inst[idp->ninstance-1] = inst; /* in case namebuf moves, need to redo name[] pointers */ np = idp->namebuf; for (j = 0; j < current->indom[i].ninstance; j++) { idp->name[j] = np; np += strlen(np)+1; } return current->last_sts = 0; } static int make_handle(const char *name, const char *instance, pmi_handle *hp) { int m; int i; int j; int spaced; const char *p; pmi_indom *idp; if (instance != NULL && instance[0] == '\0') /* map "" to NULL to help Perl callers */ instance = NULL; for (m = 0; m < current->nmetric; m++) { if (strcmp(name, current->metric[m].name) == 0) break; } if (m == current->nmetric) return current->last_sts = PM_ERR_NAME; hp->midx = m; if (current->metric[hp->midx].desc.indom == PM_INDOM_NULL) { if (instance != NULL) { /* expect "instance" to be NULL */ return current->last_sts = PMI_ERR_INSTNOTNULL; } hp->inst = PM_IN_NULL; } else { if (instance == NULL) /* don't expect "instance" to be NULL */ return current->last_sts = PMI_ERR_INSTNULL; for (i = 0; i < current->nindom; i++) { if (current->metric[hp->midx].desc.indom == current->indom[i].indom) break; } if (i == current->nindom) return current->last_sts = PM_ERR_INDOM; idp = ¤t->indom[i]; /* match to first space rule */ for (p = instance; *p && *p != ' '; p++) ; spaced = (*p == ' ') ? p - instance + 1: 0; /* +1 => *must* compare the space too */ for (j = 0; j < idp->ninstance; j++) { if (spaced) { if (strncmp(instance, idp->name[j], spaced) == 0) break; } else { if (strcmp(instance, idp->name[j]) == 0) break; } } if (j == idp->ninstance) return current->last_sts = PM_ERR_INST; hp->inst = idp->inst[j]; } return current->last_sts = 0; } int pmiPutValue(const char *name, const char *instance, const char *value) { pmi_handle tmp; int sts; if (current == NULL) return PM_ERR_NOCONTEXT; sts = make_handle(name, instance, &tmp); if (sts != 0) return current->last_sts = sts; return current->last_sts = _pmi_stuff_value(current, &tmp, value); } int pmiGetHandle(const char *name, const char *instance) { int sts; pmi_handle tmp; pmi_handle *hp; if (current == NULL) return PM_ERR_NOCONTEXT; sts = make_handle(name, instance, &tmp); if (sts != 0) return current->last_sts = sts; current->nhandle++; current->handle = (pmi_handle *)realloc(current->handle, current->nhandle*sizeof(pmi_handle)); if (current->handle == NULL) { __pmNoMem("pmiGetHandle: pmi_handle", current->nhandle*sizeof(pmi_handle), PM_FATAL_ERR); } hp = ¤t->handle[current->nhandle-1]; hp->midx = tmp.midx; hp->inst = tmp.inst; return current->last_sts = current->nhandle; } int pmiPutValueHandle(int handle, const char *value) { if (current == NULL) return PM_ERR_NOCONTEXT; if (handle <= 0 || handle > current->nhandle) return current->last_sts = PMI_ERR_BADHANDLE; return current->last_sts = _pmi_stuff_value(current, ¤t->handle[handle-1], value); } int pmiWrite(int sec, int usec) { int sts; if (current == NULL) return PM_ERR_NOCONTEXT; if (current->result == NULL) return current->last_sts = PMI_ERR_NODATA; if (sec < 0) { __pmtimevalNow(¤t->result->timestamp); } else { current->result->timestamp.tv_sec = sec; current->result->timestamp.tv_usec = usec; } if (current->result->timestamp.tv_sec < current->last_stamp.tv_sec || (current->result->timestamp.tv_sec == current->last_stamp.tv_sec && current->result->timestamp.tv_usec < current->last_stamp.tv_usec)) { fprintf(stderr, "Fatal Error: timestamp "); printstamp(stderr, ¤t->result->timestamp); fprintf(stderr, " not greater than previous valid timestamp "); printstamp(stderr, ¤t->last_stamp); fputc('\n', stderr); sts = PMI_ERR_BADTIMESTAMP; } else { sts = _pmi_put_result(current, current->result); current->last_stamp = current->result->timestamp; } pmFreeResult(current->result); current->result = NULL; return current->last_sts = sts; } int pmiPutResult(const pmResult *result) { if (current == NULL) return PM_ERR_NOCONTEXT; return current->last_sts = _pmi_put_result(current, current->result); } pcp-3.8.12ubuntu1/src/libpcp_import/GNUmakefile0000664000000000000000000000210112272262501016300 0ustar # # Copyright (C) 2001,2009 Silicon Graphics, Inc. All Rights Reserved. # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this library; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # libpcp_import.so - import performance data and create PCP archives # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs BASE = libpcp_import.a SUBDIRS = src default install: $(SUBDIRS) $(SUBDIRS_MAKERULE) include $(BUILDRULES) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmsleep/0000775000000000000000000000000012272262620013040 5ustar pcp-3.8.12ubuntu1/src/pmsleep/GNUmakefile0000664000000000000000000000157112272262501015114 0ustar # # Copyright (c) 2007 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs LLDLIBS = $(PCPLIB) CFILES = pmsleep.c CMDTARGET = pmsleep$(EXECSUFFIX) LDIRT = $(TARGET) default: $(CMDTARGET) include $(BUILDRULES) install: $(CMDTARGET) $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BINADM_DIR)/$(CMDTARGET) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmsleep/pmsleep.c0000664000000000000000000000213212272262501014645 0ustar /* * Copyright (c) 2007 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include "pmapi.h" int main(int argc, char **argv) { struct timespec rqt; struct timeval delta; int r = 0; char *msg; if (argc == 2) { if (pmParseInterval(argv[1], &delta, &msg) < 0) { fputs(msg, stderr); free(msg); } else { rqt.tv_sec = delta.tv_sec; rqt.tv_nsec = delta.tv_usec * 1000; if (0 != nanosleep(&rqt, NULL)) r = oserror(); exit(r); } } fprintf(stderr, "Usage: pmsleep interval\n"); exit(1); } pcp-3.8.12ubuntu1/src/pmdbg/0000775000000000000000000000000012272262620012464 5ustar pcp-3.8.12ubuntu1/src/pmdbg/pmdbg.c0000664000000000000000000001062612272262501013724 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1995,2002-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * pmdbg - help for PCP debug flags */ #include #include "pmapi.h" #include "impl.h" static struct { int flag; char *name; char *text; } foo[] = { { DBG_TRACE_PDU, "PDU", "Trace PDU traffic at the Xmit and Recv level" }, { DBG_TRACE_FETCH, "FETCH", "Dump results from pmFetch" }, { DBG_TRACE_PROFILE, "PROFILE", "Trace changes and xmits for instance profile" }, { DBG_TRACE_VALUE, "VALUE", "Diags for metric value extraction and conversion" }, { DBG_TRACE_CONTEXT, "CONTEXT", "Trace changes to contexts" }, { DBG_TRACE_INDOM, "INDOM", "Low-level instance profile xfers" }, { DBG_TRACE_PDUBUF, "PDUBUF", "Trace pin/unpin ops for PDU buffers" }, { DBG_TRACE_LOG, "LOG", "Diags for archive log manipulations" }, { DBG_TRACE_LOGMETA, "LOGMETA", "Diags for meta-data operations on archive logs" }, { DBG_TRACE_OPTFETCH, "OPTFETCH", "Trace optFetch magic" }, { DBG_TRACE_AF, "AF", "Trace asynchronous event scheduling" }, { DBG_TRACE_APPL0, "APPL0", "Application-specific flag 0" }, { DBG_TRACE_APPL1, "APPL1", "Application-specific flag 1" }, { DBG_TRACE_APPL2, "APPL2", "Application-specific flag 2" }, { DBG_TRACE_PMNS, "PMNS", "Diags for PMNS manipulations" }, { DBG_TRACE_LIBPMDA, "LIBPMDA", "Trace PMDA callbacks in libpcp_pmda" }, { DBG_TRACE_TIMECONTROL, "TIMECONTROL", "Trace Time Control API" }, { DBG_TRACE_PMC, "PMC", "Trace metrics class operations" }, { DBG_TRACE_DERIVE, "DERIVE", "Derived metrics operations" }, { DBG_TRACE_LOCK, "LOCK", "Trace locks (if multi-threading enabled)" }, { DBG_TRACE_INTERP, "INTERP", "Diags for value interpolation in archives" }, { DBG_TRACE_CONFIG, "CONFIG", "Trace config initialization from pmGetConfig" }, { DBG_TRACE_LOOP, "LOOP", "Diags for pmLoop* services" }, { DBG_TRACE_FAULT, "FAULT", "Trace fault injection (if enabled)" }, { DBG_TRACE_AUTH, "AUTH", "Authentication services (if enabled)" }, { DBG_TRACE_DISCOVERY, "DISCOVERY", "Service discovery (if enabled)" }, { DBG_TRACE_DESPERATE, "DESPERATE", "Desperate/verbose level" }, }; static int nfoo = sizeof(foo) / sizeof(foo[0]); static char *fmt = "DBG_TRACE_%-11.11s %7d %s\n"; int main(int argc, char **argv) { int i; int c; int code; int errflag = 0; __pmSetProgname(argv[0]); while ((c = getopt(argc, argv, "l?")) != EOF) { switch (c) { case 'l': /* list all flags */ printf("Performance Co-Pilot Debug Flags\n"); printf("#define Value Meaning\n"); for (i = 0; i < nfoo; i++) printf(fmt, foo[i].name, foo[i].flag, foo[i].text); exit(0); case '?': default: errflag++; break; } } if (errflag || optind >= argc) { fprintf(stderr, "Usage: %s [options] [code ..]\n\ \n\ Options:\n\ -l displays mnemonic and decimal values of all PCP bit fields\n", pmProgname); exit(1); } /* non-flag args are argv[optind] ... argv[argc-1] */ while (optind < argc) { char *p = argv[optind]; for (p = argv[optind]; *p && isdigit((int)*p); p++) ; if (*p == '\0') sscanf(argv[optind], "%d", &code); else { char *q; p = argv[optind]; if (*p == '0' && (p[1] == 'x' || p[1] == 'X')) p = &p[2]; for (q = p; isxdigit((int)*q); q++) ; if (*q != '\0' || sscanf(p, "%x", &code) != 1) { printf("Cannot decode \"%s\" - neither decimal nor hexadecimal\n", argv[optind]); goto next; } } printf("Performance Co-Pilot -- pmDebug value = %d (0x%x)\n", code, code); printf("#define Value Meaning\n"); for (i = 0; i < nfoo; i++) { if (code & foo[i].flag) printf(fmt, foo[i].name, foo[i].flag, foo[i].text); } next: optind++; } return 0; } pcp-3.8.12ubuntu1/src/pmdbg/GNUmakefile0000664000000000000000000000154112272262501014535 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmdbg.c CMDTARGET = pmdbg$(EXECSUFFIX) LLDLIBS = $(PCPLIB) default: $(CMDTARGET) include $(BUILDRULES) install: default $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmevent/0000775000000000000000000000000012272262620013051 5ustar pcp-3.8.12ubuntu1/src/pmevent/pmevent.h0000664000000000000000000000331212272262501014675 0ustar /* * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2008-2009 Aconex. All Rights Reserved. * Copyright (c) 2011 Red Hat Inc. * Copyright (c) 2011 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmtime.h" #define ALL_SAMPLES -1 /* performance metrics from the command line */ typedef struct { char *name; /* name of metric */ pmID pmid; /* metric identifier */ pmDesc desc; /* metric description */ int ninst; /* number of instances, 0 for all instances */ char **iname; /* instance names */ int *inst; /* instance ids */ __pmHashCtl ihash; /* mapping when all instances requested */ } metric_t; void doargs(int, char **); /* * globals ... see declarations in pmevent.c for explanations */ extern char *host; /* as per pmGetContextHostName */ extern char *archive; extern int ahtype; extern int ctxhandle; extern int verbose; extern struct timeval now; extern struct timeval first; extern struct timeval last; extern struct timeval delta; extern long samples; extern int gui; extern int port; extern pmTimeControls controls; extern metric_t *metrictab; extern int nmetric; extern pmID *pmidlist; pcp-3.8.12ubuntu1/src/pmevent/pmevent.c0000664000000000000000000003123012272262501014670 0ustar /* * pmevent - event record dumper * (based on pmval) * * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2008-2009 Aconex. All Rights Reserved. * Copyright (c) 2011 Red Hat Inc. * Copyright (c) 2011 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * TODO * + -g and -p - nothing has been checked */ #include "pmevent.h" static int amode = PM_MODE_FORW; /* archive scan mode */ static pmTime *pmtime; char *host; /* hostname according to pmGetContextHostName */ char *archive; /* archive source */ int ahtype = -1; /* archive or host or local context */ int ctxhandle = -1; /* handle for the active context */ int verbose; /* verbose diagnostic output */ struct timeval now; /* current reporting time */ struct timeval first; /* start reporting time */ struct timeval last = {INT_MAX, 999999}; /* end reporting time */ struct timeval delta; /* sample interval */ long samples; /* number of samples */ int gui; /* set if -g */ int port = -1; /* pmtime port number from -p */ pmTimeControls controls; metric_t *metrictab; /* metrics from cmd line */ int nmetric; pmID *pmidlist; /* performance metrics in the hash list */ typedef struct { char *name; /* name of metric */ pmDesc desc; /* metric description */ } hash_t; /* Fetch metric values. */ static int getvals(pmResult **result) { pmResult *rp = NULL; int sts; int i; int m; if (archive != NULL) { /* * for archives read until we find a pmResult with at least * one of the pmids we are after */ for ( ; ; ) { sts = pmFetchArchive(&rp); if (sts < 0) break; if (rp->numpmid == 0) /* skip mark records */ continue; /* * scan for any of the metrics of interest ... keep skipping * archive records until one found */ for (i = 0; i < rp->numpmid; i++) { for (m = 0; m < nmetric; m++) { if (rp->vset[i]->pmid == metrictab[m].pmid) { /* match */ goto done; } } } pmFreeResult(rp); rp = NULL; } } else sts = pmFetch(nmetric, pmidlist, &rp); done: if (sts >= 0) *result = rp; else if (rp) pmFreeResult(rp); return sts; } static void timestep(struct timeval newdelta) { /* time moved, may need to wait for previous value again */ // TODO ? } /*************************************************************************** * output ***************************************************************************/ /* Print parameter values as output header. */ static void printhdr(void) { char timebuf[26]; if (archive == NULL) { printf("host: %s\n", host); } else { printf("archive: %s\n", archive); printf("host: %s\n", host); printf("start: %s", pmCtime(&first.tv_sec, timebuf)); if (last.tv_sec != INT_MAX) printf("end: %s", pmCtime(&last.tv_sec, timebuf)); } /* sample count and interval */ if (samples == ALL_SAMPLES) printf("samples: all\n"); else printf("samples: %ld\n", samples); if (samples != ALL_SAMPLES && samples > 1 && ahtype != PM_CONTEXT_ARCHIVE) printf("interval: %1.2f sec\n", __pmtimevalToReal(&delta)); } /* * cache all of the most recently requested * pmInDom ... */ static char * lookup(pmInDom indom, int inst) { static pmInDom last = PM_INDOM_NULL; static int numinst = -1; static int *instlist; static char **namelist; int i; if (indom != last) { if (numinst > 0) { free(instlist); free(namelist); } if (archive == NULL) numinst = pmGetInDom(indom, &instlist, &namelist); else numinst = pmGetInDomArchive(indom, &instlist, &namelist); last = indom; } for (i = 0; i < numinst; i++) { if (instlist[i] == inst) return namelist[i]; } return NULL; } static void myeventdump(pmValueSet *, int); static void mydump(const char *name, pmDesc *dp, pmValueSet *vsp) { int j; char *p; if (vsp->numval == 0) { if (verbose) printf("%s: No value(s) available!\n", name); return; } else if (vsp->numval < 0) { printf("%s: Error: %s\n", name, pmErrStr(vsp->numval)); return; } printf(" %s", name); for (j = 0; j < vsp->numval; j++) { pmValue *vp = &vsp->vlist[j]; if (dp->indom != PM_INDOM_NULL) { if (vsp->numval > 1) printf("\n "); if ((p = lookup(dp->indom, vp->inst)) == NULL) printf("[%d]", vp->inst); else printf("[\"%s\"]", p); } putchar(' '); if (dp->type == PM_TYPE_AGGREGATE || dp->type == PM_TYPE_AGGREGATE_STATIC) { /* * pinched from pmPrintValue, just without the preamble of * floating point values */ char *p; int i; putchar('['); p = &vp->value.pval->vbuf[0]; for (i = 0; i < vp->value.pval->vlen - PM_VAL_HDR_SIZE; i++, p++) printf("%02x", *p & 0xff); putchar(']'); putchar('\n'); } else if (dp->type == PM_TYPE_EVENT) /* odd, nested event type! */ myeventdump(vsp, j); else { pmPrintValue(stdout, vsp->valfmt, dp->type, vp, 1); putchar('\n'); } } } static void myeventdump(pmValueSet *vsp, int idx) { int r; /* event records */ int p; /* event parameters */ int nrecords; int flags; pmResult **res; static pmID pmid_flags; static pmID pmid_missed; static __pmHashCtl hash = { 0, 0, NULL }; nrecords = pmUnpackEventRecords(vsp, idx, &res); if (nrecords < 0) { printf(" pmUnpackEventRecords: %s\n", pmErrStr(nrecords)); return; } printf(" %d event records\n", nrecords); if (pmid_flags == 0) { /* * get PMID for event.flags and event.missed * note that pmUnpackEventRecords() will have called * __pmRegisterAnon(), so the anonymous metrics * should now be in the PMNS */ char *name_flags = "event.flags"; char *name_missed = "event.missed"; int sts; sts = pmLookupName(1, &name_flags, &pmid_flags); if (sts < 0) { /* should not happen! */ fprintf(stderr, "Warning: cannot get PMID for %s: %s\n", name_flags, pmErrStr(sts)); /* avoid subsequent warnings ... */ __pmid_int(&pmid_flags)->item = 1; } sts = pmLookupName(1, &name_missed, &pmid_missed); if (sts < 0) { /* should not happen! */ fprintf(stderr, "Warning: cannot get PMID for %s: %s\n", name_missed, pmErrStr(sts)); /* avoid subsequent warnings ... */ __pmid_int(&pmid_missed)->item = 1; } } for (r = 0; r < nrecords; r++) { printf(" "); __pmPrintStamp(stdout, &res[r]->timestamp); printf(" --- event record [%d]", r); if (res[r]->numpmid == 0) { printf(" ---\n"); printf(" ==> No parameters\n"); continue; } if (res[r]->numpmid < 0) { printf(" ---\n"); printf(" Error: illegal number of parameters (%d)\n", res[r]->numpmid); continue; } flags = 0; for (p = 0; p < res[r]->numpmid; p++) { pmValueSet *xvsp = res[r]->vset[p]; int sts; __pmHashNode *hnp; hash_t *hp; if ((hnp = __pmHashSearch((unsigned int)xvsp->pmid, &hash)) == NULL) { /* first time for this pmid */ hp = (hash_t *)malloc(sizeof(hash_t)); if (hp == NULL) { __pmNoMem("hash_t", sizeof(hash_t), PM_FATAL_ERR); /*NOTREACHED*/ } if ((sts = pmNameID(xvsp->pmid, &hp->name)) < 0) { printf(" %s: pmNameID: %s\n", pmIDStr(xvsp->pmid), pmErrStr(sts)); free(hp); continue; } else { if (xvsp->pmid != pmid_flags && xvsp->pmid != pmid_missed && (sts = pmLookupDesc(xvsp->pmid, &hp->desc)) < 0) { printf(" %s: pmLookupDesc: %s\n", hp->name, pmErrStr(sts)); free(hp->name); free(hp); continue; } if ((sts = __pmHashAdd((unsigned int)xvsp->pmid, (void *)hp, &hash)) < 0) { printf(" %s: __pmHashAdd: %s\n", hp->name, pmErrStr(sts)); free(hp->name); free(hp); continue; } } } else hp = (hash_t *)hnp->data; if (p == 0) { if (xvsp->pmid == pmid_flags) { flags = xvsp->vlist[0].value.lval; printf(" flags 0x%x", flags); printf(" (%s) ---\n", pmEventFlagsStr(flags)); continue; } else printf(" ---\n"); } if ((flags & PM_EVENT_FLAG_MISSED) && (p == 1) && (xvsp->pmid == pmid_missed)) { printf(" ==> %d missed event records\n", xvsp->vlist[0].value.lval); continue; } mydump(hp->name, &hp->desc, xvsp); } } if (nrecords >= 0) pmFreeEventResult(res); } /*************************************************************************** * main ***************************************************************************/ int main(int argc, char **argv) { pmResult *rp = NULL; /* current values */ int forever; int sts; int j; int m; __pmSetProgname(argv[0]); setlinebuf(stdout); doargs(argc, argv); pmidlist = (pmID *)malloc(nmetric*sizeof(pmidlist[0])); if (pmidlist == NULL) { __pmNoMem("metrictab", nmetric*sizeof(pmidlist[0]), PM_FATAL_ERR); /*NOTREACHED*/ } for (m = 0 ; m < nmetric; m++) pmidlist[m] = metrictab[m].pmid; if (gui || port != -1) { char *rpt_tz; /* set up pmtime control */ pmWhichZone(&rpt_tz); pmtime = pmTimeStateSetup(&controls, ahtype, port, delta, now, first, last, rpt_tz, host); controls.stepped = timestep; gui = 1; /* we're using pmtime control from here on */ } else if (ahtype == PM_CONTEXT_ARCHIVE) /* no time control, go it alone */ pmTimeStateMode(amode, delta, &now); forever = (samples == ALL_SAMPLES || gui); printhdr(); /* wait till time for first sample */ if (archive == NULL) __pmtimevalPause(now); /* main loop fetching and printing sample values */ while (forever || (samples-- > 0)) { if (gui) pmTimeStateVector(&controls, pmtime); /* wait till time for sample */ if (!gui && archive == NULL) __pmtimevalSleep(delta); /* next sample */ sts = getvals(&rp); if (gui) pmTimeStateAck(&controls, pmtime); if (sts < 0) { if (sts == PM_ERR_EOL && gui) { pmTimeStateBounds(&controls, pmtime); continue; } if (sts == PM_ERR_EOL) break; if (archive == NULL) fprintf(stderr, "\n%s: pmFetch: %s\n", pmProgname, pmErrStr(sts)); else fprintf(stderr, "\n%s: pmFetchArchive: %s\n", pmProgname, pmErrStr(sts)); exit(EXIT_FAILURE); } if ((double)rp->timestamp.tv_sec + (double)rp->timestamp.tv_usec/1000000 > (double)last.tv_sec + (double)last.tv_usec/1000000) break; for (j = 0; j < rp->numpmid; j++) { for (m = 0; m < nmetric; m++) { metric_t *mp = &metrictab[m]; if (rp->vset[j]->pmid == mp->pmid) { if (gui || archive != NULL) { __pmPrintStamp(stdout, &rp->timestamp); printf(" "); } if (rp->vset[j]->numval == 0) { if (verbose) printf("%s: No values available\n", mp->name); } else if (rp->vset[j]->numval < 0) { printf("%s: Error: %s\n", mp->name, pmErrStr(rp->vset[j]->numval)); } else { int i; for (i = 0; i < rp->vset[j]->numval; i++) { if (rp->vset[j]->vlist[i].inst == PM_IN_NULL) printf("%s:", mp->name); else { int k; char *iname = NULL; if (mp->ninst > 0) { for (k = 0; k < mp->ninst; k++) { if (mp->inst[k] == rp->vset[j]->vlist[i].inst) { iname = mp->iname[k]; break; } } } else { /* all instances selected */ __pmHashNode *hnp; hnp = __pmHashSearch((unsigned int)rp->vset[j]->vlist[i].inst, &mp->ihash); if (hnp == NULL) { if (archive != NULL) sts = pmNameInDomArchive(mp->desc.indom, rp->vset[j]->vlist[i].inst, &iname); else sts = pmNameInDom(mp->desc.indom, rp->vset[j]->vlist[i].inst, &iname); if (sts < 0) { fprintf(stderr, "%s: pmNameInDom: %s[%d]: %s\n", pmProgname, mp->name, rp->vset[j]->vlist[i].inst, pmErrStr(sts)); exit(EXIT_FAILURE); } if ((sts = __pmHashAdd((unsigned int)rp->vset[j]->vlist[i].inst, (void *)iname, &mp->ihash)) < 0) { printf("%s: __pmHashAdd: %s[%s (%d)]: %s\n", pmProgname, mp->name, iname, rp->vset[j]->vlist[i].inst, pmErrStr(sts)); exit(EXIT_FAILURE); } } else iname = (char *)hnp->data; } if (iname == NULL) continue; printf("%s[%s]:", mp->name, iname); } myeventdump(rp->vset[j], i); } } break; } } } pmFreeResult(rp); } return 0; } pcp-3.8.12ubuntu1/src/pmevent/GNUmakefile0000664000000000000000000000170512272262501015124 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmevent.c doargs.c HFILES = pmevent.h LLDFLAGS = -L$(TOPDIR)/src/libpcp_gui/src LLDLIBS = $(PCP_GUILIB) $(LIB_FOR_MATH) CMDTARGET = pmevent$(EXECSUFFIX) default: $(CMDTARGET) include $(BUILDRULES) install: $(CMDTARGET) $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmevent/doargs.c0000664000000000000000000003502712272262501014501 0ustar /* * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2008-2009 Aconex. All Rights Reserved. * Copyright (c) 2011 Red Hat Inc. * Copyright (c) 2011 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmevent.h" static int setupEventTrace(int, char **, int, char *); static char *options = "a:D:gh:K:LO:p:S:s:T:t:vx:zZ:?"; static char usage[] = "Usage: %s [options] metricname ...\n\n" "Options:\n" " -a archive metrics source is a PCP archive\n" " -g start in GUI mode with new time control\n" " -h host metrics source is PMCD on host\n" " -K spec optional additional PMDA spec for local connection\n" " spec is of the form op,domain,dso-path,init-routine\n" " -L metrics source is a local context\n" " -O offset initial offset into the reporting time window\n" " -p port port number for connection to existing time control\n" " -S starttime start of the reporting time window\n" " -s samples terminate after this many samples\n" " -T endtime end of the reporting time window\n" " -t interval sample interval [default 1 second]\n" " -v increase diagnostic output\n" " -x filter optionally enable and filter the event stream\n" " -Z timezone set reporting timezone\n" " -z set reporting timezone to local timezone of metrics source\n"; /* process command line options and flags - exits on error */ void doargs(int argc, char **argv) { int c; long d; int errflag = 0; int m; int src = 0; int have_context = 0; int sts; char *endnum; char *errmsg; char *Sflag = NULL; /* argument of -S flag */ char *Tflag = NULL; /* argument of -T flag */ char *Oflag = NULL; /* argument of -O flag */ char *xflag = NULL; /* argument of -x flag */ int zflag = 0; /* for -z */ char *tz = NULL; /* for -Z timezone */ int tzh; /* initial timezone handle */ struct timeval logStart; metric_t *mp; pmMetricSpec *msp; char *msg; static pmLogLabel label; static char *default_host_conn = "local:"; char *host_conn = default_host_conn; /* argument of -h */ delta.tv_sec = 1; delta.tv_usec = 0; samples = ALL_SAMPLES; /* extract command-line arguments */ while ((c = getopt(argc, argv, options)) != EOF) { switch (c) { case 'a': /* archive */ if (++src > 1) { fprintf(stderr, "%s: at most one of -a/-h/-L allowed\n", pmProgname); errflag++; } ahtype = PM_CONTEXT_ARCHIVE; archive = optarg; break; case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case 'g': /* use "gui" mode */ if (port != -1) { fprintf(stderr, "%s: at most one of -g and -p allowed\n", pmProgname); errflag++; } else gui = 1; break; case 'h': /* host name */ if (++src > 1) { fprintf(stderr, "%s: at most one of -a/-h/-L allowed\n", pmProgname); errflag++; } ahtype = PM_CONTEXT_HOST; host_conn = optarg; break; case 'K': /* update local PMDA table */ if ((errmsg = __pmSpecLocalPMDA(optarg)) != NULL) { fprintf(stderr, "%s: illegal -K argument\n", pmProgname); fputs(errmsg, stderr); fputc('\n', stderr); errflag++; } break; case 'L': /* use local context */ if (++src > 1) { fprintf(stderr, "%s: at most one of -a/-h/-L allowed\n", pmProgname); errflag++; } ahtype = PM_CONTEXT_LOCAL; break; case 'O': /* start report time offset */ Oflag = optarg; break; case 'p': /* port for slave of existing time control */ if (gui == 1) { fprintf(stderr, "%s: at most one of -g and -p allowed\n", pmProgname); errflag++; } else { port = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0' || port < 0) { fprintf(stderr, "%s: -p requires a positive numeric argument\n", pmProgname); port = -1; errflag++; } } break; case 's': /* sample count */ d = (int)strtol(optarg, &endnum, 10); if (Tflag) { fprintf(stderr, "%s: at most one of -s and -T allowed\n", pmProgname); errflag++; } else if (*endnum != '\0' || d < 0) { fprintf(stderr, "%s: -s requires a positive numeric argument\n", pmProgname); errflag++; } else samples = d; break; case 'S': /* start report time */ Sflag = optarg; break; case 't': /* sampling interval */ if (pmParseInterval(optarg, &delta, &msg) < 0) { fprintf(stderr, "%s: illegal -t argument\n", pmProgname); fputs(msg, stderr); free(msg); errflag++; } break; case 'T': /* end reporting time */ if (samples != ALL_SAMPLES) { fprintf(stderr, "%s: at most one of -s and -T allowed\n", pmProgname); errflag++; } Tflag = optarg; break; case 'v': verbose++; break; case 'x': xflag = optarg; break; case 'z': /* timezone from metrics source */ if (tz != NULL) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); errflag++; } zflag++; break; case 'Z': /* $TZ timezone */ if (zflag) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); errflag++; } tz = optarg; break; case '?': fprintf(stderr, usage, pmProgname); exit(EXIT_FAILURE); default: errflag++; } } if (errflag) { fprintf(stderr, usage, pmProgname); exit(EXIT_FAILURE); } if (optind >= argc) { fprintf(stderr, "Error: no metricname specified\n"); exit(EXIT_FAILURE); } /* parse uniform metric spec */ for ( ; optind < argc; optind++) { if (ahtype == PM_CONTEXT_ARCHIVE) sts = pmParseMetricSpec(argv[optind], 1, archive, &msp, &msg); else sts = pmParseMetricSpec(argv[optind], 0, host_conn, &msp, &msg); if (sts < 0) { fprintf(stderr, "%s: bad metric specification\n", pmProgname); fputs(msg, stderr); free(msg); exit(EXIT_FAILURE); } if (msp->isarch == 0) { if (ahtype == -1) { ahtype = PM_CONTEXT_HOST; host_conn = msp->source; } else if ((ahtype == PM_CONTEXT_ARCHIVE) || (ahtype == PM_CONTEXT_LOCAL && (strcmp(msp->source, default_host_conn)))) { fprintf(stderr, "%s: %s: only one type of metric source allowed\n", pmProgname, argv[optind]); exit(EXIT_FAILURE); } else if (strcmp(host_conn, msp->source) != 0) { fprintf(stderr, "%s: %s: only one metric source allowed, found hosts %s and %s\n", pmProgname, argv[optind], host_conn, msp->source); exit(EXIT_FAILURE); } } else if (msp->isarch == 1) { if (ahtype == -1) { ahtype = PM_CONTEXT_ARCHIVE; archive = msp->source; } else if (ahtype != PM_CONTEXT_ARCHIVE) { fprintf(stderr, "%s: %s: only one type of metric source allowed\n", pmProgname, argv[optind]); exit(EXIT_FAILURE); } else if (strcmp(archive, msp->source) != 0) { fprintf(stderr, "%s: %s: only one metric source allowed, found archives %s and %s\n", pmProgname, argv[optind], archive, msp->source); exit(EXIT_FAILURE); } } else if (msp->isarch == 2) { if (ahtype == -1) { ahtype = PM_CONTEXT_LOCAL; } else if (ahtype != PM_CONTEXT_LOCAL) { fprintf(stderr, "%s: %s: only one type of metric source allowed\n", pmProgname, argv[optind]); exit(EXIT_FAILURE); } } if (!have_context) { if (ahtype == PM_CONTEXT_ARCHIVE) { /* open connection to archive */ if ((sts = pmNewContext(PM_CONTEXT_ARCHIVE, archive)) < 0) { fprintf(stderr, "%s: Cannot open archive \"%s\": %s\n", pmProgname, msp->source, pmErrStr(sts)); exit(EXIT_FAILURE); } ctxhandle = sts; if ((sts = pmGetArchiveLabel(&label)) < 0) { fprintf(stderr, "%s: Cannot get archive label record: %s\n", pmProgname, pmErrStr(sts)); exit(EXIT_FAILURE); } have_context = 1; logStart = label.ll_start; host = label.ll_hostname; if ((sts = pmGetArchiveEnd(&last)) < 0) { fprintf(stderr, "%s: Cannot determine end of archive: %s", pmProgname, pmErrStr(sts)); exit(EXIT_FAILURE); } } else { /* open connection to host or local context */ if ((sts = pmNewContext(ahtype, host_conn)) < 0) { if (ahtype == PM_CONTEXT_HOST) fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", pmProgname, msp->source, pmErrStr(sts)); else fprintf(stderr, "%s: Cannot establish local context: %s\n", pmProgname, pmErrStr(sts)); exit(EXIT_FAILURE); } ctxhandle = sts; have_context = 1; __pmtimevalNow(&logStart); } } /* Look up the host name according to the pmcd or the archive. */ host = strdup(pmGetContextHostName(ctxhandle)); if (host == NULL) __pmNoMem("host name copy", 0, PM_FATAL_ERR); for (m = 0; m < nmetric; m++) { if (strcmp(msp->metric, metrictab[m].name) == 0) break; } if (m < nmetric) mp = &metrictab[m]; else { nmetric++; metrictab = (metric_t *)realloc(metrictab, nmetric*sizeof(metrictab[0])); if (metrictab == NULL) { __pmNoMem("metrictab", nmetric*sizeof(metrictab[0]), PM_FATAL_ERR); /*NOTREACHED*/ } mp = &metrictab[nmetric-1]; mp->name = msp->metric; if ((sts = pmLookupName(1, &mp->name, &mp->pmid)) < 0) { fprintf(stderr, "%s: pmLookupName: %s: %s\n", pmProgname, mp->name, pmErrStr(sts)); exit(EXIT_FAILURE); } if ((sts = pmLookupDesc(mp->pmid, &mp->desc)) < 0) { fprintf(stderr, "%s: pmLookupDesc: %s: %s\n", pmProgname, mp->name, pmErrStr(sts)); exit(EXIT_FAILURE); } if (mp->desc.type != PM_TYPE_EVENT) { fprintf(stderr, "%s: %s: metrics must be of type PM_TYPE_EVENT\n", pmProgname, mp->name); exit(EXIT_FAILURE); } mp->ninst = 0; mp->iname = NULL; mp->inst = NULL; mp->ihash.nodes = 0; mp->ihash.hsize = 0; mp->ihash.hash = NULL; } if (msp->ninst > 0) { int i; int j; if (mp->desc.indom == PM_INDOM_NULL) { fprintf(stderr, "%s: %s: singular metrics do not have instances\n", pmProgname, argv[optind]); exit(EXIT_FAILURE); } i = mp->ninst; mp->ninst += msp->ninst; mp->iname = (char **)realloc(mp->iname, mp->ninst*sizeof(mp->iname[0])); if (mp->iname == NULL) { __pmNoMem("iname[]", mp->ninst*sizeof(mp->iname[0]), PM_FATAL_ERR); /*NOTREACHED*/ } mp->inst = (int *)realloc(mp->inst, mp->ninst*sizeof(mp->inst[0])); if (mp->inst == NULL) { __pmNoMem("inst[]", mp->ninst*sizeof(mp->inst[0]), PM_FATAL_ERR); /*NOTREACHED*/ } for (j = 0; j < msp->ninst; j++, i++) { mp->iname[i] = msp->inst[j]; if (ahtype == PM_CONTEXT_ARCHIVE) sts = pmLookupInDomArchive(mp->desc.indom, mp->iname[i]); else sts = pmLookupInDom(mp->desc.indom, mp->iname[i]); if (sts < 0) { fprintf(stderr, "%s: pmLookupInDom: %s[%s]: %s\n", pmProgname, mp->name, mp->iname[i], pmErrStr(sts)); exit(EXIT_FAILURE); } mp->inst[i] = sts; } } /* * don't call pmFreeMetricSpec(msp) because we retain pointers into * the structure */ } if (zflag) { if ((tzh = pmNewContextZone()) < 0) { fprintf(stderr, "%s: Cannot set context timezone: %s\n", pmProgname, pmErrStr(tzh)); exit(EXIT_FAILURE); } if (ahtype == PM_CONTEXT_ARCHIVE) { printf("Note: timezone set to local timezone of host \"%s\" from archive\n\n", host); } else { printf("Note: timezone set to local timezone of host \"%s\"\n\n", host); } } else if (tz != NULL) { if ((tzh = pmNewZone(tz)) < 0) { fprintf(stderr, "%s: Cannot set timezone to \"%s\": %s\n", pmProgname, tz, pmErrStr(tzh)); exit(EXIT_FAILURE); } printf("Note: timezone set to \"TZ=%s\"\n\n", tz); } if (pmParseTimeWindow(Sflag, Tflag, NULL, Oflag, &logStart, &last, &first, &last, &now, &msg) < 0) { fprintf(stderr, "%s", msg); exit(EXIT_FAILURE); } if (setupEventTrace(argc, argv, ahtype, xflag) < 0) exit(EXIT_FAILURE); if (pmDebug & DBG_TRACE_APPL0) { char timebuf[26]; char *tp; int i; fprintf(stderr, "first=%.6f", __pmtimevalToReal(&first)); tp = pmCtime(&first.tv_sec, timebuf); /* * tp -> Ddd Mmm DD HH:MM:SS YYYY\n * 0 4 8 1 1 2 2 2 * 1 8 0 3 4 */ fprintf(stderr, " [%24.24s]\n", tp); fprintf(stderr, "now=%.6f", __pmtimevalToReal(&now)); tp = pmCtime(&now.tv_sec, timebuf); fprintf(stderr, " [%24.24s]\n", tp); fprintf(stderr, "last=%.6f", __pmtimevalToReal(&last)); tp = pmCtime(&last.tv_sec, timebuf); fprintf(stderr, " [%24.24s]\n", tp); fprintf(stderr, "delta=%.6f\n", __pmtimevalToReal(&delta)); if (samples != ALL_SAMPLES) fprintf(stderr, "samples=%ld\n", samples); for (m = 0; m < nmetric; m++) { fprintf(stderr, "[%d] metric: %s", m, metrictab[m].name); if (metrictab[m].ninst > 0) { fprintf(stderr, " instance:"); for (i = 0; i < metrictab[m].ninst; i++) { if (i == 0) fputc(' ', stderr); else fprintf(stderr, ", "); fprintf(stderr, "%s (%d)", metrictab[m].iname[i], metrictab[m].inst[i]); } fputc('\n', stderr); } } } } int setupEventTrace(int argc, char **argv, int ahtype, char *xflag) { pmValueSet pmvs; pmValueBlock *pmvbp; pmResult store = { .numpmid = 1 }; int m, vlen; if (ahtype == PM_CONTEXT_ARCHIVE) return 0; /* nothing to do at this stage */ if (ahtype == PM_CONTEXT_HOST) __pmSetClientIdArgv(argc, argv); /* build pmResult for pmStore call if we're explicitly enabling events */ if (xflag != NULL) { vlen = PM_VAL_HDR_SIZE + strlen(xflag) + 1; pmvbp = (pmValueBlock *)malloc(vlen); if (!pmvbp) __pmNoMem("store", vlen, PM_FATAL_ERR); pmvbp->vtype = PM_TYPE_STRING; pmvbp->vlen = vlen; strcpy(pmvbp->vbuf, xflag); store.vset[0] = &pmvs; for (m = 0; m < nmetric; m++) { pmvs.pmid = metrictab[m].pmid; pmvs.numval = 1; pmvs.valfmt = PM_VAL_SPTR; pmvs.vlist[0].inst = PM_IN_NULL; pmvs.vlist[0].value.pval = pmvbp; pmStore(&store); } free(pmvbp); } return 0; } pcp-3.8.12ubuntu1/src/win32ctl/0000775000000000000000000000000012272262620013040 5ustar pcp-3.8.12ubuntu1/src/win32ctl/pmsignal.bat0000775000000000000000000000060712272262501015346 0ustar @echo off if "%OS%" == "Windows_NT" goto WinNT %PCP_DIR%\bin\sh.exe pmsignal.sh %1 %2 %3 %4 %5 %6 %7 %8 %9 goto endofbash :WinNT %PCP_DIR%\bin\sh.exe pmsignal.sh %* if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofbash if %errorlevel% == 9009 echo You do not have sh.exe in your PCP_DIR. if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul :endofbash pcp-3.8.12ubuntu1/src/win32ctl/lib/0000775000000000000000000000000012272262620013606 5ustar pcp-3.8.12ubuntu1/src/win32ctl/lib/GNUmakefile0000775000000000000000000000201412272262501015656 0ustar #!gmake # # Copyright (c) 2010-2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs ifeq "$(TARGET_OS)" "mingw" STATICLIBS = libpcp_pdh.a libpcp_tdh.a endif STATICDEFS = libpcp_pdh.def libpcp_tdh.def MKWIN32LIB = sh -c "$(DLLTOOL) -d $< -k -l $@" LSRCFILES = $(STATICDEFS) LDIRT = $(STATICLIBS) default: $(STATICLIBS) include $(BUILDRULES) libpcp_pdh.a: libpcp_pdh.def $(MKWIN32LIB) libpcp_tdh.a: libpcp_tdh.def $(MKWIN32LIB) default_pcp: default install: default install_pcp: install pcp-3.8.12ubuntu1/src/win32ctl/lib/libpcp_pdh.def0000664000000000000000000000034612272262501016373 0ustar LIBRARY pdh.dll EXPORTS DllInstall PdhAddCounterA@16 PdhRemoveCounter@4 PdhCollectQueryData@4 PdhExpandCounterPathA@12 PdhGetCounterInfoA@16 PdhGetRawCounterValue@12 PdhGetFormattedCounterValue@16 PdhOpenQueryA@12 PdhCloseQuery@4 pcp-3.8.12ubuntu1/src/win32ctl/lib/libpcp_tdh.def0000664000000000000000000000034612272262501016377 0ustar LIBRARY tdh.dll EXPORTS DllInstall TdhGetProperty@28 TdhGetPropertySize@24 TdhGetEventMapInformation@16 TdhQueryProviderFieldInformation@24 TdhGetEventInformation@20 TdhEnumerateProviderFieldInformation@16 TdhEnumerateProviders@8 pcp-3.8.12ubuntu1/src/win32ctl/services/0000775000000000000000000000000012272262620014663 5ustar pcp-3.8.12ubuntu1/src/win32ctl/services/GNUmakefile0000664000000000000000000000167612272262501016745 0ustar # # Copyright (c) 2008-2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs CFILES = pcp-services.c CMDTARGET = pcp-services.exe LLDLIBS = $(PCPLIB) LSRCFILES = $(WRAPPERS) default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "mingw" build-me: $(CMDTARGET) install: default $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) else build-me: install: endif default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/win32ctl/services/pcp-services.c0000664000000000000000000001610512272262501017433 0ustar /* * Copyright (C) 2008-2009 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include #include #include #include #include typedef enum { PCP_SERVICE_COLLECTORS = 0, PCP_SERVICE_INFERENCE = 1, PCP_SERVICE_PROXY = 2, NUM_SERVICES } PCPSERVICE; VOID WINAPI pcpCollectorsSetup(DWORD, LPTSTR *); VOID WINAPI pcpInferenceSetup(DWORD, LPTSTR *); VOID WINAPI pcpProxySetup(DWORD, LPTSTR *); DWORD WINAPI pcpCollectorsDispatch(DWORD, DWORD, LPVOID, LPVOID); DWORD WINAPI pcpInferenceDispatch(DWORD, DWORD, LPVOID, LPVOID); DWORD WINAPI pcpProxyDispatch(DWORD, DWORD, LPVOID, LPVOID); typedef VOID WINAPI (*SETUPFUNC)(DWORD, LPTSTR *); typedef DWORD WINAPI (*DISPATCHFUNC)(DWORD, DWORD, LPVOID, LPVOID); struct { TCHAR * name; TCHAR * script; HANDLE stopEvent; SERVICE_STATUS status; SERVICE_STATUS_HANDLE statusHandle; SETUPFUNC setup; DISPATCHFUNC dispatch; } services[3] = { { .name = "PCP Collector Processes", .script = "pcp", .setup = pcpCollectorsSetup, .dispatch = pcpCollectorsDispatch, }, { .name = "PCP Inference Engines", .script = "pmie", .setup = pcpInferenceSetup, .dispatch = pcpInferenceDispatch, }, { .name = "PCP Collector Proxy", .script = "pmproxy", .setup = pcpProxySetup, .dispatch = pcpProxyDispatch, }, }; static char pcpdir[MAXPATHLEN+16]; /* PCP_DIR environment variable */ static char pcpconf[MAXPATHLEN+16]; /* PCP_CONF string for putenv */ static char pcpdirenv[MAXPATHLEN+16]; /* PCP_DIR string for putenv */ int pcpScript(const char *name, const char *action) { char s[MAXPATHLEN]; snprintf(s, sizeof(s), "%s\\bin\\sh.exe /etc/%s %s", pcpdir, name, action); return system(s); } VOID pcpSetServiceState(PCPSERVICE s, DWORD state, DWORD code, DWORD waitHint) { services[s].status.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; services[s].status.dwCurrentState = state; services[s].status.dwWin32ExitCode = code; services[s].status.dwWaitHint = waitHint; if (state == SERVICE_START_PENDING) services[s].status.dwControlsAccepted = 0; else services[s].status.dwControlsAccepted = SERVICE_ACCEPT_STOP; if ((state == SERVICE_RUNNING) || (state == SERVICE_STOPPED)) services[s].status.dwCheckPoint = 0; else services[s].status.dwCheckPoint++; /* Report the status of the service to the SCM. */ SetServiceStatus(services[s].statusHandle, &services[s].status); } VOID pcpServiceMain(DWORD argc, LPTSTR *argv, PCPSERVICE s) { char *default_basedirs[] = { "C:\\Glider", "C:\\MSYS" }; char *default_service = "pcp"; char *service = NULL, *basedir = NULL; int i; if (argc > 1) { /* first argument is service name */ service = argv[1]; for (i = 0; i < NUM_SERVICES; i++) if (strcmp(service, services[i].name) == 0) break; if (i == NUM_SERVICES) return; /* unknown service requested - bail out */ } if (service == NULL) service = default_service; if (argc > 2) /* second argument is PCP_DIR */ basedir = argv[2]; else if ((basedir = getenv("PCP_DIR")) == NULL) { for (i = 0; i < 3; i++) if (access(default_basedirs[i], R_OK) == 0) { basedir = default_basedirs[i]; break; } } if (!basedir || access(basedir, R_OK) != 0) return; /* stuffed up if we have no PCP_DIR - bail out */ snprintf(pcpdir, sizeof(pcpdir), "%s", basedir); snprintf(pcpconf, sizeof(pcpconf), "PCP_CONF=%s\\etc\\pcp.conf", pcpdir); snprintf(pcpdirenv, sizeof(pcpdirenv), "PCP_DIR=%s", pcpdir); putenv(pcpconf); putenv(pcpdirenv); services[s].statusHandle = RegisterServiceCtrlHandlerEx( services[s].name, services[s].dispatch, NULL); if (!services[s].statusHandle) return; pcpSetServiceState(s, SERVICE_START_PENDING, NO_ERROR, 0); /* * Create an event. The control handler function signals * this event when it receives the stop control code. */ services[s].stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!services[s].stopEvent) { pcpSetServiceState(s, SERVICE_STOPPED, NO_ERROR, 0); return; } /* * Go, go, go... run the start script for this service. */ if (pcpScript(services[s].script, "start") != 0) { pcpSetServiceState(s, SERVICE_STOPPED, NO_ERROR, 0); return; } pcpSetServiceState(s, SERVICE_RUNNING, NO_ERROR, 0); /* Check whether to stop the service. */ WaitForSingleObject(services[s].stopEvent, INFINITE); /* ServiceState already set to SERVICE_STOP_PENDING */ pcpScript(services[s].script, "stop"); pcpSetServiceState(s, SERVICE_STOPPED, NO_ERROR, 0); } VOID WINAPI pcpCollectorsSetup(DWORD argc, LPTSTR *argv) { pcpServiceMain(argc, argv, PCP_SERVICE_COLLECTORS); } VOID WINAPI pcpInferenceSetup(DWORD argc, LPTSTR *argv) { pcpServiceMain(argc, argv, PCP_SERVICE_INFERENCE); } VOID WINAPI pcpProxySetup(DWORD argc, LPTSTR *argv) { pcpServiceMain(argc, argv, PCP_SERVICE_PROXY); } DWORD pcpServiceHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext, PCPSERVICE s) { switch(dwControl) { case SERVICE_CONTROL_STOP: services[s].status.dwCurrentState = SERVICE_STOP_PENDING; SetServiceStatus(services[s].statusHandle, &services[s].status); SetEvent(services[s].stopEvent); return NO_ERROR; default: break; } /* Send current status (done for most request types) */ SetServiceStatus(services[s].statusHandle, &services[s].status); return NO_ERROR; } DWORD WINAPI pcpCollectorsDispatch(DWORD ctrl, DWORD type, LPVOID data, LPVOID ctxt) { return pcpServiceHandler(ctrl, type, data, ctxt, PCP_SERVICE_COLLECTORS); } DWORD WINAPI pcpInferenceDispatch(DWORD ctrl, DWORD type, LPVOID data, LPVOID ctxt) { return pcpServiceHandler(ctrl, type, data, ctxt, PCP_SERVICE_INFERENCE); } DWORD WINAPI pcpProxyDispatch(DWORD ctrl, DWORD type, LPVOID data, LPVOID ctxt) { return pcpServiceHandler(ctrl, type, data, ctxt, PCP_SERVICE_PROXY); } int main(int argc, char **argv) { SERVICE_TABLE_ENTRY dispatchTable[2]; __pmSetProgname(argv[0]); /* setup dispatch table and sentinel */ dispatchTable[0].lpServiceName = services[0].name; dispatchTable[0].lpServiceProc = services[0].setup; dispatchTable[1].lpServiceName = NULL; dispatchTable[1].lpServiceProc = NULL; if (!StartServiceCtrlDispatcher(dispatchTable)) { DWORD c = GetLastError(); fprintf(stderr, "%s: cannot dispatch services (%ld)\n", pmProgname, c); if (c == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) fprintf(stderr, "%s: run as service, not on console\n", pmProgname); return 1; } return 0; } pcp-3.8.12ubuntu1/src/win32ctl/include/0000775000000000000000000000000012272262620014463 5ustar pcp-3.8.12ubuntu1/src/win32ctl/include/pdhmsg.h0000664000000000000000000001155712272262501016125 0ustar /** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the w64 mingw-runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #ifndef _PDH_MSG_H_ #define _PDH_MSG_H_ #define STATUS_SEVERITY_WARNING 0x2 #define STATUS_SEVERITY_SUCCESS 0x0 #define STATUS_SEVERITY_INFORMATIONAL 0x1 #define STATUS_SEVERITY_ERROR 0x3 #define PDH_CSTATUS_VALID_DATA ((DWORD)0x00000000L) #define PDH_CSTATUS_NEW_DATA ((DWORD)0x00000001L) #define PDH_CSTATUS_NO_MACHINE ((DWORD)0x800007D0L) #define PDH_CSTATUS_NO_INSTANCE ((DWORD)0x800007D1L) #define PDH_MORE_DATA ((DWORD)0x800007D2L) #define PDH_CSTATUS_ITEM_NOT_VALIDATED ((DWORD)0x800007D3L) #define PDH_RETRY ((DWORD)0x800007D4L) #define PDH_NO_DATA ((DWORD)0x800007D5L) #define PDH_CALC_NEGATIVE_DENOMINATOR ((DWORD)0x800007D6L) #define PDH_CALC_NEGATIVE_TIMEBASE ((DWORD)0x800007D7L) #define PDH_CALC_NEGATIVE_VALUE ((DWORD)0x800007D8L) #define PDH_DIALOG_CANCELLED ((DWORD)0x800007D9L) #define PDH_END_OF_LOG_FILE ((DWORD)0x800007DAL) #define PDH_ASYNC_QUERY_TIMEOUT ((DWORD)0x800007DBL) #define PDH_CANNOT_SET_DEFAULT_REALTIME_DATASOURCE ((DWORD)0x800007DCL) #define PDH_CSTATUS_NO_OBJECT ((DWORD)0xC0000BB8L) #define PDH_CSTATUS_NO_COUNTER ((DWORD)0xC0000BB9L) #define PDH_CSTATUS_INVALID_DATA ((DWORD)0xC0000BBAL) #define PDH_MEMORY_ALLOCATION_FAILURE ((DWORD)0xC0000BBBL) #define PDH_INVALID_HANDLE ((DWORD)0xC0000BBCL) #define PDH_INVALID_ARGUMENT ((DWORD)0xC0000BBDL) #define PDH_FUNCTION_NOT_FOUND ((DWORD)0xC0000BBEL) #define PDH_CSTATUS_NO_COUNTERNAME ((DWORD)0xC0000BBFL) #define PDH_CSTATUS_BAD_COUNTERNAME ((DWORD)0xC0000BC0L) #define PDH_INVALID_BUFFER ((DWORD)0xC0000BC1L) #define PDH_INSUFFICIENT_BUFFER ((DWORD)0xC0000BC2L) #define PDH_CANNOT_CONNECT_MACHINE ((DWORD)0xC0000BC3L) #define PDH_INVALID_PATH ((DWORD)0xC0000BC4L) #define PDH_INVALID_INSTANCE ((DWORD)0xC0000BC5L) #define PDH_INVALID_DATA ((DWORD)0xC0000BC6L) #define PDH_NO_DIALOG_DATA ((DWORD)0xC0000BC7L) #define PDH_CANNOT_READ_NAME_STRINGS ((DWORD)0xC0000BC8L) #define PDH_LOG_FILE_CREATE_ERROR ((DWORD)0xC0000BC9L) #define PDH_LOG_FILE_OPEN_ERROR ((DWORD)0xC0000BCAL) #define PDH_LOG_TYPE_NOT_FOUND ((DWORD)0xC0000BCBL) #define PDH_NO_MORE_DATA ((DWORD)0xC0000BCCL) #define PDH_ENTRY_NOT_IN_LOG_FILE ((DWORD)0xC0000BCDL) #define PDH_DATA_SOURCE_IS_LOG_FILE ((DWORD)0xC0000BCEL) #define PDH_DATA_SOURCE_IS_REAL_TIME ((DWORD)0xC0000BCFL) #define PDH_UNABLE_READ_LOG_HEADER ((DWORD)0xC0000BD0L) #define PDH_FILE_NOT_FOUND ((DWORD)0xC0000BD1L) #define PDH_FILE_ALREADY_EXISTS ((DWORD)0xC0000BD2L) #define PDH_NOT_IMPLEMENTED ((DWORD)0xC0000BD3L) #define PDH_STRING_NOT_FOUND ((DWORD)0xC0000BD4L) #define PDH_UNABLE_MAP_NAME_FILES ((DWORD)0x80000BD5L) #define PDH_UNKNOWN_LOG_FORMAT ((DWORD)0xC0000BD6L) #define PDH_UNKNOWN_LOGSVC_COMMAND ((DWORD)0xC0000BD7L) #define PDH_LOGSVC_QUERY_NOT_FOUND ((DWORD)0xC0000BD8L) #define PDH_LOGSVC_NOT_OPENED ((DWORD)0xC0000BD9L) #define PDH_WBEM_ERROR ((DWORD)0xC0000BDAL) #define PDH_ACCESS_DENIED ((DWORD)0xC0000BDBL) #define PDH_LOG_FILE_TOO_SMALL ((DWORD)0xC0000BDCL) #define PDH_INVALID_DATASOURCE ((DWORD)0xC0000BDDL) #define PDH_INVALID_SQLDB ((DWORD)0xC0000BDEL) #define PDH_NO_COUNTERS ((DWORD)0xC0000BDFL) #define PDH_SQL_ALLOC_FAILED ((DWORD)0xC0000BE0L) #define PDH_SQL_ALLOCCON_FAILED ((DWORD)0xC0000BE1L) #define PDH_SQL_EXEC_DIRECT_FAILED ((DWORD)0xC0000BE2L) #define PDH_SQL_FETCH_FAILED ((DWORD)0xC0000BE3L) #define PDH_SQL_ROWCOUNT_FAILED ((DWORD)0xC0000BE4L) #define PDH_SQL_MORE_RESULTS_FAILED ((DWORD)0xC0000BE5L) #define PDH_SQL_CONNECT_FAILED ((DWORD)0xC0000BE6L) #define PDH_SQL_BIND_FAILED ((DWORD)0xC0000BE7L) #define PDH_CANNOT_CONNECT_WMI_SERVER ((DWORD)0xC0000BE8L) #define PDH_PLA_COLLECTION_ALREADY_RUNNING ((DWORD)0xC0000BE9L) #define PDH_PLA_ERROR_SCHEDULE_OVERLAP ((DWORD)0xC0000BEAL) #define PDH_PLA_COLLECTION_NOT_FOUND ((DWORD)0xC0000BEBL) #define PDH_PLA_ERROR_SCHEDULE_ELAPSED ((DWORD)0xC0000BECL) #define PDH_PLA_ERROR_NOSTART ((DWORD)0xC0000BEDL) #define PDH_PLA_ERROR_ALREADY_EXISTS ((DWORD)0xC0000BEEL) #define PDH_PLA_ERROR_TYPE_MISMATCH ((DWORD)0xC0000BEFL) #define PDH_PLA_ERROR_FILEPATH ((DWORD)0xC0000BF0L) #define PDH_PLA_SERVICE_ERROR ((DWORD)0xC0000BF1L) #define PDH_PLA_VALIDATION_ERROR ((DWORD)0xC0000BF2L) #define PDH_PLA_VALIDATION_WARNING ((DWORD)0x80000BF3L) #define PDH_PLA_ERROR_NAME_TOO_LONG ((DWORD)0xC0000BF4L) #define PDH_INVALID_SQL_LOG_FORMAT ((DWORD)0xC0000BF5L) #define PDH_COUNTER_ALREADY_IN_QUERY ((DWORD)0xC0000BF6L) #define PDH_BINARY_LOG_CORRUPT ((DWORD)0xC0000BF7L) #define PDH_LOG_SAMPLE_TOO_SMALL ((DWORD)0xC0000BF8L) #define PDH_OS_LATER_VERSION ((DWORD)0xC0000BF9L) #define PDH_OS_EARLIER_VERSION ((DWORD)0xC0000BFAL) #define PDH_INCORRECT_APPEND_TIME ((DWORD)0xC0000BFBL) #define PDH_UNMATCHED_APPEND_COUNTER ((DWORD)0xC0000BFCL) #define PDH_SQL_ALTER_DETAIL_FAILED ((DWORD)0xC0000BFDL) #define PDH_QUERY_PERF_DATA_TIMEOUT ((DWORD)0xC0000BFEL) #endif pcp-3.8.12ubuntu1/src/win32ctl/include/evntrace.h0000664000000000000000000006567212272262501016461 0ustar /** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the w64 mingw-runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #ifndef _EVNTRACE_ #define _EVNTRACE_ /* --- start added by kenj */ #undef __MINGW_EXTENSION #if defined(__GNUC__) || defined(__GNUG__) #define __MINGW_EXTENSION __extension__ #else #define __MINGW_EXTENSION #endif /* --- end added by kenj */ #if defined(_WINNT_) || defined(WINNT) #ifndef WMIAPI #ifndef MIDL_PASS #ifdef _WMI_SOURCE_ #define WMIAPI __stdcall #else #define WMIAPI DECLSPEC_IMPORT __stdcall #endif #endif /* MIDL_PASS */ #endif /* WMIAPI */ DEFINE_GUID (EventTraceGuid,0x68fdd900,0x4a3e,0x11d1,0x84,0xf4,0x00,0x00,0xf8,0x04,0x64,0xe3); DEFINE_GUID (SystemTraceControlGuid,0x9e814aad,0x3204,0x11d2,0x9a,0x82,0x00,0x60,0x08,0xa8,0x69,0x39); DEFINE_GUID (EventTraceConfigGuid,0x01853a65,0x418f,0x4f36,0xae,0xfc,0xdc,0x0f,0x1d,0x2f,0xd2,0x35); DEFINE_GUID (DefaultTraceSecurityGuid,0x0811c1af,0x7a07,0x4a06,0x82,0xed,0x86,0x94,0x55,0xcd,0xf7,0x13); #define KERNEL_LOGGER_NAMEW L"NT Kernel Logger" #define GLOBAL_LOGGER_NAMEW L"GlobalLogger" #define EVENT_LOGGER_NAMEW L"Event Log" #define DIAG_LOGGER_NAMEW L"DiagLog" #define KERNEL_LOGGER_NAMEA "NT Kernel Logger" #define GLOBAL_LOGGER_NAMEA "GlobalLogger" #define EVENT_LOGGER_NAMEA "Event Log" #define DIAG_LOGGER_NAMEA "DiagLog" #define MAX_MOF_FIELDS 16 #ifndef _TRACEHANDLE_DEFINED #define _TRACEHANDLE_DEFINED typedef ULONG64 TRACEHANDLE,*PTRACEHANDLE; #endif #define SYSTEM_EVENT_TYPE 1 #define EVENT_TRACE_TYPE_INFO 0x00 #define EVENT_TRACE_TYPE_START 0x01 #define EVENT_TRACE_TYPE_END 0x02 #define EVENT_TRACE_TYPE_STOP 0x02 #define EVENT_TRACE_TYPE_DC_START 0x03 #define EVENT_TRACE_TYPE_DC_END 0x04 #define EVENT_TRACE_TYPE_EXTENSION 0x05 #define EVENT_TRACE_TYPE_REPLY 0x06 #define EVENT_TRACE_TYPE_DEQUEUE 0x07 #define EVENT_TRACE_TYPE_RESUME 0x07 #define EVENT_TRACE_TYPE_CHECKPOINT 0x08 #define EVENT_TRACE_TYPE_SUSPEND 0x08 #define EVENT_TRACE_TYPE_WINEVT_SEND 0x09 #define EVENT_TRACE_TYPE_WINEVT_RECEIVE 0XF0 #define TRACE_LEVEL_NONE 0 #define TRACE_LEVEL_CRITICAL 1 #define TRACE_LEVEL_FATAL 1 #define TRACE_LEVEL_ERROR 2 #define TRACE_LEVEL_WARNING 3 #define TRACE_LEVEL_INFORMATION 4 #define TRACE_LEVEL_VERBOSE 5 #define TRACE_LEVEL_RESERVED6 6 #define TRACE_LEVEL_RESERVED7 7 #define TRACE_LEVEL_RESERVED8 8 #define TRACE_LEVEL_RESERVED9 9 #define EVENT_TRACE_TYPE_LOAD 0x0A #define EVENT_TRACE_TYPE_IO_READ 0x0A #define EVENT_TRACE_TYPE_IO_WRITE 0x0B #define EVENT_TRACE_TYPE_IO_READ_INIT 0x0C #define EVENT_TRACE_TYPE_IO_WRITE_INIT 0x0D #define EVENT_TRACE_TYPE_IO_FLUSH 0x0E #define EVENT_TRACE_TYPE_IO_FLUSH_INIT 0x0F #define EVENT_TRACE_TYPE_MM_TF 0x0A #define EVENT_TRACE_TYPE_MM_DZF 0x0B #define EVENT_TRACE_TYPE_MM_COW 0x0C #define EVENT_TRACE_TYPE_MM_GPF 0x0D #define EVENT_TRACE_TYPE_MM_HPF 0x0E #define EVENT_TRACE_TYPE_MM_AV 0x0F #define EVENT_TRACE_TYPE_SEND 0x0A #define EVENT_TRACE_TYPE_RECEIVE 0x0B #define EVENT_TRACE_TYPE_CONNECT 0x0C #define EVENT_TRACE_TYPE_DISCONNECT 0x0D #define EVENT_TRACE_TYPE_RETRANSMIT 0x0E #define EVENT_TRACE_TYPE_ACCEPT 0x0F #define EVENT_TRACE_TYPE_RECONNECT 0x10 #define EVENT_TRACE_TYPE_CONNFAIL 0x11 #define EVENT_TRACE_TYPE_COPY_TCP 0x12 #define EVENT_TRACE_TYPE_COPY_ARP 0x13 #define EVENT_TRACE_TYPE_ACKFULL 0x14 #define EVENT_TRACE_TYPE_ACKPART 0x15 #define EVENT_TRACE_TYPE_ACKDUP 0x16 #define EVENT_TRACE_TYPE_GUIDMAP 0x0A #define EVENT_TRACE_TYPE_CONFIG 0x0B #define EVENT_TRACE_TYPE_SIDINFO 0x0C #define EVENT_TRACE_TYPE_SECURITY 0x0D #define EVENT_TRACE_TYPE_REGCREATE 0x0A #define EVENT_TRACE_TYPE_REGOPEN 0x0B #define EVENT_TRACE_TYPE_REGDELETE 0x0C #define EVENT_TRACE_TYPE_REGQUERY 0x0D #define EVENT_TRACE_TYPE_REGSETVALUE 0x0E #define EVENT_TRACE_TYPE_REGDELETEVALUE 0x0F #define EVENT_TRACE_TYPE_REGQUERYVALUE 0x10 #define EVENT_TRACE_TYPE_REGENUMERATEKEY 0x11 #define EVENT_TRACE_TYPE_REGENUMERATEVALUEKEY 0x12 #define EVENT_TRACE_TYPE_REGQUERYMULTIPLEVALUE 0x13 #define EVENT_TRACE_TYPE_REGSETINFORMATION 0x14 #define EVENT_TRACE_TYPE_REGFLUSH 0x15 #define EVENT_TRACE_TYPE_REGKCBCREATE 0x16 #define EVENT_TRACE_TYPE_REGKCBDELETE 0x17 #define EVENT_TRACE_TYPE_REGKCBRUNDOWNBEGIN 0x18 #define EVENT_TRACE_TYPE_REGKCBRUNDOWNEND 0x19 #define EVENT_TRACE_TYPE_REGVIRTUALIZE 0x1A #define EVENT_TRACE_TYPE_REGCLOSE 0x1B #define EVENT_TRACE_TYPE_REGSETSECURITY 0x1C #define EVENT_TRACE_TYPE_REGQUERYSECURITY 0x1D #define EVENT_TRACE_TYPE_REGCOMMIT 0x1E #define EVENT_TRACE_TYPE_REGPREPARE 0x1F #define EVENT_TRACE_TYPE_REGROLLBACK 0x20 #define EVENT_TRACE_TYPE_REGMOUNTHIVE 0x21 #define EVENT_TRACE_TYPE_CONFIG_CPU 0x0A #define EVENT_TRACE_TYPE_CONFIG_PHYSICALDISK 0x0B #define EVENT_TRACE_TYPE_CONFIG_LOGICALDISK 0x0C #define EVENT_TRACE_TYPE_CONFIG_NIC 0x0D #define EVENT_TRACE_TYPE_CONFIG_VIDEO 0x0E #define EVENT_TRACE_TYPE_CONFIG_SERVICES 0x0F #define EVENT_TRACE_TYPE_CONFIG_POWER 0x10 #define EVENT_TRACE_TYPE_CONFIG_NETINFO 0x11 #define EVENT_TRACE_TYPE_CONFIG_IRQ 0x15 #define EVENT_TRACE_TYPE_CONFIG_PNP 0x16 #define EVENT_TRACE_TYPE_CONFIG_IDECHANNEL 0x17 #define EVENT_TRACE_TYPE_CONFIG_PLATFORM 0x19 #define EVENT_TRACE_FLAG_PROCESS 0x00000001 #define EVENT_TRACE_FLAG_THREAD 0x00000002 #define EVENT_TRACE_FLAG_IMAGE_LOAD 0x00000004 #define EVENT_TRACE_FLAG_DISK_IO 0x00000100 #define EVENT_TRACE_FLAG_DISK_FILE_IO 0x00000200 #define EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS 0x00001000 #define EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS 0x00002000 #define EVENT_TRACE_FLAG_NETWORK_TCPIP 0x00010000 #define EVENT_TRACE_FLAG_REGISTRY 0x00020000 #define EVENT_TRACE_FLAG_DBGPRINT 0x00040000 #define EVENT_TRACE_FLAG_PROCESS_COUNTERS 0x00000008 #define EVENT_TRACE_FLAG_CSWITCH 0x00000010 #define EVENT_TRACE_FLAG_DPC 0x00000020 #define EVENT_TRACE_FLAG_INTERRUPT 0x00000040 #define EVENT_TRACE_FLAG_SYSTEMCALL 0x00000080 #define EVENT_TRACE_FLAG_DISK_IO_INIT 0x00000400 #define EVENT_TRACE_FLAG_ALPC 0x00100000 #define EVENT_TRACE_FLAG_SPLIT_IO 0x00200000 #define EVENT_TRACE_FLAG_DRIVER 0x00800000 #define EVENT_TRACE_FLAG_PROFILE 0x01000000 #define EVENT_TRACE_FLAG_FILE_IO 0x02000000 #define EVENT_TRACE_FLAG_FILE_IO_INIT 0x04000000 #define EVENT_TRACE_FLAG_DISPATCHER 0x00000800 #define EVENT_TRACE_FLAG_VIRTUAL_ALLOC 0x00004000 #define EVENT_TRACE_FLAG_EXTENSION 0x80000000 #define EVENT_TRACE_FLAG_FORWARD_WMI 0x40000000 #define EVENT_TRACE_FLAG_ENABLE_RESERVE 0x20000000 #define EVENT_TRACE_FILE_MODE_NONE 0x00000000 #define EVENT_TRACE_FILE_MODE_SEQUENTIAL 0x00000001 #define EVENT_TRACE_FILE_MODE_CIRCULAR 0x00000002 #define EVENT_TRACE_FILE_MODE_APPEND 0x00000004 #define EVENT_TRACE_FILE_MODE_NEWFILE 0x00000008 #define EVENT_TRACE_FILE_MODE_PREALLOCATE 0x00000020 #define EVENT_TRACE_NONSTOPPABLE_MODE 0x00000040 #define EVENT_TRACE_SECURE_MODE 0x00000080 #define EVENT_TRACE_USE_KBYTES_FOR_SIZE 0x00002000 #define EVENT_TRACE_PRIVATE_IN_PROC 0x00020000 #define EVENT_TRACE_MODE_RESERVED 0x00100000 #define EVENT_TRACE_NO_PER_PROCESSOR_BUFFERING 0x10000000 #define EVENT_TRACE_REAL_TIME_MODE 0x00000100 #define EVENT_TRACE_DELAY_OPEN_FILE_MODE 0x00000200 #define EVENT_TRACE_BUFFERING_MODE 0x00000400 #define EVENT_TRACE_PRIVATE_LOGGER_MODE 0x00000800 #define EVENT_TRACE_ADD_HEADER_MODE 0x00001000 #define EVENT_TRACE_USE_GLOBAL_SEQUENCE 0x00004000 #define EVENT_TRACE_USE_LOCAL_SEQUENCE 0x00008000 #define EVENT_TRACE_RELOG_MODE 0x00010000 #define EVENT_TRACE_USE_PAGED_MEMORY 0x01000000 #define EVENT_TRACE_CONTROL_QUERY 0 #define EVENT_TRACE_CONTROL_STOP 1 #define EVENT_TRACE_CONTROL_UPDATE 2 #define EVENT_TRACE_CONTROL_FLUSH 3 #define TRACE_MESSAGE_SEQUENCE 1 #define TRACE_MESSAGE_GUID 2 #define TRACE_MESSAGE_COMPONENTID 4 #define TRACE_MESSAGE_TIMESTAMP 8 #define TRACE_MESSAGE_PERFORMANCE_TIMESTAMP 16 #define TRACE_MESSAGE_SYSTEMINFO 32 #define TRACE_MESSAGE_POINTER32 0x0040 #define TRACE_MESSAGE_POINTER64 0x0080 #define TRACE_MESSAGE_FLAG_MASK 0xFFFF #define TRACE_HEADER_FLAG_USE_TIMESTAMP 0x00000200 #define TRACE_HEADER_FLAG_TRACED_GUID 0x00020000 #define TRACE_HEADER_FLAG_LOG_WNODE 0x00040000 #define TRACE_HEADER_FLAG_USE_GUID_PTR 0x00080000 #define TRACE_HEADER_FLAG_USE_MOF_PTR 0x00100000 #define TRACE_MESSAGE_MAXIMUM_SIZE 8*1024 #define ETW_NULL_TYPE_VALUE 0 #define ETW_OBJECT_TYPE_VALUE 1 #define ETW_STRING_TYPE_VALUE 2 #define ETW_SBYTE_TYPE_VALUE 3 #define ETW_BYTE_TYPE_VALUE 4 #define ETW_INT16_TYPE_VALUE 5 #define ETW_UINT16_TYPE_VALUE 6 #define ETW_INT32_TYPE_VALUE 7 #define ETW_UINT32_TYPE_VALUE 8 #define ETW_INT64_TYPE_VALUE 9 #define ETW_UINT64_TYPE_VALUE 10 #define ETW_CHAR_TYPE_VALUE 11 #define ETW_SINGLE_TYPE_VALUE 12 #define ETW_DOUBLE_TYPE_VALUE 13 #define ETW_BOOLEAN_TYPE_VALUE 14 #define ETW_DECIMAL_TYPE_VALUE 15 #define ETW_GUID_TYPE_VALUE 101 #define ETW_ASCIICHAR_TYPE_VALUE 102 #define ETW_ASCIISTRING_TYPE_VALUE 103 #define ETW_COUNTED_STRING_TYPE_VALUE 104 #define ETW_POINTER_TYPE_VALUE 105 #define ETW_SIZET_TYPE_VALUE 106 #define ETW_HIDDEN_TYPE_VALUE 107 #define ETW_BOOL_TYPE_VALUE 108 #define ETW_COUNTED_ANSISTRING_TYPE_VALUE 109 #define ETW_REVERSED_COUNTED_STRING_TYPE_VALUE 110 #define ETW_REVERSED_COUNTED_ANSISTRING_TYPE_VALUE 111 #define ETW_NON_NULL_TERMINATED_STRING_TYPE_VALUE 112 #define ETW_REDUCED_ANSISTRING_TYPE_VALUE 113 #define ETW_REDUCED_STRING_TYPE_VALUE 114 #define ETW_SID_TYPE_VALUE 115 #define ETW_VARIANT_TYPE_VALUE 116 #define ETW_PTVECTOR_TYPE_VALUE 117 #define ETW_WMITIME_TYPE_VALUE 118 #define ETW_DATETIME_TYPE_VALUE 119 #define ETW_REFRENCE_TYPE_VALUE 120 #define TRACE_PROVIDER_FLAG_LEGACY 0x00000001 #define TRACE_PROVIDER_FLAG_PRE_ENABLE 0x00000002 #define EVENT_CONTROL_CODE_DISABLE_PROVIDER 0 #define EVENT_CONTROL_CODE_ENABLE_PROVIDER 1 #define EVENT_CONTROL_CODE_CAPTURE_STATE 2 #define EVENT_TRACE_USE_PROCTIME 0x0001 #define EVENT_TRACE_USE_NOCPUTIME 0x0002 typedef struct _EVENT_TRACE_HEADER { USHORT Size; __MINGW_EXTENSION union { USHORT FieldTypeFlags; __MINGW_EXTENSION struct { UCHAR HeaderType; UCHAR MarkerFlags; } DUMMYSTRUCTNAME; } DUMMYUNIONNAME; __MINGW_EXTENSION union { ULONG Version; struct { UCHAR Type; UCHAR Level; USHORT Version; } Class; } DUMMYUNIONNAME2; ULONG ThreadId; ULONG ProcessId; LARGE_INTEGER TimeStamp; __MINGW_EXTENSION union { GUID Guid; ULONGLONG GuidPtr; } DUMMYUNIONNAME3; __MINGW_EXTENSION union { __MINGW_EXTENSION struct { ULONG KernelTime; ULONG UserTime; } DUMMYSTRUCTNAME; ULONG64 ProcessorTime; __MINGW_EXTENSION struct { ULONG ClientContext; ULONG Flags; } DUMMYSTRUCTNAME2; } DUMMYUNIONNAME4; } EVENT_TRACE_HEADER,*PEVENT_TRACE_HEADER; typedef struct _EVENT_INSTANCE_HEADER { USHORT Size; __MINGW_EXTENSION union { USHORT FieldTypeFlags; __MINGW_EXTENSION struct { UCHAR HeaderType; UCHAR MarkerFlags; } DUMMYSTRUCTNAME; } DUMMYUNIONNAME; __MINGW_EXTENSION union { ULONG Version; struct { UCHAR Type; UCHAR Level; USHORT Version; } Class; } DUMMYUNIONNAME2; ULONG ThreadId; ULONG ProcessId; LARGE_INTEGER TimeStamp; ULONGLONG RegHandle; ULONG InstanceId; ULONG ParentInstanceId; __MINGW_EXTENSION union { __MINGW_EXTENSION struct { ULONG KernelTime; ULONG UserTime; } DUMMYSTRUCTNAME; ULONG64 ProcessorTime; __MINGW_EXTENSION struct { ULONG EventId; ULONG Flags; } DUMMYSTRUCTNAME2; } DUMMYUNIONNAME3; ULONGLONG ParentRegHandle; } EVENT_INSTANCE_HEADER,*PEVENT_INSTANCE_HEADER; #define DEFINE_TRACE_MOF_FIELD(MOF,ptr,length,type) \ (MOF)->DataPtr = (ULONG64) (ULONG_PTR) ptr; \ (MOF)->Length = (ULONG) length; \ (MOF)->DataType = (ULONG) type; typedef struct _MOF_FIELD { ULONG64 DataPtr; ULONG Length; ULONG DataType; } MOF_FIELD,*PMOF_FIELD; #if !(defined(_NTDDK_) || defined(_NTIFS_)) || defined(_WMIKM_) typedef struct _TRACE_LOGFILE_HEADER { ULONG BufferSize; __MINGW_EXTENSION union { ULONG Version; struct { UCHAR MajorVersion; UCHAR MinorVersion; UCHAR SubVersion; UCHAR SubMinorVersion; } VersionDetail; } DUMMYUNIONNAME; ULONG ProviderVersion; ULONG NumberOfProcessors; LARGE_INTEGER EndTime; ULONG TimerResolution; ULONG MaximumFileSize; ULONG LogFileMode; ULONG BuffersWritten; __MINGW_EXTENSION union { GUID LogInstanceGuid; __MINGW_EXTENSION struct { ULONG StartBuffers; ULONG PointerSize; ULONG EventsLost; ULONG CpuSpeedInMHz; } DUMMYSTRUCTNAME; } DUMMYUNIONNAME2; #if defined(_WMIKM_) PWCHAR LoggerName; PWCHAR LogFileName; RTL_TIME_ZONE_INFORMATION TimeZone; #else LPWSTR LoggerName; LPWSTR LogFileName; TIME_ZONE_INFORMATION TimeZone; #endif LARGE_INTEGER BootTime; LARGE_INTEGER PerfFreq; LARGE_INTEGER StartTime; ULONG ReservedFlags; ULONG BuffersLost; } TRACE_LOGFILE_HEADER,*PTRACE_LOGFILE_HEADER; typedef struct _TRACE_LOGFILE_HEADER32 { ULONG BufferSize; __MINGW_EXTENSION union { ULONG Version; struct { UCHAR MajorVersion; UCHAR MinorVersion; UCHAR SubVersion; UCHAR SubMinorVersion; } VersionDetail; }; ULONG ProviderVersion; ULONG NumberOfProcessors; LARGE_INTEGER EndTime; ULONG TimerResolution; ULONG MaximumFileSize; ULONG LogFileMode; ULONG BuffersWritten; __MINGW_EXTENSION union { GUID LogInstanceGuid; __MINGW_EXTENSION struct { ULONG StartBuffers; ULONG PointerSize; ULONG EventsLost; ULONG CpuSpeedInMHz; }; }; #if defined(_WMIKM_) ULONG32 LoggerName; ULONG32 LogFileName; RTL_TIME_ZONE_INFORMATION TimeZone; #else ULONG32 LoggerName; ULONG32 LogFileName; TIME_ZONE_INFORMATION TimeZone; #endif LARGE_INTEGER BootTime; LARGE_INTEGER PerfFreq; LARGE_INTEGER StartTime; ULONG ReservedFlags; ULONG BuffersLost; } TRACE_LOGFILE_HEADER32, *PTRACE_LOGFILE_HEADER32; typedef struct _TRACE_LOGFILE_HEADER64 { ULONG BufferSize; __MINGW_EXTENSION union { ULONG Version; struct { UCHAR MajorVersion; UCHAR MinorVersion; UCHAR SubVersion; UCHAR SubMinorVersion; } VersionDetail; }; ULONG ProviderVersion; ULONG NumberOfProcessors; LARGE_INTEGER EndTime; ULONG TimerResolution; ULONG MaximumFileSize; ULONG LogFileMode; ULONG BuffersWritten; __MINGW_EXTENSION union { GUID LogInstanceGuid; __MINGW_EXTENSION struct { ULONG StartBuffers; ULONG PointerSize; ULONG EventsLost; ULONG CpuSpeedInMHz; }; }; #if defined(_WMIKM_) ULONG64 LoggerName; ULONG64 LogFileName; RTL_TIME_ZONE_INFORMATION TimeZone; #else ULONG64 LoggerName; ULONG64 LogFileName; TIME_ZONE_INFORMATION TimeZone; #endif LARGE_INTEGER BootTime; LARGE_INTEGER PerfFreq; LARGE_INTEGER StartTime; ULONG ReservedFlags; ULONG BuffersLost; } TRACE_LOGFILE_HEADER64, *PTRACE_LOGFILE_HEADER64; #endif /* !_NTDDK_ || _WMIKM_ */ typedef struct _EVENT_INSTANCE_INFO { HANDLE RegHandle; ULONG InstanceId; } EVENT_INSTANCE_INFO,*PEVENT_INSTANCE_INFO; #if !defined(_WMIKM_) && !defined(_NTDDK_) && !defined(_NTIFS_) typedef struct _EVENT_TRACE_PROPERTIES { WNODE_HEADER Wnode; ULONG BufferSize; ULONG MinimumBuffers; ULONG MaximumBuffers; ULONG MaximumFileSize; ULONG LogFileMode; ULONG FlushTimer; ULONG EnableFlags; LONG AgeLimit; ULONG NumberOfBuffers; ULONG FreeBuffers; ULONG EventsLost; ULONG BuffersWritten; ULONG LogBuffersLost; ULONG RealTimeBuffersLost; HANDLE LoggerThreadId; ULONG LogFileNameOffset; ULONG LoggerNameOffset; } EVENT_TRACE_PROPERTIES,*PEVENT_TRACE_PROPERTIES; typedef struct _TRACE_GUID_REGISTRATION { LPCGUID Guid; HANDLE RegHandle; } TRACE_GUID_REGISTRATION,*PTRACE_GUID_REGISTRATION; #endif /* !_NTDDK_ || _WMIKM_ */ typedef struct _TRACE_GUID_PROPERTIES { GUID Guid; ULONG GuidType; ULONG LoggerId; ULONG EnableLevel; ULONG EnableFlags; BOOLEAN IsEnable; } TRACE_GUID_PROPERTIES,*PTRACE_GUID_PROPERTIES; typedef struct _ETW_BUFFER_CONTEXT { UCHAR ProcessorNumber; UCHAR Alignment; USHORT LoggerId; } ETW_BUFFER_CONTEXT, *PETW_BUFFER_CONTEXT; typedef struct _TRACE_ENABLE_INFO { ULONG IsEnabled; UCHAR Level; UCHAR Reserved1; USHORT LoggerId; ULONG EnableProperty; ULONG Reserved2; ULONGLONG MatchAnyKeyword; ULONGLONG MatchAllKeyword; } TRACE_ENABLE_INFO, *PTRACE_ENABLE_INFO; typedef struct _TRACE_PROVIDER_INSTANCE_INFO { ULONG NextOffset; ULONG EnableCount; ULONG Pid; ULONG Flags; } TRACE_PROVIDER_INSTANCE_INFO, *PTRACE_PROVIDER_INSTANCE_INFO; typedef struct _TRACE_GUID_INFO { ULONG InstanceCount; ULONG Reserved; } TRACE_GUID_INFO, *PTRACE_GUID_INFO; typedef struct _EVENT_TRACE { EVENT_TRACE_HEADER Header; ULONG InstanceId; ULONG ParentInstanceId; GUID ParentGuid; PVOID MofData; ULONG MofLength; __MINGW_EXTENSION union { ULONG ClientContext; ETW_BUFFER_CONTEXT BufferContext; /* MSDN says ULONG, for XP and older? */ } DUMMYUNIONNAME; } EVENT_TRACE,*PEVENT_TRACE; #if !defined(_WMIKM_) && !defined(_NTDDK_) && !defined(_NTIFS_) #ifndef DEFINED_PEVENT_RECORD typedef struct _EVENT_RECORD EVENT_RECORD, *PEVENT_RECORD; #define DEFINED_PEVENT_RECORD 1 #endif /* for evntcons.h */ #ifndef DEFINED_PEVENT_FILTER_DESC typedef struct _EVENT_FILTER_DESCRIPTOR EVENT_FILTER_DESCRIPTOR, *PEVENT_FILTER_DESCRIPTOR; #define DEFINED_PEVENT_FILTER_DESC 1 #endif /* for evntprov.h */ typedef struct _EVENT_TRACE_LOGFILEW EVENT_TRACE_LOGFILEW,*PEVENT_TRACE_LOGFILEW; typedef struct _EVENT_TRACE_LOGFILEA EVENT_TRACE_LOGFILEA,*PEVENT_TRACE_LOGFILEA; typedef ULONG (WINAPI *PEVENT_TRACE_BUFFER_CALLBACKW)(PEVENT_TRACE_LOGFILEW Logfile); typedef ULONG (WINAPI *PEVENT_TRACE_BUFFER_CALLBACKA)(PEVENT_TRACE_LOGFILEA Logfile); typedef VOID (WINAPI *PEVENT_CALLBACK)(PEVENT_TRACE pEvent); typedef VOID (WINAPI *PEVENT_RECORD_CALLBACK)(PEVENT_RECORD EventRecord); typedef ULONG (WINAPI *WMIDPREQUEST)(WMIDPREQUESTCODE RequestCode,PVOID RequestContext,ULONG *BufferSize,PVOID Buffer); struct _EVENT_TRACE_LOGFILEW { LPWSTR LogFileName; LPWSTR LoggerName; LONGLONG CurrentTime; ULONG BuffersRead; __MINGW_EXTENSION union { ULONG LogFileMode; ULONG ProcessTraceMode; } DUMMYUNIONNAME; EVENT_TRACE CurrentEvent; TRACE_LOGFILE_HEADER LogfileHeader; PEVENT_TRACE_BUFFER_CALLBACKW BufferCallback; ULONG BufferSize; ULONG Filled; ULONG EventsLost; __MINGW_EXTENSION union { PEVENT_CALLBACK EventCallback; PEVENT_RECORD_CALLBACK EventRecordCallback; } DUMMYUNIONNAME2; ULONG IsKernelTrace; PVOID Context; }; struct _EVENT_TRACE_LOGFILEA { LPSTR LogFileName; LPSTR LoggerName; LONGLONG CurrentTime; ULONG BuffersRead; __MINGW_EXTENSION union { ULONG LogFileMode; ULONG ProcessTraceMode; } DUMMYUNIONNAME; EVENT_TRACE CurrentEvent; TRACE_LOGFILE_HEADER LogfileHeader; PEVENT_TRACE_BUFFER_CALLBACKA BufferCallback; ULONG BufferSize; ULONG Filled; ULONG EventsLost; __MINGW_EXTENSION union { PEVENT_CALLBACK EventCallback; PEVENT_RECORD_CALLBACK EventRecordCallback; } DUMMYUNIONNAME2; ULONG IsKernelTrace; PVOID Context; }; #if defined(_UNICODE) || defined(UNICODE) #define PEVENT_TRACE_BUFFER_CALLBACK PEVENT_TRACE_BUFFER_CALLBACKW #define EVENT_TRACE_LOGFILE EVENT_TRACE_LOGFILEW #define PEVENT_TRACE_LOGFILE PEVENT_TRACE_LOGFILEW #define KERNEL_LOGGER_NAME KERNEL_LOGGER_NAMEW #define GLOBAL_LOGGER_NAME GLOBAL_LOGGER_NAMEW #define EVENT_LOGGER_NAME EVENT_LOGGER_NAMEW #else #define PEVENT_TRACE_BUFFER_CALLBACK PEVENT_TRACE_BUFFER_CALLBACKA #define EVENT_TRACE_LOGFILE EVENT_TRACE_LOGFILEA #define PEVENT_TRACE_LOGFILE PEVENT_TRACE_LOGFILEA #define KERNEL_LOGGER_NAME KERNEL_LOGGER_NAMEA #define GLOBAL_LOGGER_NAME GLOBAL_LOGGER_NAMEA #define EVENT_LOGGER_NAME EVENT_LOGGER_NAMEA #endif /* defined(_UNICODE) || defined(UNICODE) */ #ifdef __cplusplus extern "C" { #endif EXTERN_C ULONG WMIAPI StartTraceW(PTRACEHANDLE TraceHandle,LPCWSTR InstanceName,PEVENT_TRACE_PROPERTIES Properties); EXTERN_C ULONG WMIAPI StartTraceA(PTRACEHANDLE TraceHandle,LPCSTR InstanceName,PEVENT_TRACE_PROPERTIES Properties); EXTERN_C ULONG WMIAPI StopTraceW(TRACEHANDLE TraceHandle,LPCWSTR InstanceName,PEVENT_TRACE_PROPERTIES Properties); EXTERN_C ULONG WMIAPI StopTraceA(TRACEHANDLE TraceHandle,LPCSTR InstanceName,PEVENT_TRACE_PROPERTIES Properties); EXTERN_C ULONG WMIAPI QueryTraceW(TRACEHANDLE TraceHandle,LPCWSTR InstanceName,PEVENT_TRACE_PROPERTIES Properties); EXTERN_C ULONG WMIAPI QueryTraceA(TRACEHANDLE TraceHandle,LPCSTR InstanceName,PEVENT_TRACE_PROPERTIES Properties); EXTERN_C ULONG WMIAPI UpdateTraceW(TRACEHANDLE TraceHandle,LPCWSTR InstanceName,PEVENT_TRACE_PROPERTIES Properties); EXTERN_C ULONG WMIAPI UpdateTraceA(TRACEHANDLE TraceHandle,LPCSTR InstanceName,PEVENT_TRACE_PROPERTIES Properties); EXTERN_C ULONG WMIAPI FlushTraceW(TRACEHANDLE TraceHandle,LPCWSTR InstanceName,PEVENT_TRACE_PROPERTIES Properties); EXTERN_C ULONG WMIAPI FlushTraceA(TRACEHANDLE TraceHandle,LPCSTR InstanceName,PEVENT_TRACE_PROPERTIES Properties); EXTERN_C ULONG WMIAPI ControlTraceW(TRACEHANDLE TraceHandle,LPCWSTR InstanceName,PEVENT_TRACE_PROPERTIES Properties,ULONG ControlCode); EXTERN_C ULONG WMIAPI ControlTraceA(TRACEHANDLE TraceHandle,LPCSTR InstanceName,PEVENT_TRACE_PROPERTIES Properties,ULONG ControlCode); EXTERN_C ULONG WMIAPI QueryAllTracesW(PEVENT_TRACE_PROPERTIES *PropertyArray,ULONG PropertyArrayCount,PULONG LoggerCount); EXTERN_C ULONG WMIAPI QueryAllTracesA(PEVENT_TRACE_PROPERTIES *PropertyArray,ULONG PropertyArrayCount,PULONG LoggerCount); EXTERN_C ULONG WMIAPI EnableTrace(ULONG Enable,ULONG EnableFlag,ULONG EnableLevel,LPCGUID ControlGuid,TRACEHANDLE TraceHandle); #if (_WIN32_WINNT >= 0x0600) EXTERN_C ULONG WMIAPI EnableTraceEx( LPCGUID ProviderId, LPCGUID SourceId, TRACEHANDLE TraceHandle, ULONG IsEnabled, UCHAR Level, ULONGLONG MatchAnyKeyword, ULONGLONG MatchAllKeyword, ULONG EnableProperty, PEVENT_FILTER_DESCRIPTOR EnableFilterDesc ); #endif /* _WIN32_WINNT >= 0x0600 */ #define ENABLE_TRACE_PARAMETERS_VERSION 1 typedef struct _ENABLE_TRACE_PARAMETERS { ULONG Version; ULONG EnableProperty; ULONG ControlFlags; GUID SourceId; PEVENT_FILTER_DESCRIPTOR EnableFilterDesc; } ENABLE_TRACE_PARAMETERS, *PENABLE_TRACE_PARAMETERS; #if (_WIN32_WINNT >= 0x0601) EXTERN_C ULONG WMIAPI EnableTraceEx2( TRACEHANDLE TraceHandle, LPCGUID ProviderId, ULONG ControlCode, UCHAR Level, ULONGLONG MatchAnyKeyword, ULONGLONG MatchAllKeyword, ULONG Timeout, PENABLE_TRACE_PARAMETERS EnableParameters ); #endif /* _WIN32_WINNT >= 0x0601 */ typedef enum _TRACE_QUERY_INFO_CLASS { TraceGuidQueryList, TraceGuidQueryInfo, TraceGuidQueryProcess, TraceStackTracingInfo, MaxTraceSetInfoClass } TRACE_QUERY_INFO_CLASS, TRACE_INFO_CLASS; #if (_WIN32_WINNT >= 0x0600) EXTERN_C ULONG WMIAPI EnumerateTraceGuidsEx( TRACE_QUERY_INFO_CLASS TraceQueryInfoClass, PVOID InBuffer, ULONG InBufferSize, PVOID OutBuffer, ULONG OutBufferSize, PULONG ReturnLength ); #endif /* _WIN32_WINNT >= 0x0600 */ /*To enable the read event type for disk IO events, set GUID to 3d6fa8d4-fe05-11d0-9dda-00c04fd7ba7c and Type to 10.*/ typedef struct _CLASSIC_EVENT_ID { GUID EventGuid; UCHAR Type; UCHAR Reserved[7]; } CLASSIC_EVENT_ID, *PCLASSIC_EVENT_ID; #if (_WIN32_WINNT >= 0x0601) EXTERN_C ULONG WMIAPI TraceSetInformation( TRACEHANDLE SessionHandle, TRACE_INFO_CLASS InformationClass, PVOID TraceInformation, ULONG InformationLength ); #endif /* _WIN32_WINNT >= 0x0601 */ EXTERN_C ULONG WMIAPI CreateTraceInstanceId(HANDLE RegHandle,PEVENT_INSTANCE_INFO pInstInfo); EXTERN_C ULONG WMIAPI TraceEvent(TRACEHANDLE TraceHandle,PEVENT_TRACE_HEADER EventTrace); EXTERN_C ULONG WMIAPI TraceEventInstance(TRACEHANDLE TraceHandle,PEVENT_INSTANCE_HEADER EventTrace,PEVENT_INSTANCE_INFO pInstInfo,PEVENT_INSTANCE_INFO pParentInstInfo); EXTERN_C ULONG WMIAPI RegisterTraceGuidsW(WMIDPREQUEST RequestAddress,PVOID RequestContext,LPCGUID ControlGuid,ULONG GuidCount,PTRACE_GUID_REGISTRATION TraceGuidReg,LPCWSTR MofImagePath,LPCWSTR MofResourceName,PTRACEHANDLE RegistrationHandle); EXTERN_C ULONG WMIAPI RegisterTraceGuidsA(WMIDPREQUEST RequestAddress,PVOID RequestContext,LPCGUID ControlGuid,ULONG GuidCount,PTRACE_GUID_REGISTRATION TraceGuidReg,LPCSTR MofImagePath,LPCSTR MofResourceName,PTRACEHANDLE RegistrationHandle); EXTERN_C ULONG WMIAPI EnumerateTraceGuids(PTRACE_GUID_PROPERTIES *GuidPropertiesArray,ULONG PropertyArrayCount,PULONG GuidCount); EXTERN_C ULONG WMIAPI UnregisterTraceGuids(TRACEHANDLE RegistrationHandle); EXTERN_C TRACEHANDLE WMIAPI GetTraceLoggerHandle(PVOID Buffer); EXTERN_C UCHAR WMIAPI GetTraceEnableLevel(TRACEHANDLE TraceHandle); EXTERN_C ULONG WMIAPI GetTraceEnableFlags(TRACEHANDLE TraceHandle); EXTERN_C TRACEHANDLE WMIAPI OpenTraceA(PEVENT_TRACE_LOGFILEA Logfile); EXTERN_C TRACEHANDLE WMIAPI OpenTraceW(PEVENT_TRACE_LOGFILEW Logfile); EXTERN_C ULONG WMIAPI ProcessTrace(PTRACEHANDLE HandleArray,ULONG HandleCount,LPFILETIME StartTime,LPFILETIME EndTime); EXTERN_C ULONG WMIAPI CloseTrace(TRACEHANDLE TraceHandle); EXTERN_C ULONG WMIAPI SetTraceCallback(LPCGUID pGuid,PEVENT_CALLBACK EventCallback); EXTERN_C ULONG WMIAPI RemoveTraceCallback (LPCGUID pGuid); EXTERN_C ULONG __cdecl TraceMessage(TRACEHANDLE LoggerHandle,ULONG MessageFlags,LPCGUID MessageGuid,USHORT MessageNumber,...); EXTERN_C ULONG WMIAPI TraceMessageVa(TRACEHANDLE LoggerHandle,ULONG MessageFlags,LPCGUID MessageGuid,USHORT MessageNumber,va_list MessageArgList); #ifdef __cplusplus } #endif #define INVALID_PROCESSTRACE_HANDLE ((TRACEHANDLE)INVALID_HANDLE_VALUE) #if defined(UNICODE) || defined(_UNICODE) #define RegisterTraceGuids RegisterTraceGuidsW #define StartTrace StartTraceW #define ControlTrace ControlTraceW #if defined(__TRACE_W2K_COMPATIBLE) #define StopTrace(a,b,c) ControlTraceW((a),(b),(c),EVENT_TRACE_CONTROL_STOP) #define QueryTrace(a,b,c) ControlTraceW((a),(b),(c),EVENT_TRACE_CONTROL_QUERY) #define UpdateTrace(a,b,c) ControlTraceW((a),(b),(c),EVENT_TRACE_CONTROL_UPDATE) #else #define StopTrace StopTraceW #define QueryTrace QueryTraceW #define UpdateTrace UpdateTraceW #endif /* defined(__TRACE_W2K_COMPATIBLE) */ #define FlushTrace FlushTraceW #define QueryAllTraces QueryAllTracesW #define OpenTrace OpenTraceW #else /* defined(UNICODE) || defined(_UNICODE) */ #define RegisterTraceGuids RegisterTraceGuidsA #define StartTrace StartTraceA #define ControlTrace ControlTraceA #if defined(__TRACE_W2K_COMPATIBLE) #define StopTrace(a,b,c) ControlTraceA((a),(b),(c),EVENT_TRACE_CONTROL_STOP) #define QueryTrace(a,b,c) ControlTraceA((a),(b),(c),EVENT_TRACE_CONTROL_QUERY) #define UpdateTrace(a,b,c) ControlTraceA((a),(b),(c),EVENT_TRACE_CONTROL_UPDATE) #else #define StopTrace StopTraceA #define QueryTrace QueryTraceA #define UpdateTrace UpdateTraceA #endif /* defined(__TRACE_W2K_COMPATIBLE) */ #define FlushTrace FlushTraceA #define QueryAllTraces QueryAllTracesA #define OpenTrace OpenTraceA #endif /* defined(UNICODE) || defined(_UNICODE) */ #endif /* !defined(_WMIKM_) && !defined(_NTDDK_) && !defined(_NTIFS_) */ #endif /* defined(_WINNT_) || defined(WINNT) */ #endif /* _EVNTRACE_ */ pcp-3.8.12ubuntu1/src/win32ctl/include/tdhmsg.h0000664000000000000000000000356412272262501016130 0ustar #define ERROR_EVT_INVALID_CHANNEL_PATH 15000L #define ERROR_EVT_INVALID_QUERY 15001L #define ERROR_EVT_PUBLISHER_METADATA_NOT_FOUND 15002L #define ERROR_EVT_EVENT_TEMPLATE_NOT_FOUND 15003L #define ERROR_EVT_INVALID_PUBLISHER_NAME 15004L #define ERROR_EVT_INVALID_EVENT_DATA 15005L #define ERROR_EVT_CHANNEL_NOT_FOUND 15007L #define ERROR_EVT_MALFORMED_XML_TEXT 15008L #define ERROR_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL 15009L #define ERROR_EVT_CONFIGURATION_ERROR 15010L #define ERROR_EVT_QUERY_RESULT_STALE 15011L #define ERROR_EVT_QUERY_RESULT_INVALID_POSITION 15012L #define ERROR_EVT_NON_VALIDATING_MSXML 15013L #define ERROR_EVT_FILTER_ALREADYSCOPED 15014L #define ERROR_EVT_FILTER_NOTELTSET 15015L #define ERROR_EVT_FILTER_INVARG 15016L #define ERROR_EVT_FILTER_INVTEST 15017L #define ERROR_EVT_FILTER_INVTYPE 15018L #define ERROR_EVT_FILTER_PARSEERR 15019L #define ERROR_EVT_FILTER_UNSUPPORTEDOP 15020L #define ERROR_EVT_FILTER_UNEXPECTEDTOKEN 15021L #define ERROR_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL 15022L #define ERROR_EVT_INVALID_CHANNEL_PROPERTY_VALUE 15023L #define ERROR_EVT_INVALID_PUBLISHER_PROPERTY_VALUE 15024L #define ERROR_EVT_CHANNEL_CANNOT_ACTIVATE 15025L #define ERROR_EVT_FILTER_TOO_COMPLEX 15026L #define ERROR_EVT_MESSAGE_NOT_FOUND 15027L #define ERROR_EVT_MESSAGE_ID_NOT_FOUND 15028L #define ERROR_EVT_UNRESOLVED_VALUE_INSERT 15029L #define ERROR_EVT_UNRESOLVED_PARAMETER_INSERT 15030L #define ERROR_EVT_MAX_INSERTS_REACHED 15031L #define ERROR_EVT_EVENT_DEFINITION_NOT_FOUND 15032L #define ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND 15033L #define ERROR_EVT_VERSION_TOO_OLD 15034L #define ERROR_EVT_VERSION_TOO_NEW 15035L #define ERROR_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY 15036L #define ERROR_EVT_PUBLISHER_DISABLED 15037L #define ERROR_EVT_FILTER_OUT_OF_RANGE 15038L pcp-3.8.12ubuntu1/src/win32ctl/include/evntcons.h0000664000000000000000000001067512272262501016502 0ustar /** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the w64 mingw-runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #ifndef _EVNTCONS_H_ #define _EVNTCONS_H_ /* --- start added by kenj */ #undef __MINGW_EXTENSION #if defined(__GNUC__) || defined(__GNUG__) #define __MINGW_EXTENSION __extension__ #else #define __MINGW_EXTENSION #endif /* --- end added by kenj */ #include #include #include #ifdef __cplusplus extern "C" { #endif typedef enum EVENTSECURITYOPERATION { EventSecuritySetDACL, EventSecuritySetSACL, EventSecurityAddDACL, EventSecurityAddSACL, EventSecurityMax } EVENTSECURITYOPERATION; typedef struct _EVENT_EXTENDED_ITEM_INSTANCE { ULONG InstanceId; ULONG ParentInstanceId; GUID ParentGuid; } EVENT_EXTENDED_ITEM_INSTANCE, *PEVENT_EXTENDED_ITEM_INSTANCE; typedef struct _EVENT_EXTENDED_ITEM_TS_ID { ULONG SessionId; } EVENT_EXTENDED_ITEM_TS_ID, *PEVENT_EXTENDED_ITEM_TS_ID; typedef struct _EVENT_EXTENDED_ITEM_RELATED_ACTIVITYID { GUID RelatedActivityId; } EVENT_EXTENDED_ITEM_RELATED_ACTIVITYID, *PEVENT_EXTENDED_ITEM_RELATED_ACTIVITYID; typedef struct _EVENT_HEADER_EXTENDED_DATA_ITEM { USHORT Reserved1; USHORT ExtType; __MINGW_EXTENSION struct { USHORT Linkage : 1; USHORT Reserved2 :15; } DUMMYSTRUCTNAME; USHORT DataSize; ULONGLONG DataPtr; } EVENT_HEADER_EXTENDED_DATA_ITEM, *PEVENT_HEADER_EXTENDED_DATA_ITEM; typedef struct _EVENT_HEADER { USHORT Size; USHORT HeaderType; USHORT Flags; USHORT EventProperty; ULONG ThreadId; ULONG ProcessId; LARGE_INTEGER TimeStamp; GUID ProviderId; EVENT_DESCRIPTOR EventDescriptor; __MINGW_EXTENSION union { __MINGW_EXTENSION struct { ULONG KernelTime; ULONG UserTime; } DUMMYSTRUCTNAME; ULONG64 ProcessorTime; } DUMMYUNIONNAME; GUID ActivityId; } EVENT_HEADER, *PEVENT_HEADER; #define EVENT_HEADER_PROPERTY_XML 0x0001 #define EVENT_HEADER_PROPERTY_FORWARDED_XML 0x0002 #define EVENT_HEADER_PROPERTY_LEGACY_EVENTLOG 0x0004 #define EVENT_HEADER_FLAG_EXTENDED_INFO 0x0001 #define EVENT_HEADER_FLAG_PRIVATE_SESSION 0x0002 #define EVENT_HEADER_FLAG_STRING_ONLY 0x0004 #define EVENT_HEADER_FLAG_TRACE_MESSAGE 0x0008 #define EVENT_HEADER_FLAG_NO_CPUTIME 0x0010 #define EVENT_HEADER_FLAG_32_BIT_HEADER 0x0020 #define EVENT_HEADER_FLAG_64_BIT_HEADER 0x0040 #define EVENT_HEADER_FLAG_CLASSIC_HEADER 0x0100 #define EVENT_HEADER_EXT_TYPE_RELATED_ACTIVITYID 0x0001 #define EVENT_HEADER_EXT_TYPE_SID 0x0002 #define EVENT_HEADER_EXT_TYPE_TS_ID 0x0003 #define EVENT_HEADER_EXT_TYPE_INSTANCE_INFO 0x0004 #define EVENT_HEADER_EXT_TYPE_STACK_TRACE32 0x0005 #define EVENT_HEADER_EXT_TYPE_STACK_TRACE64 0x0006 struct _EVENT_RECORD { EVENT_HEADER EventHeader; ETW_BUFFER_CONTEXT BufferContext; USHORT ExtendedDataCount; USHORT UserDataLength; PEVENT_HEADER_EXTENDED_DATA_ITEM ExtendedData; PVOID UserData; PVOID UserContext; }; #ifndef DEFINED_PEVENT_RECORD typedef struct _EVENT_RECORD EVENT_RECORD, *PEVENT_RECORD; #define DEFINED_PEVENT_RECORD 1 #endif /* for evntrace.h */ #if (_WIN32_WINNT >= 0x0601) typedef struct _EVENT_EXTENDED_ITEM_STACK_TRACE32 { ULONG64 MatchId; ULONG Address[ANYSIZE_ARRAY]; } EVENT_EXTENDED_ITEM_STACK_TRACE32, *PEVENT_EXTENDED_ITEM_STACK_TRACE32; typedef struct _EVENT_EXTENDED_ITEM_STACK_TRACE64 { ULONG64 MatchId; ULONG64 Address[ANYSIZE_ARRAY]; } EVENT_EXTENDED_ITEM_STACK_TRACE64, *PEVENT_EXTENDED_ITEM_STACK_TRACE64; #endif /*(_WIN32_WINNT >= 0x0601)*/ #define EVENT_ENABLE_PROPERTY_SID 0x00000001 #define EVENT_ENABLE_PROPERTY_TS_ID 0x00000002 #define EVENT_ENABLE_PROPERTY_STACK_TRACE 0x00000004 #define PROCESS_TRACE_MODE_REAL_TIME 0x00000100 #define PROCESS_TRACE_MODE_RAW_TIMESTAMP 0x00001000 #define PROCESS_TRACE_MODE_EVENT_RECORD 0x10000000 #if (_WIN32_WINNT >= 0x0600) ULONG EVNTAPI EventAccessControl( LPGUID Guid, ULONG Operation, PSID Sid, ULONG Rights, BOOLEAN AllowOrDeny ); ULONG EVNTAPI EventAccessQuery( LPGUID Guid, PSECURITY_DESCRIPTOR Buffer, PULONG BufferSize ); ULONG EVNTAPI EventAccessRemove( LPGUID Guid ); #endif /*(_WIN32_WINNT >= 0x0600)*/ #ifdef __cplusplus } #endif #endif /* _EVNTCONS_H_ */ pcp-3.8.12ubuntu1/src/win32ctl/include/winevt.h0000664000000000000000000005076712272262501016165 0ustar #ifndef WINEVT_H #define WINEVT_H typedef HANDLE EVT_HANDLE, *PEVT_HANDLE; typedef enum _EVT_VARIANT_TYPE { EvtVarTypeNull = 0, EvtVarTypeString = 1, EvtVarTypeAnsiString = 2, EvtVarTypeSByte = 3, EvtVarTypeByte = 4, EvtVarTypeInt16 = 5, EvtVarTypeUInt16 = 6, EvtVarTypeInt32 = 7, EvtVarTypeUInt32 = 8, EvtVarTypeInt64 = 9, EvtVarTypeUInt64 = 10, EvtVarTypeSingle = 11, EvtVarTypeDouble = 12, EvtVarTypeBoolean = 13, EvtVarTypeBinary = 14, EvtVarTypeGuid = 15, EvtVarTypeSizeT = 16, EvtVarTypeFileTime = 17, EvtVarTypeSysTime = 18, EvtVarTypeSid = 19, EvtVarTypeHexInt32 = 20, EvtVarTypeHexInt64 = 21, // these types used internally EvtVarTypeEvtHandle = 32, EvtVarTypeEvtXml = 35 } EVT_VARIANT_TYPE; #define EVT_VARIANT_TYPE_MASK 0x7f #define EVT_VARIANT_TYPE_ARRAY 128 typedef struct _EVT_VARIANT { union { BOOL BooleanVal; INT8 SByteVal; INT16 Int16Val; INT32 Int32Val; INT64 Int64Val; UINT8 ByteVal; UINT16 UInt16Val; UINT32 UInt32Val; UINT64 UInt64Val; float SingleVal; double DoubleVal; ULONGLONG FileTimeVal; SYSTEMTIME* SysTimeVal; GUID* GuidVal; LPCWSTR StringVal; LPCSTR AnsiStringVal; PBYTE BinaryVal; PSID SidVal; size_t SizeTVal; // array fields BOOL* BooleanArr; INT8* SByteArr; INT16* Int16Arr; INT32* Int32Arr; INT64* Int64Arr; UINT8* ByteArr; UINT16* UInt16Arr; UINT32* UInt32Arr; UINT64* UInt64Arr; float* SingleArr; double* DoubleArr; FILETIME* FileTimeArr; SYSTEMTIME* SysTimeArr; GUID* GuidArr; LPWSTR* StringArr; LPSTR* AnsiStringArr; PSID* SidArr; size_t* SizeTArr; // internal fields EVT_HANDLE EvtHandleVal; LPCWSTR XmlVal; LPCWSTR* XmlValArr; }; DWORD Count; // number of elements (not length) in bytes. DWORD Type; } EVT_VARIANT, *PEVT_VARIANT; #if 0 //////////////////////////////////////////////////////////////////////////////// // // Sessions // //////////////////////////////////////////////////////////////////////////////// typedef enum _EVT_LOGIN_CLASS { EvtRpcLogin = 1 } EVT_LOGIN_CLASS; typedef enum _EVT_RPC_LOGIN_FLAGS { EvtRpcLoginAuthDefault = 0, EvtRpcLoginAuthNegotiate, EvtRpcLoginAuthKerberos, EvtRpcLoginAuthNTLM } EVT_RPC_LOGIN_FLAGS; typedef struct _EVT_RPC_LOGIN { // all str params are optional LPWSTR Server; LPWSTR User; LPWSTR Domain; LPWSTR Password; DWORD Flags; // EVT_RPC_LOGIN_FLAGS } EVT_RPC_LOGIN; EVT_HANDLE WINAPI EvtOpenSession( EVT_LOGIN_CLASS LoginClass, PVOID Login, __reserved DWORD Timeout, // currently must be 0 __reserved DWORD Flags // currently must be 0 ); #endif //////////////////////////////////////////////////////////////////////////////// // // General Purpose Functions // //////////////////////////////////////////////////////////////////////////////// BOOL WINAPI EvtClose( EVT_HANDLE Object ); #if 0 BOOL WINAPI EvtCancel( EVT_HANDLE Object ); DWORD WINAPI EvtGetExtendedStatus( DWORD BufferSize, __out_ecount_part_opt(BufferSize, *BufferUsed) LPWSTR Buffer, __out PDWORD BufferUsed ); #endif //////////////////////////////////////////////////////////////////////////////// // // Queries // //////////////////////////////////////////////////////////////////////////////// typedef enum _EVT_QUERY_FLAGS { EvtQueryChannelPath = 0x1, EvtQueryFilePath = 0x2, EvtQueryForwardDirection = 0x100, EvtQueryReverseDirection = 0x200, EvtQueryTolerateQueryErrors = 0x1000 } EVT_QUERY_FLAGS; EVT_HANDLE WINAPI EvtQuery( EVT_HANDLE Session, LPCWSTR Path, LPCWSTR Query, DWORD Flags ); BOOL WINAPI EvtNext( EVT_HANDLE ResultSet, DWORD EventsSize, PEVT_HANDLE Events, DWORD Timeout, DWORD Flags, PDWORD Returned ); #if 0 typedef enum _EVT_SEEK_FLAGS { EvtSeekRelativeToFirst = 1, EvtSeekRelativeToLast = 2, EvtSeekRelativeToCurrent = 3, EvtSeekRelativeToBookmark = 4, EvtSeekOriginMask = 7, EvtSeekStrict = 0x10000, } EVT_SEEK_FLAGS; BOOL WINAPI EvtSeek( EVT_HANDLE ResultSet, LONGLONG Position, EVT_HANDLE Bookmark, __reserved DWORD Timeout, // currently must be 0 DWORD Flags ); //////////////////////////////////////////////////////////////////////////////// // // Subscriptions // //////////////////////////////////////////////////////////////////////////////// typedef enum _EVT_SUBSCRIBE_FLAGS { EvtSubscribeToFutureEvents = 1, EvtSubscribeStartAtOldestRecord = 2, EvtSubscribeStartAfterBookmark = 3, EvtSubscribeOriginMask = 3, EvtSubscribeTolerateQueryErrors = 0x1000, EvtSubscribeStrict = 0x10000, } EVT_SUBSCRIBE_FLAGS; typedef enum _EVT_SUBSCRIBE_NOTIFY_ACTION { EvtSubscribeActionError = 0, EvtSubscribeActionDeliver } EVT_SUBSCRIBE_NOTIFY_ACTION; typedef DWORD (WINAPI *EVT_SUBSCRIBE_CALLBACK)( EVT_SUBSCRIBE_NOTIFY_ACTION Action, PVOID UserContext, EVT_HANDLE Event ); EVT_HANDLE WINAPI EvtSubscribe( EVT_HANDLE Session, HANDLE SignalEvent, LPCWSTR ChannelPath, LPCWSTR Query, EVT_HANDLE Bookmark, PVOID context, EVT_SUBSCRIBE_CALLBACK Callback, DWORD Flags ); #endif //////////////////////////////////////////////////////////////////////////////// // // Rendering // //////////////////////////////////////////////////////////////////////////////// typedef enum _EVT_SYSTEM_PROPERTY_ID { EvtSystemProviderName = 0, // EvtVarTypeString EvtSystemProviderGuid, // EvtVarTypeGuid EvtSystemEventID, // EvtVarTypeUInt16 EvtSystemQualifiers, // EvtVarTypeUInt16 EvtSystemLevel, // EvtVarTypeUInt8 EvtSystemTask, // EvtVarTypeUInt16 EvtSystemOpcode, // EvtVarTypeUInt8 EvtSystemKeywords, // EvtVarTypeHexInt64 EvtSystemTimeCreated, // EvtVarTypeFileTime EvtSystemEventRecordId, // EvtVarTypeUInt64 EvtSystemActivityID, // EvtVarTypeGuid EvtSystemRelatedActivityID, // EvtVarTypeGuid EvtSystemProcessID, // EvtVarTypeUInt32 EvtSystemThreadID, // EvtVarTypeUInt32 EvtSystemChannel, // EvtVarTypeString EvtSystemComputer, // EvtVarTypeString EvtSystemUserID, // EvtVarTypeSid EvtSystemVersion, // EvtVarTypeUInt8 EvtSystemPropertyIdEND } EVT_SYSTEM_PROPERTY_ID; typedef enum _EVT_RENDER_CONTEXT_FLAGS { EvtRenderContextValues = 0, // Render specific properties EvtRenderContextSystem, // Render all system properties (System) EvtRenderContextUser // Render all user properties (User/EventData) } EVT_RENDER_CONTEXT_FLAGS; typedef enum _EVT_RENDER_FLAGS { EvtRenderEventValues = 0, // Variants EvtRenderEventXml, // XML EvtRenderBookmark // Bookmark } EVT_RENDER_FLAGS; EVT_HANDLE WINAPI EvtCreateRenderContext( DWORD ValuePathsCount, LPCWSTR* ValuePaths, DWORD Flags // EVT_RENDER_CONTEXT_FLAGS ); BOOL WINAPI EvtRender( EVT_HANDLE Context, EVT_HANDLE Fragment, DWORD Flags, // EVT_RENDER_FLAGS DWORD BufferSize, PVOID Buffer, PDWORD BufferUsed, PDWORD PropertyCount ); typedef enum _EVT_FORMAT_MESSAGE_FLAGS { EvtFormatMessageEvent = 1, EvtFormatMessageLevel, EvtFormatMessageTask, EvtFormatMessageOpcode, EvtFormatMessageKeyword, EvtFormatMessageChannel, EvtFormatMessageProvider, EvtFormatMessageId, EvtFormatMessageXml, } EVT_FORMAT_MESSAGE_FLAGS; BOOL WINAPI EvtFormatMessage( EVT_HANDLE PublisherMetadata, // Except for forwarded events EVT_HANDLE Event, DWORD MessageId, DWORD ValueCount, PEVT_VARIANT Values, DWORD Flags, DWORD BufferSize, LPWSTR Buffer, PDWORD BufferUsed ); #if 0 //////////////////////////////////////////////////////////////////////////////// // // Log Maintenace and Information // //////////////////////////////////////////////////////////////////////////////// typedef enum _EVT_OPEN_LOG_FLAGS { EvtOpenChannelPath = 0x1, EvtOpenFilePath = 0x2 } EVT_OPEN_LOG_FLAGS; typedef enum _EVT_LOG_PROPERTY_ID { EvtLogCreationTime = 0, // EvtVarTypeFileTime EvtLogLastAccessTime, // EvtVarTypeFileTime EvtLogLastWriteTime, // EvtVarTypeFileTime EvtLogFileSize, // EvtVarTypeUInt64 EvtLogAttributes, // EvtVarTypeUInt32 EvtLogNumberOfLogRecords, // EvtVarTypeUInt64 EvtLogOldestRecordNumber, // EvtVarTypeUInt64 EvtLogFull, // EvtVarTypeBoolean } EVT_LOG_PROPERTY_ID; EVT_HANDLE WINAPI EvtOpenLog( EVT_HANDLE Session, LPCWSTR Path, DWORD Flags ); BOOL WINAPI EvtGetLogInfo( EVT_HANDLE Log, EVT_LOG_PROPERTY_ID PropertyId, DWORD PropertyValueBufferSize, PEVT_VARIANT PropertyValueBuffer, __out PDWORD PropertyValueBufferUsed ); BOOL WINAPI EvtClearLog( EVT_HANDLE Session, LPCWSTR ChannelPath, LPCWSTR TargetFilePath, DWORD Flags ); typedef enum _EVT_EXPORTLOG_FLAGS { EvtExportLogChannelPath = 0x1, EvtExportLogFilePath = 0x2, EvtExportLogTolerateQueryErrors = 0x1000 } EVT_EXPORTLOG_FLAGS; BOOL WINAPI EvtExportLog( EVT_HANDLE Session, LPCWSTR Path, LPCWSTR Query, LPCWSTR TargetFilePath, DWORD Flags ); BOOL WINAPI EvtArchiveExportedLog( EVT_HANDLE Session, LPCWSTR LogFilePath, LCID Locale, DWORD Flags ); //////////////////////////////////////////////////////////////////////////////// // // Channel Configuration // //////////////////////////////////////////////////////////////////////////////// typedef enum _EVT_CHANNEL_CONFIG_PROPERTY_ID { EvtChannelConfigEnabled = 0, // EvtVarTypeBoolean EvtChannelConfigIsolation, // EvtVarTypeUInt32, EVT_CHANNEL_ISOLATION_TYPE EvtChannelConfigType, // EvtVarTypeUInt32, EVT_CHANNEL_TYPE EvtChannelConfigOwningPublisher, // EvtVarTypeString EvtChannelConfigClassicEventlog, // EvtVarTypeBoolean EvtChannelConfigAccess, // EvtVarTypeString EvtChannelLoggingConfigRetention, // EvtVarTypeBoolean EvtChannelLoggingConfigAutoBackup, // EvtVarTypeBoolean EvtChannelLoggingConfigMaxSize, // EvtVarTypeUInt64 EvtChannelLoggingConfigLogFilePath, // EvtVarTypeString EvtChannelPublishingConfigLevel, // EvtVarTypeUInt32 EvtChannelPublishingConfigKeywords, // EvtVarTypeUInt64 EvtChannelPublishingConfigControlGuid, // EvtVarTypeGuid EvtChannelPublishingConfigBufferSize, // EvtVarTypeUInt32 EvtChannelPublishingConfigMinBuffers, // EvtVarTypeUInt32 EvtChannelPublishingConfigMaxBuffers, // EvtVarTypeUInt32 EvtChannelPublishingConfigLatency, // EvtVarTypeUInt32 EvtChannelPublishingConfigClockType, // EvtVarTypeUInt32, EVT_CHANNEL_CLOCK_TYPE EvtChannelPublishingConfigSidType, // EvtVarTypeUInt32, EVT_CHANNEL_SID_TYPE EvtChannelPublisherList, // EvtVarTypeString | EVT_VARIANT_TYPE_ARRAY EvtChannelConfigPropertyIdEND } EVT_CHANNEL_CONFIG_PROPERTY_ID; typedef enum _EVT_CHANNEL_TYPE { EvtChannelTypeAdmin = 0, EvtChannelTypeOperational, EvtChannelTypeAnalytic, EvtChannelTypeDebug } EVT_CHANNEL_TYPE; typedef enum _EVT_CHANNEL_ISOLATION_TYPE { EvtChannelIsolationTypeApplication = 0, EvtChannelIsolationTypeSystem, EvtChannelIsolationTypeCustom } EVT_CHANNEL_ISOLATION_TYPE; typedef enum _EVT_CHANNEL_CLOCK_TYPE { EvtChannelClockTypeSystemTime = 0, // System time EvtChannelClockTypeQPC // Query performance counter } EVT_CHANNEL_CLOCK_TYPE; typedef enum _EVT_CHANNEL_SID_TYPE { EvtChannelSidTypeNone = 0, EvtChannelSidTypePublishing } EVT_CHANNEL_SID_TYPE; EVT_HANDLE WINAPI EvtOpenChannelEnum( EVT_HANDLE Session, DWORD Flags ); BOOL WINAPI EvtNextChannelPath( EVT_HANDLE ChannelEnum, DWORD ChannelPathBufferSize, __out_ecount_part_opt(ChannelPathBufferSize, *ChannelPathBufferUsed) LPWSTR ChannelPathBuffer, __out PDWORD ChannelPathBufferUsed ); EVT_HANDLE WINAPI EvtOpenChannelConfig( EVT_HANDLE Session, LPCWSTR ChannelPath, DWORD Flags ); BOOL WINAPI EvtSaveChannelConfig( EVT_HANDLE ChannelConfig, DWORD Flags ); BOOL WINAPI EvtSetChannelConfigProperty( EVT_HANDLE ChannelConfig, EVT_CHANNEL_CONFIG_PROPERTY_ID PropertyId, DWORD Flags, PEVT_VARIANT PropertyValue ); BOOL WINAPI EvtGetChannelConfigProperty( EVT_HANDLE ChannelConfig, EVT_CHANNEL_CONFIG_PROPERTY_ID PropertyId, DWORD Flags, DWORD PropertyValueBufferSize, PEVT_VARIANT PropertyValueBuffer, __out PDWORD PropertyValueBufferUsed ); //////////////////////////////////////////////////////////////////////////////// // // Publisher Metadata // //////////////////////////////////////////////////////////////////////////////// typedef enum _EVT_CHANNEL_REFERENCE_FLAGS { EvtChannelReferenceImported = 0x1, } EVT_CHANNEL_REFERENCE_FLAGS; typedef enum _EVT_PUBLISHER_METADATA_PROPERTY_ID { EvtPublisherMetadataPublisherGuid = 0, // EvtVarTypeGuid EvtPublisherMetadataResourceFilePath, // EvtVarTypeString EvtPublisherMetadataParameterFilePath, // EvtVarTypeString EvtPublisherMetadataMessageFilePath, // EvtVarTypeString EvtPublisherMetadataHelpLink, // EvtVarTypeString EvtPublisherMetadataPublisherMessageID, // EvtVarTypeUInt32 EvtPublisherMetadataChannelReferences, // EvtVarTypeEvtHandle, ObjectArray EvtPublisherMetadataChannelReferencePath, // EvtVarTypeString EvtPublisherMetadataChannelReferenceIndex, // EvtVarTypeUInt32 EvtPublisherMetadataChannelReferenceID, // EvtVarTypeUInt32 EvtPublisherMetadataChannelReferenceFlags, // EvtVarTypeUInt32 EvtPublisherMetadataChannelReferenceMessageID, // EvtVarTypeUInt32 EvtPublisherMetadataLevels, // EvtVarTypeEvtHandle, ObjectArray EvtPublisherMetadataLevelName, // EvtVarTypeString EvtPublisherMetadataLevelValue, // EvtVarTypeUInt32 EvtPublisherMetadataLevelMessageID, // EvtVarTypeUInt32 EvtPublisherMetadataTasks, // EvtVarTypeEvtHandle, ObjectArray EvtPublisherMetadataTaskName, // EvtVarTypeString EvtPublisherMetadataTaskEventGuid, // EvtVarTypeGuid EvtPublisherMetadataTaskValue, // EvtVarTypeUInt32 EvtPublisherMetadataTaskMessageID, // EvtVarTypeUInt32 EvtPublisherMetadataOpcodes, // EvtVarTypeEvtHandle, ObjectArray EvtPublisherMetadataOpcodeName, // EvtVarTypeString EvtPublisherMetadataOpcodeValue, // EvtVarTypeUInt32 EvtPublisherMetadataOpcodeMessageID, // EvtVarTypeUInt32 EvtPublisherMetadataKeywords, // EvtVarTypeEvtHandle, ObjectArray EvtPublisherMetadataKeywordName, // EvtVarTypeString EvtPublisherMetadataKeywordValue, // EvtVarTypeUInt64 EvtPublisherMetadataKeywordMessageID, // EvtVarTypeUInt32 EvtPublisherMetadataPropertyIdEND } EVT_PUBLISHER_METADATA_PROPERTY_ID; EVT_HANDLE WINAPI EvtOpenPublisherEnum( EVT_HANDLE Session, DWORD Flags ); BOOL WINAPI EvtNextPublisherId( EVT_HANDLE PublisherEnum, DWORD PublisherIdBufferSize, __out_ecount_part_opt(PublisherIdBufferSize, *PublisherIdBufferUsed) LPWSTR PublisherIdBuffer, __out PDWORD PublisherIdBufferUsed ); #endif EVT_HANDLE WINAPI EvtOpenPublisherMetadata( EVT_HANDLE Session, LPCWSTR PublisherId, LPCWSTR LogFilePath, LCID Locale, DWORD Flags ); #if 0 BOOL WINAPI EvtGetPublisherMetadataProperty( EVT_HANDLE PublisherMetadata, EVT_PUBLISHER_METADATA_PROPERTY_ID PropertyId, DWORD Flags, DWORD PublisherMetadataPropertyBufferSize, PEVT_VARIANT PublisherMetadataPropertyBuffer, __out PDWORD PublisherMetadataPropertyBufferUsed ); //////////////////////////////////////////////////////////////////////////////// // // Event Metadata Configuratin // //////////////////////////////////////////////////////////////////////////////// typedef enum _EVT_EVENT_METADATA_PROPERTY_ID { EventMetadataEventID, // EvtVarTypeUInt32 EventMetadataEventVersion, // EvtVarTypeUInt32 EventMetadataEventChannel, // EvtVarTypeUInt32 EventMetadataEventLevel, // EvtVarTypeUInt32 EventMetadataEventOpcode, // EvtVarTypeUInt32 EventMetadataEventTask, // EvtVarTypeUInt32 EventMetadataEventKeyword, // EvtVarTypeUInt64 EventMetadataEventMessageID,// EvtVarTypeUInt32 EventMetadataEventTemplate, // EvtVarTypeString EvtEventMetadataPropertyIdEND } EVT_EVENT_METADATA_PROPERTY_ID; EVT_HANDLE WINAPI EvtOpenEventMetadataEnum( EVT_HANDLE PublisherMetadata, DWORD Flags ); EVT_HANDLE WINAPI EvtNextEventMetadata( EVT_HANDLE EventMetadataEnum, DWORD Flags ); BOOL WINAPI EvtGetEventMetadataProperty( EVT_HANDLE EventMetadata, EVT_EVENT_METADATA_PROPERTY_ID PropertyId, DWORD Flags, DWORD EventMetadataPropertyBufferSize, PEVT_VARIANT EventMetadataPropertyBuffer, __out PDWORD EventMetadataPropertyBufferUsed ); //////////////////////////////////////////////////////////////////////////////// // // Array Access // //////////////////////////////////////////////////////////////////////////////// typedef HANDLE EVT_OBJECT_ARRAY_PROPERTY_HANDLE; BOOL WINAPI EvtGetObjectArraySize( EVT_OBJECT_ARRAY_PROPERTY_HANDLE ObjectArray, __out PDWORD ObjectArraySize ); BOOL WINAPI EvtGetObjectArrayProperty( EVT_OBJECT_ARRAY_PROPERTY_HANDLE ObjectArray, DWORD PropertyId, DWORD ArrayIndex, DWORD Flags, DWORD PropertyValueBufferSize, PEVT_VARIANT PropertyValueBuffer, __out PDWORD PropertyValueBufferUsed ); ///////////////////////////////////////////////////////////////////////////// // // Misc Event Consumer Functions // //////////////////////////////////////////////////////////////////////////// typedef enum _EVT_QUERY_PROPERTY_ID { // // list of channels or logfiles indentified in the query. Variant will be // array of EvtVarTypeString. // EvtQueryNames, // // Array of EvtVarTypeUInt32, indicating creation status ( Win32 error // code ) for the list of names returned by the EvtQueryNames // property. // EvtQueryStatuses, EvtQueryPropertyIdEND } EVT_QUERY_PROPERTY_ID; typedef enum _EVT_EVENT_PROPERTY_ID { EvtEventQueryIDs = 0, EvtEventPath, EvtEventPropertyIdEND } EVT_EVENT_PROPERTY_ID; BOOL WINAPI EvtGetQueryInfo( EVT_HANDLE QueryOrSubscription, EVT_QUERY_PROPERTY_ID PropertyId, DWORD PropertyValueBufferSize, PEVT_VARIANT PropertyValueBuffer, __out PDWORD PropertyValueBufferUsed ); EVT_HANDLE WINAPI EvtCreateBookmark( __in_opt LPCWSTR BookmarkXml ); BOOL WINAPI EvtUpdateBookmark( EVT_HANDLE Bookmark, EVT_HANDLE Event ); BOOL WINAPI EvtGetEventInfo( EVT_HANDLE Event, EVT_EVENT_PROPERTY_ID PropertyId, DWORD PropertyValueBufferSize, PEVT_VARIANT PropertyValueBuffer, __out PDWORD PropertyValueBufferUsed ); //////////////////////////////////////////////////////////////////////////////// // // Access Control Permissions // //////////////////////////////////////////////////////////////////////////////// #define EVT_READ_ACCESS 0x1 #define EVT_WRITE_ACCESS 0x2 #define EVT_CLEAR_ACCESS 0x4 #define EVT_ALL_ACCESS 0x7 #endif #endif // __WINEVT_H__ pcp-3.8.12ubuntu1/src/win32ctl/include/winmeta.h0000664000000000000000000000007412272262501016277 0ustar #define WINEVENT_KEYWORD_AUDIT_FAILURE 0x10000000000000LL pcp-3.8.12ubuntu1/src/win32ctl/include/wmistr.h0000664000000000000000000001342412272262501016163 0ustar /** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the w64 mingw-runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #ifndef _WMISTR_ #define _WMISTR_ /* --- start added by kenj */ #undef __MINGW_EXTENSION #if defined(__GNUC__) || defined(__GNUG__) #define __MINGW_EXTENSION __extension__ #else #define __MINGW_EXTENSION #endif #ifndef __C89_NAMELESS #define __C89_NAMELESS __MINGW_EXTENSION #define __C89_NAMELESSSTRUCTNAME #define __C89_NAMELESSUNIONNAME #endif /* --- end added by kenj */ typedef struct _WNODE_HEADER { ULONG BufferSize; ULONG ProviderId; __C89_NAMELESS union { ULONG64 HistoricalContext; __C89_NAMELESS struct { ULONG Version; ULONG Linkage; }; }; __C89_NAMELESS union { ULONG CountLost; HANDLE KernelHandle; LARGE_INTEGER TimeStamp; }; GUID Guid; ULONG ClientContext; ULONG Flags; } WNODE_HEADER,*PWNODE_HEADER; #define WNODE_FLAG_ALL_DATA 0x00000001 #define WNODE_FLAG_SINGLE_INSTANCE 0x00000002 #define WNODE_FLAG_SINGLE_ITEM 0x00000004 #define WNODE_FLAG_EVENT_ITEM 0x00000008 #define WNODE_FLAG_FIXED_INSTANCE_SIZE 0x00000010 #define WNODE_FLAG_TOO_SMALL 0x00000020 #define WNODE_FLAG_INSTANCES_SAME 0x00000040 #define WNODE_FLAG_STATIC_INSTANCE_NAMES 0x00000080 #define WNODE_FLAG_INTERNAL 0x00000100 #define WNODE_FLAG_USE_TIMESTAMP 0x00000200 #define WNODE_FLAG_PERSIST_EVENT 0x00000400 #define WNODE_FLAG_EVENT_REFERENCE 0x00002000 #define WNODE_FLAG_ANSI_INSTANCENAMES 0x00004000 #define WNODE_FLAG_METHOD_ITEM 0x00008000 #define WNODE_FLAG_PDO_INSTANCE_NAMES 0x00010000 #define WNODE_FLAG_TRACED_GUID 0x00020000 #define WNODE_FLAG_LOG_WNODE 0x00040000 #define WNODE_FLAG_USE_GUID_PTR 0x00080000 #define WNODE_FLAG_USE_MOF_PTR 0x00100000 #define WNODE_FLAG_NO_HEADER 0x00200000 #define WNODE_FLAG_SEVERITY_MASK 0xff000000 typedef struct { ULONG OffsetInstanceData; ULONG LengthInstanceData; } OFFSETINSTANCEDATAANDLENGTH,*POFFSETINSTANCEDATAANDLENGTH; typedef struct tagWNODE_ALL_DATA { struct _WNODE_HEADER WnodeHeader; ULONG DataBlockOffset; ULONG InstanceCount; ULONG OffsetInstanceNameOffsets; __C89_NAMELESS union { ULONG FixedInstanceSize; OFFSETINSTANCEDATAANDLENGTH OffsetInstanceDataAndLength[1]; }; } WNODE_ALL_DATA,*PWNODE_ALL_DATA; typedef struct tagWNODE_SINGLE_INSTANCE { struct _WNODE_HEADER WnodeHeader; ULONG OffsetInstanceName; ULONG InstanceIndex; ULONG DataBlockOffset; ULONG SizeDataBlock; UCHAR VariableData[]; } WNODE_SINGLE_INSTANCE,*PWNODE_SINGLE_INSTANCE; typedef struct tagWNODE_SINGLE_ITEM { struct _WNODE_HEADER WnodeHeader; ULONG OffsetInstanceName; ULONG InstanceIndex; ULONG ItemId; ULONG DataBlockOffset; ULONG SizeDataItem; UCHAR VariableData[]; } WNODE_SINGLE_ITEM,*PWNODE_SINGLE_ITEM; typedef struct tagWNODE_METHOD_ITEM { struct _WNODE_HEADER WnodeHeader; ULONG OffsetInstanceName; ULONG InstanceIndex; ULONG MethodId; ULONG DataBlockOffset; ULONG SizeDataBlock; UCHAR VariableData[]; } WNODE_METHOD_ITEM,*PWNODE_METHOD_ITEM; typedef struct tagWNODE_EVENT_ITEM { struct _WNODE_HEADER WnodeHeader; } WNODE_EVENT_ITEM,*PWNODE_EVENT_ITEM; typedef struct tagWNODE_EVENT_REFERENCE { struct _WNODE_HEADER WnodeHeader; GUID TargetGuid; ULONG TargetDataBlockSize; __C89_NAMELESS union { ULONG TargetInstanceIndex; WCHAR TargetInstanceName[1]; }; } WNODE_EVENT_REFERENCE,*PWNODE_EVENT_REFERENCE; typedef struct tagWNODE_TOO_SMALL { struct _WNODE_HEADER WnodeHeader; ULONG SizeNeeded; } WNODE_TOO_SMALL,*PWNODE_TOO_SMALL; typedef struct { GUID Guid; ULONG Flags; ULONG InstanceCount; __C89_NAMELESS union { ULONG InstanceNameList; ULONG BaseNameOffset; ULONG_PTR Pdo; ULONG_PTR InstanceInfo; }; } WMIREGGUIDW,*PWMIREGGUIDW; typedef WMIREGGUIDW WMIREGGUID; typedef PWMIREGGUIDW PWMIREGGUID; #define WMIREG_FLAG_EXPENSIVE 0x00000001 #define WMIREG_FLAG_INSTANCE_LIST 0x00000004 #define WMIREG_FLAG_INSTANCE_BASENAME 0x00000008 #define WMIREG_FLAG_INSTANCE_PDO 0x00000020 #define WMIREG_FLAG_REMOVE_GUID 0x00010000 #define WMIREG_FLAG_RESERVED1 0x00020000 #define WMIREG_FLAG_RESERVED2 0x00040000 #define WMIREG_FLAG_TRACED_GUID 0x00080000 #define WMIREG_FLAG_TRACE_CONTROL_GUID 0x00001000 #define WMIREG_FLAG_EVENT_ONLY_GUID 0x00000040 typedef struct { ULONG BufferSize; ULONG NextWmiRegInfo; ULONG RegistryPath; ULONG MofResourceName; ULONG GuidCount; WMIREGGUIDW WmiRegGuid[]; } WMIREGINFOW,*PWMIREGINFOW; typedef WMIREGINFOW WMIREGINFO; typedef PWMIREGINFOW PWMIREGINFO; typedef enum { WMI_GET_ALL_DATA = 0,WMI_GET_SINGLE_INSTANCE = 1,WMI_SET_SINGLE_INSTANCE = 2,WMI_SET_SINGLE_ITEM = 3,WMI_ENABLE_EVENTS = 4,WMI_DISABLE_EVENTS = 5, WMI_ENABLE_COLLECTION = 6,WMI_DISABLE_COLLECTION = 7,WMI_REGINFO = 8,WMI_EXECUTE_METHOD = 9 } WMIDPREQUESTCODE; #if defined(_WINNT_) || defined(WINNT) #define WMI_GUIDTYPE_TRACECONTROL 0 #define WMI_GUIDTYPE_TRACE 1 #define WMI_GUIDTYPE_DATA 2 #define WMI_GUIDTYPE_EVENT 3 #define WMIGUID_QUERY 0x0001 #define WMIGUID_SET 0x0002 #define WMIGUID_NOTIFICATION 0x0004 #define WMIGUID_READ_DESCRIPTION 0x0008 #define WMIGUID_EXECUTE 0x0010 #define TRACELOG_CREATE_REALTIME 0x0020 #define TRACELOG_CREATE_ONDISK 0x0040 #define TRACELOG_GUID_ENABLE 0x0080 #define TRACELOG_ACCESS_KERNEL_LOGGER 0x0100 #define TRACELOG_CREATE_INPROC 0x0200 #define TRACELOG_ACCESS_REALTIME 0x0400 #define TRACELOG_REGISTER_GUIDS 0x0800 #define WMIGUID_ALL_ACCESS (STANDARD_RIGHTS_READ | SYNCHRONIZE | WMIGUID_QUERY | WMIGUID_SET | WMIGUID_NOTIFICATION | WMIGUID_READ_DESCRIPTION | WMIGUID_EXECUTE | TRACELOG_CREATE_REALTIME | TRACELOG_CREATE_ONDISK | TRACELOG_GUID_ENABLE | TRACELOG_ACCESS_KERNEL_LOGGER | TRACELOG_CREATE_INPROC | TRACELOG_ACCESS_REALTIME | TRACELOG_REGISTER_GUIDS) #define WMI_GLOBAL_LOGGER_ID 0x0001 #endif #endif pcp-3.8.12ubuntu1/src/win32ctl/include/GNUmakefile0000664000000000000000000000157012272262501016536 0ustar # # Copyright (c) 2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs HFILES = _mingw_unicode.h pshpack8.h \ evntcons.h evntprov.h evntrace.h \ pdh.h pdhmsg.h \ tdh.h tdhmsg.h \ winevt.h winmeta.h winperf.h wmistr.h default :: default_pcp default_pcp : include $(BUILDRULES) install :: default_pcp install_pcp install_pcp : default_pcp pcp-3.8.12ubuntu1/src/win32ctl/include/tdh.h0000664000000000000000000002104712272262501015415 0ustar /** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the w64 mingw-runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #ifndef _INC_TDH #define _INC_TDH /* --- start added by kenj */ #undef __MINGW_EXTENSION #if defined(__GNUC__) || defined(__GNUG__) #define __MINGW_EXTENSION __extension__ #else #define __MINGW_EXTENSION #endif /* --- end added by kenj */ #include #include #if (_WIN32_WINNT >= 0x0600) #ifdef __cplusplus extern "C" { #endif #define __TDHCACHE_ALIGN __attribute__ ((aligned (8))) typedef enum _EVENT_FIELD_TYPE { EventKeywordInformation = 0, EventLevelInformation = 1, EventChannelInformation = 2, EventTaskInformation = 3, EventOpcodeInformation = 4, EventInformationMax = 5 } EVENT_FIELD_TYPE; typedef struct _EVENT_MAP_ENTRY { ULONG OutputOffset; __MINGW_EXTENSION union { ULONG Value; ULONG InputOffset; }; } __TDHCACHE_ALIGN EVENT_MAP_ENTRY, *PEVENT_MAP_ENTRY; typedef enum _MAP_VALUETYPE { EVENTMAP_ENTRY_VALUETYPE_ULONG = 0, EVENTMAP_ENTRY_VALUETYPE_STRING = 1 } MAP_VALUETYPE; typedef enum _MAP_FLAGS { EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP = 1, EVENTMAP_INFO_FLAG_MANIFEST_BITMAP = 2, EVENTMAP_INFO_FLAG_MANIFEST_PATTERNMAP = 4, EVENTMAP_INFO_FLAG_WBEM_VALUEMAP = 8, EVENTMAP_INFO_FLAG_WBEM_BITMAP = 16, EVENTMAP_INFO_FLAG_WBEM_FLAG = 32, EVENTMAP_INFO_FLAG_WBEM_NO_MAP = 64 } MAP_FLAGS; typedef struct _EVENT_MAP_INFO { ULONG NameOffset; MAP_FLAGS Flag; ULONG EntryCount; __MINGW_EXTENSION union { MAP_VALUETYPE MapEntryValueType; ULONG FormatStringOffset; }; EVENT_MAP_ENTRY MapEntryArray[ANYSIZE_ARRAY]; } __TDHCACHE_ALIGN EVENT_MAP_INFO, *PEVENT_MAP_INFO; typedef enum _TDH_IN_TYPE { TDH_INTYPE_NULL, TDH_INTYPE_UNICODESTRING, TDH_INTYPE_ANSISTRING, TDH_INTYPE_INT8, TDH_INTYPE_UINT8, TDH_INTYPE_INT16, TDH_INTYPE_UINT16, TDH_INTYPE_INT32, TDH_INTYPE_UINT32, TDH_INTYPE_INT64, TDH_INTYPE_UINT64, TDH_INTYPE_FLOAT, TDH_INTYPE_DOUBLE, TDH_INTYPE_BOOLEAN, TDH_INTYPE_BINARY, TDH_INTYPE_GUID, TDH_INTYPE_POINTER, TDH_INTYPE_FILETIME, TDH_INTYPE_SYSTEMTIME, TDH_INTYPE_SID, TDH_INTYPE_HEXINT32, TDH_INTYPE_HEXINT64, TDH_INTYPE_COUNTEDSTRING = 300, TDH_INTYPE_COUNTEDANSISTRING, TDH_INTYPE_REVERSEDCOUNTEDSTRING, TDH_INTYPE_REVERSEDCOUNTEDANSISTRING, TDH_INTYPE_NONNULLTERMINATEDSTRING, TDH_INTYPE_NONNULLTERMINATEDANSISTRING, TDH_INTYPE_UNICODECHAR, TDH_INTYPE_ANSICHAR, TDH_INTYPE_SIZET, TDH_INTYPE_HEXDUMP, TDH_INTYPE_WBEMSID } TDH_IN_TYPE; typedef enum _TDH_OUT_TYPE { TDH_OUTTYPE_NULL, TDH_OUTTYPE_STRING, TDH_OUTTYPE_DATETIME, TDH_OUTTYPE_BYTE, TDH_OUTTYPE_UNSIGNEDBYTE, TDH_OUTTYPE_SHORT, TDH_OUTTYPE_UNSIGNEDSHORT, TDH_OUTTYPE_INT, TDH_OUTTYPE_UNSIGNEDINT, TDH_OUTTYPE_LONG, TDH_OUTTYPE_UNSIGNEDLONG, TDH_OUTTYPE_FLOAT, TDH_OUTTYPE_DOUBLE, TDH_OUTTYPE_BOOLEAN, TDH_OUTTYPE_GUID, TDH_OUTTYPE_HEXBINARY, TDH_OUTTYPE_HEXINT8, TDH_OUTTYPE_HEXINT16, TDH_OUTTYPE_HEXINT32, TDH_OUTTYPE_HEXINT64, TDH_OUTTYPE_PID, TDH_OUTTYPE_TID, TDH_OUTTYPE_PORT, TDH_OUTTYPE_IPV4, TDH_OUTTYPE_IPV6, TDH_OUTTYPE_SOCKETADDRESS, TDH_OUTTYPE_CIMDATETIME, TDH_OUTTYPE_ETWTIME, TDH_OUTTYPE_XML, TDH_OUTTYPE_ERRORCODE, TDH_OUTTYPE_WIN32ERROR, TDH_OUTTYPE_NTSTATUS, TDH_OUTTYPE_HRESULT, TDH_OUTTYPE_CULTURE_INSENSITIVE_DATETIME, TDH_OUTTYPE_REDUCEDSTRING = 300, TDH_OUTTYPE_NOPRINT } TDH_OUT_TYPE; typedef enum _PROPERTY_FLAGS { PropertyStruct = 0x1, PropertyParamLength = 0x2, PropertyParamCount = 0x4, PropertyWBEMXmlFragment = 0x8, PropertyParamFixedLength = 0x10 } PROPERTY_FLAGS; typedef struct _EVENT_PROPERTY_INFO { PROPERTY_FLAGS Flags; ULONG NameOffset; __MINGW_EXTENSION union { struct { USHORT InType; USHORT OutType; ULONG MapNameOffset; } nonStructType; struct { USHORT StructStartIndex; USHORT NumOfStructMembers; ULONG padding; } structType; }; __MINGW_EXTENSION union { USHORT count; USHORT countPropertyIndex; }; __MINGW_EXTENSION union { USHORT length; USHORT lengthPropertyIndex; }; ULONG Reserved; } __TDHCACHE_ALIGN EVENT_PROPERTY_INFO, *PEVENT_PROPERTY_INFO; typedef enum _DECODING_SOURCE { DecodingSourceXMLFile = 0, DecodingSourceWbem = 1, DecodingSourceWPP = 2 } DECODING_SOURCE; typedef enum _TDH_CONTEXT_TYPE { TDH_CONTEXT_WPP_TMFFILE = 0, TDH_CONTEXT_WPP_TMFSEARCHPATH = 1, TDH_CONTEXT_WPP_GMT = 2, TDH_CONTEXT_POINTERSIZE = 3, TDH_CONTEXT_MAXIMUM = 4 } TDH_CONTEXT_TYPE; typedef enum _TEMPLATE_FLAGS { TEMPLATE_EVENT_DATA = 1, TEMPLATE_USER_DATA = 2 } TEMPLATE_FLAGS; typedef struct _TRACE_EVENT_INFO { GUID ProviderGuid; GUID EventGuid; EVENT_DESCRIPTOR EventDescriptor; DECODING_SOURCE DecodingSource; ULONG ProviderNameOffset; ULONG LevelNameOffset; ULONG ChannelNameOffset; ULONG KeywordsNameOffset; ULONG TaskNameOffset; ULONG OpcodeNameOffset; ULONG EventMessageOffset; ULONG ProviderMessageOffset; ULONG BinaryXMLOffset; ULONG BinaryXMLSize; ULONG ActivityIDNameOffset; ULONG RelatedActivityIDNameOffset; ULONG PropertyCount; ULONG TopLevelPropertyCount; TEMPLATE_FLAGS Flags; EVENT_PROPERTY_INFO EventPropertyInfoArray[ANYSIZE_ARRAY]; } __TDHCACHE_ALIGN TRACE_EVENT_INFO, *PTRACE_EVENT_INFO; typedef struct _PROPERTY_DATA_DESCRIPTOR { ULONGLONG PropertyName; ULONG ArrayIndex; ULONG Reserved; } __TDHCACHE_ALIGN PROPERTY_DATA_DESCRIPTOR, *PPROPERTY_DATA_DESCRIPTOR; typedef struct _TRACE_PROVIDER_INFO { GUID ProviderGuid; ULONG SchemaSource; ULONG ProviderNameOffset; } __TDHCACHE_ALIGN TRACE_PROVIDER_INFO, *PTRACE_PROVIDER_INFO; typedef struct _PROVIDER_ENUMERATION_INFO { ULONG NumberOfProviders; ULONG Padding; TRACE_PROVIDER_INFO TraceProviderInfoArray[ANYSIZE_ARRAY]; } __TDHCACHE_ALIGN PROVIDER_ENUMERATION_INFO, *PPROVIDER_ENUMERATION_INFO; typedef struct _PROVIDER_FIELD_INFO { ULONG NameOffset; ULONG DescriptionOffset; ULONGLONG Value; } __TDHCACHE_ALIGN PROVIDER_FIELD_INFO, *PPROVIDER_FIELD_INFO; typedef struct _PROVIDER_FIELD_INFOARRAY { ULONG NumberOfElements; EVENT_FIELD_TYPE FieldType; PROVIDER_FIELD_INFO FieldInfoArray[ANYSIZE_ARRAY]; } __TDHCACHE_ALIGN PROVIDER_FIELD_INFOARRAY, *PPROVIDER_FIELD_INFOARRAY; typedef struct _TDH_CONTEXT { ULONGLONG ParameterValue; TDH_CONTEXT_TYPE ParameterType; ULONG ParameterSize; } __TDHCACHE_ALIGN TDH_CONTEXT, *PTDH_CONTEXT; ULONG __stdcall TdhEnumerateProviderFieldInformation( LPGUID pGuid, EVENT_FIELD_TYPE EventFieldType, PPROVIDER_FIELD_INFOARRAY pBuffer, ULONG *pBufferSize ); ULONG __stdcall TdhEnumerateProviders( PPROVIDER_ENUMERATION_INFO pBuffer, ULONG *pBufferSize ); ULONG __stdcall TdhGetEventInformation( PEVENT_RECORD pEvent, ULONG TdhContextCount, PTDH_CONTEXT pTdhContext, PTRACE_EVENT_INFO pBuffer, ULONG *pBufferSize ); ULONG __stdcall TdhGetEventMapInformation( PEVENT_RECORD pEvent, LPWSTR pMapName, PEVENT_MAP_INFO pBuffer, ULONG *pBufferSize ); ULONG __stdcall TdhGetProperty( PEVENT_RECORD pEvent, ULONG TdhContextCount, PTDH_CONTEXT pTdhContext, ULONG PropertyDataCount, PPROPERTY_DATA_DESCRIPTOR pPropertyData, ULONG BufferSize, PBYTE pBuffer ); ULONG __stdcall TdhGetPropertySize( PEVENT_RECORD pEvent, ULONG TdhContextCount, PTDH_CONTEXT pTdhContext, ULONG PropertyDataCount, PPROPERTY_DATA_DESCRIPTOR pPropertyData, ULONG *pPropertySize ); ULONG __stdcall TdhQueryProviderFieldInformation( LPGUID pGuid, ULONGLONG EventFieldValue, EVENT_FIELD_TYPE EventFieldType, PPROVIDER_FIELD_INFOARRAY pBuffer, ULONG *pBufferSize ); #if (_WIN32_WINNT >= 0x0601) typedef struct _PROVIDER_FILTER_INFO { UCHAR Id; UCHAR Version; ULONG MessageOffset; ULONG Reserved; ULONG PropertyCount; EVENT_PROPERTY_INFO EventPropertyInfoArray[ANYSIZE_ARRAY]; } PROVIDER_FILTER_INFO, *PPROVIDER_FILTER_INFO; #endif /*(_WIN32_WINNT >= 0x0601)*/ #ifdef __cplusplus } #endif #endif /*(_WIN32_WINNT >= 0x0600)*/ #endif /*_INC_TDH*/ pcp-3.8.12ubuntu1/src/win32ctl/include/_mingw_unicode.h0000664000000000000000000000227212272262501017623 0ustar /** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the w64 mingw-runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #if !defined(_INC_CRT_UNICODE_MACROS) /* _INC_CRT_UNICODE_MACROS defined based on UNICODE flag */ #if defined(UNICODE) # define _INC_CRT_UNICODE_MACROS 1 # define __MINGW_NAME_AW(func) func##W # define __MINGW_NAME_AW_EXT(func,ext) func##W##ext # define __MINGW_NAME_UAW(func) func##_W # define __MINGW_NAME_UAW_EXT(func,ext) func##_W_##ext # define __MINGW_STRING_AW(str) L##str /* same as TEXT() from winnt.h */ # define __MINGW_PROCNAMEEXT_AW "W" #else # define _INC_CRT_UNICODE_MACROS 2 # define __MINGW_NAME_AW(func) func##A # define __MINGW_NAME_AW_EXT(func,ext) func##A##ext # define __MINGW_NAME_UAW(func) func##_A # define __MINGW_NAME_UAW_EXT(func,ext) func##_A_##ext # define __MINGW_STRING_AW(str) str /* same as TEXT() from winnt.h */ # define __MINGW_PROCNAMEEXT_AW "A" #endif #define __MINGW_TYPEDEF_AW(type) \ typedef __MINGW_NAME_AW(type) type; #define __MINGW_TYPEDEF_UAW(type) \ typedef __MINGW_NAME_UAW(type) type; #endif /* !defined(_INC_CRT_UNICODE_MACROS) */ pcp-3.8.12ubuntu1/src/win32ctl/include/evntprov.h0000664000000000000000000001526112272262501016522 0ustar /* * evntprov.h * * This file is part of the ReactOS PSDK package. * * Contributors: * Created by Amine Khaldi. * * THIS SOFTWARE IS NOT COPYRIGHTED * * This source code is offered for use in the public domain. You may * use, modify or distribute it freely. * * This code is distributed in the hope that it will be useful but * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY * DISCLAIMED. This includes but is not limited to warranties of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * */ #ifndef _EVNTPROV_H_ #define _EVNTPROV_H_ #ifndef EVNTAPI #ifndef MIDL_PASS #ifdef _EVNT_SOURCE_ #define EVNTAPI __stdcall #else #define EVNTAPI DECLSPEC_IMPORT __stdcall #endif /* _EVNT_SOURCE_ */ #endif /* MIDL_PASS */ #endif /* EVNTAPI */ #ifdef __cplusplus extern "C" { #endif #define EVENT_MIN_LEVEL 0 #define EVENT_MAX_LEVEL 0xff #define EVENT_ACTIVITY_CTRL_GET_ID 1 #define EVENT_ACTIVITY_CTRL_SET_ID 2 #define EVENT_ACTIVITY_CTRL_CREATE_ID 3 #define EVENT_ACTIVITY_CTRL_GET_SET_ID 4 #define EVENT_ACTIVITY_CTRL_CREATE_SET_ID 5 typedef ULONGLONG REGHANDLE, *PREGHANDLE; #define MAX_EVENT_DATA_DESCRIPTORS 128 #define MAX_EVENT_FILTER_DATA_SIZE 1024 #define EVENT_FILTER_TYPE_SCHEMATIZED 0x80000000 typedef struct _EVENT_DESCRIPTOR { USHORT Id; UCHAR Version; UCHAR Channel; UCHAR Level; UCHAR Opcode; USHORT Task; ULONGLONG Keyword; } EVENT_DESCRIPTOR, *PEVENT_DESCRIPTOR; typedef const EVENT_DESCRIPTOR *PCEVENT_DESCRIPTOR; typedef struct _EVENT_DATA_DESCRIPTOR { ULONGLONG Ptr; ULONG Size; ULONG Reserved; } EVENT_DATA_DESCRIPTOR, *PEVENT_DATA_DESCRIPTOR; struct _EVENT_FILTER_DESCRIPTOR { ULONGLONG Ptr; ULONG Size; ULONG Type; }; #ifndef DEFINED_PEVENT_FILTER_DESC typedef struct _EVENT_FILTER_DESCRIPTOR EVENT_FILTER_DESCRIPTOR, *PEVENT_FILTER_DESCRIPTOR; #define DEFINED_PEVENT_FILTER_DESC 1 #endif /* for evntrace.h */ typedef struct _EVENT_FILTER_HEADER { USHORT Id; UCHAR Version; UCHAR Reserved[5]; ULONGLONG InstanceId; ULONG Size; ULONG NextOffset; } EVENT_FILTER_HEADER, *PEVENT_FILTER_HEADER; #ifndef _ETW_KM_ /* for wdm.h */ typedef VOID (NTAPI *PENABLECALLBACK)( LPCGUID SourceId, ULONG IsEnabled, UCHAR Level, ULONGLONG MatchAnyKeyword, ULONGLONG MatchAllKeyword, PEVENT_FILTER_DESCRIPTOR FilterData, PVOID CallbackContext); #if (_WIN32_WINNT >= 0x0600) ULONG EVNTAPI EventRegister( LPCGUID ProviderId, PENABLECALLBACK EnableCallback, PVOID CallbackContext, PREGHANDLE RegHandle ); ULONG EVNTAPI EventUnregister( REGHANDLE RegHandle ); BOOLEAN EVNTAPI EventEnabled( REGHANDLE RegHandle, PCEVENT_DESCRIPTOR EventDescriptor ); BOOLEAN EVNTAPI EventProviderEnabled( REGHANDLE RegHandle, UCHAR Level, ULONGLONG Keyword ); ULONG EVNTAPI EventWrite( REGHANDLE RegHandle, PCEVENT_DESCRIPTOR EventDescriptor, ULONG UserDataCount, PEVENT_DATA_DESCRIPTOR UserData ); ULONG EVNTAPI EventWriteTransfer( REGHANDLE RegHandle, PCEVENT_DESCRIPTOR EventDescriptor, LPCGUID ActivityId, LPCGUID RelatedActivityId, ULONG UserDataCount, PEVENT_DATA_DESCRIPTOR UserData ); ULONG EVNTAPI EventWriteString( REGHANDLE RegHandle, UCHAR Level, ULONGLONG Keyword, PCWSTR String ); ULONG EVNTAPI EventActivityIdControl( ULONG ControlCode, LPGUID ActivityId ); #endif /*(_WIN32_WINNT >= 0x0600)*/ #if (_WIN32_WINNT >= 0x0601) ULONG EVNTAPI EventWriteEx( REGHANDLE RegHandle, PCEVENT_DESCRIPTOR EventDescriptor, ULONG64 Filter, ULONG Flags, LPCGUID ActivityId, LPCGUID RelatedActivityId, ULONG UserDataCount, PEVENT_DATA_DESCRIPTOR UserData ); #endif /*(_WIN32_WINNT >= 0x0601)*/ #endif /* _ETW_KM_ */ FORCEINLINE VOID EventDataDescCreate( PEVENT_DATA_DESCRIPTOR EventDataDescriptor, const VOID* DataPtr, ULONG DataSize) { EventDataDescriptor->Ptr = (ULONGLONG)(ULONG_PTR)DataPtr; EventDataDescriptor->Size = DataSize; EventDataDescriptor->Reserved = 0; } FORCEINLINE VOID EventDescCreate( PEVENT_DESCRIPTOR EventDescriptor, USHORT Id, UCHAR Version, UCHAR Channel, UCHAR Level, USHORT Task, UCHAR Opcode, ULONGLONG Keyword) { EventDescriptor->Id = Id; EventDescriptor->Version = Version; EventDescriptor->Channel = Channel; EventDescriptor->Level = Level; EventDescriptor->Task = Task; EventDescriptor->Opcode = Opcode; EventDescriptor->Keyword = Keyword; } FORCEINLINE VOID EventDescZero( PEVENT_DESCRIPTOR EventDescriptor) { memset(EventDescriptor, 0, sizeof(EVENT_DESCRIPTOR)); } FORCEINLINE USHORT EventDescGetId( PCEVENT_DESCRIPTOR EventDescriptor) { return (EventDescriptor->Id); } FORCEINLINE UCHAR EventDescGetVersion( PCEVENT_DESCRIPTOR EventDescriptor) { return (EventDescriptor->Version); } FORCEINLINE USHORT EventDescGetTask( PCEVENT_DESCRIPTOR EventDescriptor) { return (EventDescriptor->Task); } FORCEINLINE UCHAR EventDescGetOpcode( PCEVENT_DESCRIPTOR EventDescriptor) { return (EventDescriptor->Opcode); } FORCEINLINE UCHAR EventDescGetChannel( PCEVENT_DESCRIPTOR EventDescriptor) { return (EventDescriptor->Channel); } FORCEINLINE UCHAR EventDescGetLevel( PCEVENT_DESCRIPTOR EventDescriptor) { return (EventDescriptor->Level); } FORCEINLINE ULONGLONG EventDescGetKeyword( PCEVENT_DESCRIPTOR EventDescriptor) { return (EventDescriptor->Keyword); } FORCEINLINE PEVENT_DESCRIPTOR EventDescSetId( PEVENT_DESCRIPTOR EventDescriptor, USHORT Id) { EventDescriptor->Id = Id; return (EventDescriptor); } FORCEINLINE PEVENT_DESCRIPTOR EventDescSetVersion( PEVENT_DESCRIPTOR EventDescriptor, UCHAR Version) { EventDescriptor->Version = Version; return (EventDescriptor); } FORCEINLINE PEVENT_DESCRIPTOR EventDescSetTask( PEVENT_DESCRIPTOR EventDescriptor, USHORT Task) { EventDescriptor->Task = Task; return (EventDescriptor); } FORCEINLINE PEVENT_DESCRIPTOR EventDescSetOpcode( PEVENT_DESCRIPTOR EventDescriptor, UCHAR Opcode) { EventDescriptor->Opcode = Opcode; return (EventDescriptor); } FORCEINLINE PEVENT_DESCRIPTOR EventDescSetLevel( PEVENT_DESCRIPTOR EventDescriptor, UCHAR Level) { EventDescriptor->Level = Level; return (EventDescriptor); } FORCEINLINE PEVENT_DESCRIPTOR EventDescSetChannel( PEVENT_DESCRIPTOR EventDescriptor, UCHAR Channel) { EventDescriptor->Channel = Channel; return (EventDescriptor); } FORCEINLINE PEVENT_DESCRIPTOR EventDescSetKeyword( PEVENT_DESCRIPTOR EventDescriptor, ULONGLONG Keyword) { EventDescriptor->Keyword = Keyword; return (EventDescriptor); } FORCEINLINE PEVENT_DESCRIPTOR EventDescOrKeyword( PEVENT_DESCRIPTOR EventDescriptor, ULONGLONG Keyword) { EventDescriptor->Keyword |= Keyword; return (EventDescriptor); } #ifdef __cplusplus } #endif #endif /* _EVNTPROV_H_ */ pcp-3.8.12ubuntu1/src/win32ctl/include/pshpack8.h0000664000000000000000000000044012272262501016351 0ustar /** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the w64 mingw-runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #if !(defined(lint) || defined(RC_INVOKED)) #pragma pack(push,8) #endif pcp-3.8.12ubuntu1/src/win32ctl/include/pdh.h0000664000000000000000000006544512272262501015423 0ustar /** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the w64 mingw-runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #ifndef _PDH_H_ #define _PDH_H_ /* --- start added by kenj */ #undef __MINGW_EXTENSION #if defined(__GNUC__) || defined(__GNUG__) #define __MINGW_EXTENSION __extension__ #else #define __MINGW_EXTENSION #endif /* --- end added by kenj */ #include <_mingw_unicode.h> #include #include #ifdef __cplusplus extern "C" { #endif typedef LONG PDH_STATUS; #define PDH_FUNCTION PDH_STATUS WINAPI #define PDH_CVERSION_WIN40 ((DWORD)(0x0400)) #define PDH_CVERSION_WIN50 ((DWORD)(0x0500)) #define PDH_VERSION ((DWORD)((PDH_CVERSION_WIN50) + 0x0003)) #define IsSuccessSeverity(ErrorCode) ((((DWORD)(ErrorCode) & (0xC0000000L))==0x00000000L) ? TRUE : FALSE) #define IsInformationalSeverity(ErrorCode) ((((DWORD)(ErrorCode) & (0xC0000000L))==0x40000000L) ? TRUE : FALSE) #define IsWarningSeverity(ErrorCode) ((((DWORD)(ErrorCode) & (0xC0000000L))==0x80000000L) ? TRUE : FALSE) #define IsErrorSeverity(ErrorCode) ((((DWORD)(ErrorCode) & (0xC0000000L))==0xC0000000L) ? TRUE : FALSE) #define MAX_COUNTER_PATH 256 #define PDH_MAX_COUNTER_NAME 1024 #define PDH_MAX_INSTANCE_NAME 1024 #define PDH_MAX_COUNTER_PATH 2048 #define PDH_MAX_DATASOURCE_PATH 1024 typedef HANDLE PDH_HCOUNTER; typedef HANDLE PDH_HQUERY; typedef HANDLE PDH_HLOG; typedef PDH_HCOUNTER HCOUNTER; typedef PDH_HQUERY HQUERY; #ifndef _LMHLOGDEFINED_ typedef PDH_HLOG HLOG; #endif #ifdef INVALID_HANDLE_VALUE #undef INVALID_HANDLE_VALUE #define INVALID_HANDLE_VALUE ((HANDLE)((LONG_PTR)-1)) #endif #define H_REALTIME_DATASOURCE NULL #define H_WBEM_DATASOURCE INVALID_HANDLE_VALUE typedef struct _PDH_RAW_COUNTER { DWORD CStatus; FILETIME TimeStamp; LONGLONG FirstValue; LONGLONG SecondValue; DWORD MultiCount; } PDH_RAW_COUNTER,*PPDH_RAW_COUNTER; typedef struct _PDH_RAW_COUNTER_ITEM_A { LPSTR szName; PDH_RAW_COUNTER RawValue; } PDH_RAW_COUNTER_ITEM_A,*PPDH_RAW_COUNTER_ITEM_A; typedef struct _PDH_RAW_COUNTER_ITEM_W { LPWSTR szName; PDH_RAW_COUNTER RawValue; } PDH_RAW_COUNTER_ITEM_W,*PPDH_RAW_COUNTER_ITEM_W; typedef struct _PDH_FMT_COUNTERVALUE { DWORD CStatus; __MINGW_EXTENSION union { LONG longValue; double doubleValue; LONGLONG largeValue; LPCSTR AnsiStringValue; LPCWSTR WideStringValue; }; } PDH_FMT_COUNTERVALUE,*PPDH_FMT_COUNTERVALUE; typedef struct _PDH_FMT_COUNTERVALUE_ITEM_A { LPSTR szName; PDH_FMT_COUNTERVALUE FmtValue; } PDH_FMT_COUNTERVALUE_ITEM_A,*PPDH_FMT_COUNTERVALUE_ITEM_A; typedef struct _PDH_FMT_COUNTERVALUE_ITEM_W { LPWSTR szName; PDH_FMT_COUNTERVALUE FmtValue; } PDH_FMT_COUNTERVALUE_ITEM_W,*PPDH_FMT_COUNTERVALUE_ITEM_W; typedef struct _PDH_STATISTICS { DWORD dwFormat; DWORD count; PDH_FMT_COUNTERVALUE min; PDH_FMT_COUNTERVALUE max; PDH_FMT_COUNTERVALUE mean; } PDH_STATISTICS,*PPDH_STATISTICS; typedef struct _PDH_COUNTER_PATH_ELEMENTS_A { LPSTR szMachineName; LPSTR szObjectName; LPSTR szInstanceName; LPSTR szParentInstance; DWORD dwInstanceIndex; LPSTR szCounterName; } PDH_COUNTER_PATH_ELEMENTS_A,*PPDH_COUNTER_PATH_ELEMENTS_A; typedef struct _PDH_COUNTER_PATH_ELEMENTS_W { LPWSTR szMachineName; LPWSTR szObjectName; LPWSTR szInstanceName; LPWSTR szParentInstance; DWORD dwInstanceIndex; LPWSTR szCounterName; } PDH_COUNTER_PATH_ELEMENTS_W,*PPDH_COUNTER_PATH_ELEMENTS_W; typedef struct _PDH_DATA_ITEM_PATH_ELEMENTS_A { LPSTR szMachineName; GUID ObjectGUID; DWORD dwItemId; LPSTR szInstanceName; } PDH_DATA_ITEM_PATH_ELEMENTS_A,*PPDH_DATA_ITEM_PATH_ELEMENTS_A; typedef struct _PDH_DATA_ITEM_PATH_ELEMENTS_W { LPWSTR szMachineName; GUID ObjectGUID; DWORD dwItemId; LPWSTR szInstanceName; } PDH_DATA_ITEM_PATH_ELEMENTS_W,*PPDH_DATA_ITEM_PATH_ELEMENTS_W; typedef struct _PDH_COUNTER_INFO_A { DWORD dwLength; DWORD dwType; DWORD CVersion; DWORD CStatus; LONG lScale; LONG lDefaultScale; DWORD_PTR dwUserData; DWORD_PTR dwQueryUserData; LPSTR szFullPath; __MINGW_EXTENSION union { PDH_DATA_ITEM_PATH_ELEMENTS_A DataItemPath; PDH_COUNTER_PATH_ELEMENTS_A CounterPath; __MINGW_EXTENSION struct { LPSTR szMachineName; LPSTR szObjectName; LPSTR szInstanceName; LPSTR szParentInstance; DWORD dwInstanceIndex; LPSTR szCounterName; }; }; LPSTR szExplainText; DWORD DataBuffer[1]; } PDH_COUNTER_INFO_A,*PPDH_COUNTER_INFO_A; typedef struct _PDH_COUNTER_INFO_W { DWORD dwLength; DWORD dwType; DWORD CVersion; DWORD CStatus; LONG lScale; LONG lDefaultScale; DWORD_PTR dwUserData; DWORD_PTR dwQueryUserData; LPWSTR szFullPath; __MINGW_EXTENSION union { PDH_DATA_ITEM_PATH_ELEMENTS_W DataItemPath; PDH_COUNTER_PATH_ELEMENTS_W CounterPath; __MINGW_EXTENSION struct { LPWSTR szMachineName; LPWSTR szObjectName; LPWSTR szInstanceName; LPWSTR szParentInstance; DWORD dwInstanceIndex; LPWSTR szCounterName; }; }; LPWSTR szExplainText; DWORD DataBuffer[1]; } PDH_COUNTER_INFO_W,*PPDH_COUNTER_INFO_W; typedef struct _PDH_TIME_INFO { LONGLONG StartTime; LONGLONG EndTime; DWORD SampleCount; } PDH_TIME_INFO,*PPDH_TIME_INFO; typedef struct _PDH_RAW_LOG_RECORD { DWORD dwStructureSize; DWORD dwRecordType; DWORD dwItems; UCHAR RawBytes[1]; } PDH_RAW_LOG_RECORD,*PPDH_RAW_LOG_RECORD; typedef struct _PDH_LOG_SERVICE_QUERY_INFO_A { DWORD dwSize; DWORD dwFlags; DWORD dwLogQuota; LPSTR szLogFileCaption; LPSTR szDefaultDir; LPSTR szBaseFileName; DWORD dwFileType; DWORD dwReserved; __MINGW_EXTENSION union { __MINGW_EXTENSION struct { DWORD PdlAutoNameInterval; DWORD PdlAutoNameUnits; LPSTR PdlCommandFilename; LPSTR PdlCounterList; DWORD PdlAutoNameFormat; DWORD PdlSampleInterval; FILETIME PdlLogStartTime; FILETIME PdlLogEndTime; }; __MINGW_EXTENSION struct { DWORD TlNumberOfBuffers; DWORD TlMinimumBuffers; DWORD TlMaximumBuffers; DWORD TlFreeBuffers; DWORD TlBufferSize; DWORD TlEventsLost; DWORD TlLoggerThreadId; DWORD TlBuffersWritten; DWORD TlLogHandle; LPSTR TlLogFileName; }; }; } PDH_LOG_SERVICE_QUERY_INFO_A,*PPDH_LOG_SERVICE_QUERY_INFO_A; typedef struct _PDH_LOG_SERVICE_QUERY_INFO_W { DWORD dwSize; DWORD dwFlags; DWORD dwLogQuota; LPWSTR szLogFileCaption; LPWSTR szDefaultDir; LPWSTR szBaseFileName; DWORD dwFileType; DWORD dwReserved; __MINGW_EXTENSION union { __MINGW_EXTENSION struct { DWORD PdlAutoNameInterval; DWORD PdlAutoNameUnits; LPWSTR PdlCommandFilename; LPWSTR PdlCounterList; DWORD PdlAutoNameFormat; DWORD PdlSampleInterval; FILETIME PdlLogStartTime; FILETIME PdlLogEndTime; }; __MINGW_EXTENSION struct { DWORD TlNumberOfBuffers; DWORD TlMinimumBuffers; DWORD TlMaximumBuffers; DWORD TlFreeBuffers; DWORD TlBufferSize; DWORD TlEventsLost; DWORD TlLoggerThreadId; DWORD TlBuffersWritten; DWORD TlLogHandle; LPWSTR TlLogFileName; }; }; } PDH_LOG_SERVICE_QUERY_INFO_W,*PPDH_LOG_SERVICE_QUERY_INFO_W; #define MAX_TIME_VALUE ((LONGLONG) 0x7FFFFFFFFFFFFFFF) #define MIN_TIME_VALUE ((LONGLONG) 0) PDH_FUNCTION PdhGetDllVersion(LPDWORD lpdwVersion); PDH_FUNCTION PdhOpenQueryW(LPCWSTR szDataSource,DWORD_PTR dwUserData,PDH_HQUERY *phQuery); PDH_FUNCTION PdhOpenQueryA(LPCSTR szDataSource,DWORD_PTR dwUserData,PDH_HQUERY *phQuery); PDH_FUNCTION PdhAddCounterW(PDH_HQUERY hQuery,LPCWSTR szFullCounterPath,DWORD_PTR dwUserData,PDH_HCOUNTER *phCounter); PDH_FUNCTION PdhAddCounterA(PDH_HQUERY hQuery,LPCSTR szFullCounterPath,DWORD_PTR dwUserData,PDH_HCOUNTER *phCounter); PDH_FUNCTION PdhRemoveCounter(PDH_HCOUNTER hCounter); PDH_FUNCTION PdhCollectQueryData(PDH_HQUERY hQuery); PDH_FUNCTION PdhCloseQuery(PDH_HQUERY hQuery); PDH_FUNCTION PdhGetFormattedCounterValue(PDH_HCOUNTER hCounter,DWORD dwFormat,LPDWORD lpdwType,PPDH_FMT_COUNTERVALUE pValue); PDH_FUNCTION PdhGetFormattedCounterArrayA(PDH_HCOUNTER hCounter,DWORD dwFormat,LPDWORD lpdwBufferSize,LPDWORD lpdwItemCount,PPDH_FMT_COUNTERVALUE_ITEM_A ItemBuffer); PDH_FUNCTION PdhGetFormattedCounterArrayW(PDH_HCOUNTER hCounter,DWORD dwFormat,LPDWORD lpdwBufferSize,LPDWORD lpdwItemCount,PPDH_FMT_COUNTERVALUE_ITEM_W ItemBuffer); #define PDH_FMT_RAW ((DWORD) 0x00000010) #define PDH_FMT_ANSI ((DWORD) 0x00000020) #define PDH_FMT_UNICODE ((DWORD) 0x00000040) #define PDH_FMT_LONG ((DWORD) 0x00000100) #define PDH_FMT_DOUBLE ((DWORD) 0x00000200) #define PDH_FMT_LARGE ((DWORD) 0x00000400) #define PDH_FMT_NOSCALE ((DWORD) 0x00001000) #define PDH_FMT_1000 ((DWORD) 0x00002000) #define PDH_FMT_NODATA ((DWORD) 0x00004000) #define PDH_FMT_NOCAP100 ((DWORD) 0x00008000) #define PERF_DETAIL_COSTLY ((DWORD) 0x00010000) #define PERF_DETAIL_STANDARD ((DWORD) 0x0000FFFF) PDH_FUNCTION PdhGetRawCounterValue(PDH_HCOUNTER hCounter,LPDWORD lpdwType,PPDH_RAW_COUNTER pValue); PDH_FUNCTION PdhGetRawCounterArrayA(PDH_HCOUNTER hCounter,LPDWORD lpdwBufferSize,LPDWORD lpdwItemCount,PPDH_RAW_COUNTER_ITEM_A ItemBuffer); PDH_FUNCTION PdhGetRawCounterArrayW(PDH_HCOUNTER hCounter,LPDWORD lpdwBufferSize,LPDWORD lpdwItemCount,PPDH_RAW_COUNTER_ITEM_W ItemBuffer); PDH_FUNCTION PdhCalculateCounterFromRawValue(PDH_HCOUNTER hCounter,DWORD dwFormat,PPDH_RAW_COUNTER rawValue1,PPDH_RAW_COUNTER rawValue2,PPDH_FMT_COUNTERVALUE fmtValue); PDH_FUNCTION PdhComputeCounterStatistics(PDH_HCOUNTER hCounter,DWORD dwFormat,DWORD dwFirstEntry,DWORD dwNumEntries,PPDH_RAW_COUNTER lpRawValueArray,PPDH_STATISTICS data); PDH_FUNCTION PdhGetCounterInfoW(PDH_HCOUNTER hCounter,BOOLEAN bRetrieveExplainText,LPDWORD pdwBufferSize,PPDH_COUNTER_INFO_W lpBuffer); PDH_FUNCTION PdhGetCounterInfoA(PDH_HCOUNTER hCounter,BOOLEAN bRetrieveExplainText,LPDWORD pdwBufferSize,PPDH_COUNTER_INFO_A lpBuffer); #define PDH_MAX_SCALE (7L) #define PDH_MIN_SCALE (-7L) PDH_FUNCTION PdhSetCounterScaleFactor(PDH_HCOUNTER hCounter,LONG lFactor); PDH_FUNCTION PdhConnectMachineW(LPCWSTR szMachineName); PDH_FUNCTION PdhConnectMachineA(LPCSTR szMachineName); PDH_FUNCTION PdhEnumMachinesW(LPCWSTR szDataSource,LPWSTR mszMachineList,LPDWORD pcchBufferSize); PDH_FUNCTION PdhEnumMachinesA(LPCSTR szDataSource,LPSTR mszMachineList,LPDWORD pcchBufferSize); PDH_FUNCTION PdhEnumObjectsW(LPCWSTR szDataSource,LPCWSTR szMachineName,LPWSTR mszObjectList,LPDWORD pcchBufferSize,DWORD dwDetailLevel,WINBOOL bRefresh); PDH_FUNCTION PdhEnumObjectsA(LPCSTR szDataSource,LPCSTR szMachineName,LPSTR mszObjectList,LPDWORD pcchBufferSize,DWORD dwDetailLevel,WINBOOL bRefresh); PDH_FUNCTION PdhEnumObjectItemsW(LPCWSTR szDataSource,LPCWSTR szMachineName,LPCWSTR szObjectName,LPWSTR mszCounterList,LPDWORD pcchCounterListLength,LPWSTR mszInstanceList,LPDWORD pcchInstanceListLength,DWORD dwDetailLevel,DWORD dwFlags); PDH_FUNCTION PdhEnumObjectItemsA(LPCSTR szDataSource,LPCSTR szMachineName,LPCSTR szObjectName,LPSTR mszCounterList,LPDWORD pcchCounterListLength,LPSTR mszInstanceList,LPDWORD pcchInstanceListLength,DWORD dwDetailLevel,DWORD dwFlags); #define PDH_OBJECT_HAS_INSTANCES ((DWORD) 0x00000001) PDH_FUNCTION PdhMakeCounterPathW(PPDH_COUNTER_PATH_ELEMENTS_W pCounterPathElements,LPWSTR szFullPathBuffer,LPDWORD pcchBufferSize,DWORD dwFlags); PDH_FUNCTION PdhMakeCounterPathA(PPDH_COUNTER_PATH_ELEMENTS_A pCounterPathElements,LPSTR szFullPathBuffer,LPDWORD pcchBufferSize,DWORD dwFlags); PDH_FUNCTION PdhParseCounterPathW(LPCWSTR szFullPathBuffer,PPDH_COUNTER_PATH_ELEMENTS_W pCounterPathElements,LPDWORD pdwBufferSize,DWORD dwFlags); PDH_FUNCTION PdhParseCounterPathA(LPCSTR szFullPathBuffer,PPDH_COUNTER_PATH_ELEMENTS_A pCounterPathElements,LPDWORD pdwBufferSize,DWORD dwFlags); #define PDH_PATH_WBEM_RESULT ((DWORD) 0x00000001) #define PDH_PATH_WBEM_INPUT ((DWORD) 0x00000002) #define PDH_PATH_LANG_FLAGS(LangId,Flags) ((DWORD)(((LangId & 0x0000FFFF) << 16) | (Flags & 0x0000FFFF))) PDH_FUNCTION PdhParseInstanceNameW(LPCWSTR szInstanceString,LPWSTR szInstanceName,LPDWORD pcchInstanceNameLength,LPWSTR szParentName,LPDWORD pcchParentNameLength,LPDWORD lpIndex); PDH_FUNCTION PdhParseInstanceNameA(LPCSTR szInstanceString,LPSTR szInstanceName,LPDWORD pcchInstanceNameLength,LPSTR szParentName,LPDWORD pcchParentNameLength,LPDWORD lpIndex); PDH_FUNCTION PdhValidatePathW(LPCWSTR szFullPathBuffer); PDH_FUNCTION PdhValidatePathA(LPCSTR szFullPathBuffer); PDH_FUNCTION PdhGetDefaultPerfObjectW(LPCWSTR szDataSource,LPCWSTR szMachineName,LPWSTR szDefaultObjectName,LPDWORD pcchBufferSize); PDH_FUNCTION PdhGetDefaultPerfObjectA(LPCSTR szDataSource,LPCSTR szMachineName,LPSTR szDefaultObjectName,LPDWORD pcchBufferSize); PDH_FUNCTION PdhGetDefaultPerfCounterW(LPCWSTR szDataSource,LPCWSTR szMachineName,LPCWSTR szObjectName,LPWSTR szDefaultCounterName,LPDWORD pcchBufferSize); PDH_FUNCTION PdhGetDefaultPerfCounterA(LPCSTR szDataSource,LPCSTR szMachineName,LPCSTR szObjectName,LPSTR szDefaultCounterName,LPDWORD pcchBufferSize); typedef PDH_STATUS (WINAPI *CounterPathCallBack)(DWORD_PTR); typedef struct _BrowseDlgConfig_HW { DWORD bIncludeInstanceIndex : 1,bSingleCounterPerAdd : 1,bSingleCounterPerDialog : 1,bLocalCountersOnly : 1,bWildCardInstances : 1,bHideDetailBox : 1,bInitializePath : 1,bDisableMachineSelection : 1,bIncludeCostlyObjects : 1,bShowObjectBrowser : 1,bReserved : 22; HWND hWndOwner; PDH_HLOG hDataSource; LPWSTR szReturnPathBuffer; DWORD cchReturnPathLength; CounterPathCallBack pCallBack; DWORD_PTR dwCallBackArg; PDH_STATUS CallBackStatus; DWORD dwDefaultDetailLevel; LPWSTR szDialogBoxCaption; } PDH_BROWSE_DLG_CONFIG_HW,*PPDH_BROWSE_DLG_CONFIG_HW; typedef struct _BrowseDlgConfig_HA { DWORD bIncludeInstanceIndex : 1,bSingleCounterPerAdd : 1,bSingleCounterPerDialog : 1,bLocalCountersOnly : 1,bWildCardInstances : 1,bHideDetailBox : 1,bInitializePath : 1,bDisableMachineSelection : 1,bIncludeCostlyObjects : 1,bShowObjectBrowser : 1,bReserved:22; HWND hWndOwner; PDH_HLOG hDataSource; LPSTR szReturnPathBuffer; DWORD cchReturnPathLength; CounterPathCallBack pCallBack; DWORD_PTR dwCallBackArg; PDH_STATUS CallBackStatus; DWORD dwDefaultDetailLevel; LPSTR szDialogBoxCaption; } PDH_BROWSE_DLG_CONFIG_HA,*PPDH_BROWSE_DLG_CONFIG_HA; typedef struct _BrowseDlgConfig_W { DWORD bIncludeInstanceIndex : 1,bSingleCounterPerAdd : 1,bSingleCounterPerDialog : 1,bLocalCountersOnly : 1,bWildCardInstances : 1,bHideDetailBox : 1,bInitializePath : 1,bDisableMachineSelection : 1,bIncludeCostlyObjects : 1,bShowObjectBrowser : 1,bReserved:22; HWND hWndOwner; LPWSTR szDataSource; LPWSTR szReturnPathBuffer; DWORD cchReturnPathLength; CounterPathCallBack pCallBack; DWORD_PTR dwCallBackArg; PDH_STATUS CallBackStatus; DWORD dwDefaultDetailLevel; LPWSTR szDialogBoxCaption; } PDH_BROWSE_DLG_CONFIG_W,*PPDH_BROWSE_DLG_CONFIG_W; typedef struct _BrowseDlgConfig_A { DWORD bIncludeInstanceIndex : 1,bSingleCounterPerAdd : 1,bSingleCounterPerDialog : 1,bLocalCountersOnly : 1,bWildCardInstances : 1,bHideDetailBox : 1,bInitializePath : 1,bDisableMachineSelection : 1,bIncludeCostlyObjects : 1,bShowObjectBrowser : 1,bReserved:22; HWND hWndOwner; LPSTR szDataSource; LPSTR szReturnPathBuffer; DWORD cchReturnPathLength; CounterPathCallBack pCallBack; DWORD_PTR dwCallBackArg; PDH_STATUS CallBackStatus; DWORD dwDefaultDetailLevel; LPSTR szDialogBoxCaption; } PDH_BROWSE_DLG_CONFIG_A,*PPDH_BROWSE_DLG_CONFIG_A; PDH_FUNCTION PdhBrowseCountersW(PPDH_BROWSE_DLG_CONFIG_W pBrowseDlgData); PDH_FUNCTION PdhBrowseCountersA(PPDH_BROWSE_DLG_CONFIG_A pBrowseDlgData); PDH_FUNCTION PdhExpandCounterPathW(LPCWSTR szWildCardPath,LPWSTR mszExpandedPathList,LPDWORD pcchPathListLength); PDH_FUNCTION PdhExpandCounterPathA(LPCSTR szWildCardPath,LPSTR mszExpandedPathList,LPDWORD pcchPathListLength); PDH_FUNCTION PdhLookupPerfNameByIndexW(LPCWSTR szMachineName,DWORD dwNameIndex,LPWSTR szNameBuffer,LPDWORD pcchNameBufferSize); PDH_FUNCTION PdhLookupPerfNameByIndexA(LPCSTR szMachineName,DWORD dwNameIndex,LPSTR szNameBuffer,LPDWORD pcchNameBufferSize); PDH_FUNCTION PdhLookupPerfIndexByNameW(LPCWSTR szMachineName,LPCWSTR szNameBuffer,LPDWORD pdwIndex); PDH_FUNCTION PdhLookupPerfIndexByNameA(LPCSTR szMachineName,LPCSTR szNameBuffer,LPDWORD pdwIndex); #define PDH_NOEXPANDCOUNTERS 1 #define PDH_NOEXPANDINSTANCES 2 #define PDH_REFRESHCOUNTERS 4 PDH_FUNCTION PdhExpandWildCardPathA(LPCSTR szDataSource,LPCSTR szWildCardPath,LPSTR mszExpandedPathList,LPDWORD pcchPathListLength,DWORD dwFlags); PDH_FUNCTION PdhExpandWildCardPathW(LPCWSTR szDataSource,LPCWSTR szWildCardPath,LPWSTR mszExpandedPathList,LPDWORD pcchPathListLength,DWORD dwFlags); #define PDH_LOG_READ_ACCESS ((DWORD) 0x00010000) #define PDH_LOG_WRITE_ACCESS ((DWORD) 0x00020000) #define PDH_LOG_UPDATE_ACCESS ((DWORD) 0x00040000) #define PDH_LOG_ACCESS_MASK ((DWORD) 0x000F0000) #define PDH_LOG_CREATE_NEW ((DWORD) 0x00000001) #define PDH_LOG_CREATE_ALWAYS ((DWORD) 0x00000002) #define PDH_LOG_OPEN_ALWAYS ((DWORD) 0x00000003) #define PDH_LOG_OPEN_EXISTING ((DWORD) 0x00000004) #define PDH_LOG_CREATE_MASK ((DWORD) 0x0000000F) #define PDH_LOG_OPT_USER_STRING ((DWORD) 0x01000000) #define PDH_LOG_OPT_CIRCULAR ((DWORD) 0x02000000) #define PDH_LOG_OPT_MAX_IS_BYTES ((DWORD) 0x04000000) #define PDH_LOG_OPT_APPEND ((DWORD) 0x08000000) #define PDH_LOG_OPT_MASK ((DWORD) 0x0F000000) #define PDH_LOG_TYPE_UNDEFINED 0 #define PDH_LOG_TYPE_CSV 1 #define PDH_LOG_TYPE_TSV 2 #define PDH_LOG_TYPE_TRACE_KERNEL 4 #define PDH_LOG_TYPE_TRACE_GENERIC 5 #define PDH_LOG_TYPE_PERFMON 6 #define PDH_LOG_TYPE_SQL 7 #define PDH_LOG_TYPE_BINARY 8 PDH_FUNCTION PdhOpenLogW(LPCWSTR szLogFileName,DWORD dwAccessFlags,LPDWORD lpdwLogType,PDH_HQUERY hQuery,DWORD dwMaxSize,LPCWSTR szUserCaption,PDH_HLOG *phLog); PDH_FUNCTION PdhOpenLogA(LPCSTR szLogFileName,DWORD dwAccessFlags,LPDWORD lpdwLogType,PDH_HQUERY hQuery,DWORD dwMaxSize,LPCSTR szUserCaption,PDH_HLOG *phLog); PDH_FUNCTION PdhUpdateLogW(PDH_HLOG hLog,LPCWSTR szUserString); PDH_FUNCTION PdhUpdateLogA(PDH_HLOG hLog,LPCSTR szUserString); PDH_FUNCTION PdhUpdateLogFileCatalog(PDH_HLOG hLog); PDH_FUNCTION PdhGetLogFileSize(PDH_HLOG hLog,LONGLONG *llSize); PDH_FUNCTION PdhCloseLog(PDH_HLOG hLog,DWORD dwFlags); #define PDH_FLAGS_CLOSE_QUERY ((DWORD) 0x00000001) #define PDH_FLAGS_FILE_BROWSER_ONLY ((DWORD) 0x00000001) PDH_FUNCTION PdhSelectDataSourceW(HWND hWndOwner,DWORD dwFlags,LPWSTR szDataSource,LPDWORD pcchBufferLength); PDH_FUNCTION PdhSelectDataSourceA(HWND hWndOwner,DWORD dwFlags,LPSTR szDataSource,LPDWORD pcchBufferLength); WINBOOL PdhIsRealTimeQuery(PDH_HQUERY hQuery); PDH_FUNCTION PdhSetQueryTimeRange(PDH_HQUERY hQuery,PPDH_TIME_INFO pInfo); PDH_FUNCTION PdhGetDataSourceTimeRangeW(LPCWSTR szDataSource,LPDWORD pdwNumEntries,PPDH_TIME_INFO pInfo,LPDWORD pdwBufferSize); PDH_FUNCTION PdhGetDataSourceTimeRangeA(LPCSTR szDataSource,LPDWORD pdwNumEntries,PPDH_TIME_INFO pInfo,LPDWORD dwBufferSize); PDH_FUNCTION PdhCollectQueryDataEx(PDH_HQUERY hQuery,DWORD dwIntervalTime,HANDLE hNewDataEvent); PDH_FUNCTION PdhFormatFromRawValue(DWORD dwCounterType,DWORD dwFormat,LONGLONG *pTimeBase,PPDH_RAW_COUNTER pRawValue1,PPDH_RAW_COUNTER pRawValue2,PPDH_FMT_COUNTERVALUE pFmtValue); PDH_FUNCTION PdhGetCounterTimeBase(PDH_HCOUNTER hCounter,LONGLONG *pTimeBase); PDH_FUNCTION PdhReadRawLogRecord(PDH_HLOG hLog,FILETIME ftRecord,PPDH_RAW_LOG_RECORD pRawLogRecord,LPDWORD pdwBufferLength); #define DATA_SOURCE_REGISTRY ((DWORD) 0x00000001) #define DATA_SOURCE_LOGFILE ((DWORD) 0x00000002) #define DATA_SOURCE_WBEM ((DWORD) 0x00000004) PDH_FUNCTION PdhSetDefaultRealTimeDataSource(DWORD dwDataSourceId); PDH_FUNCTION PdhBindInputDataSourceW(PDH_HLOG *phDataSource,LPCWSTR LogFileNameList); PDH_FUNCTION PdhBindInputDataSourceA(PDH_HLOG *phDataSource,LPCSTR LogFileNameList); PDH_FUNCTION PdhOpenQueryH(PDH_HLOG hDataSource,DWORD_PTR dwUserData,PDH_HQUERY *phQuery); PDH_FUNCTION PdhEnumMachinesHW(PDH_HLOG hDataSource,LPWSTR mszMachineList,LPDWORD pcchBufferSize); PDH_FUNCTION PdhEnumMachinesHA(PDH_HLOG hDataSource,LPSTR mszMachineList,LPDWORD pcchBufferSize); PDH_FUNCTION PdhEnumObjectsHW(PDH_HLOG hDataSource,LPCWSTR szMachineName,LPWSTR mszObjectList,LPDWORD pcchBufferSize,DWORD dwDetailLevel,WINBOOL bRefresh); PDH_FUNCTION PdhEnumObjectsHA(PDH_HLOG hDataSource,LPCSTR szMachineName,LPSTR mszObjectList,LPDWORD pcchBufferSize,DWORD dwDetailLevel,WINBOOL bRefresh); PDH_FUNCTION PdhEnumObjectItemsHW(PDH_HLOG hDataSource,LPCWSTR szMachineName,LPCWSTR szObjectName,LPWSTR mszCounterList,LPDWORD pcchCounterListLength,LPWSTR mszInstanceList,LPDWORD pcchInstanceListLength,DWORD dwDetailLevel,DWORD dwFlags); PDH_FUNCTION PdhEnumObjectItemsHA(PDH_HLOG hDataSource,LPCSTR szMachineName,LPCSTR szObjectName,LPSTR mszCounterList,LPDWORD pcchCounterListLength,LPSTR mszInstanceList,LPDWORD pcchInstanceListLength,DWORD dwDetailLevel,DWORD dwFlags); PDH_FUNCTION PdhExpandWildCardPathHW(PDH_HLOG hDataSource,LPCWSTR szWildCardPath,LPWSTR mszExpandedPathList,LPDWORD pcchPathListLength,DWORD dwFlags); PDH_FUNCTION PdhExpandWildCardPathHA(PDH_HLOG hDataSource,LPCSTR szWildCardPath,LPSTR mszExpandedPathList,LPDWORD pcchPathListLength,DWORD dwFlags); PDH_FUNCTION PdhGetDataSourceTimeRangeH(PDH_HLOG hDataSource,LPDWORD pdwNumEntries,PPDH_TIME_INFO pInfo,LPDWORD pdwBufferSize); PDH_FUNCTION PdhGetDefaultPerfObjectHW(PDH_HLOG hDataSource,LPCWSTR szMachineName,LPWSTR szDefaultObjectName,LPDWORD pcchBufferSize); PDH_FUNCTION PdhGetDefaultPerfObjectHA(PDH_HLOG hDataSource,LPCSTR szMachineName,LPSTR szDefaultObjectName,LPDWORD pcchBufferSize); PDH_FUNCTION PdhGetDefaultPerfCounterHW(PDH_HLOG hDataSource,LPCWSTR szMachineName,LPCWSTR szObjectName,LPWSTR szDefaultCounterName,LPDWORD pcchBufferSize); PDH_FUNCTION PdhGetDefaultPerfCounterHA(PDH_HLOG hDataSource,LPCSTR szMachineName,LPCSTR szObjectName,LPSTR szDefaultCounterName,LPDWORD pcchBufferSize); PDH_FUNCTION PdhBrowseCountersHW(PPDH_BROWSE_DLG_CONFIG_HW pBrowseDlgData); PDH_FUNCTION PdhBrowseCountersHA(PPDH_BROWSE_DLG_CONFIG_HA pBrowseDlgData); PDH_FUNCTION PdhVerifySQLDBW(LPCWSTR szDataSource); PDH_FUNCTION PdhVerifySQLDBA(LPCSTR szDataSource); PDH_FUNCTION PdhCreateSQLTablesW(LPCWSTR szDataSource); PDH_FUNCTION PdhCreateSQLTablesA(LPCSTR szDataSource); PDH_FUNCTION PdhEnumLogSetNamesW(LPCWSTR szDataSource,LPWSTR mszDataSetNameList,LPDWORD pcchBufferLength); PDH_FUNCTION PdhEnumLogSetNamesA(LPCSTR szDataSource,LPSTR mszDataSetNameList,LPDWORD pcchBufferLength); PDH_FUNCTION PdhGetLogSetGUID(PDH_HLOG hLog,GUID *pGuid,int *pRunId); PDH_FUNCTION PdhSetLogSetRunID(PDH_HLOG hLog,int RunId); #if defined(UNICODE) #ifndef _UNICODE #define _UNICODE #endif #endif #if defined(_UNICODE) #if !defined(UNICODE) #define UNICODE #endif #endif #define PDH_COUNTER_INFO __MINGW_NAME_UAW(PDH_COUNTER_INFO) #define PPDH_COUNTER_INFO __MINGW_NAME_UAW(PPDH_COUNTER_INFO) #define PDH_COUNTER_PATH_ELEMENTS __MINGW_NAME_UAW(PDH_COUNTER_PATH_ELEMENTS) #define PPDH_COUNTER_PATH_ELEMENTS __MINGW_NAME_UAW(PPDH_COUNTER_PATH_ELEMENTS) #define PDH_BROWSE_DLG_CONFIG __MINGW_NAME_UAW(PDH_BROWSE_DLG_CONFIG) #define PPDH_BROWSE_DLG_CONFIG __MINGW_NAME_UAW(PPDH_BROWSE_DLG_CONFIG) #define PDH_FMT_COUNTERVALUE_ITEM __MINGW_NAME_UAW(PDH_FMT_COUNTERVALUE_ITEM) #define PPDH_FMT_COUNTERVALUE_ITEM __MINGW_NAME_UAW(PPDH_FMT_COUNTERVALUE_ITEM) #define PDH_RAW_COUNTER_ITEM __MINGW_NAME_UAW(PDH_RAW_COUNTER_ITEM) #define PPDH_RAW_COUNTER_ITEM __MINGW_NAME_UAW(PPDH_RAW_COUNTER_ITEM) #define PDH_LOG_SERVICE_QUERY_INFO __MINGW_NAME_UAW(PDH_LOG_SERVICE_QUERY_INFO) #define PPDH_LOG_SERVICE_QUERY_INFO __MINGW_NAME_UAW(PPDH_LOG_SERVICE_QUERY_INFO) #define PDH_BROWSE_DLG_CONFIG_H __MINGW_NAME_AW(PDH_BROWSE_DLG_CONFIG_H) #define PPDH_BROWSE_DLG_CONFIG_H __MINGW_NAME_AW(PPDH_BROWSE_DLG_CONFIG_H) #define PdhOpenQuery __MINGW_NAME_AW(PdhOpenQuery) #define PdhAddCounter __MINGW_NAME_AW(PdhAddCounter) #define PdhGetCounterInfo __MINGW_NAME_AW(PdhGetCounterInfo) #define PdhConnectMachine __MINGW_NAME_AW(PdhConnectMachine) #define PdhEnumMachines __MINGW_NAME_AW(PdhEnumMachines) #define PdhEnumObjects __MINGW_NAME_AW(PdhEnumObjects) #define PdhEnumObjectItems __MINGW_NAME_AW(PdhEnumObjectItems) #define PdhMakeCounterPath __MINGW_NAME_AW(PdhMakeCounterPath) #define PdhParseCounterPath __MINGW_NAME_AW(PdhParseCounterPath) #define PdhParseInstanceName __MINGW_NAME_AW(PdhParseInstanceName) #define PdhValidatePath __MINGW_NAME_AW(PdhValidatePath) #define PdhGetDefaultPerfObject __MINGW_NAME_AW(PdhGetDefaultPerfObject) #define PdhGetDefaultPerfCounter __MINGW_NAME_AW(PdhGetDefaultPerfCounter) #define PdhBrowseCounters __MINGW_NAME_AW(PdhBrowseCounters) #define PdhBrowseCountersH __MINGW_NAME_AW(PdhBrowseCountersH) #define PdhExpandCounterPath __MINGW_NAME_AW(PdhExpandCounterPath) #define PdhGetFormattedCounterArray __MINGW_NAME_AW(PdhGetFormattedCounterArray) #define PdhGetRawCounterArray __MINGW_NAME_AW(PdhGetRawCounterArray) #define PdhLookupPerfNameByIndex __MINGW_NAME_AW(PdhLookupPerfNameByIndex) #define PdhLookupPerfIndexByName __MINGW_NAME_AW(PdhLookupPerfIndexByName) #define PdhOpenLog __MINGW_NAME_AW(PdhOpenLog) #define PdhUpdateLog __MINGW_NAME_AW(PdhUpdateLog) #define PdhSelectDataSource __MINGW_NAME_AW(PdhSelectDataSource) #define PdhGetDataSourceTimeRange __MINGW_NAME_AW(PdhGetDataSourceTimeRange) #define PdhLogServiceControl __MINGW_NAME_AW(PdhLogServiceControl) #define PdhLogServiceQuery __MINGW_NAME_AW(PdhLogServiceQuery) #define PdhExpandWildCardPath __MINGW_NAME_AW(PdhExpandWildCardPath) #define PdhBindInputDataSource __MINGW_NAME_AW(PdhBindInputDataSource) #define PdhEnumMachinesH __MINGW_NAME_AW(PdhEnumMachinesH) #define PdhEnumObjectsH __MINGW_NAME_AW(PdhEnumObjectsH) #define PdhEnumObjectItemsH __MINGW_NAME_AW(PdhEnumObjectItemsH) #define PdhExpandWildCardPathH __MINGW_NAME_AW(PdhExpandWildCardPathH) #define PdhGetDefaultPerfObjectH __MINGW_NAME_AW(PdhGetDefaultPerfObjectH) #define PdhGetDefaultPerfCounterH __MINGW_NAME_AW(PdhGetDefaultPerfCounterH) #define PdhEnumLogSetNames __MINGW_NAME_AW(PdhEnumLogSetNames) #define PdhCreateSQLTables __MINGW_NAME_AW(PdhCreateSQLTables) #define PdhVerifySQLDB __MINGW_NAME_AW(PdhVerifySQLDB) #if (_WIN32_WINNT >= 0x0600) PDH_STATUS PdhAddEnglishCounterA( PDH_HQUERY hQuery, LPCSTR szFullCounterPath, DWORD_PTR dwUserData, PDH_HCOUNTER *phCounter ); PDH_STATUS PdhAddEnglishCounterW( PDH_HQUERY hQuery, LPCWSTR szFullCounterPath, DWORD_PTR dwUserData, PDH_HCOUNTER *phCounter ); #define PdhAddEnglishCounter __MINGW_NAME_AW(PdhAddEnglishCounter) PDH_STATUS PdhCollectQueryDataWithTime( PDH_HQUERY hQuery, LONGLONG *pllTimeStamp ); PDH_STATUS PdhValidatePathExA( PDH_HLOG hDataSource, LPCSTR szFullPathBuffer ); PDH_STATUS PdhValidatePathExA( PDH_HLOG hDataSource, LPCWSTR szFullPathBuffer ); #define PdhValidatePathEx __MINGW_NAME_AW(PdhValidatePathEx) #endif /*(_WIN32_WINNT >= 0x0600)*/ #ifdef __cplusplus } #endif #endif pcp-3.8.12ubuntu1/src/win32ctl/include/winperf.h0000664000000000000000000002250712272262501016312 0ustar /** * This file has no copyright assigned and is placed in the Public Domain. * This file is part of the w64 mingw-runtime package. * No warranty is given; refer to the file DISCLAIMER.PD within this package. */ #ifndef _WINPERF_ #define _WINPERF_ #include #define PERF_DATA_VERSION 1 #define PERF_DATA_REVISION 1 typedef struct _PERF_DATA_BLOCK { WCHAR Signature[4]; DWORD LittleEndian; DWORD Version; DWORD Revision; DWORD TotalByteLength; DWORD HeaderLength; DWORD NumObjectTypes; LONG DefaultObject; SYSTEMTIME SystemTime; LARGE_INTEGER PerfTime; LARGE_INTEGER PerfFreq; LARGE_INTEGER PerfTime100nSec; DWORD SystemNameLength; DWORD SystemNameOffset; } PERF_DATA_BLOCK,*PPERF_DATA_BLOCK; typedef struct _PERF_OBJECT_TYPE { DWORD TotalByteLength; DWORD DefinitionLength; DWORD HeaderLength; DWORD ObjectNameTitleIndex; #ifdef _WIN64 DWORD ObjectNameTitle; #else LPWSTR ObjectNameTitle; #endif DWORD ObjectHelpTitleIndex; #ifdef _WIN64 DWORD ObjectHelpTitle; #else LPWSTR ObjectHelpTitle; #endif DWORD DetailLevel; DWORD NumCounters; LONG DefaultCounter; LONG NumInstances; DWORD CodePage; LARGE_INTEGER PerfTime; LARGE_INTEGER PerfFreq; } PERF_OBJECT_TYPE,*PPERF_OBJECT_TYPE; #define PERF_NO_INSTANCES -1 #define PERF_SIZE_DWORD 0x00000000 #define PERF_SIZE_LARGE 0x00000100 #define PERF_SIZE_ZERO 0x00000200 #define PERF_SIZE_VARIABLE_LEN 0x00000300 #define PERF_TYPE_NUMBER 0x00000000 #define PERF_TYPE_COUNTER 0x00000400 #define PERF_TYPE_TEXT 0x00000800 #define PERF_TYPE_ZERO 0x00000C00 #define PERF_NUMBER_HEX 0x00000000 #define PERF_NUMBER_DECIMAL 0x00010000 #define PERF_NUMBER_DEC_1000 0x00020000 #define PERF_COUNTER_VALUE 0x00000000 #define PERF_COUNTER_RATE 0x00010000 #define PERF_COUNTER_FRACTION 0x00020000 #define PERF_COUNTER_BASE 0x00030000 #define PERF_COUNTER_ELAPSED 0x00040000 #define PERF_COUNTER_QUEUELEN 0x00050000 #define PERF_COUNTER_HISTOGRAM 0x00060000 #define PERF_COUNTER_PRECISION 0x00070000 #define PERF_TEXT_UNICODE 0x00000000 #define PERF_TEXT_ASCII 0x00010000 #define PERF_TIMER_TICK 0x00000000 #define PERF_TIMER_100NS 0x00100000 #define PERF_OBJECT_TIMER 0x00200000 #define PERF_DELTA_COUNTER 0x00400000 #define PERF_DELTA_BASE 0x00800000 #define PERF_INVERSE_COUNTER 0x01000000 #define PERF_MULTI_COUNTER 0x02000000 #define PERF_DISPLAY_NO_SUFFIX 0x00000000 #define PERF_DISPLAY_PER_SEC 0x10000000 #define PERF_DISPLAY_PERCENT 0x20000000 #define PERF_DISPLAY_SECONDS 0x30000000 #define PERF_DISPLAY_NOSHOW 0x40000000 #define PERF_COUNTER_COUNTER (PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_TICK | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC) #define PERF_COUNTER_TIMER (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_TICK | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT) #define PERF_COUNTER_QUEUELEN_TYPE (PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_QUEUELEN | PERF_TIMER_TICK | PERF_DELTA_COUNTER | PERF_DISPLAY_NO_SUFFIX) #define PERF_COUNTER_LARGE_QUEUELEN_TYPE (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_QUEUELEN | PERF_TIMER_TICK | PERF_DELTA_COUNTER | PERF_DISPLAY_NO_SUFFIX) #define PERF_COUNTER_100NS_QUEUELEN_TYPE (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_QUEUELEN | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NO_SUFFIX) #define PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_QUEUELEN | PERF_OBJECT_TIMER | PERF_DELTA_COUNTER | PERF_DISPLAY_NO_SUFFIX) #define PERF_COUNTER_BULK_COUNT (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_TICK | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC) #define PERF_COUNTER_TEXT (PERF_SIZE_VARIABLE_LEN | PERF_TYPE_TEXT | PERF_TEXT_UNICODE | PERF_DISPLAY_NO_SUFFIX) #define PERF_COUNTER_RAWCOUNT (PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX) #define PERF_COUNTER_LARGE_RAWCOUNT (PERF_SIZE_LARGE | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX) #define PERF_COUNTER_RAWCOUNT_HEX (PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_HEX | PERF_DISPLAY_NO_SUFFIX) #define PERF_COUNTER_LARGE_RAWCOUNT_HEX (PERF_SIZE_LARGE | PERF_TYPE_NUMBER | PERF_NUMBER_HEX | PERF_DISPLAY_NO_SUFFIX) #define PERF_SAMPLE_FRACTION (PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_FRACTION | PERF_DELTA_COUNTER | PERF_DELTA_BASE | PERF_DISPLAY_PERCENT) #define PERF_SAMPLE_COUNTER (PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_TICK | PERF_DELTA_COUNTER | PERF_DISPLAY_NO_SUFFIX) #define PERF_COUNTER_NODATA (PERF_SIZE_ZERO | PERF_DISPLAY_NOSHOW) #define PERF_COUNTER_TIMER_INV (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_TICK | PERF_DELTA_COUNTER | PERF_INVERSE_COUNTER | PERF_DISPLAY_PERCENT) #define PERF_SAMPLE_BASE (PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_BASE | PERF_DISPLAY_NOSHOW | 0x00000001) #define PERF_AVERAGE_TIMER (PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_FRACTION | PERF_DISPLAY_SECONDS) #define PERF_AVERAGE_BASE (PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_BASE | PERF_DISPLAY_NOSHOW | 0x00000002) #define PERF_AVERAGE_BULK (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_FRACTION | PERF_DISPLAY_NOSHOW) #define PERF_OBJ_TIME_TIMER (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_OBJECT_TIMER | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT) #define PERF_100NSEC_TIMER (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT) #define PERF_100NSEC_TIMER_INV (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_INVERSE_COUNTER | PERF_DISPLAY_PERCENT) #define PERF_COUNTER_MULTI_TIMER (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_DELTA_COUNTER | PERF_TIMER_TICK | PERF_MULTI_COUNTER | PERF_DISPLAY_PERCENT) #define PERF_COUNTER_MULTI_TIMER_INV (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_DELTA_COUNTER | PERF_MULTI_COUNTER | PERF_TIMER_TICK | PERF_INVERSE_COUNTER | PERF_DISPLAY_PERCENT) #define PERF_COUNTER_MULTI_BASE (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_BASE | PERF_MULTI_COUNTER | PERF_DISPLAY_NOSHOW) #define PERF_100NSEC_MULTI_TIMER (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_DELTA_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_MULTI_COUNTER | PERF_DISPLAY_PERCENT) #define PERF_100NSEC_MULTI_TIMER_INV (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_DELTA_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_MULTI_COUNTER | PERF_INVERSE_COUNTER | PERF_DISPLAY_PERCENT) #define PERF_RAW_FRACTION (PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_FRACTION | PERF_DISPLAY_PERCENT) #define PERF_LARGE_RAW_FRACTION (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_FRACTION | PERF_DISPLAY_PERCENT) #define PERF_RAW_BASE (PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_BASE | PERF_DISPLAY_NOSHOW | 0x00000003) #define PERF_LARGE_RAW_BASE (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_BASE | PERF_DISPLAY_NOSHOW) #define PERF_ELAPSED_TIME (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_ELAPSED | PERF_OBJECT_TIMER | PERF_DISPLAY_SECONDS) #define PERF_COUNTER_HISTOGRAM_TYPE 0x80000000 #define PERF_COUNTER_DELTA (PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_VALUE | PERF_DELTA_COUNTER | PERF_DISPLAY_NO_SUFFIX) #define PERF_COUNTER_LARGE_DELTA (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_VALUE | PERF_DELTA_COUNTER | PERF_DISPLAY_NO_SUFFIX) #define PERF_PRECISION_SYSTEM_TIMER (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_PRECISION | PERF_TIMER_TICK | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT) #define PERF_PRECISION_100NS_TIMER (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_PRECISION | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT) #define PERF_PRECISION_OBJECT_TIMER (PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_PRECISION | PERF_OBJECT_TIMER | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT) #define PERF_PRECISION_TIMESTAMP PERF_LARGE_RAW_BASE #define PERF_DETAIL_NOVICE 100 #define PERF_DETAIL_ADVANCED 200 #define PERF_DETAIL_EXPERT 300 #define PERF_DETAIL_WIZARD 400 typedef struct _PERF_COUNTER_DEFINITION { DWORD ByteLength; DWORD CounterNameTitleIndex; #ifdef _WIN64 DWORD CounterNameTitle; #else LPWSTR CounterNameTitle; #endif DWORD CounterHelpTitleIndex; #ifdef _WIN64 DWORD CounterHelpTitle; #else LPWSTR CounterHelpTitle; #endif LONG DefaultScale; DWORD DetailLevel; DWORD CounterType; DWORD CounterSize; DWORD CounterOffset; } PERF_COUNTER_DEFINITION,*PPERF_COUNTER_DEFINITION; #define PERF_NO_UNIQUE_ID -1 typedef struct _PERF_INSTANCE_DEFINITION { DWORD ByteLength; DWORD ParentObjectTitleIndex; DWORD ParentObjectInstance; LONG UniqueID; DWORD NameOffset; DWORD NameLength; } PERF_INSTANCE_DEFINITION,*PPERF_INSTANCE_DEFINITION; typedef struct _PERF_COUNTER_BLOCK { DWORD ByteLength; } PERF_COUNTER_BLOCK,*PPERF_COUNTER_BLOCK; #define PERF_QUERY_OBJECTS ((LONG)0x80000000) #define PERF_QUERY_GLOBAL ((LONG)0x80000001) #define PERF_QUERY_COSTLY ((LONG)0x80000002) typedef DWORD (WINAPI PM_OPEN_PROC)(LPWSTR); typedef DWORD (WINAPI PM_COLLECT_PROC)(LPWSTR,LPVOID *,LPDWORD,LPDWORD); typedef DWORD (WINAPI PM_CLOSE_PROC)(void); typedef DWORD (WINAPI PM_QUERY_PROC)(LPDWORD,LPVOID *,LPDWORD,LPDWORD); #define MAX_PERF_OBJECTS_IN_QUERY_FUNCTION (64L) #define WINPERF_LOG_NONE 0 #define WINPERF_LOG_USER 1 #define WINPERF_LOG_DEBUG 2 #define WINPERF_LOG_VERBOSE 3 #include #endif pcp-3.8.12ubuntu1/src/win32ctl/pmafm.bat0000775000000000000000000000060112272262501014626 0ustar @echo off if "%OS%" == "Windows_NT" goto WinNT %PCP_DIR%\bin\sh.exe pmafm.sh %1 %2 %3 %4 %5 %6 %7 %8 %9 goto endofbash :WinNT %PCP_DIR%\bin\sh.exe pmafm.sh %* if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofbash if %errorlevel% == 9009 echo You do not have sh.exe in your PCP_DIR. if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul :endofbash pcp-3.8.12ubuntu1/src/win32ctl/setevent/0000775000000000000000000000000012272262620014675 5ustar pcp-3.8.12ubuntu1/src/win32ctl/setevent/GNUmakefile0000664000000000000000000000167612272262501016757 0ustar # # Copyright (c) 2008-2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs CFILES = pcp-setevent.c CMDTARGET = pcp-setevent.exe LLDLIBS = $(PCPLIB) LSRCFILES = $(WRAPPERS) default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "mingw" build-me: $(CMDTARGET) install: default $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) else build-me: install: endif default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/win32ctl/setevent/pcp-setevent.c0000664000000000000000000000376712272262501017471 0ustar /* * Copyright (C) 2009 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" enum { PCP_SIGHUP = 1, PCP_SIGUSR1 = 2, PCP_SIGTERM = 3, PCP_SIGKILL = 4, }; int atosig(const char *sig) { if (strcmp(sig, "HUP") == 0) return PCP_SIGHUP; if (strcmp(sig, "USR1") == 0) return PCP_SIGUSR1; if (strcmp(sig, "TERM") == 0) return PCP_SIGTERM; if (strcmp(sig, "KILL") == 0) return PCP_SIGKILL; return 0; } int main(int argc, char **argv) { pid_t pid; char name[64]; int sig, error = 0; __pmSetProgname(argv[0]); if (argc != 3) error++; else if ((sig = atosig(argv[1])) < 1) error++; else if ((pid = (pid_t)atoi(argv[2])) < 1) error++; if (error) { fprintf(stderr, "Usage: %s \n", pmProgname); return 2; } if (sig == PCP_SIGKILL) { __pmProcessTerminate(pid, 1); return 0; } if (!__pmProcessExists(pid)) { fprintf(stderr, "%s: OpenEvent(%s) failed on PID %" FMT_PID " (%ld)\n", pmProgname, name, pid, GetLastError()); return 1; } snprintf(name, sizeof(name), "PCP/%" FMT_PID "/SIG%s", pid, argv[1]); HANDLE h = OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT(name)); if (!h) { fprintf(stderr, "%s: OpenEvent(%s) failed on PID %" FMT_PID " (%ld)\n", pmProgname, name, pid, GetLastError()); return 1; } if (!SetEvent(h)) { fprintf(stderr, "%s: SetEvent(%s) failed on PID %" FMT_PID " (%ld)\n", pmProgname, name, pid, GetLastError()); return 1; } return 0; } pcp-3.8.12ubuntu1/src/win32ctl/GNUmakefile0000664000000000000000000000174412272262501015116 0ustar # # Copyright (c) 2008-2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs SUBDIRS = include lib \ eventlog services setevent BATCHES = pcp.bat pmafm.bat mkaf.bat pmsignal.bat LSRCFILES = $(BATCHES) default :: default_pcp default_pcp : $(SUBDIRS) $(SUBDIRS_MAKERULE) install :: default_pcp install_pcp install_pcp : $(SUBDIRS) $(SUBDIRS_MAKERULE) ifeq "$(TARGET_OS)" "mingw" $(INSTALL) -m 755 $(BATCHES) $(PCP_BIN_DIR) endif include $(BUILDRULES) pcp-3.8.12ubuntu1/src/win32ctl/pcp.bat0000775000000000000000000000057512272262501014322 0ustar @echo off if "%OS%" == "Windows_NT" goto WinNT %PCP_DIR%\bin\sh.exe pcp.sh %1 %2 %3 %4 %5 %6 %7 %8 %9 goto endofbash :WinNT %PCP_DIR%\bin\sh.exe pcp.sh %* if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofbash if %errorlevel% == 9009 echo You do not have sh.exe in your PCP_DIR. if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul :endofbash pcp-3.8.12ubuntu1/src/win32ctl/mkaf.bat0000775000000000000000000000057712272262501014460 0ustar @echo off if "%OS%" == "Windows_NT" goto WinNT %PCP_DIR%\bin\sh.exe mkaf.sh %1 %2 %3 %4 %5 %6 %7 %8 %9 goto endofbash :WinNT %PCP_DIR%\bin\sh.exe mkaf.sh %* if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofbash if %errorlevel% == 9009 echo You do not have sh.exe in your PCP_DIR. if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul :endofbash pcp-3.8.12ubuntu1/src/win32ctl/eventlog/0000775000000000000000000000000012272262620014663 5ustar pcp-3.8.12ubuntu1/src/win32ctl/eventlog/pcp-eventlog.c0000664000000000000000000000730412272262501017434 0ustar /* * Copyright (C) 2008 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include #include int posix2win32(char *pri) { if (strcmp(pri, "alert") == 0 || strcmp(pri, "warning") == 0 || strcmp(pri, "warn") == 0) return EVENTLOG_WARNING_TYPE; if (strcmp(pri, "crit") == 0 || strcmp(pri, "emerg") == 0 || strcmp(pri, "err") == 0 || strcmp(pri, "error") == 0 || strcmp(pri, "panic") == 0) return EVENTLOG_ERROR_TYPE; if (strcmp(pri, "info") == 0 || strcmp(pri, "notice") == 0 || strcmp(pri, "debug") == 0) return EVENTLOG_INFORMATION_TYPE; return -1; } void append(char *buffer, int bsize, char *string) { static int spaced; /* first argument needs no whitespace-prefix */ static int offset; if (spaced) offset += snprintf(buffer + offset, bsize - offset, " %s", string); else { offset += snprintf(buffer + offset, bsize - offset, "%s", string); spaced = 1; /* remainder will all be space-prefixed */ } } int main(int argc, char **argv) { HANDLE sink; LPCSTR msgptr; char buffer[256]; char msg[32*1024]; char *pri = NULL; char *tag = NULL; int error = 0; int iflag = 0; int sflag = 0; int priority; int c; __pmSetProgname(argv[0]); while ((c = getopt(argc, argv, "ip:st:?")) != EOF) { switch (c) { case 'i': /* process ID */ iflag = 1; break; case 'p': /* pri (facility.level) */ pri = optarg; break; case 's': /* stderr too */ sflag = 1; break; case 't': /* tag (prefix) */ tag = optarg; break; default: error++; } } if (error) { fprintf(stderr, "Usage: %s [ options ] message\n\n" "Options:\n" " -i log process identifier with each line\n" " -s log message to standard error as well\n" " -p pri enter message with specified priority\n" " -t tag mark the line with the specified tag\n", pmProgname); return 2; } /* * Parse priority. Discard facility, pick out valid level names. */ if (!pri) priority = EVENTLOG_INFORMATION_TYPE; /* default event type */ else { char *p = strrchr(pri, '.'); if (p) pri = p; priority = posix2win32(pri); if (!priority) priority = EVENTLOG_INFORMATION_TYPE; /* default event type */ } /* * Construct the message from all contributing components. */ if (iflag) { snprintf(buffer, sizeof(buffer), "[%" FMT_PID "]", getpid()); append(msg, sizeof(msg), buffer); } if (tag) { snprintf(buffer, sizeof(buffer), "%s:", tag); append(msg, sizeof(msg), buffer); } for (c = optind; c < argc; c++) /* insert the remaining text */ append(msg, sizeof(msg), argv[c]); /* * Optionally write to the standard error stream (as well). */ if (sflag) { fputs(msg, stderr); fputc('\n', stderr); } sink = RegisterEventSource(NULL, "Application"); if (!sink) { fprintf(stderr, "%s: RegisterEventSource failed (%ld)\n", pmProgname, GetLastError()); return 1; } msgptr = msg; if (!ReportEvent(sink, priority, 0, 0, NULL, 1, 0, &msgptr, NULL)) fprintf(stderr, "%s: ReportEvent failed (%ld)\n", pmProgname, GetLastError()); DeregisterEventSource(sink); return 0; } pcp-3.8.12ubuntu1/src/win32ctl/eventlog/GNUmakefile0000664000000000000000000000167612272262501016745 0ustar # # Copyright (c) 2008-2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs CFILES = pcp-eventlog.c CMDTARGET = pcp-eventlog.exe LLDLIBS = $(PCPLIB) LSRCFILES = $(WRAPPERS) default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "mingw" build-me: $(CMDTARGET) install: default $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) else build-me: install: endif default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmclient/0000775000000000000000000000000012272262620013206 5ustar pcp-3.8.12ubuntu1/src/pmclient/README0000664000000000000000000000246112272262501014067 0ustar pmclient - a sample client using the PMAPI ========================================== pmclient is a sample client that uses the Performance Metrics Application Programming Interface (PMAPI) to report some performance data, collected from either a local host, a remote host, or a Performance Co-Pilot (PCP) performance metrics archive log. The binary is shipped as part of pcp.sw.monitor and should be installed in /usr/sbin/pmclient. A "man" page is shipped in pcp.man.pages. The source is shipped as part of pcp.sw.demo and is installed in /var/pcp/demos/pmclient. If you have the C compiler installed, the source and Makefile in this directory may be used to create a functionally equivalent binary, simply by entering the command % make The source in pmclient.c demonstrates most of the PMAPI services, and may be used as a template and style guide when creating your own PMAPI clients. Note in particular, the use of ./pmnsmap.spec and the shipped tool pmgenmap to assist in the creation of arguments to the PMAPI routines, and the manipulation of PMAPI data structures. To experiment with the archives, % rm -f mylog.* % /usr/pcp/bin/pmlogger -c config.pmclient -s 6 mylog this will collect 30 seconds of performance data into the archive stored as the files mylog.*. To play this back, % pmclient -a mylog pcp-3.8.12ubuntu1/src/pmclient/pmclient.c0000664000000000000000000003423312272262501015170 0ustar /* * pmclient - sample, simple PMAPI client * * Copyright (c) 2013 Red Hat. * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmnsmap.h" typedef struct { struct timeval timestamp; /* last fetched time */ float cpu_util; /* aggregate CPU utilization, usr+sys */ int peak_cpu; /* most utilized CPU, if > 1 CPU */ float peak_cpu_util; /* utilization for most utilized CPU */ float freemem; /* free memory (Mbytes) */ unsigned int dkiops; /* aggregate disk I/O's per second */ float load1; /* 1 minute load average */ float load15; /* 15 minute load average */ } info_t; static unsigned int ncpu; /* * real time difference, *ap minus *bp */ double tv_sub(struct timeval *ap, struct timeval *bp) { return ap->tv_sec - bp->tv_sec + (double)(ap->tv_usec - bp->tv_usec)/1000000.0; } static unsigned int get_ncpu(void) { /* there is only one metric in the pmclient_init group */ pmID pmidlist[1]; pmDesc desclist[1]; pmResult *rp; pmAtomValue atom; int sts; if ((sts = pmLookupName(1, pmclient_init, pmidlist)) < 0) { fprintf(stderr, "%s: pmLookupName: %s\n", pmProgname, pmErrStr(sts)); fprintf(stderr, "%s: metric \"%s\" not in name space\n", pmProgname, pmclient_init[0]); exit(1); } if ((sts = pmLookupDesc(pmidlist[0], desclist)) < 0) { fprintf(stderr, "%s: cannot retrieve description for metric \"%s\" (PMID: %s)\nReason: %s\n", pmProgname, pmclient_init[0], pmIDStr(pmidlist[0]), pmErrStr(sts)); exit(1); } if ((sts = pmFetch(1, pmidlist, &rp)) < 0) { fprintf(stderr, "%s: pmFetch: %s\n", pmProgname, pmErrStr(sts)); exit(1); } /* the thing we want is known to be the first value */ pmExtractValue(rp->vset[0]->valfmt, rp->vset[0]->vlist, desclist[0].type, &atom, PM_TYPE_U32); pmFreeResult(rp); return atom.ul; } static void get_sample(info_t *ip) { static pmResult *crp = NULL; /* current */ static pmResult *prp = NULL; /* prior */ static int first = 1; static int numpmid; static pmID *pmidlist; static pmDesc *desclist; static int inst1; static int inst15; static pmUnits mbyte_scale; int sts; int i; float u; pmAtomValue tmp; pmAtomValue atom; double dt; if (first) { /* first time initialization */ mbyte_scale.dimSpace = 1; mbyte_scale.scaleSpace = PM_SPACE_MBYTE; numpmid = sizeof(pmclient_sample) / sizeof(char *); if ((pmidlist = (pmID *)malloc(numpmid * sizeof(pmidlist[0]))) == NULL) { fprintf(stderr, "%s: get_sample: malloc: %s\n", pmProgname, osstrerror()); exit(1); } if ((desclist = (pmDesc *)malloc(numpmid * sizeof(desclist[0]))) == NULL) { fprintf(stderr, "%s: get_sample: malloc: %s\n", pmProgname, osstrerror()); exit(1); } if ((sts = pmLookupName(numpmid, pmclient_sample, pmidlist)) < 0) { printf("%s: pmLookupName: %s\n", pmProgname, pmErrStr(sts)); for (i = 0; i < numpmid; i++) { if (pmidlist[i] == PM_ID_NULL) fprintf(stderr, "%s: metric \"%s\" not in name space\n", pmProgname, pmclient_sample[i]); } exit(1); } for (i = 0; i < numpmid; i++) { if ((sts = pmLookupDesc(pmidlist[i], &desclist[i])) < 0) { fprintf(stderr, "%s: cannot retrieve description for metric \"%s\" (PMID: %s)\nReason: %s\n", pmProgname, pmclient_sample[i], pmIDStr(pmidlist[i]), pmErrStr(sts)); exit(1); } } } /* fetch the current metrics */ if ((sts = pmFetch(numpmid, pmidlist, &crp)) < 0) { fprintf(stderr, "%s: pmFetch: %s\n", pmProgname, pmErrStr(sts)); exit(1); } /* * minor gotcha ... for archives, it helps to do the first fetch of * real data before interrogating the instance domains ... this * forces us to be "after" the first batch of instance domain info * in the meta data files */ if (first) { /* * from now on, just want the 1 minute and 15 minute load averages, * so limit the instance profile for this metric */ pmDelProfile(desclist[LOADAV].indom, 0, NULL); /* all off */ if ((inst1 = pmLookupInDom(desclist[LOADAV].indom, "1 minute")) < 0) { fprintf(stderr, "%s: cannot translate instance for 1 minute load average\n", pmProgname); exit(1); } pmAddProfile(desclist[LOADAV].indom, 1, &inst1); if ((inst15 = pmLookupInDom(desclist[LOADAV].indom, "15 minute")) < 0) { fprintf(stderr, "%s: cannot translate instance for 15 minute load average\n", pmProgname); exit(1); } pmAddProfile(desclist[LOADAV].indom, 1, &inst15); first = 0; } /* if the second or later sample, pick the results apart */ if (prp != NULL) { dt = tv_sub(&crp->timestamp, &prp->timestamp); ip->cpu_util = 0; ip->peak_cpu_util = -1; /* force re-assignment at first CPU */ for (i = 0; i < ncpu; i++) { pmExtractValue(crp->vset[CPU_USR]->valfmt, &crp->vset[CPU_USR]->vlist[i], desclist[CPU_USR].type, &atom, PM_TYPE_FLOAT); u = atom.f; pmExtractValue(prp->vset[CPU_USR]->valfmt, &prp->vset[CPU_USR]->vlist[i], desclist[CPU_USR].type, &atom, PM_TYPE_FLOAT); u -= atom.f; pmExtractValue(crp->vset[CPU_SYS]->valfmt, &crp->vset[CPU_SYS]->vlist[i], desclist[CPU_SYS].type, &atom, PM_TYPE_FLOAT); u += atom.f; pmExtractValue(prp->vset[CPU_SYS]->valfmt, &prp->vset[CPU_SYS]->vlist[i], desclist[CPU_SYS].type, &atom, PM_TYPE_FLOAT); u -= atom.f; /* * really should use pmConvertValue, but I _know_ the times * are in msec! */ u = u / (1000 * dt); if (u > 1.0) /* small errors are possible, so clip the utilization at 1.0 */ u = 1.0; ip->cpu_util += u; if (u > ip->peak_cpu_util) { ip->peak_cpu_util = u; ip->peak_cpu = i; } } ip->cpu_util /= ncpu; /* freemem - expect just one value */ pmExtractValue(crp->vset[FREEMEM]->valfmt, crp->vset[FREEMEM]->vlist, desclist[FREEMEM].type, &tmp, PM_TYPE_FLOAT); /* convert from today's units at the collection site to Mbytes */ pmConvScale(PM_TYPE_FLOAT, &tmp, &desclist[FREEMEM].units, &atom, &mbyte_scale); ip->freemem = atom.f; /* disk IOPS - expect just one value, but need delta */ pmExtractValue(crp->vset[DKIOPS]->valfmt, crp->vset[DKIOPS]->vlist, desclist[DKIOPS].type, &atom, PM_TYPE_U32); ip->dkiops = atom.ul; pmExtractValue(prp->vset[DKIOPS]->valfmt, prp->vset[DKIOPS]->vlist, desclist[DKIOPS].type, &atom, PM_TYPE_U32); ip->dkiops -= atom.ul; ip->dkiops = ((float)(ip->dkiops) + 0.5) / dt; /* load average ... process all values, matching up the instances */ for (i = 0; i < crp->vset[LOADAV]->numval; i++) { pmExtractValue(crp->vset[LOADAV]->valfmt, &crp->vset[LOADAV]->vlist[i], desclist[LOADAV].type, &atom, PM_TYPE_FLOAT); if (crp->vset[LOADAV]->vlist[i].inst == inst1) ip->load1 = atom.f; else if (crp->vset[LOADAV]->vlist[i].inst == inst15) ip->load15 = atom.f; } /* free very old result */ pmFreeResult(prp); } ip->timestamp = crp->timestamp; /* swizzle result pointers */ prp = crp; } int main(int argc, char **argv) { int c; int sts; int errflag = 0; int type = 0; char *host = NULL; /* initialize to pander to gcc */ char *archive = NULL; char *pmnsfile = PM_NS_DEFAULT; int samples = -1; /* number of samples */ struct timeval delta = { 5, 0 }; /* initial interval (seconds) */ int pauseFlag=0; double skipSeconds = 0.0; info_t info; /* values to report each sample */ int lines = 0; pmLogLabel label; /* get hostname for archives */ int zflag = 0; /* for -z */ char *tz = NULL; /* for -Z timezone */ int tzh; /* initial timezone handle */ char timebuf[26]; /* for pmCtime result */ char *endnum; char *msg; /* error message */ __pmSetProgname(argv[0]); setlinebuf(stdout); while ((c = getopt(argc, argv, "a:D:h:n:ps:S:t:zZ:?")) != EOF) { switch (c) { case 'a': /* archive name */ if (type != 0) { fprintf(stderr, "%s: at most one of -a and/or -h allowed\n", pmProgname); errflag++; } type = PM_CONTEXT_ARCHIVE; host = optarg; break; case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case 'h': /* contact PMCD on this hostname */ if (type != 0) { fprintf(stderr, "%s: at most one of -a and/or -h allowed\n", pmProgname); errflag++; } host = optarg; type = PM_CONTEXT_HOST; break; case 'n': /* alternative name space file */ pmnsfile = optarg; break; case 'p': /* pause between updates when replaying an archive */ pauseFlag++; break; case 's': /* sample count */ samples = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0' || samples < 0.0) { fprintf(stderr, "%s: -s requires numeric argument\n", pmProgname); errflag++; } break; case 'S': /* skip from start of archive */ skipSeconds = strtod(optarg, &endnum); if (*endnum != '\0' || skipSeconds <= 0.0) { fprintf(stderr, "%s: -S requires positive numeric argument\n", pmProgname); errflag++; } break; case 't': /* interval between samples */ if ((sts = pmParseInterval(optarg, &delta, &msg)) < 0) { fprintf(stderr, "%s: illegal -t argument\n%s\n", pmProgname, msg); errflag++; } break; case 'z': /* timezone from host */ if (tz != NULL) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); errflag++; } zflag++; break; case 'Z': /* $TZ timezone */ if (zflag) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); errflag++; } tz = optarg; break; case '?': default: errflag++; break; } } if (zflag && type == 0) { fprintf(stderr, "%s: -z requires an explicit -a, or -h option\n", pmProgname); errflag++; } if (skipSeconds > 0.0 && (type == 0 || type == PM_CONTEXT_HOST)) { fprintf(stderr, "%s: -S can only be used with -a\n", pmProgname); errflag++; } if (pauseFlag && (type == 0 || type == PM_CONTEXT_HOST)) { fprintf(stderr, "%s: -p can only be used with -a\n", pmProgname); errflag++; } if (errflag || optind < argc-1) { fprintf(stderr, "Usage: %s [options]\n\ \n\ Options\n\ -a archive metrics source is a PCP log archive\n\ -h host metrics source is PMCD on host\n\ -n pmnsfile use an alternative PMNS\n\ -p pause between samples for PCP log archive\n\ -S numsec skip numsec seconds from start of PCP log archive\n\ -s samples terminate after this many samples\n\ -t interval sample interval [default 5 seconds]\n\ -Z timezone set reporting timezone\n\ -z set reporting timezone to local time of metrics source\n", pmProgname); exit(1); } if (pmnsfile != PM_NS_DEFAULT) { if ((sts = pmLoadNameSpace(pmnsfile)) < 0) { printf("%s: Cannot load namespace from \"%s\": %s\n", pmProgname, pmnsfile, pmErrStr(sts)); exit(1); } } if (type == 0) { type = PM_CONTEXT_HOST; host = "local:"; } if ((sts = pmNewContext(type, host)) < 0) { if (type == PM_CONTEXT_HOST) fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", pmProgname, host, pmErrStr(sts)); else fprintf(stderr, "%s: Cannot open archive \"%s\": %s\n", pmProgname, host, pmErrStr(sts)); exit(1); } if (type == PM_CONTEXT_ARCHIVE) { archive = host; if ((sts = pmGetArchiveLabel(&label)) < 0) { fprintf(stderr, "%s: Cannot get archive label record: %s\n", pmProgname, pmErrStr(sts)); exit(1); } host = strdup(label.ll_hostname); } if (zflag) { if ((tzh = pmNewContextZone()) < 0) { fprintf(stderr, "%s: Cannot set context timezone: %s\n", pmProgname, pmErrStr(tzh)); exit(1); } if (type == PM_CONTEXT_ARCHIVE) printf("Note: timezone set to local timezone of host \"%s\" from archive\n\n", label.ll_hostname); else printf("Note: timezone set to local timezone of host \"%s\"\n\n", host); } else if (tz != NULL) { if ((tzh = pmNewZone(tz)) < 0) { fprintf(stderr, "%s: Cannot set timezone to \"%s\": %s\n", pmProgname, tz, pmErrStr(tzh)); exit(1); } printf("Note: timezone set to \"TZ=%s\"\n\n", tz); } ncpu = get_ncpu(); if (skipSeconds > 0.0 && type == PM_CONTEXT_ARCHIVE) { label.ll_start.tv_sec += (int)skipSeconds; if ((sts = pmSetMode(PM_MODE_FORW, &label.ll_start, 0)) < 0) { fprintf(stderr, "%s: warning, can't skip %.1f seconds forward in archive: %s\n", pmProgname, skipSeconds, pmErrStr(sts)); /* don't exit */ } } get_sample(&info); while (samples == -1 || samples-- > 0) { if (lines % 15 == 0) { if (archive != NULL) printf("Archive: %s, ", archive); printf("Host: %s, %d cpu(s), %s", host, ncpu, pmCtime(&info.timestamp.tv_sec, timebuf)); /* - report format CPU Busy Busy Free Mem Disk Load Average Util CPU Util (Mbytes) IOPS 1 Min 15 Min X.XXX XXX X.XXX XXXXX.XXX XXXXXX XXXX.XX XXXX.XX */ printf(" CPU"); if (ncpu > 1) printf(" Busy Busy"); printf(" Free Mem Disk Load Average\n"); printf(" Util"); if (ncpu > 1) printf(" CPU Util"); printf(" (Mbytes) IOPS 1 Min 15 Min\n"); } if (type != PM_CONTEXT_ARCHIVE || pauseFlag) __pmtimevalSleep(delta); get_sample(&info); printf("%5.2f", info.cpu_util); if (ncpu > 1) printf(" %3d %5.2f", info.peak_cpu, info.peak_cpu_util); printf(" %9.3f", info.freemem); printf(" %6d", info.dkiops); printf(" %7.2f %7.2f\n", info.load1, info.load15); lines++; } exit(0); } pcp-3.8.12ubuntu1/src/pmclient/GNUmakefile0000664000000000000000000000252712272262501015264 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmclient.c CMDTARGET = pmclient$(EXECSUFFIX) LLDLIBS = $(PCPLIB) LDIRT = pmnsmap.h mylog.* runme.sh LSRCFILES = README GNUmakefile.install pmnsmap.spec DEMODIR=$(PCP_DEMOS_DIR)/pmclient default: $(CMDTARGET) include $(BUILDRULES) install: $(CMDTARGET) $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) $(INSTALL) -m 755 -d $(DEMODIR) $(INSTALL) -m 644 GNUmakefile.install $(DEMODIR)/Makefile $(INSTALL) -m 644 $(CFILES) README pmnsmap.spec $(DEMODIR) pmclient.o: pmnsmap.h pmnsmap.h: pmnsmap.spec sed -e "s;^\. .PCP_DIR.etc.pcp.env;. $(TOPDIR)/src/include/pcp.env;" \ ../pmgenmap/pmgenmap.sh >runme.sh; \ $(RUN_IN_BUILD_ENV) sh ./runme.sh pmnsmap.spec >pmnsmap.h default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmclient/GNUmakefile.install0000664000000000000000000000217512272262501016730 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # CFILES = pmclient.c CFLAGS = -I/usr/include/pcp -DPCP_DEBUG=1 TARGETS = pmclient LDOPTS = LDLIBS = -lpcp default: $(TARGETS) install: clobber: rm -f $(TARGETS) *.o core a.out pmnsmap.h mylog.* pmlogger.log pmclient: pmclient.c pmnsmap.h rm -f $@ $(CC) $(CFLAGS) pmclient.c -o $@ $(LDOPTS) $(LDLIBS) pmnsmap.h: pmnsmap.spec pmgenmap pmnsmap.spec >pmnsmap.h pcp-3.8.12ubuntu1/src/pmclient/pmnsmap.spec0000664000000000000000000000032212272262501015530 0ustar pmclient_init { hinv.ncpu NUMCPU } pmclient_sample { kernel.all.load LOADAV kernel.percpu.cpu.user CPU_USR kernel.percpu.cpu.sys CPU_SYS mem.freemem FREEMEM disk.all.total DKIOPS } pcp-3.8.12ubuntu1/src/pmieconf/0000775000000000000000000000000012272262620013173 5ustar pcp-3.8.12ubuntu1/src/pmieconf/GNUmakefile.rules0000664000000000000000000000322212272262501016373 0ustar # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs # localdefs needs to set ALL_RULES (all the rules files to be included # in the builds and tar balls) and set LOCAL_RULES (the subset of the # rules that will work on the TARGET_OS platform) # include localdefs WORKDIR := $(shell pwd) GROUP := $(shell basename $(WORKDIR)) RULESDIR = $(PCP_VAR_DIR)/config/pmieconf LDIRT = GNUmakefile LSRCFILES = localdefs $(ALL_RULES) CONFIGS = $(subst "./","",$(LOCAL_RULES)) default_pcp: $(LOCAL_RULES) install_pcp: install install: default_pcp $(INSTALL) -d $(RULESDIR)/$(GROUP) @for f in $(CONFIGS); do \ $(INSTALL) -m 644 $$f $(RULESDIR)/$(GROUP)/$$f; \ done rules: @test ! -d ../rules/$(GROUP) && mkdir ../rules/$(GROUP); exit 0 @rm -f ../rules/$(GROUP)/* @for f in IGNORE_DUMMY_RULE $(LOCAL_RULES); do \ [ $$f = IGNORE_DUMMY_RULE ] && continue; \ cp ../$(GROUP)/$$f ../rules/$(GROUP)/$$f; \ sed -e's|/usr/pcp/lib/pmie_email|$(PCP_BINADM_DIR)/pmie_email|' \ -e's|/usr/pcp/bin/pmpost|$(PCP_BINADM_DIR)/pmpost|' <$$f \ >../rules/$(GROUP)/$$f; \ done pmlogconf: @if [ -n "$(CONFIGS)" ]; then sh ../xtractnames $(CONFIGS); fi include $(BUILDRULES) pcp-3.8.12ubuntu1/src/pmieconf/global/0000775000000000000000000000000012272262620014433 5ustar pcp-3.8.12ubuntu1/src/pmieconf/global/localdefs0000664000000000000000000000025412272262501016311 0ustar ALL_RULES = enln_actions tngfw_actions parameters ov_actions pcp_actions LOCAL_RULES = $(ALL_RULES) ifneq ($(TARGET_OS), irix) LOCAL_RULES = parameters pcp_actions endif pcp-3.8.12ubuntu1/src/pmieconf/global/enln_actions0000664000000000000000000000241312272262501017030 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # shell global.enln_action enabled = no default = "$enln_bin$/EventsCli -q -s '$enln_severity$' -S N/A -T N/A -n 'pmie/$enln_test$ - $rule$' -h '%h' -v '%v' -u '$enln_units$'" help = "Provides a mechanism for sending local pmie-generated events into the local Enlighten DSM management framework. This action requires the \"EventsCli\" program which is part of the Enlighten DSM framework (refer to the enln_bin variable description also)."; string global.enln_bin default = "/opt/enlighten/bin" help = "The full path to the Enlighten DSM \"EventsCli\" program, which is used to propagate external events into the Enlighten DSM Framework."; unsigned global.enln_severity default = 2 display = no help = "The severity is a number between a low of 1 and a high of 5 (1=OK, 2=Informational, 3=Warning, 4=Error, 5=Severe). The default value is 2."; string global.enln_test default = "Unknown" display = no help = "The brief name of the pmie event being sent to Enlighten DSM, typically the name of an individual rule."; string global.enln_units default = "N/A" display = no help = "The units value specifies the unit of measure for the value measured."; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/global/parameters0000664000000000000000000000221212272262501016514 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # # variable definitions applicable to all rules # (unless overridden at the level of an individual rule or group) # string global.delta default = "2 min" help = "Sample interval between evaluations of this rule. Default units are seconds and common units are \"second\", \"sec\", \"minute\", \"min\" and \"hour\"."; string global.holdoff default = "10 min" help = "Once the predicate is true and the action is executed, this variable allows suppression of further action execution until the specified interval has elapsed. A value of zero enables execution of the action if the rule predicate is true at the next sample. Default units are seconds and common units are \"second\", \"sec\", \"minute\", \"min\" and \"hour\"."; hostlist global.hosts default = "" help = "May be set to a list of host names for which the rules will be evaluated. Multiple hostnames should be separated by white space. If the list is empty, the host will be the host named in the -h option to pmie(1) if specified, else the local host."; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/global/pcp_actions0000664000000000000000000000442012272262501016656 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # # action definitions applicable to all rules follow # # o $rule$ defined locally & contains the "message" to be propagated # # o $*_expand$ often overridden locally & contains the part of the # action string which is rule-semantics specific and will be expanded # possibly multiple times on truthful evaluation of the predicate to # contain values/instances/hosts which matched,e.g: # "%v@%h" might expand to "1.1@moomba 1.7@rattle 4.5@wobbly" if all # the rule is true for all of the hosts moomba, rattle and wobbly. # # some common alternatives: # %i@%h (inst@host) # %h (host) # %v[%i]@%h (value:inst@host) # %v%@%h (value%@host) # string global.action_expand display = no modify = no default = "%v@%h"; # (value@host) string global.email_expand display = no modify = no default = "%v@%h"; # (value@host) shell global.user_action enabled = no default = "$user_command$" help = "Execute \"user_command\" when the rule condition is true"; string global.user_command default = "echo $rule$^ $action_expand$" help = "Shell (sh(1)) command line to execute when rule condition is true and \"user_action\" is enabled."; shell global.email_action enabled = no default = "pmie_email '$email_recipients$|$rule$^|$email_expand$^'" help = "A mail message will be sent to \"email_recipients\" when the rule condition is true."; string global.email_recipients default = "root" help = "Space separated list of e-mail addresses for notification from the \"email_action\" when it is enabled"; shell global.pcplog_action enabled = no default = "pmpost pmie: $rule$^ $action_expand$" help = "The PCP notices file $PCP_LOG_DIR/NOTICES will be updated when the rule condition is true."; syslog global.syslog_action enabled = yes default = "$syslog_prefix$$rule$^ $action_expand$" help = "The system log file (usually /var/log/messages) will be updated when the rule condition is true."; string global.syslog_prefix display = no modify = no default = ""; # for SGI Embedded Support Partner integration, use: # $ pmieconf modify global syslog_prefix '$esp_prefix$' string global.esp_prefix display = no modify = no default = "|\\\\$($esp_type$)"; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/global/ov_actions0000664000000000000000000000413612272262501016524 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # shell global.ov_action enabled = no default = "OID=.1.3.6.1.4.1.11.2.17; export OID; $ov_bin$/ovevent -c '$ov_category$' -s '$ov_severity$' '$ov_node$' ^\\\\${OID}.1.0.58916872 \\\\${OID}.2.1.0 Integer 0 \\\\${OID}.2.2.0 OctetString '%h' \\\\${OID}.2.4.0 OctetString '$rule$^ $action_expand$^'" # 4 backquotes gives a shell variable - '$' is a special character # to pmieconf, pmie, and the shell - so need to backquote it up the # whazoo to get this to come out right! # help = "The HP OpenView Network Node Manager event subsystem on ov_node will receive an OV_Message event when the rule condition is true. This action requires the ovevent(1) program which is part of the HP OpenView package (refer to the ov_bin variable description also)."; string global.ov_bin default = "/opt/OV/bin" help = "The full path to the HP OpenView ovevent(1) program, which is used to propagate external events into the OpenView framework."; string global.ov_node default = "" help = "The node on which the HP OpenView pmd(1M) daemon is running, which will reliably broadcast the pmie event to all interested HP OpenView processes. The node can be either an Internet address or host name (see hosts(4)), and is usually the local host except when run from a management console (client host). An empty string is equivalent to the local host."; string global.ov_severity default = "Warning" display = no help = "Severity with which an event will be reported to the HP OpenView node manager on ov_node. Valid values are \"Critical\", \"Major\", \"Minor\", \"Warning\" and \"Normal\"."; string global.ov_category default = "Threshold Events" display = no help = "Category with which an event will be reported to the HP OpenView node manager on ov_node. The category must be one of the existing event categories; the default categories defined in trapd.conf(4) are: \"IGNORE\", \"LOGONLY\", \"Error Events\", \"Threshold Events\", \"Status Events\", \"Configuration Events\", and \"Application Alert Events\"."; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/global/tngfw_actions0000664000000000000000000000273212272262501017225 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # shell global.tngfw_action enabled = no default = "$tngfw_bin$/cawto -n '$tngfw_node$' -c '$tngfw_color$' -g $tngfw_category$ -s `/usr/bsd/hostname` '$rule$^ $action_expand$^'" help = "The CA Unicenter TNG console node at tngfw_node will be notified when the rule condition is true. This action requires the \"cawto\" program which is part of the CA Unicenter TNG Framework (refer to the tngfw_bin variable description also)."; string global.tngfw_bin default = "/usr/TNGFW/bin" help = "The full path to the TNG Framework \"cawto\" program, which is used to propagate external events into the Unicenter TNG Framework."; string global.tngfw_node default = "" help = "The node on which the CA Unicenter TNG monitoring software is running. The node can be either an Internet address or host name (see hosts(4)), and is usually the local host. An empty string is equivalent to the local host."; string global.tngfw_color default = "default" display = no help = "The color that the CA Unicenter TNG event console on tngfw_node will use to display the event message string. Valid values are \"default\", \"Red\", \"Orange\", \"yellow\", \"green\", \"blue\", \"pink\" or \"purple\"."; string global.tngfw_category default = "Performance" display = no help = "The category with which the CA Unicenter TNG event console on tngfw_node will associate each event."; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/rules.h0000664000000000000000000001140712272262501014477 0ustar /* * rules.h - rule description data structures and parsing * * Copyright 1998, Silicon Graphics, Inc. * ALL RIGHTS RESERVED * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef RULES_H #define RULES_H /* defaults relative to $PCP_VAR_DIR */ #ifdef IS_MINGW #define DEFAULT_RULES "config\\pmieconf" #define DEFAULT_ROOT_PMIE "pmie\\config.default" #else #define DEFAULT_RULES "config/pmieconf" #define DEFAULT_ROOT_PMIE "pmie/config.default" #endif /* default relative to $HOME */ #ifdef IS_MINGW #define DEFAULT_USER_PMIE ".pcp\\pmie\\config.pmie" #else #define DEFAULT_USER_PMIE ".pcp/pmie/config.pmie" #endif #define TYPE_STRING 0 /* arbitrary string (default) */ #define TYPE_DOUBLE 1 /* real number */ #define TYPE_INTEGER 2 /* integer number */ #define TYPE_UNSIGNED 3 /* cardinal number */ #define TYPE_PERCENT 4 /* percentage 0..100 */ #define TYPE_HOSTLIST 5 /* list of host names */ #define TYPE_INSTLIST 6 /* list of metric instances */ #define TYPE_PRINT 7 /* print action */ #define TYPE_SHELL 8 /* shell action */ #define TYPE_ALARM 9 /* alarm window action */ #define TYPE_SYSLOG 10 /* syslog action */ #define TYPE_RULE 11 /* rule definition */ #define ATTRIB_HELP 0 /* help= text */ #define ATTRIB_MODIFY 1 /* modify= text */ #define ATTRIB_ENABLED 2 /* enabled= y/n */ #define ATTRIB_DISPLAY 3 /* display= y/n */ #define ATTRIB_DEFAULT 4 /* default= value */ #define ATTRIB_VERSION 5 /* version= int */ #define ATTRIB_PREDICATE 6 /* predicate= text */ #define ATTRIB_ENUMERATE 7 /* enumerate= text */ #define IS_ACTION(t) \ (t==TYPE_PRINT || t==TYPE_SHELL || t==TYPE_ALARM || t==TYPE_SYSLOG) #define IS_RULE(t) (t == TYPE_RULE) /* generic data block definition */ struct atom_type { char *name; /* atom identifier */ char *data; /* value string */ char *ddata; /* default value */ char *help; /* help text */ unsigned int type : 16; /* data type */ unsigned int modify : 1; /* advice for editor */ unsigned int display : 1; /* advice for editor */ unsigned int enabled : 1; /* switched on/off */ unsigned int denabled: 1; /* default on/off */ unsigned int changed : 1; /* has value been changed? */ unsigned int global : 1; /* global scope */ unsigned int padding : 10; /* unused */ struct atom_type *next; }; typedef struct atom_type atom_t; typedef struct { unsigned int version; atom_t self; char *predicate; char *enumerate; /* list of hostlist/instlist params */ } rule_t; extern rule_t *rulelist; extern unsigned int rulecount; extern rule_t *globals; extern char errmsg[]; /* error message buffer */ /* * routines below returning char*, on success return NULL else failure message */ char *initialise(char *, char *, char *, size_t); /* setup global data */ char *get_pmiefile(void); char *get_rules(void); char *get_aname(rule_t *, atom_t *); void sort_rules(void); char *find_rule(char *, rule_t **); char *lookup_rules(char *, rule_t ***, unsigned int *, int); char *value_string(atom_t *, int); /* printable string form of atoms value */ char *value_change(rule_t *, char *, char *); /* change rule parameter value */ char *validate(int, char *, char *); /* check proposed value for named type */ char *write_pmiefile(char *, int); char *lookup_processes(int *, char ***); int is_attribute(char *); char *get_attribute(char *, atom_t *); char *rule_defaults(rule_t *, char *); int is_overridden(rule_t *, atom_t *); int read_token(FILE *, char *, int, int); char *dollar_expand(rule_t *, char *, int); /* deprecated rules stuff */ #define DEPRECATE_NORULE 0 #define DEPRECATE_VERSION 1 typedef struct { unsigned int version; /* version not matching/in rules */ char *name; /* full name of the offending rule */ char *reason; /* ptr to deprecation description */ int type; /* reason for deprecating this rule */ } dep_t; int fetch_deprecated(dep_t **list); /* generic symbol table definition */ typedef struct { int symbol_id; char *symbol; } symbol_t; /* lookup keyword, returns symbol identifier or -1 if not there */ int map_symbol(symbol_t *, int, char *); /* lookup symbol identifier, returns keyword or NULL if not there */ char *map_identifier(symbol_t *, int, int); /* parse yes/no attribute value; returns 0 no, 1 yes, -1 error */ int map_boolean(char *); #endif pcp-3.8.12ubuntu1/src/pmieconf/pmieconf.c0000664000000000000000000005137312272262501015146 0ustar /* * Copyright (c) 1998-2001, Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include "pmapi.h" #include "impl.h" #include "rules.h" #define MAXSYMLEN (MAXPATHLEN+1) #define MAXVARLEN (512+1) #define MAXBUFLEN (1024+1) static int verbose; static int autocreate; static int interactive = 1; static int pmiefile_modified; static char warn[MAXBUFLEN]; /* buffer for any warning messages */ static char usage[] = \ "Usage: %s [options] [ command [args...] ]\n" "\n" "Options:\n" " -c an automated pmie configuration by the system\n" " -F force creation/update of pmie file, then exit\n" " -f filename location of generated pmie configuration file\n" " [for root, default is %s/%s and\n" " for other users, default is $HOME/%s]\n" " -r rulepath path specifying groups of rule files [%s/%s]\n" " -v verbose mode\n" "\n" "Commands:\n%s\n"; static char help[] = \ " 1. help [ { . | all | global | | } [] ]\n" " descriptive text on one or more variables or rules\n" " 2. rules [ enabled | disabled ]\n" " list of available, enabled, or disabled rules\n" " 3. groups list of available groups of rules\n" " 4. status print status information\n" " 5. enable { . | all | | }\n" " switch evaluation on for given rule(s)\n" " 6. disable { . | all | | }\n" " switch evaluation off for given rule(s)\n" " 7. list { . | all | global | | } []\n" " print values of variables for given rule(s)\n" " 8. modify { . | all | global | | } \n" " change the value of a rule variable\n" " 9. undo { . | all | global | | } []\n" " revert to default value of rule variable\n" " 10. verbose [ { on | off } ]\n" " change amount of info displayed ('*' denotes global variables)\n" " 11. quit save changes then exit\n" " 12. abort discard changes then exit"; #define MAXARGS 4 static char inbuf[MAXARGS][MAXBUFLEN+1]; /* input buffer */ static char previous[MAXVARLEN+1]; /* buffer for last rule name */ static symbol_t commands[] = { #define COMMAND_HELP 1 { COMMAND_HELP, "help" }, { COMMAND_HELP, "h" }, { COMMAND_HELP, "?" }, #define COMMAND_RULES 2 { COMMAND_RULES, "rules" }, { COMMAND_RULES, "r" }, #define COMMAND_GROUPS 3 { COMMAND_GROUPS, "groups" }, { COMMAND_GROUPS, "g" }, #define COMMAND_STATUS 4 { COMMAND_STATUS, "status" }, { COMMAND_STATUS, "s" }, #define COMMAND_ENABLE 5 { COMMAND_ENABLE, "enable" }, { COMMAND_ENABLE, "e" }, #define COMMAND_DISABLE 6 { COMMAND_DISABLE, "disable" }, { COMMAND_DISABLE, "d" }, #define COMMAND_LIST 7 { COMMAND_LIST, "list" }, { COMMAND_LIST, "l" }, #define COMMAND_MODIFY 8 { COMMAND_MODIFY, "modify" }, { COMMAND_MODIFY, "m" }, #define COMMAND_UNDO 9 { COMMAND_UNDO, "undo" }, { COMMAND_UNDO, "u" }, #define COMMAND_VERBOSE 10 { COMMAND_VERBOSE, "verbose" }, { COMMAND_VERBOSE, "v" }, #define COMMAND_QUIT 11 { COMMAND_QUIT, "quit" }, { COMMAND_QUIT, "q" }, #define COMMAND_ABORT 12 { COMMAND_ABORT, "abort" }, { COMMAND_ABORT, "a" }, #define LAST_COMMAND 12 }; static int ncommands = (sizeof(commands)/sizeof(commands[0])); /* io-related stuff */ extern void setio(int); extern void setscroll(void); extern void onwinch(int); extern int pprintf(char *, ...); extern void error(char *, ...); /* * #### simple printing routines ### */ static void print_helpstring(char *value) { char *s; char *str; int i = 0; if (value == NULL) { pprintf(" help: No help available.\n"); return; } if ((str = strdup(value)) == NULL) { error("insufficient memory to display help"); exit(1); } s = strtok(str, "\n"); while (s != NULL) { pprintf("%s%s\n", i++ == 0? " help: ":"\t", s); s = strtok(NULL, "\n"); } free(str); } static void print_predicatestring(char *value) { char *s; char *str; if ((str = strdup(value)) == NULL) { error("insufficient memory to display predicate"); exit(1); } s = strtok(str, "\n"); pprintf("\tpredicate = \n"); while (s != NULL) { pprintf("\t %s\n", s); s = strtok(NULL, "\n"); } free(str); } /* prints help string for a parameter of a rule */ void print_help(rule_t *rule, char *attrib) { atom_t *aptr; for (aptr = &rule->self; aptr != NULL; aptr = aptr->next) if (strcmp(get_aname(rule, aptr), attrib) == 0) { if (aptr->help == NULL) goto nohelp; print_helpstring(aptr->help); return; } for (aptr = &globals->self; aptr != NULL; aptr = aptr->next) if (strcmp(get_aname(globals, aptr), attrib) == 0) { if (aptr->help == NULL) goto nohelp; print_helpstring(aptr->help); return; } nohelp: error("no help available for variable \"%s\" of rule %s", attrib, rule->self.name); } /* prints a named parameter from a rule, return -1 on failure */ int print_attribute(rule_t *rule, char *attrib, int dohelp) { atom_t *aptr; int isattrib = is_attribute(attrib); if (isattrib == ATTRIB_PREDICATE && rule != globals) print_predicatestring(rule->predicate); else if (isattrib == ATTRIB_HELP) print_helpstring(rule->self.help); else if (isattrib != -1 && rule != globals) { if (dohelp) pprintf(" var: %s\n help: No help available.\n", attrib); else pprintf("\t%s = %s\n", attrib, get_attribute(attrib, &rule->self)); } else { for (aptr = rule->self.next; aptr != NULL; aptr = aptr->next) if (strcmp(get_aname(rule, aptr), attrib) == 0) { if (dohelp) { pprintf(" var: %s\n", attrib); print_helpstring(aptr->help); } else pprintf("\t%s = %s\n", attrib, value_string(aptr, 1)); return 0; } for (aptr = globals->self.next; aptr != NULL; aptr = aptr->next) if (strcmp(get_aname(globals, aptr), attrib) == 0) { if (dohelp) { pprintf(" var: %s\n", attrib); print_helpstring(aptr->help); } else pprintf("\t%s = %s\n", attrib, value_string(aptr, 1)); return 0; } error("variable \"%s\" is undefined for rule %s", attrib, rule->self.name); return -1; } return 0; } /* one line summary (name and short help) for a given rule */ void print_rule_summary(rule_t *rule, char *prefix) { char *str; char fmt[] = "%s%s [%s]\n"; if ((str = dollar_expand(rule, rule->self.data, 0)) == NULL) return; pprintf(fmt, prefix, rule->self.name, str); free(str); } void print_rule(rule_t *rule) { atom_t *a; int needvars = 1; print_rule_summary(rule, " rule: "); if (rule->self.help != NULL) print_helpstring(rule->self.help); if (rule != globals) { /* non-global */ print_predicatestring(rule->predicate); pprintf(" vars: enabled = %s\n", rule->self.enabled?"yes":"no"); } for (a = rule->self.next; a != NULL; a = a->next) { if (!a->display) continue; pprintf("%s%s = %s\n", (rule == globals && needvars)? " vars: ":"\t", get_aname(rule, a), value_string(a, 1)); needvars = 0; } if (verbose && rule != globals) { for (a = globals->self.next; a != NULL; a = a->next) { if (is_overridden(rule, a)) continue; /* printed already as part of attribs */ pprintf("\t%s = %s (*)\n", get_aname(globals,a), value_string(a,1)); } } } /* print out the list of unique group names (sort done previously) */ static int print_grouplist(int argcount) { int i; char *j; char lastgroup[MAXVARLEN]; if (argcount != 0) { error("too many arguments for \"groups\" command"); return -1; } lastgroup[0] = '\0'; for (i = 1; i < rulecount; i++) { if ((j = strchr(rulelist[i].self.name, '.')) != NULL) { *j = '\0'; /* mark end of group name */ if (strcmp(rulelist[i].self.name, lastgroup) != 0) { strcpy(lastgroup, rulelist[i].self.name); pprintf(" %s\n", lastgroup); } *j = '.'; /* repair the rule name */ } } return 0; } /* * print out the current verbosity setting, running pmies using this * pmie file, total number of rules & number of rules switched on. */ static int print_status(int argcount) { int i, count = 0, pcount = 0; char **processes; if (argcount != 0) { error("too many arguments for \"status\" command"); return -1; } for (i = 1; i < rulecount; i++) /* find enabled rules */ if (rulelist[i].self.enabled) count++; lookup_processes(&pcount, &processes); /* find running pmies */ printf(" verbose: %s\n" " enabled rules: %u of %u\n" " pmie configuration file: %s\n" " pmie %s using this file: ", verbose? "on" : "off", count, rulecount-1, get_pmiefile(), pcount == 1? "process (PID)" : "processes (PIDs)"); if (pcount == 0) printf(" (none found)"); else { for (i = 0; i < pcount; i++) { printf(" %s", processes[i]); free(processes[i]); } free(processes); } printf("\n"); return 0; } int write_pmie(void) { int i, count; char *msg; dep_t *list; if ((msg = write_pmiefile(pmProgname, autocreate)) != NULL) { error(msg); return 1; } if ((count = fetch_deprecated(&list)) > 0) { if (interactive) pprintf(" Warning - some rules have been deprecated:\n"); else pprintf("%s: some rules have been deprecated:\n", pmProgname); for (i = 0; i < count; i++) { pprintf(" %s (deprecated, %s)\n", list[i].name, list[i].reason); free(list[i].name); } free(list); pprintf("\n See %s for details\n", get_pmiefile()); } return 0; } /* display the list of available, enabled or disabled rules */ static int command_rules(int argcount) { int i; if (argcount > 1) { error("too many arguments for \"rules\" command"); return -1; } if (argcount == 0) for (i = 1; i < rulecount; i++) print_rule_summary(&rulelist[i], " "); else { if (strcmp(inbuf[1], "enabled") == 0) { for (i = 1; i < rulecount; i++) if (rulelist[i].self.enabled) print_rule_summary(&rulelist[i], " "); } else if (strcmp(inbuf[1], "disabled") == 0) { for (i = 1; i < rulecount; i++) if (!rulelist[i].self.enabled) print_rule_summary(&rulelist[i], " "); } else { error("invalid argument for \"rules\" command"); return -1; } } return 0; } /* display or set the verbosity level */ static int command_verbose(int argcount) { int sts; if (argcount < 1) { printf(" verbose: %s\n", verbose? "on" : "off"); return 0; } else if (argcount > 1) { error("too many arguments for \"verbose\" command"); return -1; } if (strcmp(inbuf[1], "on") == 0) sts = 1; else if (strcmp(inbuf[1], "off") == 0) sts = 0; else { error("invalid argument, expected \"on\" or \"off\""); return -1; } verbose = sts; return 0; } static int command_list(int argcount) { unsigned int rcount; rule_t **rptr; char *msg; int all = 0; int sts = 0; int i; if (argcount < 1) { error("too few arguments for \"list\" command"); return -1; } else if (argcount > 2) { error("too many arguments for \"list\" command"); return -1; } if (strcmp(".", inbuf[1]) == 0) strcpy(inbuf[1], previous); if (strcmp("all", inbuf[1]) == 0) all = 1; if ((msg = lookup_rules(inbuf[1], &rptr, &rcount, all)) != NULL) { error(msg); return -1; } if (argcount == 1) { /* print out one rule or one group */ for (i = 0; i < rcount; i++) { if (i > 0) pprintf("\n"); print_rule(rptr[i]); } } else { /* print out one rule/group variable */ for (i = 0; i < rcount; i++) { print_rule_summary(rptr[i], " rule: "); if (print_attribute(rptr[i], inbuf[2], 0) == -1) sts = -1; /* failure */ } } free(rptr); strcpy(previous, inbuf[1]); return sts; } static int command_undo(int argcount) { unsigned int rcount; rule_t **rptr; char *msg = NULL; char *var = NULL; int all = 0; int i; if (argcount < 1) { error("too few arguments for \"undo\" command"); return -1; } else if (argcount > 2) { error("too many arguments for \"undo\" command"); return -1; } if (strcmp(".", inbuf[1]) == 0) strcpy(inbuf[1], previous); if (strcmp("all", inbuf[1]) == 0) all = 1; if ((msg = lookup_rules(inbuf[1], &rptr, &rcount, all)) != NULL) { error(msg); return -1; } if (argcount == 2) var = inbuf[2]; for (i = 0; i < rcount; i++) if ((msg = rule_defaults(rptr[i], var)) != NULL) break; free(rptr); if (msg != NULL) { error(msg); return -1; } strcpy(previous, inbuf[1]); pmiefile_modified = 1; return 0; } static int command_modify(int command, int argcount) { unsigned int rcount; rule_t **rptr; char *msg; int all = 0; int c; if (command == COMMAND_MODIFY) { if (argcount != 3) { error("too %s arguments for \"modify\" command", argcount < 3? "few":"many"); return -1; } } else if (strcmp(inbuf[1], "global") == 0) { error("invalid argument - \"global\""); return -1; } else if (command == COMMAND_ENABLE) { if (argcount != 1) { error("too %s arguments for \"enable\" command", argcount < 1? "few":"many"); return -1; } strcpy(inbuf[2], "enabled"); strcpy(inbuf[3], "yes"); } else { /* (command == COMMAND_DISABLE) */ if (argcount != 1) { error("too %s arguments for \"disable\" command", argcount < 1? "few":"many"); return -1; } strcpy(inbuf[2], "enabled"); strcpy(inbuf[3], "no"); } if (strcmp(".", inbuf[1]) == 0) strcpy(inbuf[1], previous); if (strcmp("all", inbuf[1]) == 0) all = 1; if ( ((c = is_attribute(inbuf[2])) != -1) && c != ATTRIB_ENABLED ) { error("no change - variable \"%s\" is always readonly", inbuf[2]); return -1; } if ((msg = lookup_rules(inbuf[1], &rptr, &rcount, all)) != NULL) { error(msg); return -1; } for (c = 0; c < rcount; c++) { if ((msg = value_change(rptr[c], inbuf[2], inbuf[3])) != NULL) { error("change aborted - %s", msg); free(rptr); return -1; } } pmiefile_modified = 1; free(rptr); strcpy(previous, inbuf[1]); return 0; } static int command_help(int argcount) { unsigned int rcount; rule_t **rptr; char *msg; int sts = 0; int all = 0; int i; if (argcount < 1) { puts(help); return 0; } else if (argcount > 2) { error("too many arguments for \"help\" command"); return -1; } if (strcmp(".", inbuf[1]) == 0) strcpy(inbuf[1], previous); if (strcmp("all", inbuf[1]) == 0) all = 1; if ((msg = lookup_rules(inbuf[1], &rptr, &rcount, all)) != NULL) { error(msg); return -1; } if (argcount == 1) { for (i = 0; i < rcount; i++) { print_rule_summary(rptr[i], " rule: "); print_helpstring(rptr[i]->self.help); } } else { for (i = 0; i < rcount; i++) { print_rule_summary(rptr[i], " rule: "); if (print_attribute(rptr[i], inbuf[2], 1) == -1) sts = -1; /* failure */ } } free(rptr); strcpy(previous, inbuf[1]); return sts; } static void command_quit(void) { static int done = 0; int i, pcount = 0; char **processes; char *msg; /* must only come thru here once, but can be called multiple times */ if (done != 0) return; done = 1; if (pmiefile_modified && write_pmie() != 0) exit(1); /* show any running pmie processes which use this pmie config */ if (interactive && pmiefile_modified) { if ((msg = lookup_processes(&pcount, &processes)) != NULL) error(msg); else if (pcount > 0) { pprintf(" %s is in use by %d running pmie process%s:\n\t", get_pmiefile(), pcount, pcount == 1? "":"es"); for (i = 0; i < pcount; i++) pprintf("%s ", processes[i]); pprintf("\n Restart %s for the configuration change to take effect.", pcount == 1 ? "this process" : "these processes"); pprintf("\n o Use kill(1) to stop; e.g.\tkill -INT "); for (i = 0; i < pcount; i++) { pprintf("%s ", processes[i]); free(processes[i]); } free(processes); pprintf("\n\ o Refer to pmie_check(1) for a convenient mechanism for restarting pmie\n\ daemons launched under the control of %s/pmie/control;\n\ e.g.\t%s/pmie_check -V\n", pmGetConfig("PCP_SYSCONF_DIR"), pmGetConfig("PCP_BINADM_DIR")); } } } /* * workhorse routine - dishes out work depending on user command; * returns 1 on user-quit, 0 on success, -1 on failure */ static int configure(int count) { int command = atoi(inbuf[0]); if (command <= 0 || command > LAST_COMMAND) command = map_symbol(commands, ncommands, inbuf[0]); switch(command) { case COMMAND_HELP: return command_help(count-1); case COMMAND_RULES: return command_rules(count-1); case COMMAND_GROUPS: return print_grouplist(count-1); case COMMAND_STATUS: return print_status(count-1); case COMMAND_VERBOSE: return command_verbose(count-1); case COMMAND_ENABLE: /* shortcut for modify */ case COMMAND_DISABLE: /* shortcut for modify */ case COMMAND_MODIFY: return command_modify(command, count-1); case COMMAND_LIST: return command_list(count-1); case COMMAND_UNDO: return command_undo(count-1); case COMMAND_QUIT: command_quit(); return 1; case COMMAND_ABORT: exit(0); default: error("unrecognised command \"%s\" - try \"help\"", inbuf[0]); return -1; } /*NOTREACHED*/ } static void interact(void) { int done = 0; int n, sts; if (interactive) printf("Updates will be made to %s\n", get_pmiefile()); do { sts = 0; for (n = 0; n < MAXARGS; n++) inbuf[n][0] = '\0'; if (interactive) { setio(0); printf("\n%s> ", pmProgname); fflush(stdout); } do { if ((n = read_token(stdin, inbuf[sts], MAXBUFLEN, '\n')) == -1) { error("failed to parse argument %d correctly", sts+1); break; } else if (n > 0) sts++; else { if (n == -2) { command_quit(); done = 1; } break; } } while (sts <= MAXARGS); if (n < 0) /* done (EOF) or error reported above */ continue; else if (sts > MAXARGS) { error("too many arguments - try \"help\""); /* consume until '\n' reached... */ while ((n = read_token(stdin, inbuf[0], MAXBUFLEN, '\n')) > 0); if (n == -2) { command_quit(); done = 1; /* reached EOF, bail out! */ } } else if (sts > 0 && !done) done = (configure(sts) == 1); } while (!done); } int main(int argc, char **argv) { int c; int force = 0; int errflag = 0; char *p; char *in_rules = NULL; char *in_pmie = NULL; __pmSetProgname(argv[0]); while ((c = getopt(argc, argv, "cFf:r:v?")) != EOF) { switch (c) { case 'c': autocreate = 1; interactive = 0; break; case 'F': force = 1; break; case 'f': in_pmie = optarg; break; case 'r': in_rules = optarg; break; case 'v': verbose = 1; break; case '?': default: errflag++; } } if (force && optind < argc) { fprintf(stderr, "%s: cannot use -F with a command\n", pmProgname); optind = argc; errflag++; } for (c = 0; optind < argc && c < MAXARGS; c++) { strncpy(inbuf[c], argv[optind++], MAXBUFLEN); inbuf[c][MAXBUFLEN] = '\0'; interactive = 0; } if (optind < argc) { fprintf(stderr, "%s: too many arguments\n", pmProgname); errflag++; } if (errflag) { fprintf(stderr, usage, pmProgname, pmGetConfig("PCP_SYSCONF_DIR"), DEFAULT_ROOT_PMIE, DEFAULT_USER_PMIE, pmGetConfig("PCP_VAR_DIR"), DEFAULT_RULES, help); exit(1); } if ((p = initialise(in_rules, in_pmie, warn, sizeof(warn))) != NULL) { error(p); exit(1); } sort_rules(); if (rulecount <= 1) { fprintf(stderr, "%s: no rules were found using rule path: %s\n", pmProgname, get_rules()); exit(1); } if (force || (*warn && p == NULL)) { /* force/pmie doesn't exist */ if (write_pmie() != 0) exit(1); else if (force) exit(0); } else if (*warn) /* some other warning */ error(warn); if (interactive) { if (!isatty(0)) /* reading commands from a file */ interactive = 0; else if (isatty(1)) { /* be $PAGER, handle window-resize */ setscroll(); onwinch(0); } interact(); } else if (configure(c) == -1) exit(1); command_quit(); exit(0); /*NOTREACHED*/ } pcp-3.8.12ubuntu1/src/pmieconf/percpu/0000775000000000000000000000000012272262620014471 5ustar pcp-3.8.12ubuntu1/src/pmieconf/percpu/context_switch0000664000000000000000000000300512272262501017455 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule per_cpu.context_switch summary = "$rule$" enumerate = "hosts" predicate = "some_host ( some_inst ( kernel.percpu.pswitch $hosts$ > $threshold$ count/sec ) && hinv.ncpu $hosts$ > 1 )" enabled = yes version = 1 help = "The number of context switches per second for at least one CPU exceeded $threshold$ over the past sample interval. This rule only applies to multi-processor systems, for single-processor systems refer to the cpu.context_switch rule. For Origin 200 and Origin 2000 systems, use the command $ pminfo -f hinv.map.cpu to discover the abbreviated PCP names of the installed CPUs and their corresponding full names in the /hw file system."; string rule default = "High per CPU context switch rate" modify = no display = no; double threshold default = 5000 help = "The threshold number of context switches per second per CPU."; string action_expand default = %vctxsw/s[%i]@%h display = no modify = no; string email_expand default = "host: %h CPU: %i context switches: %v/sec" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x200056" display = no modify = no; # for EnlightenDSM integration: string enln_test default = per_cpu.context_switch display = no modify = no; string enln_units default = ctxsw/s[%i] display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/percpu/many_util0000664000000000000000000000377512272262501016427 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule per_cpu.many_util summary = "$rule$" enumerate = hosts predicate = "some_host ( $pct$ %_inst ( 100 * ( kernel.percpu.cpu.user $hosts$ + kernel.percpu.cpu.sys $hosts$ + kernel.percpu.cpu.intr $hosts$ ) > $threshold$ ) && hinv.ncpu $hosts$ > $min_cpu_count$ )" enabled = yes version = 1 help = "The processor utilization for at least pct percent of the CPUs exceeded threshold percent during the last sample interval. Only applies to multi-processor systems having more than min_cpu_count processors - for single-processor systems refer to the cpu.util rule, for multi-processor systems with less than min_cpu_count processors refer to the per_cpu.some_util rule."; string rule default = "High number of saturated processors" modify = no display = no; percent threshold default = 95 help = "Threshold percentage for CPU saturation, in the range 0 (idle) to 100 (completely busy)"; percent pct default = 80 help = "Percentage of the processors which must be utilized greater than threshold percent, in the range 0 (no processors utilized) to 100 (all processors)."; unsigned min_cpu_count default = 4 help = "Lower limit on number of processors for this rule - this rule will apply to configurations of greater than min_cpu_count CPUs. For smaller processor counts, the per_cpu.some_util rule may be more appropriate."; string action_expand default = "\\\\>$pct$%cpus@%h" display = no modify = no; string email_expand default = "host: %h more than $pct$% of the processors are saturated" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x20005F" display = no modify = no; # for EnlightenDSM integration: string enln_test default = per_cpu.many_util display = no modify = no; string enln_units default = "busy_CPUs" display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/percpu/syscall0000664000000000000000000000402312272262501016063 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule per_cpu.syscall summary = "$rule$" enumerate = hosts predicate = "some_host ( some_inst ( kernel.percpu.syscall $hosts$ > $threshold$ count/sec ) && hinv.ncpu $hosts$ > 1 )" enabled = yes version = 1 help = "The number of system calls per second for at least one CPU exceeded threshold over the past sample interval. This rule only applies to multi-processor systems, for single-processor systems refer to the cpu.syscall rule. For Origin 200 and Origin 2000 systems, use the command $ pminfo -f hinv.map.cpu to discover the abbreviated PCP names of the installed CPUs and their corresponding full names in the /hw file system."; string rule default = "High per CPU system call rate" modify = no display = no; double threshold default = 12000 help = "The threshold of system calls per second per CPU. The appropriate value here is a function of the processor type and the workload, but here are some indicative figures of sustained system call rates for a single process: getpid() - 380000 syscalls/sec lseek() to start of file - 280000 syscalls/sec gettimeofday() - 200000 syscalls/sec read() at end of file - 83000 syscalls/sec file creat() and close() - 65000 syscalls/sec socket(), connect() and close() - 7000 syscalls/sec (generated using an otherwise idle system with 180MHz R10000 processors)."; string action_expand default = %vscall/s[%i]@%h display = no modify = no; string email_expand default = "host: %h CPU: %i syscalls/sec: %v" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x200057" display = no modify = no; # for EnlightenDSM integration: string enln_test default = per_cpu.syscall display = no modify = no; string enln_units default = scall/s[%i] display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/percpu/localdefs0000664000000000000000000000174112272262501016351 0ustar ALL_RULES = syscall some_util many_util context_switch system LOCAL_RULES = $(ALL_RULES) # Metrics missing from Linux # # rule: context_switch # kernel.percpu.pswitch -12357 Unknown metric name # # rule: syscall # kernel.percpu.syscall -12357 Unknown metric name # ifeq ($(TARGET_OS), linux) LOCAL_RULES = some_util many_util system endif # Metrics missing from Mac OS X # # rule: syscall # kernel.percpu.syscall -12357 Unknown metric name # # rule: some_util # kernel.percpu.cpu.intr -12357 Unknown metric name # # rule: many_util # kernel.percpu.cpu.intr -12357 Unknown metric name # # rule: context_switch # kernel.percpu.pswitch -12357 Unknown metric name # ifeq ($(TARGET_OS), darwin) LOCAL_RULES = system endif # Metrics missing from Solaris # # rule: many_util # kernel.percpu.cpu.intr -12357 Unknown metric name # # rule: some_util # kernel.percpu.cpu.intr -12357 Unknown metric name # ifeq ($(TARGET_OS), solaris) LOCAL_RULES = syscall context_switch system endif pcp-3.8.12ubuntu1/src/pmieconf/percpu/system0000664000000000000000000000412412272262501015737 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule per_cpu.system summary = "$rule$" enumerate = hosts # need first conjunct to get %v in actions... predicate = "some_host ( some_inst ( // first term is always true, but provides %v for actions ... ( 100 * kernel.percpu.cpu.sys $hosts$ ) > 0 && 100 * ( kernel.percpu.cpu.user $hosts$ + kernel.percpu.cpu.sys $hosts$ ) > $busy$ && 100 * kernel.percpu.cpu.sys $hosts$ / ( kernel.percpu.cpu.user $hosts$ + kernel.percpu.cpu.sys $hosts$ ) > $threshold$ ) && hinv.ncpu $hosts$ > 1 )" enabled = yes version = 1 help = "Over the last sample interval, at least one CPU was active for busy percent or more, and the ratio of system time to busy time exceeded threshold percent. Only applies to multi-processor systems, for single-processor systems refer to the cpu.system rule. For Origin 200 and Origin 2000 systems, use the command $ pminfo -f hinv.map.cpu to discover the abbreviated PCP names of the installed CPUs and their corresponding full names in the /hw file system."; string rule default = "Some CPU busy executing in system mode" modify = no display = no; percent busy default = 75 help = "Busy percentage for average CPU utilization, in the range 0 (idle) to 100 (completely busy), independent of the number of CPUs."; percent threshold default = 80 help = "Threshold percentage for system time as a fraction of the non-idle CPU time, in the range 0 (no system time) to 100 (all system time), independent of the number of CPUs."; string action_expand default = %v%sys[%i]@%h display = no modify = no; string email_expand default = "host: %h CPU: %i system mode: %v%" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x200058" display = no modify = no; # for EnlightenDSM integration: string enln_test default = per_cpu.system display = no modify = no; string enln_units default = %sys[%i] display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/percpu/some_util0000664000000000000000000000377712272262501016430 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule per_cpu.some_util summary = "$rule$" enumerate = hosts predicate = "some_host ( some_inst ( ( 100 * ( kernel.percpu.cpu.user $hosts$ + kernel.percpu.cpu.sys $hosts$ + kernel.percpu.cpu.intr $hosts$ ) ) > $threshold$ ) && hinv.ncpu $hosts$ > 1 && hinv.ncpu $hosts$ <= $max_cpu_count$ )" enabled = yes version = 1 help = "The processor utilization for at least one CPU exceeded threshold percent during the last sample interval. Only applies to multi-processor systems with less than max_cpu_count processors - for single-processor systems refer to the cpu.util rule, and for multi-processor systems with more than max_cpu_count processors refer to the cpu.many_util rule. For Origin 200 and Origin 2000 systems, use the command $ pminfo -f hinv.map.cpu to discover the abbreviated PCP names of the installed CPUs and their corresponding full names in the /hw file system."; string rule default = "High per CPU processor utilization" modify = no display = no; percent threshold default = 95 help = "Threshold percentage for CPU saturation, in the range 0 (idle) to 100 (completely busy)"; unsigned max_cpu_count default = 4 help = "Upper limit on number of processors for this rule - this rule will apply to configurations of between two and max_cpu_count CPUs. For larger processor counts, the per_cpu.many_util rule may be more appropriate."; string action_expand default = %v%util[%i]@%h display = no modify = no; string email_expand default = "host: %h CPU: %i utilization: %v%" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x200059" display = no modify = no; # for EnlightenDSM integration: string enln_test default = per_cpu.some_util display = no modify = no; string enln_units default = %util[%i] display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/io.c0000664000000000000000000001145112272262501013746 0ustar /* * Copyright 1998, Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "impl.h" #ifdef HAVE_SYS_IOCTL_H #include #endif #ifdef HAVE_TERMIOS_H #include #endif #ifdef HAVE_TERMIO_H #include #endif #define MINCOLS 80 #define MINROWS 24 static int neols = -1; static int needresize; static int needscroll; static int skiprest; static int nrows; static int ncols; static char shortmsg[] = "more? (h=help) "; static char longmsg[] = \ "[q or n to stop, y or to go on, to step] more? "; #ifdef HAVE_TERMIO_H static struct termio otty; #endif void setio(int reset) { neols = 0; skiprest = reset; } void setscroll(void) { needscroll = 1; } int resized(void) { return needresize; } /* looks after window resizing for the printing routine */ void onwinch(int dummy) { #ifdef SIGWINCH __pmSetSignalHandler(SIGWINCH, onwinch); #endif needresize = 1; } /* in interactive mode scrolling, if no more wanted skiprest is set */ static void promptformore(void) { int i; int ch; int sts = 1; char c; char *prompt; #ifdef HAVE_TERMIO_H static int first = 1; struct termio ntty; #endif #ifdef HAVE_TERMIO_H if (first) { if (ioctl(0, TCGETA, &otty) < 0) { fprintf(stderr, "%s: TCGETA ioctl failed: %s\n", pmProgname, osstrerror()); exit(1); } first = 0; } /* put terminal into raw mode so we can read input immediately */ memcpy(&ntty, &otty, sizeof(struct termio)); ntty.c_cc[VMIN] = 1; ntty.c_cc[VTIME] = 1; ntty.c_lflag &= ~(ICANON | ECHO); if (ioctl(0, TCSETAW, &ntty) < 0) { fprintf(stderr, "%s: TCSETAW ioctl failed: %s\n", pmProgname, osstrerror()); exit(1); } #endif prompt = shortmsg; while (sts == 1) { putchar('\r'); for (i = 0; i < ncols-1; i++) putchar(' '); putchar('\r'); printf("%s", prompt); fflush(stdout); if (read(0, &c, 1) != 1) { sts = 1; goto reset_tty; } ch = (int)c; switch(ch) { case 'n': /* stop */ case 'q': setio(1); sts = 0; break; case 'y': /* page down */ case ' ': neols = sts = 0; break; case '\n': /* step down */ neols = nrows; sts = 0; break; default: prompt = longmsg; } } reset_tty: #ifdef HAVE_TERMIO_H if (ioctl(0, TCSETAW, &otty) < 0) { fprintf(stderr, "%s: reset TCSETAW ioctl failed: %s\n", pmProgname, osstrerror()); exit(1); } #endif putchar('\r'); for (i = 0; i < ncols-1; i++) putchar(' '); putchar('\r'); fflush(stdout); } /* * generic printing routine which can pause at end of a screenful. * if this returns 1, the user has requested an end to this info, * so the caller must always observe the pprintf return value. */ void pprintf(char *format, ...) { char *p; va_list args; #ifdef TIOCGWINSZ struct winsize geom; #endif static int first = 1; if (first == 1) { /* first time thru */ first = 0; #ifdef TIOCGWINSZ ioctl(0, TIOCGWINSZ, &geom); nrows = (geom.ws_row < MINROWS? MINROWS : geom.ws_row); ncols = (geom.ws_col < MINCOLS? MINCOLS : geom.ws_col); #else nrows = MINROWS; ncols = MINCOLS; #endif } if (skiprest) return; va_start(args, format); if (needscroll) { /* * use the fact that i know we never print more than MINROWS at once * to figure out how many lines we've done before doing the vfprintf */ if (neols >= nrows-1) { promptformore(); if (skiprest) { va_end(args); return; } } for (p = format; *p != '\0'; p++) if (*p == '\n') neols++; vfprintf(stdout, format, args); } else vfprintf(stdout, format, args); va_end(args); if (needresize) { #ifdef HAVE_TIOCGWINSZ ioctl(0, TIOCGWINSZ, &geom); nrows = (geom.ws_row < MINROWS? MINROWS : geom.ws_row); ncols = (geom.ws_col < MINCOLS? MINCOLS : geom.ws_col); #ifdef PMIECONF_DEBUG printf("debug - reset size: cols=%d rows=%d\n", ncols, nrows); #endif #endif needresize = 0; } } /* general error printing routine */ void error(char *format, ...) { va_list args; FILE *f; if (skiprest) return; va_start(args, format); if (needscroll) { f = stdout; fprintf(f, " Error - "); } else { f = stderr; fprintf(f, "%s: error - ", pmProgname); } vfprintf(f, format, args); fprintf(f, "\n"); neols++; va_end(args); } pcp-3.8.12ubuntu1/src/pmieconf/GNUmakefile0000664000000000000000000000437312272262501015252 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs MKFILE_SUBDIRS = cpu filesys memory percpu pernetif global SUBDIRS = $(MKFILE_SUBDIRS) CMDTARGET = pmieconf$(EXECSUFFIX) CFILES = pmieconf.c rules.c io.c HFILES = rules.h PMLOGCONF_TOOLS = $(PCP_VAR_DIR)/config/pmlogconf/tools LSRCFILES = GNUmakefile.rules check-rules pmie_email xtractnames $(RFILES) LLDLIBS = $(PCPLIB) LCFLAGS = -I$(TOPDIR)/src/pmie/src LDIRT = rules local $(CMDTARGET) rate-syscalls \ pmlogconf.tmp pmlogconf \ cpu/GNUmakefile filesys/GNUmakefile memory/GNUmakefile \ percpu/GNUmakefile pernetif/GNUmakefile LDIRDIRT = .pcp default_pcp: $(CMDTARGET) makefiles rules pmlogconf # for src-link-pcp target from buildrules $(SUBDIRS): makefiles $(CMDTARGET) : $(OBJECTS) pmieconf.o rules.o: rules.h .NOTPARALLEL: makefiles: @for d in $(MKFILE_SUBDIRS); do \ rm -f $$d/GNUmakefile; \ cd $$d; \ $(LN_S) ../GNUmakefile.rules GNUmakefile; \ cd ..; \ done rules: $(SUBDIRS) rm -fr rules local; mkdir rules; exit 0 $(SUBDIRS_MAKERULE) $(RUN_IN_BUILD_ENV) ./$(CMDTARGET) -F -r rules -f local pmlogconf: $(SUBDIRS) @rm -f pmlogconf @echo "#pmlogconf-setup 2.0" >pmlogconf @echo "ident metrics used by pmie(1) rules from the pmieconf(1) command" >>pmlogconf @echo "force available" >>pmlogconf $(SUBDIRS_MAKERULE) | grep -v '===' >pmlogconf.tmp @$(PCP_SORT_PROG) -u pmlogconf.tmp | sed -e 's/^/ /' >>pmlogconf install_pcp: install install: default_pcp $(SUBDIRS) $(SUBDIRS_MAKERULE) $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) $(INSTALL) -m 755 pmie_email $(PCP_BINADM_DIR)/pmie_email $(INSTALL) -m 644 pmlogconf $(PMLOGCONF_TOOLS)/pmieconf include $(BUILDRULES) pcp-3.8.12ubuntu1/src/pmieconf/xtractnames0000775000000000000000000000306712272262501015456 0ustar #!/bin/sh # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # Extract metric names (or likely looking ones) from pmieconf files # In comparison to the tools/xtractnames version, this one is a little # more context sensitive, and not PMNS-driven # for d in ../include ../../include /etc do if [ -f $d/pcp.conf ] then . $d/pcp.conf break fi done tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 trap "rm -rf $tmp; exit" 0 1 2 3 15 _usage() { echo "Usage: xtractnames [file ...]" } while getopts "?" c do case $c in ?) _usage exit 1 ;; esac done shift `expr $OPTIND - 1` if [ $# -eq 0 ] then # no args, from stdin cat >$tmp/in set -- $tmp/in fi for file do awk <$file ' /^[ ]*predicate[ ]*=/ { want = 1 } /^[ ]*enabled[ ]*=/ { exit } want == 1 { print }' \ | tr -cs 'a-zA-Z0-9_.' '[\012*]' \ | grep '[a-zA-Z].*\.[a-zA-Z0-9_]' done \ | $PCP_SORT_PROG -u exit pcp-3.8.12ubuntu1/src/pmieconf/pmie_email0000775000000000000000000000341012272262501015216 0ustar #!/bin/sh # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # pmie_email is intended for use in pmie actions to send e-mail. # # the one argument consists of a multi-line message, separated by # '|' characters ... # # "line" 1 - e-mail addressee, as passed to a mail program # "line" 2 - mail Subject: will be "pmie alert: " and then this # text # "line" 2,3,.. - body of the message [optional] # source the PCP configuration environment variables . /etc/pcp.env prog=`basename $0` if [ $# -ne 1 ] then echo "Usage: $prog long|format|message|as|one|argument" exit 1 fi if [ -z "$PCP_MUA" ] ; then for mua in Mail mailx; do if which $mua > /dev/null 2>&1 then PCP_MUA=`which $mua` break fi done fi if [ -z "$PCP_MUA" ] ; then echo "Cannot find a mail program" exit 1 fi cat < #include #include #include #include #include #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "rules.h" #include "stats.h" #define SEP __pmPathSeparator() #define PMIE_FILE "pmieconf-pmie" #define PMIE_VERSION "1" /* local configurations file format version */ #define RULES_FILE "pmieconf-rules" #define RULES_VERSION "1" /* rule description file format version */ #define START_STRING \ "// --- START GENERATED SECTION (do not change this section) ---\n" #define END_STRING \ "// --- END GENERATED SECTION (changes below will be preserved) ---\n" #define TOKEN_LENGTH 2048 /* max length of input token, incl string */ #define LINE_LENGTH 4096 #if !defined(sgi) #define PROC_DIR "/proc" #else #define PROC_DIR "/proc/pinfo" #endif char errmsg[512]; /* error message buffer */ char rulepath[MAXPATHLEN+1]; /* root of rules files */ char pmiefile[MAXPATHLEN+1]; /* pmie configuration file */ char token[TOKEN_LENGTH+1]; rule_t *rulelist; /* global list of rules */ unsigned int rulecount; /* # rule list elements */ rule_t *globals; /* list of atoms with global scope */ #define GLOBAL_LEN 7 static char global_name[] = "global"; /* GLOBAL_LEN chars long */ static char global_data[] = "generic variables applied to all rules"; static char global_help[] = \ "The global variables are used by all rules, but their values can be\n" "overridden at the level of an individual rule or group of rules."; static char yes[] = "yes"; static char no[] = "no"; static char *filename; /* file currently being parsed */ static unsigned int linenum; /* input line number */ symbol_t types[] = { { TYPE_STRING, "string" }, /* predicate data types */ { TYPE_DOUBLE, "double" }, { TYPE_INTEGER, "integer" }, { TYPE_UNSIGNED, "unsigned" }, { TYPE_PERCENT, "percent" }, { TYPE_HOSTLIST, "hostlist" }, { TYPE_INSTLIST, "instlist" }, { TYPE_PRINT, "print" }, /* action types */ { TYPE_SHELL, "shell" }, { TYPE_ALARM, "alarm" }, { TYPE_SYSLOG, "syslog" }, { TYPE_RULE, "rule" }, /* fundamental type */ }; int numtypes = (sizeof(types)/sizeof(types[0])); symbol_t attribs[] = { { ATTRIB_HELP, "help" }, { ATTRIB_MODIFY, "modify" }, { ATTRIB_ENABLED, "enabled" }, { ATTRIB_DISPLAY, "display" }, { ATTRIB_DEFAULT, "default" }, { ATTRIB_DEFAULT, "summary" }, /* alias for "default" */ { ATTRIB_VERSION, "version" }, /* applies to rules only */ { ATTRIB_PREDICATE, "predicate" }, /* applies to rules only */ { ATTRIB_ENUMERATE, "enumerate" }, /* applies to rules only */ }; int numattribs = (sizeof(attribs)/sizeof(attribs[0])); /* pmiefile variables */ static int gotpath; /* state flag - has realpath been run */ static char *save_area; /* holds text to restore on write */ static int sa_size; /* current size of save area */ static int sa_mark = 1; /* number used chars in save area, 1 for \0 */ static dep_t *dlist; /* list of depreciated rules */ static int dcount; /* number of entries in dlist */ static char drulestring[] = "rule definition no longer exists"; static char dverstring[] = "rule version no longer supported"; /* io-related stuff */ extern int resized(void); char *get_pmiefile(void) { return &pmiefile[0]; } char *get_rules(void) { return &rulepath[0]; } char * get_aname(rule_t *r, atom_t *a) { if (r == globals) return &a->name[GLOBAL_LEN]; /* lose "globals." at the start */ return a->name; } /* * #### error reporting routines ### */ static void alloc_error(size_t request) { if (linenum == 0) /* parsing user input, not a file */ snprintf(errmsg, sizeof(errmsg), "insufficient memory for requested operation.\n" " requested: %u bytes", (unsigned int)request); else snprintf(errmsg, sizeof(errmsg), "insufficient memory for parsing file.\n" " requested: %u bytes", (unsigned int)request); } static void parse_error(char *expected, char *found) { if (linenum == 0) /* parsing user input, not a file */ snprintf(errmsg, sizeof(errmsg), "input is invalid - expected %.60s, got \"%.60s\"", expected, found); else snprintf(errmsg, sizeof(errmsg), "file parsing error.\n" " line number: %u (\"%s\")\n" " expected: %.60s\n" " found: %.60s", linenum, filename, expected, found); } /* report attribute format error */ static void type_error(char *attrib, char *expected) { snprintf(errmsg, sizeof(errmsg), "%s's value is invalid.\n" " It should %s.", attrib, expected); } /* * #### search routines ### */ char * find_rule(char *name, rule_t **rule) { int i; for (i = 0; i < rulecount; i++) { if (strcmp(rulelist[i].self.name, name) == 0) { *rule = &rulelist[i]; return NULL; } } snprintf(errmsg, sizeof(errmsg), "rule named \"%s\" does not exist", name); return errmsg; } /* is global attribute 'atom' overridden by a local in 'rule's atom list */ int is_overridden(rule_t *rule, atom_t *atom) { atom_t *aptr; for (aptr = rule->self.next; aptr != NULL; aptr = aptr->next) if (strcmp(get_aname(globals, atom), get_aname(rule, aptr)) == 0) return 1; return 0; } /* tests whether a rule is in the fullname group, if so returns 0 */ int rule_match(char *fullname, char *rulename) { char *s; /* if fullname == rulename, then obvious match */ if (strcmp(fullname, rulename) == 0) return 1; /* fullname may be a group, so match against rulename's groups */ s = strcpy(token, rulename); /* reuse the token buffer */ while ((s = strrchr(s, '.')) != NULL) { s[0] = '\0'; if (strcmp(token, fullname) == 0) return 1; } return 0; } /* find rule or set of rules in given rule or group name */ char * lookup_rules(char *name, rule_t ***rlist, unsigned int *count, int all) { size_t size; rule_t **rptr = NULL; unsigned int i; unsigned int matches = 0; /* search through the rulelist and build up rlist & count */ for (i = 0; i < rulecount; i++) { /* don't match globals if we've been asked for "all" */ if ((all && i > 0) || rule_match(name, rulelist[i].self.name)) { size = (1 + matches) * sizeof(rule_t *); if ((rptr = (rule_t **)realloc(rptr, size)) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory for rule search" " (needed %u bytes)\n", (unsigned int)size); return errmsg; } rptr[matches] = &rulelist[i]; matches++; } } if (matches == 0) { snprintf(errmsg, sizeof(errmsg), "no group or rule names match \"%s\"", name); return errmsg; } *rlist = rptr; /* rlist must be freed by caller */ *count = matches; return NULL; } /* * #### memory management routines ### */ static char * alloc_string(size_t size) { char *p; if ((p = (char *)malloc(size)) == NULL) alloc_error(size); return p; } atom_t * alloc_atom(rule_t *r, atom_t atom, int global) { atom_t *aptr; atom_t *tmp; /* create some space and copy in the atom data we have already */ if ((aptr = (atom_t *)malloc(sizeof(atom_t))) == NULL) { alloc_error(sizeof(atom_t)); return NULL; } *aptr = atom; aptr->next = NULL; /* want contents of this atom, but not rest of list */ if (global) { /* applies to all rules */ r = rulelist; aptr->global = 1; } aptr->next = NULL; /* want contents of this atom, but not rest of list */ /* stick into the list of atoms associated with this rule */ if (r->self.next == NULL) r->self.next = aptr; /* insert at head of list */ else { for (tmp = r->self.next; tmp->next != NULL; tmp = tmp->next); tmp->next = aptr; /* append at tail of list */ } return aptr; } rule_t * alloc_rule(rule_t rule) { size_t size; rule_t *rptr; /* first check that name is unique */ if (find_rule(rule.self.name, &rptr) == NULL) { snprintf(errmsg, sizeof(errmsg), "rule name \"%s\" has already been used, duplicate name" " found in:\n\t\"%.60s\", line %u.", rule.self.name, filename, linenum); return NULL; } size = (rulecount+1) * sizeof(rule_t); if ((rulelist = globals = (rule_t *)realloc(rulelist, size)) == NULL) { alloc_error(size); return NULL; } rptr = &rulelist[rulecount]; *rptr = rule; rulecount++; return rptr; } /* * #### misc parsing routines ### */ /* given string contains no isgraph chars? */ int empty_string(char *s) { char *str = s; while (*str != '\0') { if (isgraph((int)*str)) return 0; str++; } return 1; } /* lookup keyword, returns symbol identifier or -1 if not there */ int map_symbol(symbol_t *table, int tsize, char *symbol) { int i; for (i = 0; i < tsize; i++) { if (strcmp(symbol, table[i].symbol) == 0) return table[i].symbol_id; } return -1; } /* lookup symbol identifier, returns keyword or NULL if not there */ char * map_identifier(symbol_t *table, int tsize, int symbol_id) { int i; for (i = 0; i < tsize; i++) { if (symbol_id == table[i].symbol_id) return table[i].symbol; } return NULL; } /* parse yes/no attribute value; returns 0 no, 1 yes, -1 error */ int map_boolean(char *token) { if (token[0] == 'y') return 1; if (token[0] == 'n') return 0; parse_error("yes or no", token); return -1; } /* scan token from string, return 1 ok, 0 no more, -1 error */ int string_token(char **scan, char *token) { char *s = *scan; char *t = token; while (! isgraph((int)*s) || *s == ',') { if (*s == '\0') return 0; s++; } if (*s == '\'') { /* quoted token */ *t++ = *s++; while (*s != '\'') { if (*s == '\\') s++; if (*s == '\0') return -1; *t++ = *s++; } *t++ = *s++; } else { /* ordinary token */ while (isgraph((int)*s) && *s != ',') *t++ = *s++; } *t = '\0'; *scan = s; return 1; } /* check proposed value for type, returns NULL/failure message */ char * validate(int type, char *name, char *value) { int x; char *s; double d; /* * Below we don't care about the value from strtol() and strtoul() * we're interested in updating the pointer "s". The messiness is * thanks to gcc and glibc ... strtol() amd strtoul() are marked * __attribute__((warn_unused_result)) ... to avoid warnings on all * platforms, assign to dummy variables that are explicitly marked * unused. */ long l __attribute__((unused)); unsigned long ul __attribute__((unused)); switch (type) { case TYPE_RULE: case TYPE_STRING: break; case TYPE_SHELL: case TYPE_PRINT: case TYPE_ALARM: case TYPE_SYSLOG: if (map_boolean(value) < 0) return errmsg; break; case TYPE_DOUBLE: d = strtod(value, &s); if (*s != '\0') { type_error(name, "be a real number"); return errmsg; } break; case TYPE_INTEGER: l = strtol(value, &s, 10); if (*s != '\0') { type_error(name, "be an integer number"); return errmsg; } break; case TYPE_UNSIGNED: ul = strtoul(value, &s, 10); if (*s != '\0') { type_error(name, "be a positive integer number"); return errmsg; } break; case TYPE_PERCENT: if ((s = strrchr(value, '%')) != NULL) /* % as final char is OK */ *s = '\0'; d = strtod(value, &s); if (*s != '\0' || d < 0.0 || d > 100.0) { type_error(name, "be a percentage between 0.0 and 100.0"); return errmsg; } break; case TYPE_HOSTLIST: case TYPE_INSTLIST: if ((s = alloc_string(strlen(value)+1)) == NULL) return errmsg; while ((x = string_token(&value, s)) > 0) ; if (x < 0) { type_error(name, "include a closing single quote"); return errmsg; } free(s); break; } return NULL; } /* * printable string form of atoms value, returns NULL terminated string * pp (pretty print) argument valued 1 means use format appropriate for * a user interface */ char * value_string(atom_t *atom, int pp) { int key; int i = 0; int start = 1; int quoted = 0; char *s; switch (atom->type) { case TYPE_RULE: case TYPE_STRING: if (pp) { snprintf(token, sizeof(token), "\"%s\"", atom->data); return token; } return atom->data; case TYPE_PRINT: case TYPE_SHELL: case TYPE_ALARM: case TYPE_SYSLOG: return atom->enabled? yes : no; case TYPE_HOSTLIST: case TYPE_INSTLIST: if (pp) token[i++] = '"'; if (atom->type == TYPE_HOSTLIST) key = ':'; else key = '#'; for (s = atom->data; *s != '\0'; s++) { if (!isspace((int)*s)) { if (start && !pp) { token[i++] = key; token[i++] = '\''; if (*s != '\'') quoted = 0; else if (!quoted) { quoted = 1; start = 0; continue; } } else if (*s == '\'' && !start && !pp) quoted = 0; start = 0; } else if (!pp && !quoted) { quoted = 0; if (i > 0 && token[i-1] != '\'') token[i++] = '\''; start = 1; } token[i++] = *s; } if (!pp && i > 0 && token[i-1] != '\'') token[i++] = '\''; else if (pp) token[i++] = '"'; token[i++] = '\0'; return token; case TYPE_DOUBLE: snprintf(token, sizeof(token), "%g", strtod(atom->data, &s)); return token; case TYPE_INTEGER: snprintf(token, sizeof(token), "%ld", strtol(atom->data, &s, 10)); return token; case TYPE_UNSIGNED: snprintf(token, sizeof(token), "%lu", strtoul(atom->data, &s, 10)); return token; case TYPE_PERCENT: snprintf(token, sizeof(token), "%g%c", strtod(atom->data, &s), pp? '%':'\0'); return token; } return NULL; } /* #### rules file parsing routines #### */ /* returns attrib number or -1 if not an attribute */ int is_attribute(char *aname) { return map_symbol(attribs, numattribs, aname); } /* returns attrib value as a string, or NULL on error */ char * get_attribute(char *attrib, atom_t *atom) { char *value = NULL; switch (map_symbol(attribs, numattribs, attrib)) { case ATTRIB_HELP: value = atom->help; break; case ATTRIB_MODIFY: if (atom->modify) value = yes; else value = no; break; case ATTRIB_ENABLED: if (atom->enabled) value = yes; else value = no; break; case ATTRIB_DISPLAY: if (atom->display) value = yes; else value = no; break; case ATTRIB_DEFAULT: if (IS_ACTION(atom->type)) { if (atom->enabled) value = yes; else value = no; } else value = atom->data; break; } return value; } /* * #### sorting routines ### */ static int compare_rules(const void *a, const void *b) { rule_t *ra = (rule_t *)a; rule_t *rb = (rule_t *)b; return strcmp(ra->self.name, rb->self.name); } void sort_rules(void) { /* start at second array element so that 'globals' is skipped */ qsort(&rulelist[1], rulecount-1, sizeof(rule_t), compare_rules); } /* revert to default rules file values for a single atom (enabled/data/both) */ static char * atom_defaults(atom_t *a, atom_t *p, char *param) { int sts = map_symbol(attribs, numattribs, param); if (sts != -1) { /* an attribute - is it valid? */ if (sts == ATTRIB_ENABLED) { if (a->global) { /* this was a global atom promoted to local */ if (p) p->next = a->next; free(a->name); free(a); a = NULL; } else { a->enabled = a->denabled; /* reset enabled flag */ a->changed = 0; } return NULL; } snprintf(errmsg, sizeof(errmsg), "variable \"%s\" is inappropriate for this " "operation", param); return errmsg; } else { if (a->global) { /* this was a global atom promoted to local */ if (p) p->next = a->next; free(a->name); free(a); a = NULL; } else { if (strcmp(a->data, a->ddata) != 0) { /* need to alloc mem? */ free(a->data); if ((a->data = strdup(a->ddata)) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory to set defaults"); return errmsg; } } a->enabled = a->denabled; a->changed = 0; } return NULL; } } /* revert to default rules values for a rule or attribute (enabled/data/both) */ char * rule_defaults(rule_t *rule, char *param) { atom_t *aptr; atom_t *prev = NULL; if (param == NULL) { /* for this rule, reset all attributes */ for (aptr = &rule->self; aptr != NULL; aptr = aptr->next) { atom_defaults(aptr, prev, aptr->name); prev = aptr; } } else { /* find the associated atom, and just reset that */ if (map_symbol(attribs, numattribs, param) != -1) { rule->self.enabled = rule->self.denabled; /* reset enabled flag */ rule->self.changed = 0; return NULL; } for (aptr = &rule->self; aptr != NULL; aptr = aptr->next) { if (strcmp(get_aname(rule, aptr), param) == 0) return atom_defaults(aptr, prev, param); prev = aptr; } } return NULL; } /* set an attribute field in an atom; returns NULL/failure message */ static char * set_attribute(rule_t *r, atom_t *atom, int attrib, char *value, int changed) { char *s; int sts; switch(attrib) { case ATTRIB_HELP: if (empty_string(value)) { parse_error("non-empty string for help", value); return errmsg; } if ((s = alloc_string(strlen(value)+1)) == NULL) return errmsg; atom->help = strcpy(s, value); break; case ATTRIB_MODIFY: if ((sts = map_boolean(value)) < 0) return errmsg; atom->modify = sts; break; case ATTRIB_ENABLED: if ((sts = map_boolean(value)) < 0) return errmsg; if (!changed) /* initially, set enabled to default */ atom->denabled = sts; atom->enabled = sts; break; case ATTRIB_DISPLAY: if ((sts = map_boolean(value)) < 0) return errmsg; atom->display = sts; break; case ATTRIB_DEFAULT: if (IS_ACTION(atom->type) && changed) { if ((sts = map_boolean(value)) < 0) return errmsg; atom->enabled = sts; } else { /* actions from rules file (string) handled here too... */ if (!IS_ACTION(atom->type) && (validate(atom->type, get_aname(r, atom), value) != NULL)) return errmsg; sts = strlen(value)+1; if ((s = alloc_string(sts)) == NULL) return errmsg; atom->data = strcpy(s, value); if (!changed) { /* initially, set the default as well */ if ((s = alloc_string(sts)) == NULL) { free(atom->data); atom->data = NULL; return errmsg; } atom->ddata = strcpy(s, value); } } break; } if (changed) atom->changed = 1; return NULL; } /* set a parameter field in a rule; returns NULL/failure message */ char * value_change(rule_t *rule, char *param, char *value) { int sts; atom_t *aptr; if ((sts = map_symbol(attribs, numattribs, param)) != -1) return set_attribute(rule, &rule->self, sts, value, 1); else { for (aptr = rule->self.next; aptr != NULL; aptr = aptr->next) { if (strcmp(get_aname(rule, aptr), param) == 0) return set_attribute(rule, aptr, ATTRIB_DEFAULT, value, 1); } /* if found in globals, promote the global to customised local.. */ for (aptr = globals->self.next; aptr != NULL; aptr = aptr->next) { if (strcmp(get_aname(globals, aptr), param) == 0) { if ((aptr = alloc_atom(rule, *aptr, 0)) == NULL) return errmsg; if ((aptr->name = strdup(get_aname(globals, aptr))) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory to change value"); return errmsg; } return set_attribute(globals, aptr, ATTRIB_DEFAULT, value, 1); } } } snprintf(errmsg, sizeof(errmsg), "variable \"%s\" is undefined for rule %s", param, rule->self.name); return errmsg; } static char * append_string(char *s, char *append, int len) { size_t size = (strlen(s) + len + 1); #ifdef PMIECONF_DEBUG fprintf(stderr, "debug - \"%s\" + (%d)\"%s\" = (%d chars)\n", s, len, append, size); #endif if ((s = (char *)realloc(s, size)) == NULL) return NULL; strncat(s, append, len); s[size-1] = '\0'; return s; } /* fix up value strings by doing variable expansion */ char * dollar_expand(rule_t *rule, char *string, int pp) { atom_t *aptr; char *tmp, *r; char *sptr; char *s; char *mark = NULL; char localbuf[TOKEN_LENGTH]; #ifdef PMIECONF_DEBUG fprintf(stderr, "debug - dollar_expand %s in %s\n", string, rule->self.name); #endif if ((s = (char *)malloc(sizeof(char))) == NULL) return NULL; *s = '\0'; for (sptr = string; *sptr != '\0'; sptr++) { if (*sptr == '\\' && *(sptr+1) == '$') { /* skip escaped $ */ if ((s = append_string(s, sptr+1, 1)) == NULL) return NULL; sptr++; /* move passed the escaped char */ continue; } if (*sptr == '$') { if (mark == NULL) /* start of an expansion section */ mark = sptr+1; else { /* end of an expansion section */ /* look through atom list & if not there search globally */ strncpy(localbuf, mark, sptr - mark); localbuf[sptr - mark] = '\0'; mark = NULL; #ifdef PMIECONF_DEBUG fprintf(stderr, "debug - expand localbuf: %s\n", localbuf); #endif if ((tmp = get_attribute(localbuf, &rule->self)) == NULL) { for (aptr = &rule->self; tmp == NULL && aptr != NULL; aptr = aptr->next) if (strcmp(get_aname(rule, aptr), localbuf) == 0) tmp = value_string(aptr, pp); for (aptr = globals->self.next; tmp == NULL && aptr != NULL; aptr = aptr->next) if (strcmp(get_aname(globals, aptr), localbuf) == 0) tmp = value_string(aptr, pp); #ifdef PMIECONF_DEBUG fprintf(stderr, "debug - expanded localbuf? %s\n", tmp); #endif if (tmp == NULL) { snprintf(errmsg, sizeof(errmsg), "variable \"$%s$\" in %s is undefined", localbuf, rule->self.name); free(s); return NULL; } } if (tmp != NULL) { if ((r = dollar_expand(rule, tmp, pp)) == NULL) { free(s); return NULL; } if ((s = append_string(s, r, strlen(r))) == NULL) { free(r); return NULL; } free(r); } } } else if (mark == NULL) { /* need memory to hold this character */ if ((s = append_string(s, sptr, 1)) == NULL) return NULL; } } if (mark != NULL) /* no terminating '$' */ s = append_string(s, mark, strlen(mark)); #ifdef PMIECONF_DEBUG fprintf(stderr, "debug - expanded '%s' to '%s'\n", string, s); #endif return s; } /* * #### main parsing routines ### */ /* need a SIGWINCH-aware read routine for interactive pmieconf */ static int mygetc(FILE *f) { int c; for (;;) { setoserror(0); c = getc(f); /* did we get told to resize the window during read? */ if (c == -1 && oserror() == EINTR && resized() == 1) continue; /* signal handled, try reading again */ break; } return c; } /* * skip leading white space and comments, return first character in next token * or zero on end of file */ static int prime_next_pread(FILE *f, int end) { int c; do { c = mygetc(f); if (c == '#') do { c = mygetc(f); } while (c != '\n' && c != end && c != EOF); if (c == end) return 0; else if (c == EOF) return -2; if (c == '\n' && end != '\n') linenum++; } while (!isgraph(c)); return c; } /* * read next input token; returns 1 ok, 0 end, -1 error, -2 EOF (if end!=EOF) * nb: `end' can be either EOL or EOF, depending on use of this routine */ int read_token(FILE *f, char *token, int token_length, int end) { int c; int n = 0; switch (c = prime_next_pread(f, end)) { case 0: /* end */ case -2: /* EOF */ return c; case '"': /* scan string */ c = mygetc(f); while (c != '"') { if (c == '\\') c = mygetc(f); if (c == end || c == EOF || n == token_length) { token[n] = '\0'; parse_error("end-of-string", token); return -1; } if (c == '\n' && end != '\n') linenum++; token[n++] = c; c = mygetc(f); } break; case ';': case '=': token[n++] = c; /* single char token */ break; default: /* some other token */ while (isgraph(c)) { if (c == '=' || c == ';') { ungetc(c, f); break; } if (n == token_length) { token[n] = '\0'; parse_error("end-of-token", token); return -1; } token[n++] = c; c = mygetc(f); if (c == end || c == EOF) ungetc(c, f); } if (c == '\n' && end != '\n') linenum++; break; } token[n] = '\0'; return 1; } /* * get attribute list part of an atom; returns -1 on error, 0 on reaching * the end of the attribute list, and 1 at end of each attribute. */ static int read_next_attribute(FILE *f, char **attr, char **value) { int sts; if ((sts = read_token(f, token, TOKEN_LENGTH, EOF)) <= 0) { if (sts == 0) parse_error("attribute or ';'", "end-of-file"); return -1; } if (token[0] == ';') return 0; if (map_symbol(attribs, numattribs, token) < 0) { parse_error("attribute keyword", token); return -1; } if ((*attr = alloc_string(strlen(token)+1)) == NULL) return -1; strcpy(*attr, token); if ((sts = read_token(f, token, TOKEN_LENGTH, EOF)) <= 0 || token[0] != '=') { if (sts == 0) parse_error("=", "end-of-file"); else parse_error("=", token); free(*attr); return -1; } if ((sts = read_token(f, token, TOKEN_LENGTH, EOF)) <= 0) { if (sts == 0) parse_error("attribute value", "end-of-file"); else parse_error("attribute value", token); free(*attr); return -1; } if ((*value = alloc_string(strlen(token)+1)) == NULL) { free(*attr); return -1; } strcpy(*value, token); return 1; } /* parse an atom, return NULL/failure message */ static char * read_atom(FILE *f, rule_t *r, char *name, int type, int global) { int sts; int attrib; char *attr; char *value; atom_t atom; memset(&atom, 0, sizeof(atom_t)); atom.name = name; atom.type = type; atom.enabled = atom.display = atom.modify = 1; /* defaults */ for (;;) { if ((sts = read_next_attribute(f, &attr, &value)) < 0) return errmsg; else if (sts == 0) { /* end of parameter list */ if (alloc_atom(r, atom, global) == NULL) return errmsg; break; } else { if ((attrib = map_symbol(attribs, numattribs, attr)) < 0) { parse_error("attribute keyword", attr); goto fail; } if (set_attribute(r, &atom, attrib, value, 0) != NULL) goto fail; free(attr); free(value); } } return NULL; fail: free(attr); free(value); return errmsg; } /* parse type-identifier pair, return NULL/failure message */ static char * read_type(FILE *f, rule_t *r, int *type, int *global, char **name) { int sts; /* read type - rule, percent, double, unsigned, string... */ if ((sts = read_token(f, token, TOKEN_LENGTH, EOF)) < 0) return errmsg; else if (sts == 0) return NULL; if ((*type = map_symbol(types, numtypes, token)) < 0) { parse_error("type keyword", token); return errmsg; } /* read name identifying this rule/atom of type '*type' */ if ((sts = read_token(f, token, TOKEN_LENGTH, EOF)) <= 0) return errmsg; if ((*name = alloc_string(strlen(token)+1)) == NULL) return errmsg; strcpy(*name, token); *global = (strncmp(*name, "global.", GLOBAL_LEN) == 0)? 1 : 0; /* do some simple validity checks */ if (IS_RULE(*type) && strncmp(*name, global_name, GLOBAL_LEN-1) == 0) { snprintf(errmsg, sizeof(errmsg), "rule name may not be \"%s\" - this is reserved", global_name); free(*name); return errmsg; } if (r == NULL) { /* any rule defined yet? - simple validity checks */ if (*global && IS_RULE(*type)) { snprintf(errmsg, sizeof(errmsg), "rules not allowed in global group: \"%s\"", *name); free(*name); return errmsg; } else if (!*global && !IS_RULE(*type)) { /* not global, and no rule */ snprintf(errmsg, sizeof(errmsg), "no rule defined, cannot make sense of %s \"%s\"" " without one\n line number: %u (\"%s\")\n", types[*type].symbol, *name, linenum, filename); free(*name); return errmsg; } } return NULL; } /* set an attribute field in an atom; returns NULL/failure message */ static char * set_rule_attribute(rule_t *rule, int attrib, char *value) { char *s; if (attrib == ATTRIB_PREDICATE) { if ((s = alloc_string(strlen(value)+1)) == NULL) return errmsg; rule->predicate = strcpy(s, value); return NULL; } if (attrib == ATTRIB_ENUMERATE) { if ((s = alloc_string(strlen(value)+1)) == NULL) return errmsg; rule->enumerate = strcpy(s, value); return NULL; } else if (attrib == ATTRIB_VERSION) { rule->version = strtoul(value, &s, 10); if (*s != '\0') { parse_error("version number", "be a positive integer number"); return errmsg; } return NULL; } /* else */ return set_attribute(rule, &rule->self, attrib, value, 0); } /* parse a single "rule" expression, return NULL/failure message */ static char * read_rule(FILE *f, rule_t **r, char *name) { int sts; int attrib; char *attr; char *value; rule_t rule; memset(&rule, 0, sizeof(rule_t)); rule.self.name = name; rule.self.type = TYPE_RULE; rule.version = rule.self.enabled = rule.self.display = 1; /* defaults */ for (;;) { if ((sts = read_next_attribute(f, &attr, &value)) < 0) return errmsg; else if (sts == 0) { /* end of attribute list */ if ((*r = alloc_rule(rule)) == NULL) return errmsg; break; } else { if ((attrib = map_symbol(attribs, numattribs, attr)) < 0) { parse_error("rule attribute keyword", attr); goto fail; } if (set_rule_attribute(&rule, attrib, value) != NULL) goto fail; free(attr); free(value); } } return NULL; fail: free(attr); free(value); return errmsg; } /* parse rule description file; returns NULL/failure message */ static char * read_all_rules(FILE *f) { rule_t *rule = NULL; /* current rule */ char *name = NULL; int type = 0; int global = 0; /* rule files have quite a simple grammar, along these lines: TYPE identifier [ ATTRIB '=' value ]* ';' */ for (;;) { if (read_type(f, rule, &type, &global, &name) != NULL) return errmsg; if (feof(f)) /* end of file reached without error */ break; if (type == TYPE_RULE) { if (read_rule(f, &rule, name) != NULL) return errmsg; } else { if (read_atom(f, rule, name, type, global) != NULL) return errmsg; } } return NULL; } /* * validate header of rule description file, return NULL/failure message */ static char * read_pheader(FILE *f) { int c; c = getc(f); if (c != '#' || read_token(f, token, TOKEN_LENGTH, EOF) != 1 || strcmp(token, RULES_FILE) != 0 || read_token(f, token, TOKEN_LENGTH, EOF) != 1) { snprintf(errmsg, sizeof(errmsg), "%s is not a rule description file (bad header)\n" "found \"%s\", expected \"%s\"", filename, token, RULES_FILE); return errmsg; } else if (strcmp(token, RULES_VERSION) != 0) { /* one version only */ snprintf(errmsg, sizeof(errmsg), "unknown version number in %s: \"%s\" (expected %s)", filename, token, RULES_VERSION); return errmsg; } return NULL; } /* * builds up rule data structures for all rule files in given directory * and all its subdirectories, returns NULL/failure message */ char * read_rule_subdir(char *subdir) { struct stat sbuf; struct dirent *dp; FILE *fp; DIR *dirp; char fullpath[MAXPATHLEN+1]; if (stat(subdir, &sbuf) < 0) { snprintf(errmsg, sizeof(errmsg), "cannot stat %s: %s", subdir, osstrerror()); return errmsg; } if (!S_ISDIR(sbuf.st_mode)) { if ((fp = fopen(subdir, "r")) == NULL) { snprintf(errmsg, sizeof(errmsg), "cannot open %s: %s", subdir, osstrerror()); return errmsg; } linenum = 1; filename = subdir; if (read_pheader(fp) == NULL) { if (read_all_rules(fp) != NULL) { fclose(fp); return errmsg; } } #ifdef PMIECONF_DEBUG else { fprintf(stderr, "debug - %s isn't a pmie rule file: %s\n", filename, errmsg); } #endif fclose(fp); } else { /* iterate through the rules directory and for each subdirectory */ /* fetch all the rules along with associated parameters & values */ if ((dirp = opendir(subdir)) == NULL) { snprintf(errmsg, sizeof(errmsg), "cannot opendir %s: %s", subdir, osstrerror()); return errmsg; } while ((dp = readdir(dirp)) != NULL) { /* groups */ if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) continue; snprintf(fullpath, sizeof(fullpath), "%s%c%s", subdir, SEP, dp->d_name); if (read_rule_subdir(fullpath) != NULL) { /* recurse */ closedir(dirp); return errmsg; } } closedir(dirp); } return NULL; } /* ##### pmiefile parsing routines #### */ /* returns NULL on successfully adding rule to list, else failure message */ char * deprecate_rule(char *name, unsigned int version, int type) { int index; /* first check to see if this rule is deprecated already */ for (index = 0; index < dcount; index++) { if (strcmp(dlist[index].name, name) == 0 && dlist[index].version == version) return NULL; } /* get the memory we need & then keep a copy of deprecated rule info */ if ((dlist = (dep_t *)realloc(dlist, (dcount+1)*sizeof(dep_t))) == NULL || (dlist[dcount].name = strdup(name)) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory to deprecate rule %s", name); return errmsg; } dlist[dcount].type = type; dlist[dcount].version = version; if (type == DEPRECATE_NORULE) dlist[dcount].reason = drulestring; else dlist[dcount].reason = dverstring; dcount++; return NULL; } /* * makes list of deprecated rules available to caller (for warning message) * nb: called following a pmiefile write to see what was deprecated during * that write - subsequent writing of this pmiefile should not deprecate * anything (deprecations done once & not again). caller must free list. */ int fetch_deprecated(dep_t **list) { int sts; *list = dlist; sts = dcount; dcount = 0; return sts; } /* merges local customisations back into the rules atom list */ static char * merge_local(unsigned int version, char *name, char *attrib, char *value) { atom_t *aptr; rule_t *rule; int a; /* first find the rule to which this local belongs, then figure out what sort of attribute this really is, and finally merge the customisation back into the values in the rules attribs. */ if (find_rule(name, &rule) != NULL) /* in pmiefile but not rules */ return NULL; /* this will be deprecated later */ else if (rule->version != version) /* no rule for this version */ return NULL; /* this will be deprecated later */ if ((a = is_attribute(attrib)) != -1) return set_attribute(rule, &rule->self, a, value, 1); else { /* search through this rules list of atoms */ for (aptr = rule->self.next; aptr != NULL; aptr = aptr->next) { if (strcmp(get_aname(rule, aptr), attrib) == 0) return set_attribute(rule, aptr, ATTRIB_DEFAULT, value, 1); } for (aptr = globals->self.next; aptr != NULL; aptr = aptr->next) { if (strcmp(get_aname(globals, aptr), attrib) == 0) { /* promote global to become a local */ if ((aptr = alloc_atom(rule, *aptr, 0)) == NULL) return errmsg; if ((aptr->name = strdup(get_aname(globals, aptr))) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory to change value"); return errmsg; } return set_attribute(globals, aptr, ATTRIB_DEFAULT, value, 1); } } } snprintf(errmsg, sizeof(errmsg), "variable \"%s\" is undefined for rule %s", attrib, name); return errmsg; } /* * #### produce pmie configuration file from rules ### */ char * action_string(int type) { switch (type) { case TYPE_PRINT: return "print"; case TYPE_SHELL: return "shell"; case TYPE_ALARM: return "alarm"; case TYPE_SYSLOG: return "syslog"; } return NULL; } static int expand_action(FILE *f, int count, rule_t *rule, atom_t *atom) { char *p; char *str; if (IS_ACTION(atom->type) && atom->enabled) { if ((str = dollar_expand(rule, " $holdoff$ ", 0)) == NULL) return count; if (count == 0) fprintf(f, " -> "); else fprintf(f, "\n & "); fprintf(f, "%s", action_string(atom->type)); fprintf(f, "%s", str); free(str); if ((str = dollar_expand(rule, atom->data, 0)) == NULL) { fprintf(stderr, "Warning - failed to expand action for rule %s\n" " string: \"%s\"\n", rule->self.name, atom->data); /* keep going - too late to bail out without file corruption */ } #ifdef PMIECONF_DEBUG else { fprintf(stderr, "expanded action= \"%s\"\n", str); } #endif fputc('"', f); for (p = str; p != NULL && *p; p++) { /* expand the '^' character */ if (*p == '/' && *(p+1) == '^') { fputc(*p, f); p++; fputc(*p, f); p++; } else if (*p == '^') fputs("\" \"", f); else fputc(*p, f); } fputc('"', f); if (str != NULL) free(str); return count + 1; } return count; } /* * this struct and the enumerate function are used only in generate_rules() * and the enumerate() routines, for enumeration of either a hostlist or an * instlist */ typedef struct { atom_t *atom; int nvalues; char **valuelist; char *restore; } enumlist_t; static enumlist_t *list; static int nlistitems; static int writecount; /* * expands and writes out a single rule, and optionally the delta * note: in the single rule case (not enumerated), we absolutely * must write out the delta every time */ static char * write_rule(FILE *f, rule_t *rule) { atom_t *aptr; char *dgen = NULL; /* holds generated "delta" */ char *pgen; /* holds generated "predicate" */ int actions = 0; #ifdef PMIECONF_DEBUG fprintf(stderr, "debug - writing rule %s\n", rule->self.name); #endif if (writecount == 0 && (dgen = dollar_expand(rule, "$delta$", 0)) == NULL) { snprintf(errmsg, sizeof(errmsg), "\"$delta$\" variable expansion failed for rule %s", rule->self.name); return errmsg; } if ((pgen = dollar_expand(rule, rule->predicate, 0)) == NULL) { snprintf(errmsg, sizeof(errmsg), "\"$predicate$\" variable expansion failed " "for rule %s", rule->self.name); return errmsg; } if (writecount == 0) { fprintf(f, "// %u %s\ndelta = %s;\n%s = \n", rule->version, rule->self.name, dgen, rule->self.name); free(dgen); } else /* we're enumerating, need to differentiate rule names */ fprintf(f, "%s%u = \n", rule->self.name, writecount); fputs(pgen, f); free(pgen); for (aptr = rule->self.next; aptr != NULL; aptr = aptr->next) actions = expand_action(f, actions, rule, aptr); for (aptr = globals->self.next; aptr != NULL; aptr = aptr->next) actions = expand_action(f, actions, rule, aptr); fprintf(f, ";\n\n"); writecount++; return NULL; } /* parses the "enumerate" value string passed in thru the rules file */ char * parse_enumerate(rule_t *rule) { atom_t *ap; char *p = rule->enumerate; int needsave = 0; /* should we save this variable name yet? */ int i = 0; #ifdef PMIECONF_DEBUG fprintf(stderr, "debug - parse_enumerate called for %s\n", rule->self.name); #endif nlistitems = 0; list = NULL; while (*p != '\0') { if (!isspace((int)*p)) { needsave = 1; token[i++] = *p; } p++; if ((isspace((int)*p) && needsave) || *p == '\0') { token[i] = '\0'; i = 0; if (map_symbol(attribs, numattribs, token) != -1) { snprintf(errmsg, sizeof(errmsg), "cannot enumerate rule %s using attribute" " \"%s\"", rule->self.name, token); return errmsg; } else { for (ap = rule->self.next; ap != NULL; ap = ap->next) if (strcmp(get_aname(rule, ap), token) == 0) goto foundname; for (ap = globals->self.next; ap != NULL; ap = ap->next) if (strcmp(get_aname(globals, ap), token) == 0) goto foundname; snprintf(errmsg, sizeof(errmsg), "variable \"%s\" undefined for enumerated" " rule %s", token, rule->self.name); return errmsg; } foundname: if (ap->type != TYPE_HOSTLIST && ap->type != TYPE_INSTLIST) { snprintf(errmsg, sizeof(errmsg), "rules file error - \"$%s$\" in \"enumerate\" " "clause of rule %s is not of type hostlist or instlist", token, rule->self.name); return errmsg; } /* increase size of list & keep a copy of the variable name */ if ((list = realloc(list, (nlistitems+1)*sizeof(enumlist_t))) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory to write rules"); return errmsg; } list[nlistitems].atom = ap; list[nlistitems].nvalues = 0; list[nlistitems].valuelist = NULL; list[nlistitems].restore = NULL; #ifdef PMIECONF_DEBUG fprintf(stderr, "debug - variable %s added to enum list (#%d)\n", list[nlistitems].atom->name, nlistitems); #endif nlistitems++; needsave = 0; } } return NULL; } /* * converts a host/inst list into individual elements, overwrites liststr * (turns all spaces to NULLs to mark string ends - reduces mallocing) */ char ** get_listitems(char *liststr, int *count) { char **result = NULL; char *p = liststr; int keepwhite = 0; int startagain = 0; /* set to signify new list item has started */ int ptrcount = 0; if ((result = realloc(result, (ptrcount+1) * sizeof(char *))) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory to get list elements"); return NULL; } result[ptrcount++] = p; while (*p != '\0') { if (!isspace((int)*p) || keepwhite) { if (startagain) { result = realloc(result, (ptrcount+1) * sizeof(char *)); if (result == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory to get list elements"); return NULL; } result[ptrcount++] = p; startagain = 0; } if (*p == '\\') p++; else if (*p == '\'') keepwhite = !keepwhite; } else { *p = '\0'; startagain = 1; } p++; } #ifdef PMIECONF_DEBUG fputs("debug - instances are:", stderr); for (keepwhite = 0; keepwhite < ptrcount; keepwhite++) fprintf(stderr, " %s", result[keepwhite]); fputs("\n", stderr); #endif *count = ptrcount; return result; } /* expands variables from the "enumerate" string in the rules file */ char * expand_enumerate(rule_t *rule) { int i, j; char *p; #ifdef PMIECONF_DEBUG fprintf(stderr, "debug - expanding enum variables for rule %s\n", rule->self.name); #endif for (i = 0; i < nlistitems; i++) { if ((p = dollar_expand(rule, list[i].atom->data, 0)) == NULL) return errmsg; if ((list[i].valuelist = realloc(list[i].valuelist, sizeof(char *) * (list[i].nvalues + 1))) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory for rule enumeration"); free(p); return errmsg; } if ((list[i].valuelist = get_listitems(p, &j)) == NULL) { free(p); return errmsg; } list[i].nvalues = j; #ifdef PMIECONF_DEBUG fprintf(stderr, "debug - %s value list:", list[i].atom->name); for (j = 0; j < list[i].nvalues; j++) fprintf(stderr, " %s", list[i].valuelist[j]); fprintf(stderr, "\n"); #endif } return NULL; } void enumerate(FILE *f, rule_t *r, enumlist_t *listoffset, int wssize, char **wset) { int i; if (wssize < nlistitems) { for (i = 0; i < listoffset->nvalues; i++) { /* add current word to word set, and move down a level */ wset[wssize] = listoffset->valuelist[i]; enumerate(f, r, &list[wssize+1], wssize+1, wset); } } else { /* have a full set, generate rule */ #ifdef PMIECONF_DEBUG for (i = 0; i < wssize; i++) printf("%s=%s ", list[i].atom->name, wset[i]); printf("\n"); #endif for (i = 0; i < wssize; i++) { list[i].restore = list[i].atom->data; list[i].atom->data = wset[i]; } write_rule(f, r); for (i = 0; i < wssize; i++) list[i].atom->data = list[i].restore; } } /* generate pmie rules for rule, returns rule string/NULL */ static char * generate_rules(FILE *f, rule_t *rule) { int i; if (rule->self.enabled == 0) return NULL; if (rule->enumerate == NULL) { writecount = 0; write_rule(f, rule); } else { char **workingset; /* holds current variable values set */ #ifdef PMIECONF_DEBUG fprintf(stderr, "debug - generating enumerated rule %s\n", rule->self.name); #endif /* "enumerate" attrib is a space-separated list of variables */ /* 1.create a list of variable info structs (name->valuelist) */ /* 2.recurse thru lists, when each set built, write out rule */ if ((parse_enumerate(rule)) != NULL) return errmsg; if ((expand_enumerate(rule)) != NULL) return errmsg; if ((workingset = malloc(nlistitems * sizeof(char*))) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory to generate rules"); return errmsg; } writecount = 0; enumerate(f, rule, list, 0, workingset); free(workingset); for (i = 0; i < nlistitems; i++) free(list[i].valuelist); /* alloc'd by dollar_expand */ free(list); } return NULL; } /* generate local configuration changes, returns rule string/NULL */ static char * generate_pmiefile(FILE *f, rule_t *rule) { atom_t *aptr; for (aptr = &rule->self; aptr != NULL; aptr = aptr->next) { if (aptr->changed == 0) continue; if (IS_RULE(aptr->type)) { fprintf(f, "// %u %s %s = %s\n", rule->version, get_aname(rule, aptr), "enabled", rule->self.enabled? "yes" : "no"); } else { fprintf(f, "// %u %s %s = %s\n", rule->version, rule->self.name, get_aname(rule, aptr), value_string(aptr, 1)); } } return NULL; } /* generate pmie rules and write to file, returns NULL/failure message */ char * write_pmiefile(char *program, int autocreate) { time_t now = time(NULL); char *p, *msg = NULL; char buf[MAXPATHLEN+10]; char *fname = get_pmiefile(); FILE *fp; int i; /* create full path to file if it doesn't exist */ if ((p = strrchr(fname, '/')) != NULL) { struct stat sbuf; *p = '\0'; /* p is the dirname of fname */ if (stat(fname, &sbuf) < 0) { snprintf(buf, sizeof(buf), "/bin/mkdir -p %s", fname); if (system(buf) < 0) { snprintf(errmsg, sizeof(errmsg), "failed to create directory \"%s\"", p); return errmsg; } } else if (!S_ISDIR(sbuf.st_mode)) { snprintf(errmsg, sizeof(errmsg), "\"%s\" exists and is not a directory", p); return errmsg; } fname[strlen(fname)] = '/'; /* stitch together */ } if ((fp = fopen(fname, "w")) == NULL) { snprintf(errmsg, sizeof(errmsg), "cannot write file %s: %s", fname, osstrerror()); return errmsg; } else if (!gotpath) { strcpy(token, fname); if (realpath(token, pmiefile) == NULL) { fclose(fp); snprintf(errmsg, sizeof(errmsg), "failed to resolve %s realpath: %s", token, osstrerror()); return errmsg; } gotpath = 1; } fprintf(fp, "// %s %s %s\n", PMIE_FILE, PMIE_VERSION, get_rules()); for (i = 0; i < rulecount; ++i) if ((msg = generate_pmiefile(fp, &rulelist[i])) != NULL) goto imouttahere; fputs("// end\n//\n", fp); fprintf(fp, "%s// %sgenerated by %s on: %s//\n\n", START_STRING, autocreate ? "Auto-" : " ", program, ctime(&now)); for (i = 1; i < rulecount; ++i) /* 1: start _after_ globals */ if ((msg = generate_rules(fp, &rulelist[i])) != NULL) goto imouttahere; /* write user-modifications area */ fprintf(fp, END_STRING); /* finally any other local changes */ if (save_area != NULL) fputs(save_area, fp); imouttahere: fclose(fp); return msg; } /* * #### pmiefile manipulation routines ### */ /* * skip leading white space and comments, return first character in next token * or zero on end of file */ static int prime_next_lread(FILE *f) { int c; do { c = getc(f); if (c == EOF) return 0; if (c == '\n') { linenum++; if (getc(f) != '/') return 0; if (getc(f) != '/') return 0; } } while (! isgraph(c)); return c; } /* read next input token; returns 1 ok, 0 eof, -1 error */ static int read_ltoken(FILE *f) { int c; int n = 0; switch (c = prime_next_lread(f)) { case 0: /* EOF */ return 0; case '"': /* scan string */ c = getc(f); while (c != '"') { if (c == '\\') c = getc(f); if (c == EOF || n == TOKEN_LENGTH) { token[n] = '\0'; parse_error("end-of-string", token); return -1; } if (c == '\n') { token[n] = '\0'; parse_error("end-of-string", "end-of-line"); return -1; } token[n++] = c; c = getc(f); } break; case '=': token[n++] = c; /* single char token */ break; default: /* some other token */ while (isgraph(c)) { if (c == '=') { ungetc(c, f); break; } if (n == TOKEN_LENGTH) { token[n] = '\0'; parse_error("end-of-token", token); return -1; } token[n++] = c; c = getc(f); } if (c == '\n') { linenum++; if (strncmp(token, "end", 3) == 0) break; if (getc(f) != '/') return 0; if (getc(f) != '/') return 0; } break; } token[n] = '\0'; return 1; } /* allocates memory & appends a string to the save area */ char * save_area_append(char *str) { int size = strlen(str); while ( (size+1) >= (sa_size-sa_mark) ) { sa_size += 256; /* increase area by 256 bytes at a time */ if ((save_area = (char *)realloc(save_area, sa_size)) == NULL) return NULL; } if (sa_mark == 1) save_area = strcpy(save_area, str); else save_area = strcat(save_area, str); sa_mark += size; return save_area; } /* read and save text which is to be restored on pmiefile write */ static char * read_restore(FILE *f) { unsigned int version; rule_t *rule; char buf[LINE_LENGTH]; int saverule = 0; int saveall = 0; do { if (fgets(buf, LINE_LENGTH, f) == NULL) break; if (!saveall) { /* not yet at start of explicit "save" position */ if (strcmp(buf, END_STRING) == 0) saveall = 1; else if (sscanf(buf, "// %u %s\n", &version, token) == 2) { /* * where the rule has disappeared or its version does not match * the one in the pmiefile, add the rule name & version to list * of rules to be deprecated (i.e. moved to the "save area") */ /* check that we still have this rule definition */ if (find_rule(token, &rule) != NULL) { /* not found! */ snprintf(buf, sizeof(buf), "// %u %s (deprecated, %s)\n", version, token, drulestring); deprecate_rule(token, version, DEPRECATE_NORULE); saverule = 1; } else if (rule->version != version) { /* not supported! */ snprintf(buf, sizeof(buf), "// %u %s (deprecated, %s)\n", version, token, dverstring); deprecate_rule(token, version, DEPRECATE_VERSION); saverule = 1; } else saverule = 0; } if (!saveall && saverule) { if (save_area_append("// ") == NULL || save_area_append(buf) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory to deprecate a rule"); return errmsg; } } } else if (save_area_append(buf) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory to preserve save area"); return errmsg; } } while (!feof(f)); return NULL; } /* read custom values, return NULL/failure message */ static char * read_locals(FILE *f) { int sts; char *rule; char *attrib; char *value; unsigned int version; /* general pmiefile format: version rulename attribute = value */ for (;;) { if ((sts = read_ltoken(f)) < 0) return errmsg; else if (sts == 0) { parse_error("rule identifier or \"end\" symbol", "end-of-file"); return errmsg; } if (strcmp("end", token) == 0) break; /* read the version number for this rule */ version = strtoul(token, &value, 10); if (*value != '\0') { parse_error("version number", token); return errmsg; } /* read the name of the rule */ if ((sts = read_ltoken(f)) != 1 || (rule = alloc_string(strlen(token)+1)) == NULL) { if (sts == 0) parse_error("rule name", token); return errmsg; } strcpy(rule, token); /* read the rule attribute component */ if ((sts = read_ltoken(f)) != 1 || (attrib = alloc_string(strlen(token)+1)) == NULL) { free(rule); if (sts == 0) parse_error("rule attribute", token); return errmsg; } strcpy(attrib, token); if ((sts = read_ltoken(f)) != 1 || strcmp("=", token) != 0) { free(rule); free(attrib); if (sts == 0) parse_error("'=' symbol", "end-of-file"); return errmsg; } /* read the modified value of this attribute */ if ((sts = read_ltoken(f)) != 1 || (value = alloc_string(strlen(token)+1)) == NULL) { free(rule); free(attrib); if (sts == 0) parse_error("rule attribute value", "end-of-file"); return errmsg; } strcpy(value, token); if (merge_local(version, rule, attrib, value) != NULL) { free(rule); free(attrib); free(value); return errmsg; } free(rule); free(attrib); free(value); /* no longer need these */ } return NULL; } /* validate header of rule customizations file, return NULL/failure message */ static char * read_lheader(FILE *f, char **proot) { if (read_ltoken(f) != 1 || strcmp(token, "//") || read_ltoken(f) != 1 || strcmp(token, PMIE_FILE) || read_ltoken(f) != 1) { snprintf(errmsg, sizeof(errmsg), "%s is not a rule customization file (bad header)", filename); return errmsg; } else if (strcmp(token, PMIE_VERSION) != 0) { /* one version only */ snprintf(errmsg, sizeof(errmsg), "unknown version number in %s: \"%s\" (expected %s)", filename, token, PMIE_VERSION); return errmsg; } else if (read_ltoken(f) != 1) { snprintf(errmsg, sizeof(errmsg), "no rules path specified in %s after version number", filename); return errmsg; } *proot = token; return NULL; } /* * read the pmiefile format into global data structures */ char * read_pmiefile(char *warning, size_t warnlen) { char *tmp = NULL; char *p, *home; FILE *f; char *rule_path_sep; if ((f = fopen(get_pmiefile(), "r")) == NULL) { if (oserror() == ENOENT) return NULL; snprintf(errmsg, sizeof(errmsg), "cannot open %s: %s", get_pmiefile(), osstrerror()); return errmsg; } linenum = 1; filename = get_pmiefile(); if (read_lheader(f, &tmp) != NULL) { fclose(f); return errmsg; } /* check that we have access to all components of the path */ if ((home = strdup(tmp)) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory for pmie file parsing"); return errmsg; } #ifdef IS_MINGW rule_path_sep = ";"; #else rule_path_sep = ":"; #endif p = strtok(home, rule_path_sep); while (p != NULL) { if (access(p, F_OK) < 0) { free(home); snprintf(errmsg, sizeof(errmsg), "cannot access rules path component: \"%s\"", p); return errmsg; } p = strtok(NULL, rule_path_sep); } free(home); if (strcmp(get_rules(), tmp) != 0) snprintf(warning, warnlen, "warning - pmie configuration file \"%s\"\n" " may not have been built using rules path:\n\t\"%s\"\n" " (originally built using \"%s\")", filename, get_rules(), tmp); tmp = NULL; if (read_locals(f) != NULL || read_restore(f) != NULL) tmp = errmsg; fclose(f); return tmp; } /* #### setup global data structures; return NULL/failure message #### */ char * initialise(char *in_rules, char *in_pmie, char *warning, size_t warnlen) { char *p; char *home; rule_t global; char *rule_path_sep; /* setup pointers to the configuration files */ #ifdef IS_MINGW if ((home = getenv("USERPROFILE")) == NULL) { snprintf(errmsg, sizeof(errmsg), "USERPROFILE undefined in environment"); return errmsg; } if (in_pmie == NULL) snprintf(pmiefile, sizeof(pmiefile), "%s\\%s", home, DEFAULT_USER_PMIE); else strcpy(pmiefile, in_pmie); rule_path_sep = ";"; #else if (getuid() == 0) { if (in_pmie == NULL) snprintf(pmiefile, sizeof(pmiefile), "%s%c%s", pmGetConfig("PCP_SYSCONF_DIR"), SEP, DEFAULT_ROOT_PMIE); else if (realpath(in_pmie, pmiefile) == NULL && oserror() != ENOENT) { snprintf(errmsg, sizeof(errmsg), "failed to resolve realpath for %s: %s", in_pmie, osstrerror()); return errmsg; } else if (oserror() != ENOENT) gotpath = 1; } else { if ((home = getenv("HOME")) == NULL) { snprintf(errmsg, sizeof(errmsg), "$HOME undefined in environment"); return errmsg; } if (in_pmie == NULL) snprintf(pmiefile, sizeof(pmiefile), "%s%c%s", home, SEP, DEFAULT_USER_PMIE); else strcpy(pmiefile, in_pmie); } rule_path_sep = ":"; #endif if (in_rules == NULL) { if ((p = getenv("PMIECONF_PATH")) == NULL) snprintf(rulepath, sizeof(rulepath), "%s%c%s", pmGetConfig("PCP_VAR_DIR"), SEP, DEFAULT_RULES); else strcpy(rulepath, p); } else snprintf(rulepath, sizeof(rulepath), "%s", in_rules); memset(&global, 0, sizeof(rule_t)); global.self.name = global_name; global.self.data = global_data; global.self.help = global_help; global.self.global = 1; if (alloc_rule(global) == NULL) { /* 1st rule holds global (fake rule) */ snprintf(errmsg, sizeof(errmsg), "insufficient memory for global parameters"); return errmsg; } if ((home = strdup(rulepath)) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory for rules path parsing"); return errmsg; } p = strtok(home, rule_path_sep); while (p != NULL) { if (read_rule_subdir(p) != NULL) { free(home); return errmsg; } p = strtok(NULL, rule_path_sep); } free(home); if (read_pmiefile(warning, warnlen) != NULL) return errmsg; linenum = 0; /* finished all parsing */ return NULL; } /* iterate through the pmie status directory and find running pmies */ char * lookup_processes(int *count, char ***processes) { int fd; int running = 0; DIR *dirp; void *ptr; char proc[MAXPATHLEN+1]; char **proc_list = NULL; size_t size; pmiestats_t *stats; struct dirent *dp; struct stat statbuf; int sep = __pmPathSeparator(); snprintf(proc, sizeof(proc), "%s%c%s", pmGetConfig("PCP_TMP_DIR"), sep, PMIE_SUBDIR); if ((dirp = opendir(proc)) == NULL) { snprintf(errmsg, sizeof(errmsg), "cannot opendir %s: %s", proc, osstrerror()); return NULL; } while ((dp = readdir(dirp)) != NULL) { /* bunch of checks to find valid pmie data files... */ if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) continue; snprintf(proc, sizeof(proc), "%s%c%s", PROC_DIR, sep, dp->d_name); /* check /proc */ if (access(proc, F_OK) < 0) continue; /* process has exited */ snprintf(proc, sizeof(proc), "%s%c%s%c%s", pmGetConfig("PCP_TMP_DIR"), sep, PMIE_SUBDIR, sep, dp->d_name); if (stat(proc, &statbuf) < 0) continue; if (statbuf.st_size != sizeof(pmiestats_t)) continue; if ((fd = open(proc, O_RDONLY)) < 0) continue; ptr = __pmMemoryMap(fd, statbuf.st_size, 0); close(fd); if (ptr == NULL) continue; stats = (pmiestats_t *)ptr; if (strcmp(stats->config, get_pmiefile()) != 0) continue; size = (1 + running) * sizeof(char *); if ((proc_list = (char **)realloc(proc_list, size)) == NULL || (proc_list[running] = strdup(dp->d_name)) == NULL) { snprintf(errmsg, sizeof(errmsg), "insufficient memory for process search"); if (proc_list) free(proc_list); closedir(dirp); close(fd); return errmsg; } running++; } closedir(dirp); *count = running; *processes = proc_list; return NULL; } pcp-3.8.12ubuntu1/src/pmieconf/cpu/0000775000000000000000000000000012272262620013762 5ustar pcp-3.8.12ubuntu1/src/pmieconf/cpu/util0000664000000000000000000000234112272262501014660 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule cpu.util summary = "$rule$" predicate = "some_host ( 100 * ( kernel.all.cpu.user $hosts$ + kernel.all.cpu.sys $hosts$ + kernel.all.cpu.intr $hosts$ ) / hinv.ncpu $hosts$ > $threshold$ )" enabled = yes version = 1 help = "The average processor utilization over all CPUs exceeded threshold percent during the last sample interval."; string rule default = "High average processor utilization" modify = no display = no; percent threshold default = 90 help = "Threshold percentage for CPU saturation, in the range 0 (idle) to 100 (completely busy), independent of the number of CPUs."; string action_expand default = %v%util@%h display = no modify = no; string email_expand default = "host: %h average CPU utilization: %v%" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x200045" display = no modify = no; # for EnlightenDSM integration: string enln_test default = cpu.util display = no modify = no; string enln_units default = %util display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/cpu/context_switch0000664000000000000000000000216712272262501016756 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule cpu.context_switch summary = "$rule$" predicate = "some_host ( kernel.all.pswitch $hosts$ > hinv.ncpu $hosts$ * $threshold$ count/sec )" enabled = yes version = 1 help = "Average number of context switches per CPU per second exceeded threshold over the past sample interval."; string rule default = "High aggregate context switch rate" modify = no display = no; double threshold default = 4000 help = "The threshold number of process context switches per second."; string action_expand default = %vctxsw/s@%h display = no modify = no; string email_expand default = "host: %h aggregate context switches: %v/sec" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x20005C" display = no modify = no; # for EnlightenDSM integration: string enln_test default = cpu.context_switch display = no modify = no; string enln_units default = ctxsw/s display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/cpu/excess_fpe0000664000000000000000000000316012272262501016027 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule cpu.excess_fpe summary = "$rule$" enumerate = hosts predicate = "some_host ( some_inst ( ( 100 * kernel.percpu.cpu.sys $hosts$ > $systime_util$ ) && kernel.percpu.syscall $hosts$ < $syscall_rate$ ) )" enabled = no version = 1 help = "This predicate attempts to detect processes generating very large numbers of floating point exceptions (FPEs). Characteristic of this situation is heavy system time coupled with low system call rates (exceptions are delivered through the kernel to the process, taking some system time, but no system call is serviced on the application's behalf)."; string rule default = "Possible high floating point exception rate" modify = no display = no; percent systime_util default = 50 help = "Threshold percentage for kernel CPU utilization, in the range 0 (idle) to 100 (completely busy)"; double syscall_rate default = 100 help = "Threshold system call rate (calls per second) below which something is deemed amiss."; string action_expand default = %v%sys[%i]@%h display = no modify = no; string email_expand default = "host: %h CPU: %i system mode: %v% and low syscall rate" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x200041" display = no modify = no; # for EnlightenDSM integration: string enln_test default = cpu.excess_fpe display = no modify = no; string enln_units default = %sys[%i] display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/cpu/syscall0000664000000000000000000000323012272262501015353 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule cpu.syscall summary = "$rule$" predicate = "some_host ( kernel.all.syscall $hosts$ > hinv.ncpu $hosts$ * $threshold$ count/sec )" enabled = yes version = 1 help = "Average number of system calls per CPU per second exceeded threshold over the past sample interval."; string rule default = "High aggregate system call rate" modify = no display = no; double threshold default = 10000 help = "The threshold of system calls per second per CPU. The appropriate value here is a function of the processor type and the workload, but here are some indicative figures of sustained system call rates for a single process: getpid() - 380000 syscalls/sec lseek() to start of file - 280000 syscalls/sec gettimeofday() - 200000 syscalls/sec read() at end of file - 83000 syscalls/sec file creat() and close() - 65000 syscalls/sec socket(), connect() and close() - 7000 syscalls/sec (generated using an otherwise idle system with 180MHz R10000 processors)."; string action_expand default = %vscall/s@%h display = no modify = no; string email_expand default = "host: %h aggregate syscalls/sec: %v" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x200043" display = no modify = no; # for EnlightenDSM integration: string enln_test default = cpu.syscall display = no modify = no; string enln_units default = scall/s display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/cpu/localdefs0000664000000000000000000000212612272262501015640 0ustar ALL_RULES = util syscall context_switch system load_average \ excess_fpe low_util LOCAL_RULES = $(ALL_RULES) # Metrics missing from Linux # # rule: excess_fpe # kernel.percpu.syscall -12357 Unknown metric name # # rule: syscall # kernel.all.syscall -12357 Unknown metric name # ifeq ($(TARGET_OS), linux) LOCAL_RULES = util context_switch system load_average low_util endif # Metrics missing from Mac OS X # # rule: util # kernel.all.cpu.intr -12357 Unknown metric name # # rule: syscall # kernel.all.syscall -12357 Unknown metric name # # rule: context_switch # kernel.all.pswitch -12357 Unknown metric name # # rule: excess_fpe # kernel.percpu.syscall -12357 Unknown metric name # # rule: low_util # kernel.all.cpu.intr -12357 Unknown metric name # ifeq ($(TARGET_OS), darwin) LOCAL_RULES = system load_average endif # Metrics missing from Solaris # # rule: low_util # kernel.all.cpu.intr -12357 Unknown metric name # # rule: util # kernel.all.cpu.intr -12357 Unknown metric name # ifeq ($(TARGET_OS), solaris) LOCAL_RULES = syscall context_switch system load_average excess_fpe endif pcp-3.8.12ubuntu1/src/pmieconf/cpu/system0000664000000000000000000000326312272262501015233 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule cpu.system summary = "$rule$" predicate = "some_host ( // first term is always true, but provides %v for actions ... ( 100 * kernel.all.cpu.sys $hosts$ / hinv.ncpu $hosts$ ) > 0 && 100 * ( kernel.all.cpu.user $hosts$ + kernel.all.cpu.sys $hosts$ ) > $busy$ * hinv.ncpu $hosts$ && 100 * kernel.all.cpu.sys $hosts$ / ( kernel.all.cpu.user $hosts$ + kernel.all.cpu.sys $hosts$ ) > $threshold$ )" enabled = yes version = 1 help = "Over the last sample interval, the average utilization per CPU was busy percent or more, and the ratio of system time to busy time exceeded threshold percent."; string rule default = "Busy executing in system mode" modify = no display = no; percent busy default = 70 help = "Busy percentage for average CPU utilization, in the range 0 (idle) to 100 (completely busy), independent of the number of CPUs."; percent threshold default = 75 help = "Threshold percentage for system time as a fraction of the non-idle CPU time, in the range 0 (no system time) to 100 (all system time), independent of the number of CPUs."; string action_expand default = %v%sys@%h display = no modify = no; string email_expand default = "host: %h system mode: %v%" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x200044" display = no modify = no; # for EnlightenDSM integration: string enln_test default = cpu.system display = no modify = no; string enln_units default = %sys display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/cpu/load_average0000664000000000000000000000343712272262501016323 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule cpu.load_average summary = "$rule$" predicate = "some_host ( // threshold scales with the number of CPUs (works better for // large systems) and there is an absolute lower bound, // especially for small systems kernel.all.load $hosts$ #'1 minute' > hinv.ncpu $hosts$ * $per_cpu_load$ && kernel.all.load $hosts$ #'1 minute' > $min_load$ )" enabled = yes version = 1 help = "The current 1-minute load average is higher than the larger of min_load and ( per_cpu_load times the number of CPUs ). The load average measures the number of processes that are running, runnable or soon to be runnable (i.e. in short term sleep)."; string rule default = "High 1-minute load average" modify = no display = no; double per_cpu_load default = 3 help = "The multiplier per CPU for the minimum load to make the rule true, when expressed as a function of the number of CPUs. Typically in the range 1.0 (very light load) to 8.0 (very heavy load )."; double min_load default = 4 help = "The minimum load average before the rule is true. Most useful for single-processor systems or where the desired threshold is absolute, rather than a function of the number of CPUs."; string action_expand default = %vload@%h display = no modify = no; string email_expand default = "host: %h load average: %v" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x200042" display = no modify = no; # for EnlightenDSM integration: string enln_test default = cpu.load_average display = no modify = no; string enln_units default = load display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/cpu/low_util0000664000000000000000000000323012272262501015537 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule cpu.low_util summary = "$rule$" predicate = "some_host ( // kernel.all.cpu metrics count up to 1 second of CPU time // per second per CPU 100 * ( kernel.all.cpu.user $hosts$ + kernel.all.cpu.sys $hosts$ + kernel.all.cpu.intr $hosts$ ) / hinv.ncpu $hosts$ < $threshold$ )" enabled = no version = 1 help = "The average processor utilization over all CPUs was below threshold percent during the last sample interval. This rule is effectively the opposite of cpu.util and is disabled by default - it is only useful in specialized environments where, for example, processing is batch oriented and low processor utilization is indicative of poor use of system resources. In such a situation the cpu.low_util rule should be enabled, and cpu.util disabled."; string rule default = "Low average processor utilization" modify = no display = no; percent threshold default = 25 help = "Lower bound percentage for CPU utilization, in the range 0 (idle) to 100 (completely busy), independent of the number of CPUs."; string action_expand default = %v%util@%h display = no modify = no; string email_expand default = "host: %h average CPU utilization: %v%" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x20005E" display = no modify = no; # for EnlightenDSM integration: string enln_test default = cpu.low_util display = no modify = no; string enln_units default = %util display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/memory/0000775000000000000000000000000012272262620014503 5ustar pcp-3.8.12ubuntu1/src/pmieconf/memory/exhausted0000664000000000000000000000332112272262501016415 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # rule memory.exhausted summary = "$rule$" # first conjunct for %v, second is real condition... predicate = "some_host ( ( avg_sample ( swap.pagesout $hosts$ @0..9 ) ) > 0 && $pct$ %_sample swap.pagesout $hosts$ @0..9 >= $threshold$ )" enabled = yes version = 1 help = "The system is swapping modified pages out of main memory to the swap partitions, and has been doing this at the rate of at least threshold pages swapped out per second for at least pct of the last 10 samples, ie. sustained page out activity."; double threshold default = 5 help = "Threshold rate of pages swapped out per second."; percent pct default = 30 help = "Percentage of the last 10 observations with at least threshold pages swapped out per second required to make the rule true."; string rule default = "Severe demand for real memory" modify = no display = no; string action_expand default = "%vpgsout/s@%h" modify = no display = no; string email_expand default = "host: %h recent average: %v pageouts/sec" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x20004B" display = no modify = no; # for HP OpenView integration: string ov_severity display = no default = "Critical"; # for CA/Unicenter TNG integration: string tngfw_color display = no default = "Red"; # for EnlightenDSM integration: string enln_test default = memory.exhausted display = no modify = no; string enln_units default = pgsout/s display = no modify = no; unsigned enln_severity display = no default = 5; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmieconf/memory/localdefs0000664000000000000000000000106112272262501016356 0ustar ALL_RULES = swap_low exhausted LOCAL_RULES = $(ALL_RULES) # Metrics missing from Mac OS X # # rule: swap_low # swap.free -12357 Unknown metric name # swap.length -12357 Unknown metric name # # rule: exhausted # swap.pagesout -12357 Unknown metric name # ifeq ($(TARGET_OS), darwin) LOCAL_RULES = endif # Metrics missing from Solaris # # rule: exhausted # swap.pagesout -12357 Unknown metric name # # rule: swap_low # swap.free -12357 Unknown metric name # swap.length -12357 Unknown metric name # ifeq ($(TARGET_OS), solaris) LOCAL_RULES = endif pcp-3.8.12ubuntu1/src/pmieconf/memory/swap_low0000664000000000000000000000311312272262501016255 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) # # Based on a rule originally developed by Kevin Wang at Silicon Graphics # rule memory.swap_low summary = "$rule$" predicate = "some_host ( ( 100 * ( swap.free $hosts$ / swap.length $hosts$ ) ) < $threshold$ && swap.length $hosts$ > 0 // ensure swap in use )" enabled = no version = 1 help = "There is only threshold percent swap space remaining - the system may soon run out of virtual memory. Reduce the number and size of the running programs or add more swap(1) space before it completely runs out."; percent threshold default = 10 help = "Threshold percent of total swap space which is free, in the range 0 (none free) to 100 (all swap is unused)."; string rule default = "Low free swap space" modify = no display = no; string action_expand default = "%v%free@%h" modify = no display = no; string email_expand default = "host: %h free swap space: %v%" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x20004C" display = no modify = no; # for HP OpenView integration: string ov_severity display = no default = "Critical"; # for CA/Unicenter TNG integration: string tngfw_color display = no default = "Red"; # for EnlightenDSM integration: string enln_test default = memory.swap_low display = no modify = no; string enln_units default = %free display = no modify = no; unsigned enln_severity display = no default = 5; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmsocks/0000775000000000000000000000000012272262620013052 5ustar pcp-3.8.12ubuntu1/src/pmsocks/tsocks.sh0000775000000000000000000000300212272262501014710 0ustar #!/bin/sh # # Copyright (c) 1995-1999,2008 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Dynamically sockify the argument program using tsocks # from http://www.progsoc.uts.edu.au/~delius/ # prog=`basename $0` if [ $# -eq 0 -o "X$1" = "X-?" ] then echo "Usage: $prog [path]program [args ...]" exit 1 fi if [ ! -f /etc/tsocks.conf -o ! -f /usr/lib/libtsocks.so ] then echo "$prog: Error \"tsocks\" doesn't seem to be installed." echo "*** Get it from http://www.progsoc.uts.edu.au/~delius/" exit 1 fi target=`which "$1" 2>/dev/null | grep -v "^alias "` if [ -z "$target" -o ! -x "$target" ] then echo "$prog: Error: \"$1\": Command not found." exit 1 fi shift args="" for arg do args="$args \"$1\"" shift done LD_PRELOAD=/usr/lib/libtsocks.so export LD_PRELOAD eval exec $target $args pcp-3.8.12ubuntu1/src/pmsocks/GNUmakefile0000664000000000000000000000175712272262501015134 0ustar # # Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs LSRCFILES = tsocks.sh default : include $(BUILDRULES) install : default $(INSTALL) -m 755 tsocks.sh $(PCP_BIN_DIR)/pmsocks default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmie/0000775000000000000000000000000012272262620012325 5ustar pcp-3.8.12ubuntu1/src/pmie/crontab.in0000664000000000000000000000043412272262501014304 0ustar # # Performance Co-Pilot crontab entries for a monitored site # with one or more pmie instances running # # daily processing of pmie logs 08 0 * * * @user@ @path@/pmie_daily # every 30 minutes, check pmie instances are running 28,58 * * * * @user@ @path@/pmie_check -C pcp-3.8.12ubuntu1/src/pmie/src/0000775000000000000000000000000012272262620013114 5ustar pcp-3.8.12ubuntu1/src/pmie/src/act.sk0000664000000000000000000002037412272262501014226 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*********************************************************************** * skeleton: act.sk - actions * ***********************************************************************/ /* * operator: actAnd */ void actAnd(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; EVALARG(arg1) EVALARG(arg2) *(Truth *)x->ring = (*(Truth *)arg1->ring == TRUE) && (*(Truth *)arg2->ring == TRUE); } /* * operator: actOr */ void actOr(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; EVALARG(arg1) if (*(Truth *)arg1->ring == FALSE) { EVALARG(arg2) *(Truth *)x->ring = *(Truth *)arg2->ring; } else *(Truth *)x->ring = TRUE; } /* * operator: actShell */ void actShell(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; #ifndef IS_MINGW pid_t pid; #endif int sts; if ((arg2 == NULL) || (x->smpls[0].stamp == 0) || (now >= *(RealTime *)arg2->ring + x->smpls[0].stamp)) { EVALARG(arg1) fflush(stdout); fflush(stderr); #ifdef IS_MINGW putenv("IFS=\t\n"); sts = system((char *)arg1->ring); need_wait = 1; if (sts < 0) { __pmNotifyErr(LOG_ERR, "spawn for shell failed\n"); *(Truth *)x->ring = FALSE; } else { *(Truth *)x->ring = TRUE; x->smpls[0].stamp = now; x->valid = 0; } #else /*POSIX*/ pid = fork(); if (pid == 0) { /* child, run the command */ setsid(); putenv("PATH=/usr/sbin:/sbin:/usr/bin:/bin"); putenv("IFS=\t\n"); sts = system((char *)arg1->ring); _exit(WEXITSTATUS(sts)); /* avoid atexit() handler */ } else if (pid > 0) { /* parent, wait for child to exit to catch status */ #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "actShell: fork: pid=%" FMT_PID "\n", pid); } #endif sts = waitpid(pid, &x->valid, 0); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "actShell: wait: pid=%" FMT_PID " status=0x%x", pid, x->valid); if (WIFEXITED(x->valid)) fprintf(stderr, " exit=%d", WEXITSTATUS(x->valid)); if (WIFSIGNALED(x->valid)) fprintf(stderr, " signal=%d", WTERMSIG(x->valid)); fprintf(stderr, " (wait returns %d)\n", sts); } #endif if (WIFEXITED(x->valid)) x->valid = WEXITSTATUS(x->valid); else /* if no exit, then assume non-zero exit, hence failure! */ x->valid = 1; if (sts < 0 || x->valid != 0) *(Truth *)x->ring = FALSE; else *(Truth *)x->ring = TRUE; x->smpls[0].stamp = now; } else { __pmNotifyErr(LOG_ERR, "fork for shell failed\n"); *(Truth *)x->ring = FALSE; } #endif perf->actions++; } } /* * operator: actAlarm */ void actAlarm(Expr *x) { static char *alarmv[] = { NULL, /* path to PCP_XCONFIRM_PROG inserted here */ "-header", "Performance Co-Pilot Alarm", "-b", "Cancel", "-icon", "warning", "-t", NULL, "-t", NULL, NULL}; char ctime[26]; Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; time_t clock; int sts; if (alarmv[0] == NULL) { /* * one trip to get path for xconfirm(1) */ alarmv[0] = pmGetConfig("PCP_XCONFIRM_PROG"); if (strcmp(alarmv[0], "") == 0) { __pmNotifyErr(LOG_ERR, "PCP_XCONFIRM_PROG not found, using echo(1)\n"); alarmv[0] = "/bin/echo"; } } #ifndef IS_MINGW /* if old alarm still active, don't post new one */ if (x->valid != 0) { pid_t pid; pid = waitpid((pid_t)x->valid, &sts, WNOHANG); if (pid <= 0) { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "actAlarm: wait: pid=%d not done (wait returns %" FMT_PID ")\n", x->valid, pid); } #endif return; } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "actAlarm: wait: pid=%d done status=0x%x", x->valid, sts); if (WIFEXITED(sts)) fprintf(stderr, " exit=%d", WEXITSTATUS(sts)); if (WIFSIGNALED(sts)) fprintf(stderr, " signal=%d", WTERMSIG(sts)); fprintf(stderr, " (wait returns %" FMT_PID ")\n", pid); } #endif x->valid = 0; } #endif if ((arg2 == NULL) || (x->smpls[0].stamp == 0) || (now >= *(RealTime *)arg2->ring + x->smpls[0].stamp)) { EVALARG(arg1) clock = (time_t)(now+0.5); pmCtime(&clock, ctime); #ifdef IS_MINGW alarmv[8] = ctime; alarmv[10] = (char *)arg1->ring; sts = spawnvp(_P_DETACH, alarmv[0], (const char * const *)alarmv); if (sts < 0) { __pmNotifyErr(LOG_ERR, "spawn for PCP_XCONFIRM_PROG failed\n"); *(Truth *)x->ring = FALSE; } else { *(Truth *)x->ring = TRUE; x->smpls[0].stamp = now; x->valid = 0; } #else sts = fork(); if (sts == 0) { alarmv[8] = ctime; alarmv[10] = (char *)arg1->ring; setsid(); if (strcmp(alarmv[0], "/bin/echo") != 0) { /* only echo needs stdio, when xconfirm cannot be found */ fclose(stdin); fclose(stdout); fclose(stderr); } execvp(alarmv[0], alarmv); _exit(1); /* avoid atexit() handler */ } else if (sts > 0) { need_wait = 1; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "actAlarm: fork: pid=%d\n", sts); } #endif x->valid = sts; *(Truth *)x->ring = TRUE; x->smpls[0].stamp = now; } else { __pmNotifyErr(LOG_ERR, "fork for alarm failed\n"); *(Truth *)x->ring = FALSE; } #endif perf->actions++; } } /* * operator: actSyslog */ void actSyslog(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; int *pri; char *tag; if ((arg2 == NULL) || (x->smpls[0].stamp == 0) || (now >= *(RealTime *)arg2->ring + x->smpls[0].stamp)) { pri = (int *)arg1->arg2->ring; tag = &((char *)arg1->arg2->ring)[sizeof(int)]; EVALARG(arg1) openlog(tag, LOG_PID|LOG_CONS, LOG_DAEMON); if (arg1->ring == NULL) syslog(*pri, "%s", ""); else syslog(*pri, "%s", (char *)arg1->ring); closelog(); *(Truth *)x->ring = TRUE; x->smpls[0].stamp = now; perf->actions++; } } /* * operator: actPrint */ void actPrint(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; time_t clock = (time_t)now; char bfr[26]; if ((arg2 == NULL) || (x->smpls[0].stamp == 0) || (now >= *(RealTime *)arg2->ring + x->smpls[0].stamp)) { EVALARG(arg1) *(Truth *)x->ring = TRUE; x->smpls[0].stamp = now; pmCtime(&clock, bfr); bfr[24] = '\0'; printf("%s: %s\n", bfr, (char *)arg1->ring); fflush(stdout); perf->actions++; } } /* * operator: actStomp */ void actStomp(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; if ((arg2 == NULL) || (x->smpls[0].stamp == 0) || (now >= *(RealTime *)arg2->ring + x->smpls[0].stamp)) { EVALARG(arg1) x->smpls[0].stamp = now; if (stompSend((const char *)arg1->ring) != 0) *(Truth *)x->ring = FALSE; else *(Truth *)x->ring = TRUE; perf->actions++; } } /* * action argument handling ... including %h, %v and %i substitution */ void actArg(Expr *x) { Expr *sp = x->arg1; char *string = (char *)0; size_t length = 0; for (sp = x->arg1; sp != NULL; sp = sp->arg1) length = formatSatisfyingValue((char *)sp->ring, length, &string); newStringBfr(x, length, string); } /* * fake actions for archive mode */ void actFake(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; time_t clock = (time_t)now; char bfr[26]; if ((arg2 == NULL) || (x->smpls[0].stamp == 0) || (now >= *(RealTime *)arg2->ring + x->smpls[0].stamp)) { EVALARG(arg1) *(Truth *)x->ring = TRUE; x->smpls[0].stamp = now; pmCtime(&clock, bfr); bfr[24] = '\0'; printf("%s %s: %s\n", opStrings(x->op), bfr, (char *)arg1->ring); } } pcp-3.8.12ubuntu1/src/pmie/src/logger.h0000664000000000000000000000455612272262501014554 0ustar /* * Provided by Alan Hoyt as part of the Solaris port, * this code came from * http://www.mit.edu/afs/sipb/service/logging/arch/sun4x_55/build/zephyr/clients/syslogd/syslogd.c-test1 * * Copyright (c) 1983, 1988 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #define NOPRI 0x10 /* the "no priority" priority */ #define LOG_MAKEPRI(f,p) (((f) << 3) + (p)) #define LOG_MARK LOG_MAKEPRI(LOG_NFACILITIES, 0) /* mark "facility" */ #ifndef LOG_PRIMASK #define LOG_PRIMASK 0x07 #endif #ifndef LOG_FACMASK #define LOG_FACMASK 0x03f8 #endif typedef struct code { char *c_name; int c_val; } CODE; struct code prioritynames[] = { { "panic", LOG_EMERG }, { "alert", LOG_ALERT }, { "crit", LOG_CRIT }, { "error", LOG_ERR }, { "warning", LOG_WARNING }, { "notice", LOG_NOTICE }, { "info", LOG_INFO }, { "debug", LOG_DEBUG }, { "none", NOPRI }, { "emerg", LOG_EMERG }, { "err", LOG_ERR }, { "warn", LOG_WARNING }, { NULL, -1 } }; struct code facilitynames[] = { { "daemon", LOG_DAEMON }, #ifndef IS_MINGW { "kern", LOG_KERN }, { "user", LOG_USER }, { "mail", LOG_MAIL }, { "auth", LOG_AUTH }, { "syslog", LOG_SYSLOG }, { "lpr", LOG_LPR }, { "news", LOG_NEWS }, { "uucp", LOG_UUCP }, { "cron", LOG_CRON }, { "reserved", -1 }, { "reserved", -1 }, { "reserved", -1 }, { "cron", LOG_CRON }, { "local0", LOG_LOCAL0 }, { "local1", LOG_LOCAL1 }, { "local2", LOG_LOCAL2 }, { "local3", LOG_LOCAL3 }, { "local4", LOG_LOCAL4 }, { "local5", LOG_LOCAL5 }, { "local6", LOG_LOCAL6 }, { "local7", LOG_LOCAL7 }, { "security", LOG_AUTH }, { "mark", LOG_MARK }, #endif { NULL, -1 } }; pcp-3.8.12ubuntu1/src/pmie/src/syntax.c0000664000000000000000000003756612272262501014625 0ustar /*********************************************************************** * syntax.c - inference rule language parser *********************************************************************** * * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2013 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "pmapi.h" #include "impl.h" #include #include #ifdef HAVE_REGEX_H #include #endif #include "dstruct.h" #include "symbol.h" #include "syntax.h" #include "lexicon.h" #include "grammar.h" #include "pragmatics.h" #include "eval.h" #include "show.h" /*********************************************************************** * constants ***********************************************************************/ #define NAMEGEN_MAX 12 /*********************************************************************** * variables ***********************************************************************/ Symbol parse; /* result of parse */ int errs; /* error count */ /*********************************************************************** * miscellaneous local functions ***********************************************************************/ /* generate unique name, only good till next call */ static char * nameGen(void) { static int state = 0; static char bfr[NAMEGEN_MAX]; state++; snprintf(bfr, sizeof(bfr), "expr_%1d", state); return bfr; } /* check domains cardinality agreement */ static int checkDoms(Expr *x1, Expr *x2) { if ((x1->nvals != 1) && (x2->nvals != 1)) { if (x1->hdom != x2->hdom) { synerr(); fprintf(stderr, "host domains have different size (%d and %d)\n", x1->hdom, x2->hdom); return 0; } if (x1->e_idom != x2->e_idom) { synerr(); fprintf(stderr, "instance domains have different size (%d and %d)\n", x1->e_idom, x2->e_idom); return 0; } if (x1->tdom != x2->tdom) { synerr(); fprintf(stderr, "time domains have different size (%d and %d)\n", x1->tdom, x2->tdom); return 0; } } return 1; } /* evaluate constant expression */ static void evalConst(Expr *x) { if ((x->op < ACT_SHELL) && (x->arg1->op == NOP) && ((x->arg2 == NULL) || (x->arg2->op == NOP))) { (x->eval)(x); x->op = NOP; x->eval = NULL; freeExpr(x->arg1); x->arg1 = NULL; freeExpr(x->arg2); x->arg2 = NULL; } } /*********************************************************************** * error reporting ***********************************************************************/ static void report(char *msg) { LexIn *x = lin; fprintf(stderr, "%s: %s - ", pmProgname, msg); if (x) { fprintf(stderr, "near line %d of ", x->lno); if (x->stream) { if (x->name) fprintf(stderr, "file %s", x->name); else fprintf(stderr, "standard input"); } else { fprintf(stderr, "macro $%s", x->name); do x = x->prev; while (x && x->stream == NULL); if (x) { fprintf(stderr, " called from "); if (x->name) fprintf(stderr, "file %s", x->name); else fprintf(stderr, "standard input"); } } } else fprintf(stderr, "at end of file"); putc('\n', stderr); } void synwarn(void) { report("warning"); } void synerr(void) { report("syntax error"); errs++; } void yyerror(char *s) { synerr(); } /*********************************************************************** * post processing * - propagate instance information from fetch expressions towards * the root of the expression tree, allocating ring buffers etc. * along the way. ***********************************************************************/ static void postExpr(Expr *x) { if (x->op == CND_FETCH) { instFetchExpr(x); } else { if (x->arg1) { postExpr(x->arg1); if (x->arg2) postExpr(x->arg2); } } } /*********************************************************************** * parser actions ***********************************************************************/ /* statement */ Symbol statement(char *name, Expr *x) { Symbol s; /* error guard */ if (x == NULL) return NULL; /* if name not given, make one up */ if (name == NULL) name = nameGen(); /* the parsed object is a rule (expression to evaluate) */ if (x->op != NOP) { if (symLookup(&rules, name)) { synerr(); fprintf(stderr, "rule \"%s\" multiply defined\n", name); freeExpr(x); return NULL; } else { if (errs == 0) { postExpr(x); s = symIntern(&rules, name); } else return NULL; } } /* the parsed object is a non-rule */ else { if ( (s = symLookup(&vars, name)) ) freeExpr(symValue(s)); else s = symIntern(&vars, name); } symValue(s) = x; return s; } /* construct rule Expr */ Expr * ruleExpr(Expr *cond, Expr *act) { Expr *x; if (cond == NULL) return act; if (act == NULL) return cond; if (cond->nvals != 1) { synerr(); fprintf(stderr, "rule condition must have a single truth value\n"); } perf->numrules++; x = newExpr(RULE, cond, act, -1, -1, -1, 1, SEM_TRUTH); newRingBfr(x); findEval(x); return x; } /* action expression */ Expr * actExpr(int op, Expr *arg1, Expr *arg2) { Expr *x; /* error guard */ if (arg1 == NULL) return NULL; /* construct expression node */ x = newExpr(op, arg1, arg2, -1, -1, -1, 1, SEM_TRUTH); newRingBfr(x); findEval(x); return x; } /* action argument expression */ Expr * actArgExpr(Expr *arg1, Expr *arg2) { Expr *x; /* error guard */ if (arg1 == NULL) return NULL; /* construct expression node */ x = newExpr(ACT_ARG, arg1, arg2, -1, 1, -1, 1, SEM_CHAR); newRingBfr(x); findEval(x); return x; } /* action argument */ Expr * actArgList(Expr *arg1, char *str) { Expr *x; /* construct expression node for an action argument string */ x = (Expr *) zalloc(sizeof(Expr)); x->op = NOP; x->smpls[0].ptr = x->ring = sdup(str); x->valid = x->nsmpls = x->nvals = 1; x->tspan = strlen(str); x->sem = SEM_CHAR; if (arg1) { x->arg1 = arg1; arg1->parent = x; } return x; } /* relational operator expression */ Expr * relExpr(int op, Expr *arg1, Expr *arg2) { Expr *x; Expr *arg; int i; int sts; /* error guard */ if (arg1 == NULL || arg2 == NULL) return NULL; /* check domains */ sts = checkDoms(arg1, arg2); /* decide primary argument for inheritance of Expr attributes */ arg = primary(arg1, arg2); /* construct expression node */ x = newExpr(op, arg1, arg2, arg->hdom, arg->e_idom, arg->tdom, abs(arg->tdom), SEM_TRUTH); #if PCP_DEBUG if (sts == 0 && (pmDebug & DBG_TRACE_APPL1)) { fprintf(stderr, "relExpr: checkDoms(" PRINTF_P_PFX "%p, " PRINTF_P_PFX "%p) failed ...\n", arg1, arg2); __dumpTree(1, x); } #endif newRingBfr(x); if (x->tspan > 0) { for (i = 0; i < x->nsmpls; i++) *((char *)x->ring + i) = DUNNO; } findEval(x); /* evaluate constant expression now */ evalConst(x); return x; } /* binary operator expression */ Expr * binaryExpr(int op, Expr *arg1, Expr *arg2) { Expr *x; Expr *arg; int sts; /* error guard */ if (arg1 == NULL || arg2 == NULL) return NULL; if (op != CND_MATCH && op != CND_NOMATCH) { /* check domains */ sts = checkDoms(arg1, arg2); /* decide primary argument for inheritance of Expr attributes */ arg = primary(arg1, arg2); } else { regex_t *pat; pat = alloc(sizeof(*pat)); if (regcomp(pat, (char *)arg2->ring, REG_EXTENDED|REG_NOSUB) != 0) { /* bad pattern */ fprintf(stderr, "illegal regular expression \"%s\"\n", (char *)arg2->ring); free(pat); return NULL; } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "binaryExpr: regex=\"%s\" handle=" PRINTF_P_PFX "%p\n", (char *)arg2->ring, pat); } #endif /* * change operand from the string form of the pattern to the * compiled regex */ free(arg2->ring); arg2->tspan = 1; arg2->ring = pat; arg2->sem = SEM_REGEX; sts = 1; arg = arg1; } /* construct expression node */ x = newExpr(op, arg1, arg2, arg->hdom, arg->e_idom, arg->tdom, abs(arg->tdom), arg->sem); #if PCP_DEBUG if (sts == 0 && (pmDebug & DBG_TRACE_APPL1)) { fprintf(stderr, "binaryExpr: checkDoms(" PRINTF_P_PFX "%p, " PRINTF_P_PFX "%p) failed ...\n", arg1, arg2); __dumpTree(1, x); } #endif newRingBfr(x); findEval(x); /* evaluate constant expression now */ evalConst(x); return x; } /* unary operator expression */ Expr * unaryExpr(int op, Expr *arg) { Expr *x; /* error guard */ if (arg == NULL) return NULL; /* construct expression node */ x = newExpr(op, arg, NULL, arg->hdom, arg->e_idom, arg->tdom, abs(arg->tdom), arg->sem); newRingBfr(x); findEval(x); /* evaluate constant expression now */ evalConst(x); return x; } /* aggregation/quantification operator expression */ Expr * domainExpr(int op, int dom, Expr *arg) { Expr *x; int hdom; int idom; int tdom; /* error guard */ if (arg == NULL) return NULL; hdom = arg->hdom; idom = arg->e_idom; tdom = arg->tdom; switch (dom) { case HOST_DOM: if (hdom == -1) { synerr(); fprintf(stderr, "no host domain\n"); freeExpr(arg); return NULL; } hdom = -1; idom = -1; dom = 0; break; case INST_DOM: #if 0 /* * I believe this test is no longer correct ... the instance * domain may be unobtainable at this point, or may change * later so checking at the syntactic level is not helpful */ if (idom == -1) { synerr(); fprintf(stderr, "no instance domain\n"); freeExpr(arg); return NULL; } #endif idom = -1; dom = 1; break; case TIME_DOM: if (tdom == -1) { synerr(); fprintf(stderr, "no time domain\n"); freeExpr(arg); return NULL; } tdom = -1; dom = 2; } if (op == CND_COUNT_HOST) { x = newExpr(op + dom, arg, NULL, hdom, idom, tdom, abs(tdom), PM_SEM_INSTANT); newRingBfr(x); x->units = countUnits; } else { x = newExpr(op + dom, arg, NULL, hdom, idom, tdom, abs(tdom), arg->sem); newRingBfr(x); } findEval(x); return x; } /* percentage quantifier */ Expr * percentExpr(double pcnt, int dom, Expr *arg) { Expr *x; /* error guard */ if (arg == NULL) return NULL; x = domainExpr(CND_PCNT_HOST, dom, arg); x->arg2 = newExpr(NOP, NULL, NULL, -1, -1, -1, 1, SEM_NUMCONST); newRingBfr(x->arg2); *(double *)x->arg2->ring = pcnt / 100.0; x->arg2->valid = 1; return x; } /* merge expression */ static Expr * mergeExpr(int op, Expr *arg) { Expr *x; /* force argument to buffer at least two samples */ if (arg->nsmpls < 2) changeSmpls(&arg, 2); /* construct expression node */ x = newExpr(op, arg, NULL, arg->hdom, arg->e_idom, arg->tdom, abs(arg->tdom), arg->sem); newRingBfr(x); findEval(x); return x; } /* numeric merge expression */ Expr * numMergeExpr(int op, Expr *arg) { /* error guard */ if (arg == NULL) return NULL; /* check argument semantics */ if ((arg->sem == SEM_TRUTH) || (arg->sem == SEM_CHAR)) { synerr(); fprintf(stderr, "operator \"%s\" requires numeric valued argument\n", opStrings(op)); return NULL; } return mergeExpr(op, arg); } /* boolean merge expression */ Expr * boolMergeExpr(int op, Expr *arg) { /* error guard */ if (arg == NULL) return NULL; /* check argument semantics */ if (arg->sem != SEM_TRUTH) { synerr(); fprintf(stderr, "operator \"%s\" requires boolean valued argument\n", opStrings(op)); return NULL; } return mergeExpr(op, arg); } /* fetch expression */ Expr * fetchExpr(char *mname, StringArray hnames, StringArray inames, Interval times) { Expr *x; Metric *marr, *m; int fsz, dsz; int sum; int i; /* calculate samplecounts for fetch and delay */ if (times.t1 == 0) { fsz = times.t2 - times.t1 + 1; dsz = 0; } else { fsz = times.t1 + 1; dsz = times.t2 - times.t1 + 1; } /* default host */ if (hnames.n == 0) { hnames.n = 1; } /* construct Metrics array */ marr = m = (Metric *) zalloc(hnames.n * sizeof(Metric)); sum = 0; for (i = 0; i < hnames.n; i++) { m->mname = symIntern(&metrics, mname); if (hnames.ss) m->hname = symIntern(&hosts, hnames.ss[i]); else m->hname = symIntern(&hosts, dfltHostName); m->desc.sem = SEM_UNKNOWN; m->m_idom = -1; if (inames.n > 0) { m->specinst = inames.n; m->iids = alloc(inames.n * sizeof(int)); m->inames = inames.ss; } else { m->specinst = 0; m->iids = NULL; m->inames = NULL; } if (errs == 0) { int sts = initMetric(m); if (sts < 0) errs++; if (m->m_idom > 0) sum += m->m_idom; } m++; } if (sum == 0) sum = -1; /* error exit */ if (errs) { m = marr; for (i = 0; i < hnames.n; i++) { if (m->iids) free(m->iids); m++; } free(marr); return NULL; } /* construct fetch node */ x = newExpr(CND_FETCH, NULL, NULL, hnames.n, sum, fsz, fsz, SEM_UNKNOWN); newRingBfr(x); x->metrics = marr; findEval(x); instFetchExpr(x); /* patch in fetch node reference in each Metric */ m = marr; for (i = 0; i < hnames.n; i++) { m->expr = x; m++; } /* construct delay node */ if (dsz) { x = newExpr(CND_DELAY, x, NULL, x->hdom, x->e_idom, dsz, dsz, SEM_UNKNOWN); newRingBfr(x); findEval(x); } return x; } /* numeric constant */ Expr * numConst(double v, pmUnits u) { Expr *x; x = newExpr(NOP, NULL, NULL, -1, -1, -1, 1, SEM_NUMCONST); newRingBfr(x); x->units = canon(u); x->valid = 1; *(double *) x->ring = scale(u) * v; return x; } /* string constant */ Expr * strConst(char *s) { Expr *x; int n = (int) strlen(s) + 1; x = newExpr(NOP, NULL, NULL, -1, -1, -1, 1, SEM_CHAR); x->valid = 1; x->tspan = n; newRingBfr(x); strcpy((char *)x->ring, s); return x; } /* boolean constant */ Expr * boolConst(Truth v) { Expr *x; x = newExpr(NOP, NULL, NULL, -1, -1, -1, 1, SEM_TRUTH); newRingBfr(x); x->valid = 1; *(Truth *) x->ring = v; return x; } /* numeric valued variable */ Expr * numVar(Expr *x) { if (x->sem == SEM_TRUTH || x->sem == SEM_CHAR) { synerr(); fprintf(stderr, "numeric valued variable expected\n"); return NULL; } return x; } /* truth valued variable */ Expr * boolVar(Expr *x) { if (x->sem == SEM_CHAR) { synerr(); fprintf(stderr, "truth valued variable expected\n"); return NULL; } return x; } /*********************************************************************** * parser ***********************************************************************/ /* Initialization to be called at the start of new input file. */ int synInit(char *fname) { return lexInit(fname); } /* parse single statement */ Symbol syntax(void) { while (lexMore()) { errs = 0; parse = NULL; yyparse(); if (parse) return parse; } lexFinal(); return NULL; } pcp-3.8.12ubuntu1/src/pmie/src/stats.h0000664000000000000000000000252512272262501014425 0ustar /* * Copyright (c) 1999 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef STATS_H #define STATS_H #include #include /* subdir nested under PCP_TMP_DIR */ #define PMIE_SUBDIR "pmie" /* pmie performance instrumentation */ typedef struct { char config[MAXPATHLEN+1]; char logfile[MAXPATHLEN+1]; char defaultfqdn[MAXHOSTNAMELEN+1]; float eval_expected; /* pmcd.pmie.eval.expected */ unsigned int numrules; /* pmcd.pmie.numrules */ unsigned int actions; /* pmcd.pmie.actions */ unsigned int eval_true; /* pmcd.pmie.eval.true */ unsigned int eval_false; /* pmcd.pmie.eval.false */ unsigned int eval_unknown; /* pmcd.pmie.eval.unknown */ unsigned int eval_actual; /* pmcd.pmie.eval.actual */ unsigned int version; } pmiestats_t; #endif /* STATS_H */ pcp-3.8.12ubuntu1/src/pmie/src/lexicon.h0000664000000000000000000000472312272262501014732 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*********************************************************************** * lexicon.h - lexical scanner ***********************************************************************/ #ifndef LEXICON_H #define LEXICON_H /*********************************************************************** * ONLY FOR USE BY: lexicon.c and syntax.c ***********************************************************************/ #define LEX_MAX 254 /* max length of token */ /* scanner input context stack entry */ typedef struct lexin { struct lexin *prev; /* calling context on stack */ FILE *stream; /* rule input stream */ char *macro; /* input from macro definition */ char *name; /* file/macro name */ int lno; /* current line number */ int cno; /* current column number */ int lookin; /* lookahead buffer input index */ int lookout; /* lookahead buffer output index */ signed char look[LEX_MAX + 2]; /* lookahead ring buffer */ } LexIn; extern LexIn *lin; /* current input context */ /*********************************************************************** * public ***********************************************************************/ /* initialize scan of new input file */ int lexInit(char *); /* finalize scan of input stream */ void lexFinal(void); /* not end of input stream? */ int lexMore(void); /* discard input until ';' or EOF */ void lexSync(void); /* scanner main function */ int yylex(void); /* yacc parser */ int yyparse(void); #endif /* LEXICON_H */ pcp-3.8.12ubuntu1/src/pmie/src/stomp.h0000664000000000000000000000213712272262501014430 0ustar /* * Copyright (c) 2006 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Streaming Text Orientated Messaging Protocol implementation * http://stomp.codehaus.org/ */ extern int stomping; /* true if stomp actions present */ extern char *stompfile; /* stomp config file */ extern int stompInit(void); /* connect to stomp server */ extern int stompSend(const char *); /* send to JMS server, via stomp */ pcp-3.8.12ubuntu1/src/pmie/src/grammar.y0000664000000000000000000003574012272262501014743 0ustar /*********************************************************************** * grammar.y - yacc grammar for rule language *********************************************************************** * * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ %{ #include "dstruct.h" #include "syntax.h" #include "lexicon.h" #include "pragmatics.h" #include "systemlog.h" #include "stomp.h" #include "show.h" /* strings for error reporting */ char precede[] = "precede"; char follow[] = "follow"; char act_str[] = "action"; char bexp_str[] = "logical expression"; char aexp_str[] = "arithmetic expression"; char quant_str[] = "quantifier"; char aggr_str[] = "aggregation operator"; char pcnt_str[] = "percentage quantifier"; char host_str[] = "host name"; char inst_str[] = "instance name"; char sample_str[] = "sample number(s)"; char tstr_str[] = "(time interval optional) and string"; char num_str[] = "number"; /* report grammatical error */ static void gramerr(char *phrase, char *pos, char *op) { fprintf(stderr, "%s expected to %s %s\n", phrase, pos, op); lexSync(); } %} /*********************************************************************** * yacc token and operator declarations ***********************************************************************/ %expect 184 %start stmnt %token ARROW %token SHELL %token ALARM %token SYSLOG %token PRINT %token STOMP %token SOME_QUANT %token ALL_QUANT %token PCNT_QUANT %token LEQ_REL %token GEQ_REL %token NEQ_REL %token EQ_REL %token AND %token SEQ %token OR %token ALT %token NOT %token RISE %token FALL %token MATCH %token NOMATCH %token MIN_AGGR %token MAX_AGGR %token AVG_AGGR %token SUM_AGGR %token COUNT_AGGR %token TIME_DOM %token INST_DOM %token HOST_DOM %token UNIT_SLASH %token INTERVAL %token EVENT_UNIT %token TIME_UNIT %token SPACE_UNIT %token NUMBER %token IDENT %token STRING %token TRU %token FALS %token VAR %type exp %type rule %type act %type bexp %type rexp %type actarg %type arglist %type aexp %type quant %type aggr %type num %type str %type dom %type fetch %type metric %type hosts %type insts %type times %type units %type unit %left NAME_DELIM %left ARROW %left AND OR SEQ ALT %left NOT RISE FALL %left ALL_QUANT SOME_QUANT PCNT_QUANT %left MATCH NOMATCH %left '>' '<' EQ_REL NEQ_REL GEQ_REL LEQ_REL %left '+' '-' %left '*' '/' %left UMINUS RATE %left SUM_AGGR AVG_AGGR MAX_AGGR MIN_AGGR COUNT_AGGR %left SHELL ALARM SYSLOG PRINT STOMP %left ':' '#' '@' %left UNIT_SLASH INTERVAL %% /*********************************************************************** * yacc productions ***********************************************************************/ stmnt : /* empty */ { parse = NULL; } | IDENT '=' exp { parse = statement($1, $3); if ((agent || applet) && $3 != NULL && ($3->op == RULE || $3->op == ACT_SEQ || $3->op == ACT_ALT || $3->op == ACT_SHELL || $3->op == ACT_ALARM || $3->op == ACT_SYSLOG || $3->op == ACT_PRINT || $3->op == ACT_STOMP)) { synerr(); fprintf(stderr, "operator %s not allowed in agent " "mode\n", opStrings($3->op)); parse = NULL; } } | exp { parse = statement(NULL, $1); if (agent) { synerr(); fprintf(stderr, "expressions must be named in agent " "mode\n"); parse = NULL; } } ; exp : rule { $$ = $1; } | bexp { $$ = $1; } | aexp { $$ = $1; } | act { $$ = $1; } | str { $$ = $1; } ; rule : bexp ARROW act { $$ = ruleExpr($1, $3); } /* error reporting */ | error ARROW { gramerr(bexp_str, precede, opStrings(RULE)); $$ = NULL; } | bexp ARROW error { gramerr(act_str, follow, opStrings(RULE)); $$ = NULL; } ; act : '(' act ')' { $$ = $2; } | act SEQ act { $$ = actExpr(ACT_SEQ, $1, $3); } | act ALT act { $$ = actExpr(ACT_ALT, $1, $3); } | SHELL actarg { $$ = actExpr(ACT_SHELL, $2, NULL); } | SHELL num actarg /* holdoff format */ { $$ = actExpr(ACT_SHELL, $3, $2); } | ALARM actarg { $$ = actExpr(ACT_ALARM, $2, NULL); } | ALARM num actarg /* holdoff format */ { $$ = actExpr(ACT_ALARM, $3, $2); } | SYSLOG actarg { do_syslog_args($2); $$ = actExpr(ACT_SYSLOG, $2, NULL); } | SYSLOG num actarg /* holdoff format */ { do_syslog_args($3); $$ = actExpr(ACT_SYSLOG, $3, $2); } | PRINT actarg { $$ = actExpr(ACT_PRINT, $2, NULL); } | PRINT num actarg /* holdoff format */ { $$ = actExpr(ACT_PRINT, $3, $2); } | STOMP actarg { stomping = 1; $$ = actExpr(ACT_STOMP, $2, NULL); } | STOMP num actarg /* holdoff format */ { stomping = 1; $$ = actExpr(ACT_STOMP, $3, $2); } /* error reporting */ | error SEQ { gramerr(act_str, precede, opStrings(ACT_SEQ)); $$ = NULL; } /*** following cause harmless shift/reduce conflicts ***/ | act SEQ error { gramerr(act_str, follow, opStrings(ACT_SEQ)); $$ = NULL; } | error ALT { gramerr(act_str, precede, opStrings(ACT_ALT)); $$ = NULL; } | act ALT error { gramerr(act_str, follow, opStrings(ACT_ALT)); $$ = NULL; } /*** preceding cause harmless shift/reduce conflicts ***/ | SHELL error { gramerr(tstr_str, follow, opStrings(ACT_SHELL)); $$ = NULL; } | ALARM error { gramerr(tstr_str, follow, opStrings(ACT_ALARM)); $$ = NULL; } | SYSLOG error { gramerr(tstr_str, follow, opStrings(ACT_SYSLOG)); $$ = NULL; } | PRINT error { gramerr(tstr_str, follow, opStrings(ACT_PRINT)); $$ = NULL; } | STOMP error { gramerr(tstr_str, follow, opStrings(ACT_STOMP)); $$ = NULL; } ; actarg : arglist { $$ = actArgExpr($1, NULL); } ; arglist : STRING { $$ = actArgList(NULL, $1); } | STRING arglist { $$ = actArgList($2, $1); } ; bexp : '(' bexp ')' { $$ = $2; } | rexp { $$ = $1; } | quant { $$ = $1; } | TRU { $$ = boolConst(TRUE); } | FALS { $$ = boolConst(FALSE); } | NOT bexp { $$ = unaryExpr(CND_NOT, $2); } | RISE bexp { $$ = boolMergeExpr(CND_RISE, $2); } | FALL bexp { $$ = boolMergeExpr(CND_FALL, $2); } | bexp AND bexp { $$ = binaryExpr(CND_AND, $1, $3); } | bexp OR bexp { $$ = binaryExpr(CND_OR, $1, $3); } | MATCH str bexp { /* * note args are reversed so bexp is to the "left" * of the operand node in the expr tree */ $$ = binaryExpr(CND_MATCH, $3, $2); } | NOMATCH str bexp { $$ = binaryExpr(CND_NOMATCH, $3, $2); } /* error reporting */ | NOT error { gramerr(bexp_str, follow, opStrings(CND_NOT)); $$ = NULL; } | RISE error { gramerr(bexp_str, follow, opStrings(CND_RISE)); $$ = NULL; } | FALL error { gramerr(bexp_str, follow, opStrings(CND_FALL)); $$ = NULL; } | MATCH error { gramerr("regular expression", follow, opStrings(CND_MATCH)); $$ = NULL; } | MATCH str error { gramerr(bexp_str, follow, "regular expression"); $$ = NULL; } | NOMATCH error { gramerr("regular expression", follow, opStrings(CND_NOMATCH)); $$ = NULL; } | NOMATCH str error { gramerr(bexp_str, follow, "regular expression"); $$ = NULL; } /*** following cause harmless shift/reduce conflicts ***/ | error AND { gramerr(bexp_str, precede, opStrings(CND_AND)); $$ = NULL; } | bexp AND error { gramerr(bexp_str, follow, opStrings(CND_AND)); $$ = NULL; } | error OR { gramerr(bexp_str, precede, opStrings(CND_OR)); $$ = NULL; } | bexp OR error { gramerr(bexp_str, follow, opStrings(CND_OR)); $$ = NULL; } /*** preceding cause harmless shift/reduce conflicts ***/ ; quant : ALL_QUANT dom bexp { $$ = domainExpr(CND_ALL_HOST, $2, $3); } | SOME_QUANT dom bexp { $$ = domainExpr(CND_SOME_HOST, $2, $3); } | NUMBER PCNT_QUANT dom bexp { $$ = percentExpr($1, $3, $4); } /* error reporting */ | ALL_QUANT dom error { gramerr(bexp_str, follow, quant_str); $$ = NULL; } | SOME_QUANT dom error { gramerr(bexp_str, follow, quant_str); $$ = NULL; } | NUMBER PCNT_QUANT dom error { gramerr(bexp_str, follow, quant_str); $$ = NULL; } | error PCNT_QUANT { gramerr(num_str, precede, pcnt_str); $$ = NULL; } ; rexp : aexp EQ_REL aexp { $$ = relExpr(CND_EQ, $1, $3); } | aexp NEQ_REL aexp { $$ = relExpr(CND_NEQ, $1, $3); } | aexp '<' aexp { $$ = relExpr(CND_LT, $1, $3); } | aexp '>' aexp { $$ = relExpr(CND_GT, $1, $3); } | aexp LEQ_REL aexp { $$ = relExpr(CND_LTE, $1, $3); } | aexp GEQ_REL aexp { $$ = relExpr(CND_GTE, $1, $3); } /* error reporting */ | error EQ_REL { gramerr(aexp_str, precede, opStrings(CND_EQ)); $$ = NULL; } | aexp EQ_REL error { gramerr(aexp_str, follow, opStrings(CND_EQ)); $$ = NULL; } | error NEQ_REL { gramerr(aexp_str, precede, opStrings(CND_NEQ)); $$ = NULL; } | aexp NEQ_REL error { gramerr(aexp_str, follow, opStrings(CND_NEQ)); $$ = NULL; } | error '<' { gramerr(aexp_str, precede, opStrings(CND_LT)); $$ = NULL; } | aexp '<' error { gramerr(aexp_str, follow, opStrings(CND_LT)); $$ = NULL; } | error '>' { gramerr(aexp_str, precede, opStrings(CND_GT)); $$ = NULL; } | aexp '>' error { gramerr(aexp_str, follow, opStrings(CND_GT)); $$ = NULL; } | error LEQ_REL { gramerr(aexp_str, precede, opStrings(CND_LTE)); $$ = NULL; } | aexp LEQ_REL error { gramerr(aexp_str, follow, opStrings(CND_LTE)); $$ = NULL; } | error GEQ_REL { gramerr(aexp_str, precede, opStrings(CND_GTE)); $$ = NULL; } | aexp GEQ_REL error { gramerr(aexp_str, follow, opStrings(CND_GTE)); $$ = NULL; } ; aexp : '(' aexp ')' { $$ = $2; } | fetch { $$ = $1; } | num { $$ = $1; } | VAR { $$ = $1; } | aggr { $$ = $1; } | RATE aexp { $$ = numMergeExpr(CND_RATE, $2); } | '-' aexp %prec UMINUS { $$ = unaryExpr(CND_NEG, $2); } | aexp '+' aexp { $$ = binaryExpr(CND_ADD, $1, $3); } | aexp '-' aexp { $$ = binaryExpr(CND_SUB, $1, $3); } | aexp '*' aexp { $$ = binaryExpr(CND_MUL, $1, $3); } | aexp '/' aexp { $$ = binaryExpr(CND_DIV, $1, $3); } /* error reporting */ | RATE error { gramerr(aexp_str, follow, opStrings(CND_RATE)); $$ = NULL; } | '-' error %prec UMINUS { gramerr(aexp_str, follow, opStrings(CND_NEG)); $$ = NULL; } /*** following cause harmless shift/reduce conflicts ***/ | error '+' { gramerr(aexp_str, precede, opStrings(CND_ADD)); $$ = NULL; } | aexp '+' error { gramerr(aexp_str, follow, opStrings(CND_ADD)); $$ = NULL; } | error '-' { gramerr(aexp_str, precede, opStrings(CND_SUB)); $$ = NULL; } | aexp '-' error { gramerr(aexp_str, follow, opStrings(CND_SUB)); $$ = NULL; } | error '*' { gramerr(aexp_str, precede, opStrings(CND_MUL)); $$ = NULL; } | aexp '*' error { gramerr(aexp_str, follow, opStrings(CND_MUL)); $$ = NULL; } | error '/' { gramerr(aexp_str, precede, opStrings(CND_DIV)); $$ = NULL; } | aexp '/' error { gramerr(aexp_str, follow, opStrings(CND_DIV)); $$ = NULL; } /*** preceding cause harmless shift/reduce conflicts ***/ ; aggr : SUM_AGGR dom aexp { $$ = domainExpr(CND_SUM_HOST, $2, $3); } | AVG_AGGR dom aexp { $$ = domainExpr(CND_AVG_HOST, $2, $3); } | MAX_AGGR dom aexp { $$ = domainExpr(CND_MAX_HOST, $2, $3); } | MIN_AGGR dom aexp { $$ = domainExpr(CND_MIN_HOST, $2, $3); } | COUNT_AGGR dom bexp { $$ = domainExpr(CND_COUNT_HOST, $2, $3); } /* error reporting */ | SUM_AGGR dom error { gramerr(aexp_str, follow, aggr_str); $$ = NULL; } | AVG_AGGR dom error { gramerr(aexp_str, follow, aggr_str); $$ = NULL; } | MAX_AGGR dom error { gramerr(aexp_str, follow, aggr_str); $$ = NULL; } | MIN_AGGR dom error { gramerr(aexp_str, follow, aggr_str); $$ = NULL; } ; dom : HOST_DOM { $$ = HOST_DOM; } | INST_DOM { $$ = INST_DOM; } | TIME_DOM { $$ = TIME_DOM; } ; fetch : metric hosts insts times { $$ = fetchExpr($1, $2, $3, $4); } ; metric : IDENT { $$ = $1; } ; hosts : /* empty */ { $$.n = 0; $$.ss = NULL; } | hosts ':' IDENT { $$.n = $1.n + 1; $$.ss = (char **) ralloc($1.ss, $$.n * sizeof(char *)); $$.ss[$1.n] = $3; } /* error reporting */ | hosts ':' error { gramerr(host_str, follow, ":"); $$.n = 0; $$.ss = NULL; } ; insts : /* empty */ { $$.n = 0; $$.ss = NULL; } | insts '#' IDENT { $$.n = $1.n + 1; $$.ss = (char **) ralloc($1.ss, $$.n * sizeof(char *)); $$.ss[$1.n] = $3; } /* error reporting */ | insts '#' error { gramerr(inst_str, follow, "#"); $$.n = 0; $$.ss = NULL; } ; times : /* empty */ { $$.t1 = 0; $$.t2 = 0; } | '@' NUMBER { $$.t1 = $2; $$.t2 = $2; } | '@' NUMBER INTERVAL NUMBER { if ($2 <= $4) { $$.t1 = $2; $$.t2 = $4; } else { $$.t1 = $4; $$.t2 = $2; } } /* error reporting */ | '@' error { gramerr(sample_str, follow, "@"); $$.t1 = 0; $$.t2 = 0; } ; num : NUMBER units { $$ = numConst($1, $2); } ; units : /* empty */ { $$ = noUnits; } | units unit { $$ = $1; if ($2.dimSpace) { $$.dimSpace = $2.dimSpace; $$.scaleSpace = $2.scaleSpace; } else if ($2.dimTime) { $$.dimTime = $2.dimTime; $$.scaleTime = $2.scaleTime; } else { $$.dimCount = $2.dimCount; $$.scaleCount = $2.scaleCount; } } | units UNIT_SLASH unit { $$ = $1; if ($3.dimSpace) { $$.dimSpace = -$3.dimSpace; $$.scaleSpace = $3.scaleSpace; } else if ($3.dimTime) { $$.dimTime = -$3.dimTime; $$.scaleTime = $3.scaleTime; } else { $$.dimCount = -$3.dimCount; $$.scaleCount = $3.scaleCount; } } ; unit : SPACE_UNIT { $$ = $1; } | SPACE_UNIT '^' NUMBER { $$ = $1; $$.dimSpace = $3; } | TIME_UNIT { $$ = $1; } | TIME_UNIT '^' NUMBER { $$ = $1; $$.dimTime = $3; } | EVENT_UNIT { $$ = $1; } | EVENT_UNIT '^' NUMBER { $$ = $1; $$.dimCount = $3; } ; str : STRING { $$ = strConst($1); } ; %% pcp-3.8.12ubuntu1/src/pmie/src/andor.c0000664000000000000000000002445712272262501014375 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*********************************************************************** * andor.c * * These functions were originally generated from skeletons .sk * by the shell-script './meta', then modified to support the semantics * of the boolean AND/OR operators correctly. These are different to * every other operator in that they do not always require both sides * of the expression to be available in order to be evaluated, i.e. * OR: if either side of the expression is true, expr is true * AND: if either side of the expression is false, expr is false ***********************************************************************/ #include "pmapi.h" #include "dstruct.h" #include "pragmatics.h" #include "fun.h" #include "show.h" #include "stomp.h" /* * operator: cndOr */ #define OR(x,y) (((x) == TRUE || (y) == TRUE) ? TRUE : (((x) == FALSE && (y) == FALSE) ? FALSE : DUNNO)) #define OR1(x) ((x) == TRUE ? TRUE : DUNNO) void cndOr_n_n(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg2->smpls[0]; Sample *os = &x->smpls[0]; Truth *ip1; Truth *ip2; Truth *op; int i; EVALARG(arg1) EVALARG(arg2) ROTATE(x) if (arg1->valid && arg2->valid && x->tspan > 0) { ip1 = (Truth *)is1->ptr; ip2 = (Truth *)is2->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = OR(*ip1, *ip2); ip1++; ip2++; } os->stamp = (is1->stamp > is2->stamp) ? is1->stamp : is2->stamp; x->valid++; } else if (arg1->valid && x->tspan > 0) { ip1 = (Truth *)is1->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = OR1(*ip1); ip1++; } os->stamp = is1->stamp; x->valid++; } else if (arg2->valid && x->tspan > 0) { ip2 = (Truth *)is2->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = OR1(*ip2); ip2++; } os->stamp = is2->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cndOr_n_n(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void cndOr_n_1(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg2->smpls[0]; Sample *os = &x->smpls[0]; Truth *ip1; Truth iv2; Truth *op; int i; EVALARG(arg1) EVALARG(arg2) ROTATE(x) if (arg1->valid && arg2->valid && x->tspan > 0) { ip1 = (Truth *)is1->ptr; iv2 = *(Truth *)is2->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = OR(*ip1, iv2); ip1++; } os->stamp = (is1->stamp > is2->stamp) ? is1->stamp : is2->stamp; x->valid++; } else if (arg1->valid && x->tspan > 0) { ip1 = (Truth *)is1->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = OR1(*ip1); ip1++; } os->stamp = is1->stamp; x->valid++; } else if (arg2->valid && x->tspan > 0) { *(Truth *)os->ptr = OR1(*(Truth *)is2->ptr); os->stamp = is2->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cndOr_n_1(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void cndOr_1_n(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg2->smpls[0]; Sample *os = &x->smpls[0]; Truth iv1; Truth *ip2; Truth *op; int i; EVALARG(arg1) EVALARG(arg2) ROTATE(x) if (arg1->valid && arg2->valid && x->tspan > 0) { iv1 = *(Truth *)is1->ptr; ip2 = (Truth *)is2->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = OR(iv1, *ip2); ip2++; } os->stamp = (is1->stamp > is2->stamp) ? is1->stamp : is2->stamp; x->valid++; } else if (arg1->valid && x->tspan > 0) { *(Truth *)os->ptr = OR1(*(Truth *)is1->ptr); os->stamp = is1->stamp; x->valid++; } else if (arg2->valid && x->tspan > 0) { ip2 = (Truth *)is2->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = OR1(*ip2); ip2++; } os->stamp = is2->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cndOr_1_n(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void cndOr_1_1(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg2->smpls[0]; Sample *os = &x->smpls[0]; EVALARG(arg1) EVALARG(arg2) ROTATE(x) if (arg1->valid && arg2->valid) { *(Truth *)os->ptr = OR(*(Truth *)is1->ptr, *(Truth *)is2->ptr); os->stamp = (is1->stamp > is2->stamp) ? is1->stamp : is2->stamp; x->valid++; } else if (arg1->valid) { *(Truth *)os->ptr = OR1(*(Truth *)is1->ptr); os->stamp = is1->stamp; x->valid++; } else if (arg2->valid) { *(Truth *)os->ptr = OR1(*(Truth *)is2->ptr); os->stamp = is2->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cndOr_1_1(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } /* * operator: cndAnd */ #define AND(x,y) (((x) == TRUE && (y) == TRUE) ? TRUE : (((x) == FALSE || (y) == FALSE) ? FALSE : DUNNO)) #define AND1(x) (((x) == FALSE) ? FALSE : DUNNO) void cndAnd_n_n(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg2->smpls[0]; Sample *os = &x->smpls[0]; Truth *ip1; Truth *ip2; Truth *op; int i; EVALARG(arg1) EVALARG(arg2) ROTATE(x) if (arg1->valid && arg2->valid) { ip1 = (Truth *)is1->ptr; ip2 = (Truth *)is2->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = AND(*ip1, *ip2); ip1++; ip2++; } os->stamp = (is1->stamp > is2->stamp) ? is1->stamp : is2->stamp; x->valid++; } else if (arg1->valid) { ip1 = (Truth *)is1->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = AND1(*ip1); ip1++; } os->stamp = is1->stamp; x->valid++; } else if (arg2->valid) { ip2 = (Truth *)is2->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = AND1(*ip2); ip2++; } os->stamp = is2->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cndAnd_n_n(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void cndAnd_n_1(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg2->smpls[0]; Sample *os = &x->smpls[0]; Truth *ip1; Truth iv2; Truth *op; int i; EVALARG(arg1) EVALARG(arg2) ROTATE(x) if (arg1->valid && arg2->valid && x->tspan > 0) { ip1 = (Truth *)is1->ptr; iv2 = *(Truth *)is2->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = AND(*ip1, iv2); ip1++; } os->stamp = (is1->stamp > is2->stamp) ? is1->stamp : is2->stamp; x->valid++; } else if (arg1->valid && x->tspan > 0) { ip1 = (Truth *)is1->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = AND1(*ip1); ip1++; } os->stamp = is1->stamp; x->valid++; } else if (arg2->valid && x->tspan > 0) { *(Truth *)os->ptr = AND1(*(Truth *)is2->ptr); os->stamp = is2->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cndAnd_n_1(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void cndAnd_1_n(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg2->smpls[0]; Sample *os = &x->smpls[0]; Truth iv1; Truth *ip2; Truth *op; int i; EVALARG(arg1) EVALARG(arg2) ROTATE(x) if (arg1->valid && arg2->valid && x->tspan > 0) { iv1 = *(Truth *)is1->ptr; ip2 = (Truth *)is2->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = AND(iv1, *ip2); ip2++; } os->stamp = (is1->stamp > is2->stamp) ? is1->stamp : is2->stamp; x->valid++; } else if (arg1->valid && x->tspan > 0) { *(Truth *)os->ptr = AND1(*(Truth *)is1->ptr); os->stamp = is1->stamp; x->valid++; } else if (arg2->valid && x->tspan > 0) { ip2 = (Truth *)is2->ptr; op = (Truth *)os->ptr; for (i = 0; i < x->tspan; i++) { *op++ = AND1(*ip2); ip2++; } os->stamp = is2->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cndAnd_1_n(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void cndAnd_1_1(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg2->smpls[0]; Sample *os = &x->smpls[0]; EVALARG(arg1) EVALARG(arg2) ROTATE(x) if (arg1->valid && arg2->valid) { *(Truth *)os->ptr = AND(*(Truth *)is1->ptr, *(Truth *)is2->ptr); os->stamp = (is1->stamp > is2->stamp) ? is1->stamp : is2->stamp; x->valid++; } else if (arg1->valid) { *(Truth *)os->ptr = AND1(*(Truth *)is1->ptr); os->stamp = is1->stamp; x->valid++; } else if (arg2->valid) { *(Truth *)os->ptr = AND1(*(Truth *)is2->ptr); os->stamp = is2->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cndAnd_1_1(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } pcp-3.8.12ubuntu1/src/pmie/src/symbol.h0000664000000000000000000000545412272262501014600 0ustar /*********************************************************************** * symbol.h - a symbol is an object with a name, a value and a * reference count *********************************************************************** * * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SYMBOL_H #define SYMBOL_H /*********************************************************************** * private ***********************************************************************/ union symunion; /* for forward reference */ typedef struct { union symunion *next; /* forward pointer */ union symunion *prev; /* backward pointer */ union symunion *free; /* free list head */ } SymHdr; typedef struct { union symunion *ptr; /* free list pointer */ int count; /* number of free entries */ } SymFree; typedef struct { char *name; /* name string */ void *value; /* arbitrary value */ } SymUsed; typedef struct { union { SymFree free; /* free symbol table entry */ SymUsed used; /* occupied symbol table entry */ } stat; int refs; /* refernce count */ } SymEntry; typedef union symunion { SymHdr hdr; /* symbol table or bucket header */ SymEntry entry; /* symbol or free slot */ } SymUnion; /*********************************************************************** * public ***********************************************************************/ #define SYM_NULL NULL typedef SymUnion *Symbol; typedef SymUnion SymbolTable; /* access to name string, value and reference count */ #define symName(sym) ((sym)->entry.stat.used.name) #define symValue(sym) ((sym)->entry.stat.used.value) #define symRefs(sym) ((sym)->entry.refs) /* initialize symbol table */ void symSetTable(SymbolTable *); /* reset symbol table */ void symClearTable(SymbolTable *); /* convert string to symbol */ Symbol symIntern(SymbolTable *, char *); /* lookup symbol by name */ Symbol symLookup(SymbolTable *, char *); /* copy symbol */ Symbol symCopy(Symbol); /* remove reference to symbol */ void symFree(Symbol); #endif /* SYMBOL_H */ pcp-3.8.12ubuntu1/src/pmie/src/meta0000775000000000000000000001064212272262501013771 0ustar #!/bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Generate evaluator functions from skeletons. # ############## # procedures # ############## CULLCOPYRIGHT="/^ \* Copyright.* Silicon Graphics.*$/d" _fetch() { fin=fetch.sk sed -e "$CULLCOPYRIGHT" $fin >> $fout } _misc() { fin=misc.sk sed -e "$CULLCOPYRIGHT" \ -e "s/@ITYPE/$itype/g" \ -e "s/@OTYPE/$otype/g" \ $fin >> $fout } _aggr() { fin=aggregate.sk sed -e "$CULLCOPYRIGHT" \ -e "s/@FUN/$fun/g" \ -e "s/@ITYPE/$itype/g" \ -e "s/@OTYPE/$otype/g" \ -e "s/@TTYPE/$ttype/g" \ -e "s/@TOP/$top/g" \ -e "s/@LOOP/$loop/g" \ -e "s/@BOT/$bot/g" \ -e "s/@NOTVALID/$notvalid/g" \ $fin >> $fout } _unary() { fin=unary.sk sed -e "$CULLCOPYRIGHT" \ -e "s/@FUN/$fun/g" \ -e "s/@ITYPE/$itype/g" \ -e "s/@OTYPE/$otype/g" \ -e "s/@OP/$op/g" \ $fin >> $fout } _binary() { fin=binary.sk sed -e "$CULLCOPYRIGHT" \ -e "s/@FUN/$fun/g" \ -e "s/@ITYPE/$itype/g" \ -e "s/@OTYPE/$otype/g" \ -e "s/@OP/$op/g" \ $fin >> $fout } _merge() { fin=merge.sk if [ -z "$scale" ] then sed -e '/RealTime/d' $fin else cat $fin fi \ | sed -e "$CULLCOPYRIGHT" \ -e "s/@FUN/$fun/g" \ -e "s/@ITYPE/$itype/g" \ -e "s/@OTYPE/$otype/g" \ -e "s/@OP/$op/g" \ -e "s/@DELTA/$delta/g" \ -e "s/@SCALE/$scale/g" \ >> $fout } _act() { fin=act.sk sed -e "$CULLCOPYRIGHT" $fin >> $fout } ######## # main # ######## fout=fun.c rm -f $fout cat hdr.sk > $fout # # fetch # _fetch # # rule and delay # itype=double otype=double _misc # # aggregation operators # itype=double otype=double ttype=double notvalid="x->valid = 0;" fun=cndSum top="a = *ip;" loop="a += *ip;" bot="*op++ = a;" _aggr fun=cndAvg top="a = *ip;" loop="a += *ip;" bot="*op++ = a \/ n;" _aggr fun=cndMax top="a = *ip;" loop="if (*ip > a) a = *ip;" bot="*op++ = a;" _aggr fun=cndMin top="a = *ip;" loop="if (*ip < a) a = *ip;" bot="*op++ = a;" _aggr # # arithmetic operators # itype=double otype=double ttype=double fun=cndNeg op="OP(x) -(x)" _unary fun=cndAdd op="OP(x,y) ((x) + (y))" _binary fun=cndSub op="OP(x,y) ((x) - (y))" _binary fun=cndMul op="OP(x,y) ((x) * (y))" _binary fun=cndDiv op="OP(x,y) ((x) \/ (y))" _binary fun=cndRate delta="delta = is1->stamp - is2->stamp;" op="-" scale="*op = *op \\/ delta;" _merge # # relational operators # itype=double otype=Truth ttype=Truth fun=cndEq op="OP(x,y) ((x) == (y))" _binary fun=cndNeq op="OP(x,y) ((x) != (y))" _binary fun=cndLt op="OP(x,y) ((x) < (y))" _binary fun=cndLte op="OP(x,y) ((x) <= (y))" _binary fun=cndGt op="OP(x,y) ((x) > (y))" _binary fun=cndGte op="OP(x,y) ((x) >= (y))" _binary # # boolean connectives # itype=Truth otype=Truth ttype=Truth fun=cndNot op="OP(x) (((x) == TRUE || (x) == FALSE) ? !(x) : DUNNO)" _unary fun=cndRise delta="" op=">" scale="" _merge fun=cndFall delta="" op="<" scale="" _merge # # quantifiers # itype=Truth otype=Truth ttype=Truth fun=cndAll top="a = *ip;" loop="if (*ip == FALSE) a = FALSE;\\ else if (*ip == DUNNO \\&\\& a != DUNNO) a = DUNNO;" bot="*op++ = a;" notvalid="*op++ = DUNNO; os->stamp = is->stamp; x->valid++;" _aggr fun=cndSome top="a = *ip;" loop="if (*ip == TRUE) a = TRUE;\\ else if (*ip == DUNNO \\&\\& a != DUNNO) a = DUNNO;" bot="*op++ = a;" notvalid="*op++ = DUNNO; os->stamp = is->stamp; x->valid++;" _aggr fun=cndPcnt ttype='int ' top="a = *ip;" loop="a += *ip;" bot="*op++ = (a >= (int)(0.5 + *(double *)x->arg2->ring * n)) ? TRUE : FALSE;" notvalid="*op++ = DUNNO; os->stamp = is->stamp; x->valid++;" _aggr # # truth counter # itype=Truth otype=double notvalid="x->valid = 0;" fun=cndCount top="a = *ip;" loop="a += *ip;" bot="*op++ = a;" _aggr # # actions # _act # discourage changes to fun.c # chmod 444 $fout pcp-3.8.12ubuntu1/src/pmie/src/match_inst.c0000664000000000000000000000626012272262501015413 0ustar /* * Copyright (c) 1999 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "pmapi.h" /* _pmCtime only */ #include "impl.h" /* _pmCtime only */ #include "dstruct.h" #include "fun.h" #include "show.h" /* * x-arg1 is the bexp, x->arg2 is the regex */ void cndMatch_inst(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Truth *ip1; Truth *op; int n; int i; int sts; int mi; Metric *m; EVALARG(arg1) ROTATE(x) #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "match_inst(" PRINTF_P_PFX "%p): regex handle=" PRINTF_P_PFX "%p desire %s\n", x, arg2->ring, x->op == CND_MATCH ? "match" : "nomatch"); dumpExpr(x); } #endif if (arg2->sem != SEM_REGEX) { fprintf(stderr, "cndMatch_inst: internal botch arg2 not SEM_REGEX?\n"); dumpExpr(arg2); exit(1); } if (arg1->tspan > 0) { mi = 0; m = &arg1->metrics[mi++]; i = 0; ip1 = (Truth *)(&arg1->smpls[0])->ptr; op = (Truth *)(&x->smpls[0])->ptr; for (n = 0; n < arg1->tspan; n++) { if (!arg2->valid || !arg1->valid) { *op++ = DUNNO; } else if (x->e_idom <= 0) { *op++ = FALSE; } else { while (i >= m->m_idom) { /* * no more values, next metric */ m = &arg1->metrics[mi++]; i = 0; } if (m->inames == NULL) { *op++ = FALSE; } else { sts = regexec((regex_t *)arg2->ring, m->inames[i], 0, NULL, 0); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { if (x->op == CND_MATCH && sts != REG_NOMATCH) { fprintf(stderr, "match_inst: inst=\"%s\" match && %s\n", m->inames[i], *ip1 == TRUE ? "true" : (*ip1 == FALSE ? "false" : (*ip1 == DUNNO ? "unknown" : "bogus" ))); } else if (x->op == CND_NOMATCH && sts == REG_NOMATCH) { fprintf(stderr, "match_inst: inst=\"%s\" nomatch && %s\n", m->inames[i], *ip1 == TRUE ? "true" : (*ip1 == FALSE ? "false" : (*ip1 == DUNNO ? "unknown" : "bogus" ))); } } #endif if ((x->op == CND_MATCH && sts != REG_NOMATCH) || (x->op == CND_NOMATCH && sts == REG_NOMATCH)) *op++ = *ip1 && TRUE; else *op++ = *ip1 && FALSE; } i++; } ip1++; } x->valid++; } else x->valid = 0; x->smpls[0].stamp = arg1->smpls[0].stamp; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cndMatch_inst(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } pcp-3.8.12ubuntu1/src/pmie/src/pmie.c0000664000000000000000000006073212272262521014222 0ustar /*********************************************************************** * pmie.c - performance inference engine *********************************************************************** * * Copyright (c) 2013 Red Hat, Inc. * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * pmie debug flags: * APPL0 - lexical scanning * APPL1 - parse/expression tree construction * APPL2 - expression execution */ #include #include #include "pmapi.h" #include "impl.h" #include #include #include "dstruct.h" #include "stomp.h" #include "syntax.h" #include "pragmatics.h" #include "eval.h" #include "show.h" #if HAVE_TRACE_BACK_STACK #define MAX_PCS 30 /* max callback procedure depth */ #define MAX_SIZE 48 /* max function name length */ #include #endif /*********************************************************************** * constants ***********************************************************************/ #define LINE_LENGTH 255 /* max length of command token */ #define PROC_FNAMESIZE 20 /* from proc pmda - proc.h */ static char *prompt = "pmie> "; static char *intro = "Performance Co-Pilot Inference Engine (pmie), " "Version %s\n\n%s%s"; char *clientid; static FILE *logfp; static char logfile[MAXPATHLEN+1]; static char perffile[MAXPATHLEN+1]; /* /var/tmp/ file name */ static char *username; static char menu[] = "pmie debugger commands\n\n" " f [file-name] - load expressions from given file or stdin\n" " l [expr-name] - list named expression or all expressions\n" " r [interval] - run for given or default interval\n" " S time-spec - set start time for run\n" " T time-spec - set default interval for run command\n" " v [expr-name] - print subexpression used for %h, %i and\n" " %v bindings\n" " h or ? - print this menu of commands\n" " q - quit\n\n"; static char usage[] = "Usage: %s [options] [filename ...]\n\n" "Options:\n" " -A align align sample times on natural boundaries\n" " -a archive metrics source is a PCP log archive\n" " -b one line buffered output stream, stdout on stderr\n" " -C parse configuration and exit\n" " -c filename configuration file\n" " -d interactive debugging mode\n" " -e force timestamps to be reported when used with -V, -v or -W\n" " -f run in foreground\n" " -H do not do a name lookup on the default hostname\n" " -h host metrics source is PMCD on host\n" " -j stompfile stomp protocol (JMS) file [default %s%cconfig%cpmie%cstomp]\n" " -l logfile send status and error messages to logfile\n" " -n pmnsfile use an alternative PMNS\n" " -O offset initial offset into the time window\n" " -S starttime start of the time window\n" " -T endtime end of the time window\n" " -t interval sample interval [default 10 seconds]\n" " -U username in daemon mode, run as named user [default pcp]\n" " -V verbose mode, annotated expression values printed\n" " -v verbose mode, expression values printed\n" " -W verbose mode, satisfying expression values printed\n" " -x run in domain agent mode (summary PMDA)\n" " -Z timezone set reporting timezone\n" " -z set reporting timezone to local time of metrics source\n"; /*********************************************************************** * usage message ***********************************************************************/ static void usageMessage(void) { int sep = __pmPathSeparator(); fprintf(stderr, usage, pmProgname, pmGetConfig("PCP_VAR_DIR"), sep,sep,sep); exit(1); } /*********************************************************************** * interactive commands ***********************************************************************/ /* read command input line */ static int readLine(char *bfr, int max) { int c, i; /* skip blanks */ do c = getchar(); while (isspace(c)); /* scan till end of line */ i = 0; while ((c != '\n') && (c != EOF) && (i < max)) { bfr[i++] = c; c = getchar(); } bfr[i] = '\0'; return (c != EOF); } /* scan interactive command token */ static char * scanCmd(char **pp) { char *p = *pp; /* skip blanks */ while (isspace((int)*p)) p++; /* single char token */ if (isgraph((int)*p)) { *pp = p + 1; return p; } return NULL; } /* scan interactive command argument */ static char * scanArg(char *p) { char *q; /* strip leading blanks */ while (isspace((int)*p)) p++; if (*p == '\0') return NULL; q = p; /* strip trailing blanks */ while (*q != '\0') q++; q--; while (isspace((int)*q)) q--; *(q + 1) = '\0'; /* return result */ return p; } /* load rules from given file or stdin */ static void load(char *fname) { Symbol s; Expr *d; int sts = 0; int sep = __pmPathSeparator(); char config[MAXPATHLEN+1]; /* search for configfile on configuration file path */ if (fname && access(fname, F_OK) != 0) { sts = oserror(); /* always report the first error */ if (__pmAbsolutePath(fname)) { fprintf(stderr, "%s: cannot access config file %s: %s\n", pmProgname, fname, strerror(sts)); exit(1); } #if PCP_DEBUG else if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "load: cannot access config file %s: %s\n", fname, strerror(sts)); } #endif snprintf(config, sizeof(config)-1, "%s%c" "pmie" "%c%s", pmGetConfig("PCP_SYSCONF_DIR"), sep, sep, fname); if (access(config, F_OK) != 0) { fprintf(stderr, "%s: cannot access config file as either %s or %s: %s\n", pmProgname, fname, config, strerror(sts)); exit(1); } #if PCP_DEBUG else if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "load: using standard config file %s\n", config); } #endif fname = config; } #if PCP_DEBUG else if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "load: using config file %s\n", fname == NULL? "":fname); } #endif if (perf->config[0] == '\0') { /* keep record of first config */ if (fname == NULL) strcpy(perf->config, ""); else if (realpath(fname, perf->config) == NULL) { fprintf(stderr, "%s: failed to resolve realpath for %s: %s\n", pmProgname, fname, osstrerror()); exit(1); } } if (synInit(fname)) { while ((s = syntax()) != NULL) { d = (Expr *) symValue(symDelta); pragmatics(s, *(RealTime *)d->smpls[0].ptr); } } } /* list given expression or all expressions */ static void list(char *name) { Task *t; Symbol *r; Symbol s; int i; if (name) { /* single named rule */ if ( (s = symLookup(&rules, name)) ) showSyntax(stdout, s); else printf("%s: error - rule \"%s\" not defined\n", pmProgname, name); } else { /* all rules */ t = taskq; while (t) { r = t->rules; for (i = 0; i < t->nrules; i++) { showSyntax(stdout, *r); r++; } t = t->next; } } } /* list binding subexpression of given expression or all expressions */ static void sublist(char *name) { Task *t; Symbol *r; Symbol s; int i; if (name) { /* single named rule */ if ( (s = symLookup(&rules, name)) ) showSubsyntax(stdout, s); else printf("%s: error - rule '%s' not defined\n", pmProgname, name); } else { /* all rules */ t = taskq; while (t) { r = t->rules; for (i = 0; i < t->nrules; i++) { showSubsyntax(stdout, *r); r++; } t = t->next; } } } /*********************************************************************** * manipulate the performance instrumentation data structure ***********************************************************************/ static void stopmonitor(void) { if (*perffile) unlink(perffile); } static void startmonitor(void) { void *ptr; char *path; int fd; char zero = '\0'; char pmie_dir[MAXPATHLEN]; /* try to create the port file directory. OK if it already exists */ snprintf(pmie_dir, sizeof(pmie_dir), "%s%c%s", pmGetConfig("PCP_TMP_DIR"), __pmPathSeparator(), PMIE_SUBDIR); if (mkdir2(pmie_dir, S_IRWXU | S_IRWXG | S_IRWXO) < 0) { if (oserror() != EEXIST) { fprintf(stderr, "%s: warning cannot create stats file dir %s: %s\n", pmProgname, pmie_dir, osstrerror()); } } atexit(stopmonitor); /* create and initialize memory mapped performance data file */ sprintf(perffile, "%s%c%" FMT_PID, pmie_dir, __pmPathSeparator(), getpid()); unlink(perffile); if ((fd = open(perffile, O_RDWR | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { /* cannot create stats file; too bad, so sad, continue on without it */ perf = &instrument; return; } /* seek to struct size and write one zero */ lseek(fd, sizeof(pmiestats_t)-1, SEEK_SET); if (write(fd, &zero, 1) != 1) { fprintf(stderr, "%s: Warning: write failed for stats file %s: %s\n", pmProgname, perffile, osstrerror()); } /* map perffile & associate the instrumentation struct with it */ if ((ptr = __pmMemoryMap(fd, sizeof(pmiestats_t), 1)) == NULL) { fprintf(stderr, "%s: memory map failed for stats file %s: %s\n", pmProgname, perffile, osstrerror()); perf = &instrument; } else { perf = (pmiestats_t *)ptr; } close(fd); path = (logfile[0] == '\0') ? "" : logfile; strncpy(perf->logfile, path, sizeof(perf->logfile)); perf->logfile[sizeof(perf->logfile)-1] = '\0'; strncpy(perf->defaultfqdn, dfltHostName, sizeof(perf->defaultfqdn)); perf->defaultfqdn[sizeof(perf->defaultfqdn)-1] = '\0'; perf->version = 1; } /*********************************************************************** * signal handling ***********************************************************************/ static void sigintproc(int sig) { __pmSetSignalHandler(SIGINT, SIG_IGN); __pmSetSignalHandler(SIGTERM, SIG_IGN); __pmNotifyErr(LOG_INFO, "%s caught SIGINT or SIGTERM\n", pmProgname); exit(1); } static void sigbye(int sig) { exit(0); } static void remap_stdout_stderr(void) { int i, j; fflush(stderr); fflush(stdout); setlinebuf(stderr); setlinebuf(stdout); i = fileno(stdout); close(i); if ((j = dup(fileno(stderr))) != i) fprintf(stderr, "%s: Warning: failed to link stdout ... " "dup() returns %d, expected %d (stderr=%d)\n", pmProgname, j, i, fileno(stderr)); } static void sighupproc(int sig) { FILE *fp; int sts; fp = __pmRotateLog(pmProgname, logfile, logfp, &sts); if (sts != 0) { fprintf(stderr, "pmie: PID = %" FMT_PID ", default host = %s via %s\n\n", getpid(), dfltHostName, dfltHostConn); remap_stdout_stderr(); logfp = fp; } else { __pmNotifyErr(LOG_ERR, "pmie: log rotation failed\n"); } } static void dotraceback(void) { #if HAVE_TRACE_BACK_STACK __uint64_t call_addr[MAX_PCS]; char *call_fn[MAX_PCS]; char names[MAX_PCS][MAX_SIZE]; int res; int i; fprintf(stderr, "\nProcedure call traceback ...\n"); for (i = 0; i < MAX_PCS; i++) call_fn[i] = names[i]; res = trace_back_stack(MAX_PCS, call_addr, call_fn, MAX_PCS, MAX_SIZE); for (i = 1; i < res; i++) fprintf(stderr, " " PRINTF_P_PFX "%p [%s]\n", (void *)call_addr[i], call_fn[i]); #endif return; } static void sigbadproc(int sig) { __pmNotifyErr(LOG_ERR, "Unexpected signal %d ...\n", sig); dotraceback(); fprintf(stderr, "\nDumping to core ...\n"); fflush(stderr); stopmonitor(); abort(); } /*********************************************************************** * command line processing - extract command line arguments & initialize ***********************************************************************/ static void getargs(int argc, char *argv[]) { char *configfile = NULL; char *commandlog = NULL; char *subopts; char *subopt; char *msg; int checkFlag = 0; int foreground = 0; int err = 0; int sts; int c; int bflag = 0; int dfltConn = 0; /* default context type */ Archive *a; struct timeval tv, tv1, tv2; extern int showTimeFlag; extern int errs; /* syntax errors from syntax.c */ memset(&tv, 0, sizeof(tv)); memset(&tv1, 0, sizeof(tv1)); memset(&tv2, 0, sizeof(tv2)); dstructInit(); while ((c=getopt(argc, argv, "a:A:bc:CdD:efHh:j:l:n:O:S:t:T:U:vVWXxzZ:?")) != EOF) { switch (c) { case 'a': /* archives */ if (dfltConn && dfltConn != PM_CONTEXT_ARCHIVE) { /* (technically, multiple -a's are allowed.) */ fprintf(stderr, "%s: at most one of -a or -h allowed\n", pmProgname); err++; break; } dfltConn = PM_CONTEXT_ARCHIVE; subopts = optarg; for ( ; ; ) { subopt = subopts; subopts = strchr(subopts, ','); if (subopts != NULL) { *subopts++ = '\0'; } a = (Archive *)zalloc(sizeof(Archive)); a->fname = subopt; if (!initArchive(a)) { exit(1); } if (subopts == NULL) break; } foreground = 1; break; case 'A': /* sample alignment */ alignFlag = optarg; break; case 'b': /* line buffered, stdout on stderr */ bflag++; break; case 'c': /* configuration file */ if (interactive) { fprintf(stderr, "%s: at most one of -c and -d allowed\n", pmProgname); err++; break; } configfile = optarg; break; case 'C': /* check config and exit */ checkFlag = 1; break; case 'd': /* interactive mode */ if (configfile) { fprintf(stderr, "%s: at most one of -c and -d allowed\n", pmProgname); err++; break; } interactive = 1; break; case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification " "(%s)\n", pmProgname, optarg); err++; } else pmDebug |= sts; break; case 'e': /* force timestamps */ showTimeFlag = 1; break; case 'f': /* in foreground, not as daemon */ foreground = 1; break; case 'H': /* no name lookup on exported host */ noDnsFlag = 1; break; case 'h': /* default host name */ if (dfltConn) { fprintf(stderr, "%s: at most one of -a or -h allowed\n", pmProgname); err++; break; } dfltConn = PM_CONTEXT_HOST; dfltHostConn = optarg; dfltHostName = ""; /* unknown until newContext */ break; case 'j': /* stomp protocol (JMS) config */ stompfile = optarg; break; case 'l': /* alternate log file */ if (commandlog != NULL) { fprintf(stderr, "%s: at most one -l option is allowed\n", pmProgname); err++; break; } commandlog = optarg; isdaemon = 1; break; case 'n': /* alternate namespace file */ pmnsfile = optarg; break; case 'O': /* position within time window */ offsetFlag = optarg; break; case 'S': /* start run time */ startFlag = optarg; break; case 't': /* sample interval */ if (pmParseInterval(optarg, &tv1, &msg) == 0) dfltDelta = realize(tv1); else { fprintf(stderr, "%s: could not parse -t argument (%s)\n", pmProgname, optarg); fputs(msg, stderr); free(msg); err++; } break; case 'T': /* evaluation period */ stopFlag = optarg; break; case 'U': /* run as named user */ username = optarg; isdaemon = 1; break; case 'v': /* print values */ verbose = 1; break; case 'V': /* print annotated values */ verbose = 2; break; case 'W': /* print satisfying values */ verbose = 3; break; case 'X': /* secret applet flag */ applet = 1; verbose = 1; setlinebuf(stdout); break; case 'x': /* summary PMDA flag */ agent = 1; verbose = 1; isdaemon = 1; break; case 'z': /* timezone from host */ hostZone = 1; if (timeZone) { fprintf(stderr, "%s: only one of -Z and -z allowed\n", pmProgname); err++; } break; case 'Z': /* explicit TZ string */ timeZone = optarg; if (hostZone) { fprintf(stderr, "%s: only one of -Z and -z allowed\n", pmProgname); err++; } break; case '?': err++; } } if (configfile && optind != argc) { fprintf(stderr, "%s: extra filenames cannot be given after using -c\n", pmProgname); err++; } if (bflag && agent) { fprintf(stderr, "%s: the -b and -x options are incompatible\n", pmProgname); err++; } if (err) usageMessage(); if (foreground) isdaemon = 0; if (archives || interactive) perf = &instrument; if (isdaemon) { /* daemon mode */ /* done before opening log to get permissions right */ __pmSetProcessIdentity(username); #if defined(HAVE_TERMIO_SIGNALS) signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTSTP, SIG_IGN); #endif __pmSetSignalHandler(SIGINT, sigintproc); __pmSetSignalHandler(SIGTERM, sigintproc); __pmSetSignalHandler(SIGBUS, sigbadproc); __pmSetSignalHandler(SIGSEGV, sigbadproc); } else { /* need to catch these so the atexit() processing is done */ __pmSetSignalHandler(SIGINT, sigbye); __pmSetSignalHandler(SIGTERM, sigbye); } if (commandlog != NULL) { logfp = __pmOpenLog(pmProgname, commandlog, stderr, &sts); if (realpath(commandlog, logfile) == NULL) { fprintf(stderr, "%s: cannot find realpath for log %s: %s\n", pmProgname, commandlog, osstrerror()); exit(1); } __pmSetSignalHandler(SIGHUP, (isdaemon && !agent) ? sighupproc : SIG_IGN); } else { __pmSetSignalHandler(SIGHUP, SIG_IGN); } /* * -b ... force line buffering and stdout onto stderr */ if ((bflag || isdaemon) && !agent) remap_stdout_stderr(); /* default host from leftmost archive on command line, or from discovery after a brief connection */ if (archives) { a = archives; while (a->next) a = a->next; dfltHostName = a->hname; /* already filled in during initArchive() */ } else if (!dfltConn || dfltConn == PM_CONTEXT_HOST) { if (dfltConn == 0) /* default case, no -a or -h */ dfltHostConn = "local:"; sts = pmNewContext(PM_CONTEXT_HOST, dfltHostConn); /* pmcd down locally, try to extract hostname manually */ if (sts < 0 && (!dfltConn || !strcmp(dfltHostConn, "localhost") || !strcmp(dfltHostConn, "local:") || !strcmp(dfltHostConn, "unix:"))) sts = pmNewContext(PM_CONTEXT_LOCAL, NULL); if (sts < 0) { __pmNotifyErr(LOG_ERR, "%s: cannot find host name for %s\n" "pmNewContext failed: %s\n", pmProgname, dfltHostConn, pmErrStr(sts)); dfltHostName = "?"; } else { if ((dfltHostName = strdup(pmGetContextHostName(sts))) == NULL) __pmNoMem("host name copy", 0, PM_FATAL_ERR); pmDestroyContext(sts); } } assert (dfltHostName != NULL); if (!archives && !interactive) { if (commandlog != NULL) fprintf(stderr, "pmie: PID = %" FMT_PID ", default host = %s via %s\n\n", getpid(), dfltHostName, dfltHostConn); startmonitor(); } /* initialize time */ now = archives ? first : getReal() + 1.0; zoneInit(); reflectTime(dfltDelta); /* parse time window - just to check argument syntax */ unrealize(now, &tv1); if (archives) { unrealize(last, &tv2); } else { tv2.tv_sec = INT_MAX; /* sizeof(time_t) == sizeof(int) */ tv2.tv_usec = 0; } if (pmParseTimeWindow(startFlag, stopFlag, alignFlag, offsetFlag, &tv1, &tv2, &tv, &tv2, &tv1, &msg) < 0) { fputs(msg, stderr); exit(1); } start = realize(tv1); stop = realize(tv2); runTime = stop - start; /* initialize PMAPI */ if (pmnsfile != PM_NS_DEFAULT && (sts = pmLoadNameSpace(pmnsfile)) < 0) { fprintf(stderr, "%s: pmLoadNameSpace failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } /* when not in secret agent mode, register client id with pmcd */ if (!agent) clientid = __pmGetClientId(argc, argv); if (!interactive && optind == argc) { /* stdin or config file */ load(configfile); } else { /* list of 1/more filenames */ while (optind < argc) { load(argv[optind]); optind++; } } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) dumpRules(); #endif if (checkFlag) exit(errs == 0 ? 0 : 1); /* exit 1 for syntax errors ... * suggestion from * Kevin Wang */ if (isdaemon) { /* daemon mode */ /* Note: we can no longer unilaterally close stdin here, as it * can really confuse remap_stdout_stderr() during log rotation! */ if (agent) close(fileno(stdin)); #ifndef IS_MINGW setsid(); /* not process group leader, lose controlling tty */ #endif } if (stomping) stompInit(); /* connect to our message server */ if (agent) agentInit(); /* initialize secret agent stuff */ /* really parse time window */ if (!archives) { now = getReal() + 1.0; reflectTime(dfltDelta); } unrealize(now, &tv1); if (archives) { unrealize(last, &tv2); } else { tv2.tv_sec = INT_MAX; tv2.tv_usec = 0; } if (pmParseTimeWindow(startFlag, stopFlag, alignFlag, offsetFlag, &tv1, &tv2, &tv, &tv2, &tv1, &msg) < 0) { fputs(msg, stderr); exit(1); } /* set run timing window */ start = realize(tv1); stop = realize(tv2); runTime = stop - start; } /*********************************************************************** * interactive (debugging) mode ***********************************************************************/ static void interact(void) { int quit = 0; char *line = (char *)zalloc(LINE_LENGTH + 2); char *finger; char *token; char *msg; RealTime rt; struct timeval tv1, tv2; printf(intro, PCP_VERSION, menu, prompt); fflush(stdout); while (!quit && readLine(line, LINE_LENGTH)) { finger = line; if ( (token = scanCmd(&finger)) ) { switch (*token) { case 'f': token = scanArg(finger); load(token); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) dumpRules(); #endif break; case 'l': token = scanArg(finger); list(token); break; case 'r': token = scanArg(finger); if (token) { if (pmParseInterval(token, &tv1, &msg) == 0) runTime = realize(tv1); else { fputs(msg, stderr); free(msg); break; } } if (!archives) { invalidate(); rt = getReal(); if (now < rt) now = rt; start = now; } stop = start + runTime; run(); break; case 'S': token = scanArg(finger); if (token == NULL) { fprintf(stderr, "%s: error - argument required\n", pmProgname); break; } unrealize(start, &tv1); if (archives) { unrealize(last, &tv2); } else { tv2.tv_sec = INT_MAX; tv2.tv_usec = 0; } if (__pmParseTime(token, &tv1, &tv2, &tv1, &msg) < 0) { fputs(msg, stderr); free(msg); break; } start = realize(tv1); if (archives) invalidate(); break; case 'T': token = scanArg(finger); if (token == NULL) { fprintf(stderr, "%s: error - argument required\n", pmProgname); break; } if (pmParseInterval(token, &tv1, &msg) < 0) { fputs(msg, stderr); free(msg); break; } runTime = realize(tv1); break; case 'q': quit = 1; break; case 'v': token = scanArg(finger); sublist(token); break; case '?': default: printf("%s", menu); } } if (!quit) { printf("%s", prompt); fflush(stdout); } } free(line); } /*********************************************************************** * main ***********************************************************************/ int main(int argc, char **argv) { __pmSetProgname(argv[0]); __pmGetUsername(&username); setlinebuf(stdout); /* PCP_COUNTER_WRAP in environment enables "counter wrap" logic */ if (getenv("PCP_COUNTER_WRAP") != NULL) dowrap = 1; getargs(argc, argv); if (interactive) interact(); else run(); exit(0); } pcp-3.8.12ubuntu1/src/pmie/src/symbol.c0000664000000000000000000001410412272262501014563 0ustar /*********************************************************************** * symbol.c - a symbol is an object with a name, a value and a * reference count *********************************************************************** * * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "symbol.h" #include "dstruct.h" #include "pmapi.h" /*********************************************************************** * constants ***********************************************************************/ /* bucket memory alignment, address mask and size */ #undef ALIGN #define ALIGN 1024 #undef MASK #define MASK (ALIGN - 1) #undef BSIZE #define BSIZE (ALIGN / sizeof(SymUnion)) /*********************************************************************** * types ***********************************************************************/ typedef SymUnion Bucket[BSIZE]; /*********************************************************************** * local functions ***********************************************************************/ static void addBucket(SymUnion *st) { SymUnion *bckt = (SymUnion *) aalloc(ALIGN, sizeof(Bucket)); SymUnion *scoop = bckt + 1; bckt->hdr.prev = st; bckt->hdr.next = st->hdr.next; bckt->hdr.free = scoop; st->hdr.next->hdr.prev = bckt; st->hdr.next = bckt; scoop->entry.refs = 0; scoop->entry.stat.free.ptr = NULL; scoop->entry.stat.free.count = BSIZE - 1; } static void remBucket(SymUnion *bckt) { SymUnion *prev = bckt->hdr.prev; SymUnion *next = bckt->hdr.next; SymUnion *scan; int i = 1; prev->hdr.next = next; next->hdr.prev = prev; while (i < BSIZE) { scan = bckt + i; if (scan->entry.refs == 0) i += scan->entry.stat.free.count; else { free(scan->entry.stat.used.name); i++; } } free(bckt); } /*********************************************************************** * exported functions ***********************************************************************/ /* initialize symbol table */ void symSetTable(SymbolTable *st) { /* start with one clean bucket */ st->hdr.next = st; st->hdr.prev = st; addBucket(st); } /* reset symbol table */ void symClearTable(SymbolTable *st) { /* unchain all buckets and free storage */ while (st->hdr.next != st) remBucket(st->hdr.next); /* start with one clean bucket */ addBucket(st); } /* Convert string to symbol. A copy of the name string is made on the heap for use by the symbol. */ Symbol symIntern(SymbolTable *st, char *name) { SymUnion *bckt; SymUnion *scoop = NULL; char *copy; int i; /* pick up existing symbol */ bckt = st->hdr.next; while (bckt != st) { i = 1; while (i < BSIZE) { scoop = bckt + i; if (scoop->entry.refs) { if (strcmp(name, scoop->entry.stat.used.name) == 0) { scoop->entry.refs++; return scoop; } i++; } else i += scoop->entry.stat.free.count; } bckt = bckt->hdr.next; } /* pick up free entry */ bckt = st->hdr.next; while (bckt != st) { if ((scoop = bckt->hdr.free)) { if (scoop->entry.stat.free.count > 1) scoop += --scoop->entry.stat.free.count; else bckt->hdr.free = scoop->entry.stat.free.ptr; break; } bckt = bckt->hdr.next; } /* no free entry - allocate new bucket */ if (scoop == NULL) { addBucket(st); scoop = st->hdr.next + 1; scoop += --scoop->entry.stat.free.count; } /* initialize symbol */ scoop->entry.refs = 1; copy = (char *) alloc(strlen(name) + 1); strcpy(copy, name); scoop->entry.stat.used.name = copy; scoop->entry.stat.used.value = NULL; return scoop; } /* lookup symbol by name */ Symbol symLookup(SymbolTable *st, char *name) { SymUnion *bckt; SymUnion *scoop; int i; bckt = st->hdr.next; while (bckt != st) { i = 1; while (i < BSIZE) { scoop = bckt + i; if (scoop->entry.refs) { if (strcmp(name, scoop->entry.stat.used.name) == 0) { scoop->entry.refs++; return scoop; } i++; } else i += scoop->entry.stat.free.count; } bckt = bckt->hdr.next; } return NULL; } /* copy symbol */ Symbol symCopy(Symbol sym) { sym->entry.refs++; return sym; } /* remove reference to symbol */ void symFree(Symbol sym) { SymUnion *bckt; SymUnion *lead, *lag; if ((sym != SYM_NULL) && (--sym->entry.refs <= 0)) { /* free up name string BUT NOT value */ free(sym->entry.stat.used.name); /* find correct place in ordered free list */ bckt = (SymUnion *) ((char *) sym - ((long) sym & MASK)); lead = bckt->hdr.free; lag = NULL; while ((lead != NULL) && (lead < sym)) { lag = lead; lead = lead->entry.stat.free.ptr; } if (lag != NULL && (lag + lag->entry.stat.free.count) == sym) { /* coalesce with preceding free block */ lag->entry.stat.free.count++; sym = lag; } else { /* link up as single free entry */ if (lag) lag->entry.stat.free.ptr = sym; else bckt->hdr.free = sym; sym->entry.stat.free.count = 1; sym->entry.stat.free.ptr = lead; } if (sym + sym->entry.stat.free.count == lead) { /* coalesce with following free block */ sym->entry.stat.free.count += lead->entry.stat.free.count; sym->entry.stat.free.ptr = lead->entry.stat.free.ptr; } } } pcp-3.8.12ubuntu1/src/pmie/src/GNUmakefile0000664000000000000000000000474212272262501015173 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs TARGET = pmie$(EXECSUFFIX) CFILES = pmie.c symbol.c dstruct.c lexicon.c syntax.c pragmatics.c eval.c \ show.c match_inst.c systemlog.c stomp.c andor.c HFILES = fun.h dstruct.h eval.h lexicon.h pragmatics.h stats.h \ show.h symbol.h syntax.h systemlog.h stomp.h andor.h SKELETAL = hdr.sk fetch.sk misc.sk aggregate.sk unary.sk binary.sk \ merge.sk act.sk LSRCFILES = $(SKELETAL) meta logger.h LDIRT += $(YFILES:%.y=%.tab.?) fun.c fun.o $(TARGET) grammar.h LLDLIBS = $(PCPLIB) $(LIB_FOR_MATH) $(LIB_FOR_REGEX) LCFLAGS += $(PIECFLAGS) LLDFLAGS += $(PIELDFLAGS) default: $(TARGET) YFILES = grammar.y .NOTPARALLEL: grammar.h grammar.tab.c: grammar.y $(YACC) -d -b `basename $< .y` $< && cp `basename $@ .h`.tab.h $@ pmie$(EXECSUFFIX): $(OBJECTS) fun.o $(CCF) -o $@ $(LDFLAGS) $(OBJECTS) fun.o $(LDLIBS) install: default $(INSTALL) -m 755 $(TARGET) $(PCP_BIN_DIR)/$(TARGET) lexicon.o syntax.o: grammar.h fun.o: fun.h fun.c: $(SKELETAL) meta @echo $@ ./meta include $(BUILDRULES) default_pcp: default install_pcp: install fun.h: andor.h andor.o dstruct.o eval.o fun.o grammar.tab.o lexicon.o match_inst.o pmie.o pragmatics.o show.o syntax.o systemlog.o: dstruct.h dstruct.o eval.o pmie.o pragmatics.o syntax.o systemlog.o: eval.h andor.o dstruct.o eval.o fun.o match_inst.o: fun.h lexicon.o syntax.o: grammar.h grammar.tab.o lexicon.o show.o syntax.o: lexicon.h systemlog.o: logger.h andor.o dstruct.o eval.o fun.o grammar.tab.o lexicon.o pmie.o pragmatics.o show.o syntax.o: pragmatics.h andor.o dstruct.o eval.o fun.o grammar.tab.o match_inst.o pmie.o show.o syntax.o: show.h andor.o fun.o grammar.tab.o pmie.o stomp.o: stomp.h andor.o dstruct.o eval.o fun.o grammar.tab.o lexicon.o match_inst.o pmie.o pragmatics.o show.o symbol.o syntax.o systemlog.o: symbol.h grammar.tab.o lexicon.o pmie.o syntax.o systemlog.o: syntax.h fun.o grammar.tab.o systemlog.o: systemlog.h pcp-3.8.12ubuntu1/src/pmie/src/merge.sk0000664000000000000000000000442512272262501014555 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*********************************************************************** * skeleton: merge.sk ***********************************************************************/ /* * operator: @FUN */ void @FUN_n(Expr *x) { Expr *arg1 = x->arg1; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg1->smpls[1]; Sample *os = &x->smpls[0]; @ITYPE *ip1; @ITYPE *ip2; @OTYPE *op; RealTime delta; int n; int i; EVALARG(arg1) ROTATE(x) if (arg1->valid >= 2 && x->tspan > 0) { ip1 = (@ITYPE *)is1->ptr; ip2 = (@ITYPE *)is2->ptr; op = (@OTYPE *)os->ptr; n = x->tspan; @DELTA for (i = 0; i < n; i++) { *op = *ip1++ @OP *ip2++; @SCALE op++; } os->stamp = is1->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "@FUN_n(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void @FUN_1(Expr *x) { Expr *arg1 = x->arg1; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg1->smpls[1]; Sample *os = &x->smpls[0]; @ITYPE *ip1; @ITYPE *ip2; @OTYPE *op; RealTime delta; EVALARG(arg1) ROTATE(x) if (arg1->valid >= 2) { ip1 = (@ITYPE *)is1->ptr; ip2 = (@ITYPE *)is2->ptr; op = (@OTYPE *)os->ptr; @DELTA *op = *ip1 @OP *ip2; @SCALE os->stamp = is1->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "@FUN_1(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } pcp-3.8.12ubuntu1/src/pmie/src/systemlog.c0000664000000000000000000001057512272262501015314 0ustar /* * Copyright (c) 1999-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #define SYSLOG_NAMES #include "dstruct.h" #include "eval.h" #include "syntax.h" #include "systemlog.h" #include "pmapi.h" #if defined(IS_SOLARIS) || defined(IS_AIX) || defined(IS_MINGW) #include "logger.h" #endif /* * based on source for logger(1) */ static int decode(char *name, CODE *codetab) { CODE *c; if (isdigit((int)*name)) return (atoi(name)); for (c = codetab; c->c_name; c++) if (!strcasecmp(name, c->c_name)) return (c->c_val); return (-1); } /* * Decode a symbolic name to a numeric value * ... based on source for logger(1) */ static int pencode(char *s) { char *save; int fac, lev; save = s; while (*s && *s != '.') ++s; if (*s) { *s = '\0'; fac = decode(save, facilitynames); if (fac < 0) { synwarn(); fprintf(stderr, "Ignoring unknown facility (%s) for -p in syslog action\n", save); fac = 0; } s++; } else { fac = 0; s = save; } lev = decode(s, prioritynames); if (lev < 0) { synwarn(); fprintf(stderr, "Ignoring unknown priority (%s) for -p in syslog action\n", s); lev = LOG_NOTICE; } return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK)); } /* * handle splitting of -t tag and -p prio across one or two * arguments to the syslog action in the rule */ static void nextch(char **p, Expr **x) { static char end = '\0'; (*p)++; while (**p == '\0') { if ((*x)->arg1 == NULL) { *p = &end; return; } *x = (*x)->arg1; *p = (*x)->ring; } } /* * post-process the expression tree for a syslog action to gather * any -t tag or -p pri options (as for logger(1)) and build the * encoded equivalent as a new expression accessed via arg2 from * the head of the arguments list */ void do_syslog_args(Expr *act) { int pri = -1; char *tag = NULL; char *p; char *q; Expr *others; Expr *tmp; Expr *new; /* * scan for -p pri and -t tag */ for (others = act->arg1; others != NULL; ) { if (others->ring == NULL) break; p = others->ring; if (*p != '-') break; nextch(&p, &others); if (*p == 'p' && pri == -1) { nextch(&p, &others); while (*p && isspace((int)*p)) nextch(&p, &others); if (*p == '\0') { synwarn(); fprintf(stderr, "Missing [facility.]priority after -p in syslog action\n"); } else { q = p+1; while (*q && !isspace((int)*q)) q++; if (*q) { synwarn(); fprintf(stderr, "Ignoring extra text (%s) after -p pri in syslog action\n", q); *q = '\0'; } pri = pencode(p); } } else if (*p == 't' && tag == NULL) { nextch(&p, &others); while (*p && isspace((int)*p)) nextch(&p, &others); if (*p == '\0') { synwarn(); fprintf(stderr, "Missing tag after -t in syslog action\n"); } else { q = p+1; while (*q && !isspace((int)*q)) q++; if (*q) { synwarn(); fprintf(stderr, "Ignoring extra text (%s) after -t tag in syslog action\n", q); *q = '\0'; } tag = p; } } else break; others = others->arg1; } /* defaults if -t and/or -p not seen */ if (pri < 0) pri = LOG_NOTICE; if (tag == NULL) tag = "pcp-pmie"; /* * construct new arg2 argument node, with * ring -> pri (int) and tag (char *) concatenated */ new = (Expr *) zalloc(sizeof(Expr)); new->op = NOP; new->ring = (char *)alloc(sizeof(int)+strlen(tag)+1); *((int *)new->ring) = pri; strcpy(&((char *)new->ring)[sizeof(int)], tag); act->arg2 = new; new->parent = act; /* free old argument nodes used for -p and/or -t specifications */ for (tmp = act->arg1; tmp != others; ) { if (tmp->ring) { free(tmp->ring); } new = tmp->arg1; free(tmp); tmp = new; } /* re-link remaining argument nodes */ if (others != act->arg1) { act->arg1 = others; if (others != NULL) others->parent = act; } } pcp-3.8.12ubuntu1/src/pmie/src/unary.sk0000664000000000000000000000402612272262501014611 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*********************************************************************** * skeleton: unary.sk - unary operator ***********************************************************************/ /* * operator: @FUN */ #define @OP void @FUN_n(Expr *x) { Expr *arg1 = x->arg1; Sample *is = &arg1->smpls[0]; Sample *os = &x->smpls[0]; @ITYPE *ip; @OTYPE *op; int n; int i; EVALARG(arg1) ROTATE(x) if (arg1->valid && x->tspan > 0) { ip = (@ITYPE *) is->ptr; op = (@OTYPE *) os->ptr; n = x->tspan; for (i = 0; i < n; i++) { *op = OP(*ip); op++; ip++; } os->stamp = is->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "@FUN_n(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void @FUN_1(Expr *x) { Expr *arg1 = x->arg1; Sample *is = &arg1->smpls[0]; Sample *os = &x->smpls[0]; EVALARG(arg1) ROTATE(x) if (arg1->valid) { *(@OTYPE *)os->ptr = OP(*(@ITYPE *)is->ptr); os->stamp = is->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "@FUN_1(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } #undef OP pcp-3.8.12ubuntu1/src/pmie/src/andor.h0000664000000000000000000000242012272262501014364 0ustar /*********************************************************************** * andor.h - Logical AND/OR expression evaluator functions *********************************************************************** * * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef ANDOR_H #define ANDOR_H /* expression evaluator function prototypes */ void cndOr_n_n(Expr *); void cndOr_1_n(Expr *); void cndOr_n_1(Expr *); void cndOr_1_1(Expr *); void cndAnd_n_n(Expr *); void cndAnd_1_n(Expr *); void cndAnd_n_1(Expr *); void cndAnd_1_1(Expr *); #endif /* ANDOR_H */ pcp-3.8.12ubuntu1/src/pmie/src/fetch.sk0000664000000000000000000002431512272262501014547 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*********************************************************************** * skeleton: fetch.sk - fetch metric values ***********************************************************************/ /* * operator: cndFetch */ static int indom_changed(Metric *m) { int changed = 0; int j; /* check for changes in the instance domain */ if (m->vset == NULL || m->vset->numval <= 0) { if (m->m_idom > 0) changed = 1; } else { if (m->vset->numval != m->m_idom) changed = 1; else { for (j = 0; j < m->m_idom; j++) { if (m->iids[j] != m->vset->vlist[j].inst) { changed = 1; break; } } } } if (changed) { int old; int new; int numval; char **inames; int *iids; int sts; int handle = -1; int old_handle = -1; char **get_inames; int *get_iids; int numinst = -1; if (m->vset == NULL || m->vset->numval <= 0) numval = 0; else numval = m->vset->numval; /* build new inames[] and iids[] */ if (numval > 0) { inames = (char **)alloc(numval * sizeof(char *)); iids = (int *)alloc(numval * sizeof(int)); if (numval > m->m_idom && m->desc.sem == PM_SEM_COUNTER) { /* more instances, so expand the val array */ m->vals = (double *)ralloc(m->vals, numval * sizeof(double)); for (j = m->m_idom; j < numval; j++) m->vals[j] = 0; } } else { inames = NULL; iids = NULL; } for (new = 0; new < numval; new++) { for (old = 0; old < m->m_idom; old++) { if (m->iids[old] == m->vset->vlist[new].inst) break; } if (old < m->m_idom) { /* in both lists */ inames[new] = m->inames[old]; m->inames[old] = NULL; iids[new] = m->iids[old]; if (m->desc.sem == PM_SEM_COUNTER && new != old) { /* swap vals[] */ double d; d = m->vals[new]; m->vals[new] = m->vals[old]; m->vals[old] = d; } } else { /* new one */ inames[new] = NULL; iids[new] = m->vset->vlist[new].inst; } } /* * clean up old inames and iids, the install new ones */ if (m->m_idom > 0 && m->inames != NULL) { for (old = 0; old < m->m_idom; old++) { if (m->inames[old] != NULL) free(m->inames[old]); } } if (m->inames != NULL) free(m->inames); if (m->iids != NULL) free(m->iids); m->inames = inames; m->iids = iids; m->m_idom = numval; for (new = 0; new < m->m_idom; new++) { if (m->inames[new] == NULL) { if (handle < 0) { /* set up temporary context */ if (old_handle < 0) old_handle = pmWhichContext(); handle = newContext(symName(m->hname)); } if (handle < 0) { sts = -1; } else { if (archives) { if ((sts = pmNameInDomArchive(m->desc.indom, m->iids[new], &m->inames[new])) < 0) { __pmNotifyErr(LOG_ERR, "metric %s from %s: instance domain not " "available in archive\npmNameInDomArchive failed: %s\n", symName(m->mname), findsource(symName(m->hname)), pmErrStr(sts)); } } else { if (numinst == -1) { if ((sts = pmGetInDom(m->desc.indom, &get_iids, &get_inames)) < 0) { __pmNotifyErr(LOG_ERR, "metric %s from %s: instance domain not (currently) available\n" "pmGetInDom failed: %s\n", symName(m->mname), findsource(symName(m->hname)), pmErrStr(sts)); } else numinst = sts; } sts = -1; for (j = 0; j < numinst; j++) { if (m->iids[new] == get_iids[j]) { m->inames[new] = sdup(get_inames[j]); sts = 0; break; } } } } if (sts < 0) { /* ugly, but not much choice */ m->inames[new] = sdup("inst#xxxxxxxxxxxx?"); sprintf(m->inames[new], "inst#%d?", m->iids[new]); } if (m->desc.sem == PM_SEM_COUNTER) m->vals[new] = 0; } } if (handle >= 0) { pmDestroyContext(handle); if (old_handle >= 0) pmUseContext(old_handle); } if (numinst > 0) { /* pmGetInDom returned some instances above */ free(get_iids); free(get_inames); } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "indom_changed: %s from %s\n", symName(m->mname), symName(m->hname)); if (m->m_idom < 1) fprintf(stderr, " %d instances!\n", m->m_idom); for (j = 0; j < m->m_idom; j++) { fprintf(stderr, " indom[%d] %d \"%s\"\n", j, m->iids[j], m->inames[j]); } } #endif } return changed; } /* null instance domain - so 1 instance only */ void cndFetch_1(Expr *x) { Metric *m = x->metrics; double *op; RealTime stamp = 0; pmAtomValue a; double t; int i, j; ROTATE(x) x->valid++; op = (double *)x->smpls[0].ptr; for (i = 0; i < x->hdom; i++) { /* extract value */ if (m->vset && m->vset->numval == 1) { pmExtractValue(m->vset->valfmt, &m->vset->vlist[0], m->desc.type, &a, PM_TYPE_DOUBLE); *op++ = m->conv * a.d; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cndFetch_1: %s from %s = %g", symName(m->mname), symName(m->hname), m->conv * a.d); if (m->conv != 1) fprintf(stderr, " (unconv = %g)", a.d); fputc('\n', stderr); } #endif } /* no value */ else { x->valid = 0; for (j = i; j < x->hdom; j++) { m->stomp = 0; m->vset = NULL; m++; } return; } m->vset = NULL; /* rate computation */ if (m->desc.sem == PM_SEM_COUNTER) { op--; if (m->m_idom > 0) { t = *op - m->vals[0]; if (t < 0.0 && dowrap) { switch (m->desc.type) { case PM_TYPE_32: case PM_TYPE_U32: t += (double)UINT_MAX+1; break; case PM_TYPE_64: case PM_TYPE_U64: t += (double)ULONGLONG_MAX+1; break; } } t /= (m->stamp - m->stomp); m->vals[0] = *op; if (t < 0.0) x->valid = 0; else *op = t; op++; } if (m->stomp == 0) x->valid = 0; m->stomp = m->stamp; } /* pick up most recent timestamp */ if (m->stamp > stamp) stamp = m->stamp; m++; } x->smpls[0].stamp = stamp; } void cndFetch_all(Expr *x) { Metric *m = x->metrics; double *op; RealTime stamp = 0; pmAtomValue a; double t; int fix_idom = 0; int i, j; ROTATE(x) x->valid++; /* preliminary scan through Metrics */ for (i = 0; i < x->hdom; i++) { /* check for different instances */ if (indom_changed(m)) { fix_idom = 1; m->stomp = 0; x->valid = 1; } m++; } if (fix_idom) { /* * propagate indom changes up the expression tree * and reshape the ring buffer if required */ instFetchExpr(x); } /* extract values */ op = (double *)x->smpls[0].ptr; m = x->metrics; for (i = 0; i < x->hdom; i++) { /* extract values from m->vset */ for (j = 0; j < m->m_idom; j++) { pmExtractValue(m->vset->valfmt, &m->vset->vlist[j], m->desc.type, &a, PM_TYPE_DOUBLE); *op++ = m->conv * a.d; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cndFetch_all: %s[%s] from %s = %g", symName(m->mname), m->inames[j], symName(m->hname), m->conv * a.d); if (m->conv != 1) fprintf(stderr, " (unconv = %g)", a.d); fputc('\n', stderr); } #endif } m->vset = NULL; /* rate computation */ if (m->desc.sem == PM_SEM_COUNTER) { op -= m->m_idom; for (j = 0; j < m->m_idom; j++) { t = *op - m->vals[j]; if (t < 0.0 && dowrap) { switch (m->desc.type) { case PM_TYPE_32: case PM_TYPE_U32: t += (double)UINT_MAX+1; break; case PM_TYPE_64: case PM_TYPE_U64: t += (double)ULONGLONG_MAX+1; break; } } t /= (m->stamp - m->stomp); m->vals[j] = *op; if (t < 0.0) x->valid = 0; else *op = t; op++; } if (m->stomp == 0) x->valid = 0; m->stomp = m->stamp; } /* pick up most recent timestamp */ if (m->stamp > stamp) stamp = m->stamp; m++; } x->smpls[0].stamp = stamp; } void cndFetch_n(Expr *x) { Metric *m = x->metrics; double *op; RealTime stamp = 0; pmAtomValue a; double t; int i, j, k; ROTATE(x) x->valid++; op = (double *)x->smpls[0].ptr; for (i = 0; i < x->hdom; i++) { /* no values */ if ((m->vset == NULL) || (m->vset->numval < 0)) { x->valid = 0; for (j = i; j < x->hdom; j++) { m->stomp = 0; m->vset = NULL; m++; } return; } /* extract values */ for (j = 0; j < m->m_idom; j++) { for (k = 0; k < m->vset->numval; k++) { if (m->iids[j] == m->vset->vlist[k].inst) { pmExtractValue(m->vset->valfmt, &m->vset->vlist[k], m->desc.type, &a, PM_TYPE_DOUBLE); *op++ = m->conv * a.d; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cndFetch_n: %s[%s] from %s = %g", symName(m->mname), m->inames[j], symName(m->hname), m->conv * a.d); if (m->conv != 1) fprintf(stderr, " (unconv = %g)", a.d); fputc('\n', stderr); } #endif break; } } /* missing value */ if (k == m->vset->numval) { x->valid = 0; m->stomp = 0; m->vset = NULL; return; } } m->vset = NULL; /* rate computation */ if (m->desc.sem == PM_SEM_COUNTER) { op -= m->m_idom; for (j = 0; j < m->m_idom; j++) { t = *op - m->vals[j]; if (t < 0.0 && dowrap) { switch (m->desc.type) { case PM_TYPE_32: case PM_TYPE_U32: t += (double)UINT_MAX+1; break; case PM_TYPE_64: case PM_TYPE_U64: t += (double)ULONGLONG_MAX+1; break; } } t /= (m->stamp - m->stomp); m->vals[j] = *op; if (t < 0.0) x->valid = 0; else *op = t; op++; } if (m->stomp == 0) x->valid = 0; m->stomp = m->stamp; } /* pick up most recent timestamp */ if (m->stamp > stamp) stamp = m->stamp; m++; } x->smpls[0].stamp = stamp; } pcp-3.8.12ubuntu1/src/pmie/src/pragmatics.h0000664000000000000000000000564212272262501015424 0ustar /*********************************************************************** * pragmatics.h - inference engine pragmatics analysis * * The analysis of how to organize the fetching of metrics (pragmatics) * and other parts of the inference engine that are particularly * sensitive to details of the performance metrics API are kept here. *********************************************************************** * * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PRAG_H #define PRAG_H #include "pmapi.h" /* report where PCP data is coming from */ char *findsource(char *); /* initialize performance metrics API */ void pmcsInit(void); /* juggle contexts */ int newContext(char *); /* initialize access to archive */ int initArchive(Archive *); /* initialize timezone */ void zoneInit(void); /* convert to canonical units */ pmUnits canon(pmUnits); /* scale factor to canonical pmUnits */ double scale(pmUnits); /* initialize Metric */ int initMetric(Metric *); /* reinitialize Metric */ int reinitMetric(Metric *); /* put initialiaed Metric onto fetch list */ void bundleMetric(Host *, Metric *); /* reconnect attempt to host */ int reconnect(Host *); /* pragmatics analysis */ void pragmatics(Symbol, RealTime); /* execute fetches for given Task */ void taskFetch(Task *); /* convert Expr value to pmValueSet value */ void fillVSet(Expr *, pmValueSet *); /* send pmDescriptors for all expressions in given task */ void sendDescs(Task *); /* put Metric onto wait list */ void waitMetric(Metric *); /* remove Metric from wait list */ void unwaitMetric(Metric *); /* check that pmUnits dimensions are equal */ #define dimeq(x, y) (((x).dimSpace == (y).dimSpace) && \ ((x).dimTime == (y).dimTime) && \ ((x).dimCount == (y).dimCount)) /* check equality of two pmUnits */ #define unieq(x, y) (((x).dimSpace == (y).dimSpace) && \ ((x).dimTime == (y).dimTime) && \ ((x).dimCount == (y).dimCount) && \ ((x).scaleSpace == (y).scaleSpace) && \ ((x).scaleTime == (y).scaleTime) && \ ((x).scaleCount == (y).scaleCount)) /* for initialization of pmUnits struct */ extern pmUnits noUnits; extern pmUnits countUnits; /* flag processes spawned */ extern int need_wait; #endif /* PRAG_H */ pcp-3.8.12ubuntu1/src/pmie/src/aggregate.sk0000664000000000000000000000701012272262501015375 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*********************************************************************** * skeleton: aggregate.sk - aggregation and quantification ***********************************************************************/ /*********************************************************************** * operator: @FUN ***********************************************************************/ void @FUN_host(Expr *x) { Expr *arg1 = x->arg1; Sample *is = &arg1->smpls[0]; Sample *os = &x->smpls[0]; @ITYPE *ip; @OTYPE *op; @TTYPE a; int n; int i; EVALARG(arg1) ROTATE(x) if (arg1->valid && arg1->hdom > 0) { ip = (@ITYPE *)is->ptr; op = (@OTYPE *)os->ptr; n = arg1->hdom; @TOP for (i = 1; i < n; i++) { ip++; @LOOP } @BOT os->stamp = is->stamp; x->valid++; } else { x->valid = 0; } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "@FUN_host(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void @FUN_inst(Expr *x) { Expr *arg1 = x->arg1; Sample *is = &arg1->smpls[0]; Sample *os = &x->smpls[0]; @ITYPE *ip; @OTYPE *op; @TTYPE a; Metric *m; int n; int i, j; EVALARG(arg1) ROTATE(x) if (arg1->valid && x->hdom != 0) { ip = (@ITYPE *)is->ptr; op = (@OTYPE *)os->ptr; if (abs(x->hdom) == 1) { n = arg1->e_idom; if (n < 1) { @NOTVALID goto done; } @TOP for (i = 1; i < n; i++) { ip++; @LOOP } @BOT } else { m = x->metrics; for (i = 0; i < x->hdom; i++) { n = m->m_idom; if (n < 1) { @NOTVALID goto done; } @TOP for (j = 1; j < n; j++){ /* Note! no break allowed in this loop */ ip++; @LOOP } @BOT m++; } } os->stamp = is->stamp; x->valid++; } else { x->valid = 0; } done: #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "@FUN_inst(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void @FUN_time(Expr *x) { Expr *arg1 = x->arg1; Sample *is = &arg1->smpls[0]; Sample *os = &x->smpls[0]; @ITYPE *ring = (@ITYPE *)arg1->ring; @ITYPE *ip; @OTYPE *op; @TTYPE a; int n = arg1->tdom; int tspan; int i, j; EVALARG(arg1) ROTATE(x) if (arg1->valid >= n && x->tspan > 0 && arg1->tdom > 0) { op = (@OTYPE *)os->ptr; tspan = x->tspan; for (i = 0; i < tspan; i++) { ip = ring + i; @TOP for (j = 1; j < n; j++){ ip += tspan; @LOOP } @BOT } os->stamp = is->stamp; x->valid++; } else { x->valid = 0; } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "@FUN_time(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } pcp-3.8.12ubuntu1/src/pmie/src/stomp.c0000664000000000000000000002244712272262501014431 0ustar /* * Copyright (c) 2006 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "impl.h" static int stomp_connect(const char *hostname, int port); static void stomp_disconnect(void); int stomping; char *stompfile; extern int verbose; static int fd = -1; static int port = -1; static int timeout = 2; /* default 2 sec to timeout JMS server ACKs */ static char *hostname; static char *username; static char *passcode; static char *topic; /* JMS "topic" for pmie messages */ static char pmietopic[] = "PMIE"; /* default JMS "topic" for pmie */ static char buffer[4096]; static int stomp_connect(const char *hostname, int port) { int sts, nodelay = 1; struct linger nolinger = { 1, 0 }; struct sockaddr_in myaddr; struct hostent *servinfo; if ((servinfo = gethostbyname(hostname)) == NULL) return -1; /* socket setup */ if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) return -2; if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, /* avoid 200 ms delay */ (char *)&nodelay, (socklen_t)sizeof(nodelay)) < 0) { stomp_disconnect(); return -3; } if (setsockopt(fd, SOL_SOCKET, SO_LINGER, /* don't linger on close */ (char *)&nolinger, (socklen_t)sizeof(nolinger)) < 0) { stomp_disconnect(); return -4; } memset(&myaddr, 0, sizeof(myaddr)); myaddr.sin_family = AF_INET; memcpy(&myaddr.sin_addr, servinfo->h_addr, servinfo->h_length); myaddr.sin_port = htons(port); if ((sts = connect(fd, (struct sockaddr *)&myaddr, sizeof(myaddr))) < 0) { stomp_disconnect(); return -5; } return fd; } static int stomp_read_ack(void) { struct timeval tv; fd_set fds, readyfds; int nready, sts; FD_ZERO(&fds); FD_SET(fd, &fds); tv.tv_sec = timeout; tv.tv_usec = 0; memcpy(&readyfds, &fds, sizeof(readyfds)); nready = select(fd + 1, &readyfds, NULL, NULL, &tv); if (nready <= 0) { if (nready == 0) __pmNotifyErr(LOG_ERR, "Timed out waiting for server %s:%d - %s", hostname, port, netstrerror()); else __pmNotifyErr(LOG_ERR, "Error waiting for server %s:%d - %s", hostname, port, netstrerror()); stomp_disconnect(); return -1; } do { sts = recv(fd, buffer, sizeof(buffer), 0); if (sts < 0) { __pmNotifyErr(LOG_ERR, "Error recving from server %s:%d - %s", hostname, port, netstrerror()); stomp_disconnect(); return -1; } /* check for anything else we need to read to clear this ACK */ memset(&tv, 0, sizeof(tv)); memcpy(&readyfds, &fds, sizeof(readyfds)); } while (select(fd + 1, &readyfds, NULL, NULL, &tv) > 0); return 0; } static int stomp_write(const char *buffer, int length) { int sts; do { sts = send(fd, buffer, length, 0); if (sts < 0) { __pmNotifyErr(LOG_ERR, "Write error to JMS server %s:%d - %s", hostname, port, netstrerror()); stomp_disconnect(); return -1; } else if (sts == 0) break; length -= sts; } while (length > 0); return 0; } static int stomp_authenticate(void) { int len; if (fd < 0) return -1; len = snprintf(buffer, sizeof(buffer), "CONNECT\nlogin:%s\npasscode:%s\n\n", username, passcode); if (stomp_write(buffer, len) < 0) return -1; if (stomp_write("\0\n", 2) < 0) return -1; return 0; } static int stomp_destination(void) { int len; if (fd < 0) return -1; len = snprintf(buffer, sizeof(buffer), "SUB\ndestination:/topic/%s\n\n", topic); if (stomp_write(buffer, len) < 0) return -1; if (stomp_write("\0\n", 2) < 0) return -1; return 0; } static int stomp_hello(void) { int len; if (fd < 0) return -1; len = snprintf(buffer, sizeof(buffer), "SEND\ndestination:/topic/%s\n\n" "INFO: PMIE: Established initial connection", topic); if (stomp_write(buffer, len) < 0) return -1; if (stomp_write("\0\n", 2) < 0) return -1; return 0; } static void stomp_disconnect(void) { if (fd >= 0) close(fd); fd = -1; } static char *isspace_terminate(char *string) { int i = 0; while (!isspace((int)string[i++])) /* do nothing */ ; if (i) string[i-1] = '\0'; return string; } /* * Parse our stomp configuration file, simple format: * host= # JMS server machine * port= # server port number * username= | user= * passcode= | password= * timeout= # optional * topic= # optional */ static void stomp_parse(void) { char config[MAXPATHLEN+1]; FILE *f; int sep = __pmPathSeparator(); if (stompfile) strncat(config, stompfile, sizeof(config)-1); else snprintf(config, sizeof(config), "%s%c" "config" "%c" "pmie" "%c" "stomp", pmGetConfig("PCP_VAR_DIR"), sep, sep, sep); if ((f = fopen(config, "r")) == NULL) { __pmNotifyErr(LOG_ERR, "Cannot open STOMP configuration file %s: %s", config, osstrerror()); exit(1); } while (fgets(buffer, sizeof(buffer), f)) { if (strncmp(buffer, "port=", 5) == 0) port = atoi(isspace_terminate(&buffer[5])); else if (strncmp(buffer, "host=", 5) == 0) hostname = strdup(isspace_terminate(&buffer[5])); else if (strncmp(buffer, "hostname=", 9) == 0) hostname = strdup(isspace_terminate(&buffer[9])); else if (strncmp(buffer, "user=", 5) == 0) username = strdup(isspace_terminate(&buffer[5])); else if (strncmp(buffer, "username=", 9) == 0) username = strdup(isspace_terminate(&buffer[9])); else if (strncmp(buffer, "password=", 9) == 0) passcode = strdup(isspace_terminate(&buffer[9])); else if (strncmp(buffer, "passcode=", 9) == 0) passcode = strdup(isspace_terminate(&buffer[9])); else if (strncmp(buffer, "timeout=", 8) == 0) /* optional */ timeout = atoi(isspace_terminate(&buffer[8])); else if (strncmp(buffer, "topic=", 6) == 0) /* optional */ topic = strdup(isspace_terminate(&buffer[6])); } fclose(f); if (!hostname) __pmNotifyErr(LOG_ERR, "No host in STOMP config file %s", config); if (port == -1) __pmNotifyErr(LOG_ERR, "No port in STOMP config file %s", config); if (!username) __pmNotifyErr(LOG_ERR, "No username in STOMP config file %s", config); if (!passcode) __pmNotifyErr(LOG_ERR, "No passcode in STOMP config file %s", config); if (port == -1 || !hostname || !username || !passcode) exit(1); } /* * Setup the connection to the stomp server, and handle initial protocol * negotiations (sending user/passcode over to the server in particular). * Stomp protocol is clear text... (we don't need no stinkin' security!). * Note: this routine is used for both the initial connection and also for * any subsequent reconnect attempts. */ void stompInit(void) { time_t thistime; static time_t lasttime; static int firsttime = 1; if (firsttime) { /* initial connection attempt */ stomp_parse(); if (!topic) topic = pmietopic; atexit(stomp_disconnect); } else { /* reconnect attempt, if not too soon */ time(&thistime); if (thistime < lasttime + 60) goto disconnect; } if (verbose) __pmNotifyErr(LOG_INFO, "Connecting to %s, port %d", hostname, port); if (stomp_connect(hostname, port) < 0) { __pmNotifyErr(LOG_ERR, "Could not connect to the message server"); goto disconnect; } if (verbose) __pmNotifyErr(LOG_INFO, "Connected; sending stomp connect message"); if (stomp_authenticate() < 0) { __pmNotifyErr(LOG_ERR, "Could not sent STOMP CONNECT frame to server"); goto disconnect; } if (verbose) __pmNotifyErr(LOG_INFO, "Sent; waiting for server ACK"); if (stomp_read_ack() < 0) { __pmNotifyErr(LOG_ERR, "Could not read STOMP ACK frame."); goto disconnect; } if (verbose) __pmNotifyErr(LOG_INFO, "ACK; sending initial PMIE topic and hello"); if (stomp_destination() < 0) { __pmNotifyErr(LOG_ERR, "Could not read TOPIC frame."); goto disconnect; } if (stomp_hello() < 0) { __pmNotifyErr(LOG_ERR, "Could not send HELLO frame."); goto disconnect; } if (verbose) __pmNotifyErr(LOG_INFO, "Sent; waiting for server ACK"); if (stomp_read_ack() < 0) { __pmNotifyErr(LOG_ERR, "Could not read STOMP ACK frame"); goto disconnect; } if (!firsttime) __pmNotifyErr(LOG_INFO, "Reconnected to STOMP protocol server"); else if (verbose) __pmNotifyErr(LOG_INFO, "Initial STOMP protocol setup complete"); firsttime = 0; goto finished; disconnect: stomp_disconnect(); if (firsttime) exit(1); /* otherwise, we attempt reconnect on next message firing (>1min) */ finished: lasttime = thistime; } /* * Send a message to the stomp server. */ int stompSend(const char *msg) { int len; if (fd < 0) stompInit(); /* reconnect */ if (fd < -1) return -1; len = snprintf(buffer, sizeof(buffer), "SEND\ndestination:/topic/%s\n\n", topic); if (stomp_write(buffer, len) < 0) return -1; if (stomp_write(msg, strlen(msg)) < 0) return -1; if (stomp_write("\0\n", 2) < 0) return -1; return 0; } pcp-3.8.12ubuntu1/src/pmie/src/misc.sk0000664000000000000000000000422412272262501014406 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*********************************************************************** * skeleton: misc.sk ***********************************************************************/ /* * operator RULE */ void rule(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; int sts; EVALARG(arg1) if ((x->valid = arg1->valid) > 0) { sts = (*(Truth *)x->ring = *(Truth *)arg1->ring); if (sts == FALSE) perf->eval_false++; else if (sts == TRUE) { perf->eval_true++; EVALARG(arg2) } else perf->eval_unknown++; } else perf->eval_unknown++; } /* * operator: cndDelay */ void cndDelay_n(Expr *x) { Expr *arg1 = x->arg1; int n = arg1->tdom; Sample *is = &arg1->smpls[n - 1]; Sample *os = &x->smpls[0]; @ITYPE *ip; @OTYPE *op; int i; EVALARG(arg1) ROTATE(x) if (arg1->valid >= n && x->tspan > 0) { ip = (@ITYPE *)is->ptr; op = (@OTYPE *)os->ptr; for (i = 0; i < x->tspan; i++) *op++ = *ip++; os->stamp = is->stamp; x->valid++; } else x->valid = 0; } void cndDelay_1(Expr *x) { Expr *arg1 = x->arg1; int n = arg1->tdom; Sample *is = &arg1->smpls[n - 1]; Sample *os = &x->smpls[0]; EVALARG(arg1) ROTATE(x) if (arg1->valid >= n) { *(@OTYPE *)os->ptr = *(@ITYPE *)is->ptr; os->stamp = is->stamp; x->valid++; } else x->valid = 0; } pcp-3.8.12ubuntu1/src/pmie/src/eval.c0000664000000000000000000003400612272262501014210 0ustar /*********************************************************************** * eval.c - task scheduling and expression evaluation *********************************************************************** * * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "dstruct.h" #include "eval.h" #include "fun.h" #include "pragmatics.h" #include "show.h" /*********************************************************************** * scheduling ***********************************************************************/ /* enter Task into task queue */ static void enque(Task *t) { Task *q; RealTime tt; RealTime qt; q = taskq; if (q == NULL) { taskq = t; t->next = NULL; t->prev = NULL; } else { tt = (t->retry && t->retry < t->eval) ? t->retry : t->eval; while (q) { qt = (q->retry && q->retry < q->eval) ? q->retry : q->eval; if (tt <= qt) { t->next = q; t->prev = q->prev; if (q->prev) q->prev->next = t; else taskq = t; q->prev = t; break; } if (q->next == NULL) { q->next = t; t->next = NULL; t->prev = q; break; } q = q->next; } } } /*********************************************************************** * reconnect ***********************************************************************/ /* any hosts down or unavailable metrics in this task? */ static int waiting(Task *t) { Host *h; h = t->hosts; while (h) { if (h->down || h->waits) return 1; h = h->next; } return 0; } /* * state values * STATE_INIT * STATE_FAILINIT * STATE_RECONN * STATE_LOSTCONN */ typedef struct hstate { struct hstate *next; char *name; int state; } hstate_t; static hstate_t *host_map = NULL; int host_state_changed(char *host, int state) { hstate_t *hsp; for (hsp = host_map; hsp != NULL; hsp = hsp->next) { if (strcmp(host, hsp->name) == 0) break; } if (hsp == NULL) { hsp = (hstate_t *)alloc(sizeof(*hsp)); hsp->next = host_map; hsp->name = sdup(host); hsp->state = STATE_INIT; host_map = hsp; } if (state == hsp->state) return 0; if (state == STATE_FAILINIT) __pmNotifyErr(LOG_INFO, "Cannot connect to pmcd on host %s\n", host); else if (state == STATE_RECONN && hsp->state != STATE_INIT) __pmNotifyErr(LOG_INFO, "Re-established connection to pmcd on host %s\n", host); else if (state == STATE_LOSTCONN) __pmNotifyErr(LOG_INFO, "Lost connection to pmcd on host %s\n", host); hsp->state = state; return 1; } /* try to reconnect to hosts and initialize missing metrics */ static void enable(Task *t) { Host *h; Metric *m; Metric **p; h = t->hosts; while (h) { /* reconnect to host */ if (h->down) { if (reconnect(h)) { h->down = 0; host_state_changed(symName(h->name), STATE_RECONN); } } /* reinitialize waiting Metrics */ if ((! h->down) && (h->waits)) { p = &h->waits; m = *p; while (m) { switch (reinitMetric(m)) { case 1: *p = m->next; unwaitMetric(m); bundleMetric(h,m); break; case 0: p = &m->next; break; case -1: *p = m->next; m->next = h->duds; h->duds = m; break; } m = *p; } } h = h->next; } } /*********************************************************************** * evaluation ***********************************************************************/ int showTimeFlag = 0; /* set when -e used on the command line */ /* evaluate Task */ static void eval(Task *task) { Symbol *s; pmValueSet *vset; int i; /* fetch metrics */ taskFetch(task); /* evaluate rule expressions */ s = task->rules; for (i = 0; i < task->nrules; i++) { curr = symValue(*s); if (curr->op < NOP) { (curr->eval)(curr); perf->eval_actual++; } s++; } if (verbose) { /* send binary values */ if (agent) { int sts; s = task->rules; for (i = 0; i < task->nrules; i++) { vset = task->rslt->vset[i]; fillVSet(symValue(*s), vset); s++; } __pmOverrideLastFd(PDU_OVERRIDE2); sts = __pmSendResult(STDOUT_FILENO, pmWhichContext(), task->rslt); if (sts < 0) { fprintf(stderr, "Error: __pmSendResult to summary agent failed: %s\n", pmErrStr(sts)); exit(0); } } /* send values to applet */ else if (applet) { s = task->rules; for (i = 0; i < task->nrules; i++) { showValue(stdout, symValue(*s)); putchar(' '); s++; } putchar('\n'); } /* print values in ASCII */ else { s = task->rules; for (i = 0; i < task->nrules; i++) { printf("%s", symName(*s)); if (archives || showTimeFlag) { printf(" ("); showTime(stdout, now); putchar(')'); } printf(": "); switch (verbose) { case 1: showValue(stdout, symValue(*s)); break; case 2: showAnnotatedValue(stdout, symValue(*s)); break; case 3: showSatisfyingValue(stdout, symValue(*s)); break; } putchar('\n'); s++; } putchar('\n'); } } } /* Mark expression as having invalid values */ void clobber(Expr *x) { int i; Truth *t; double *d; if (x->op < NOP) { if (x->arg1) clobber(x->arg1); if (x->arg2) clobber(x->arg2); x->valid = 0; /* * numeric variable or variable? */ if (x->sem == PM_SEM_COUNTER || x->sem == PM_SEM_INSTANT || x->sem == PM_SEM_DISCRETE || x->sem == SEM_NUMVAR) { d = (double *) x->ring; for (i = 0; i < x->nvals; i++) *d++ = mynan; } else if (x->sem == SEM_TRUTH) { t = (Truth *) x->ring; for (i = 0; i < x->nvals; i++) *t++ = DUNNO; } } } /*********************************************************************** * exported functions ***********************************************************************/ /* fill in appropriate evaluator function for given Expr */ void findEval(Expr *x) { int arity = 0; Metric *m; /* * arity values constructed from bit masks * 1 arg1 has tspan 1, and must always have one metric value * 2 arg2 has tspan 1, and must always have one metric value */ if (x->arg1 && x->arg1->tspan == 1) { for (m = x->arg1->metrics; m; m = m->next) { if (m->desc.indom == PM_INDOM_NULL) continue; if (m->specinst == 0) break; } if (m == NULL) arity |= 1; } if (x->arg2 && x->arg2->tspan == 1) { for (m = x->arg2->metrics; m; m = m->next) { if (m->desc.indom == PM_INDOM_NULL) continue; if (m->specinst == 0) break; } if (m == NULL) arity |= 2; } /* * never come here with x->op == NULL or OP_VAR */ switch (x->op) { case RULE: x->eval = rule; break; case CND_FETCH: if (x->metrics->desc.indom == PM_INDOM_NULL || x->metrics->conv == 0) x->eval = cndFetch_1; else if (x->metrics->specinst == 0) x->eval = cndFetch_all; else x->eval = cndFetch_n; break; case CND_SUM_HOST: x->eval = cndSum_host; break; case CND_SUM_INST: x->eval = cndSum_inst; break; case CND_SUM_TIME: x->eval = cndSum_time; break; case CND_AVG_HOST: x->eval = cndAvg_host; break; case CND_AVG_INST: x->eval = cndAvg_inst; break; case CND_AVG_TIME: x->eval = cndAvg_time; break; case CND_MAX_HOST: x->eval = cndMax_host; break; case CND_MAX_INST: x->eval = cndMax_inst; break; case CND_MAX_TIME: x->eval = cndMax_time; break; case CND_MIN_HOST: x->eval = cndMin_host; break; case CND_MIN_INST: x->eval = cndMin_inst; break; case CND_MIN_TIME: x->eval = cndMin_time; break; case CND_ALL_HOST: x->eval = cndAll_host; break; case CND_ALL_INST: x->eval = cndAll_inst; break; case CND_ALL_TIME: x->eval = cndAll_time; break; case CND_SOME_HOST: x->eval = cndSome_host; break; case CND_SOME_INST: x->eval = cndSome_inst; break; case CND_SOME_TIME: x->eval = cndSome_time; break; case CND_PCNT_HOST: x->eval = cndPcnt_host; break; case CND_PCNT_INST: x->eval = cndPcnt_inst; break; case CND_PCNT_TIME: x->eval = cndPcnt_time; break; case CND_COUNT_HOST: x->eval = cndCount_host; break; case CND_COUNT_INST: x->eval = cndCount_inst; break; case CND_COUNT_TIME: x->eval = cndCount_time; break; case ACT_SEQ: x->eval = actAnd; break; case ACT_ALT: x->eval = actOr; break; case ACT_SHELL: x->eval = actShell; break; case ACT_ALARM: x->eval = actAlarm; break; case ACT_STOMP: x->eval = actStomp; break; case ACT_SYSLOG: x->eval = actSyslog; break; case ACT_PRINT: x->eval = actPrint; break; case ACT_ARG: x->eval = actArg; break; case CND_DELAY: if (arity & 1) x->eval = cndDelay_1; else x->eval = cndDelay_n; break; case CND_RATE: if (arity & 1) x->eval = cndRate_1; else x->eval = cndRate_n; break; case CND_NEG: if (arity & 1) x->eval = cndNeg_1; else x->eval = cndNeg_n; break; case CND_NOT: if (arity & 1) x->eval = cndNot_1; else x->eval = cndNot_n; break; case CND_RISE: if (arity & 1) x->eval = cndRise_1; else x->eval = cndRise_n; break; case CND_FALL: if (arity & 1) x->eval = cndFall_1; else x->eval = cndFall_n; break; case CND_ADD: if (arity & 1) { if (arity & 2) x->eval = cndAdd_1_1; else x->eval = cndAdd_1_n; } else { if (arity & 2) x->eval = cndAdd_n_1; else x->eval = cndAdd_n_n; } break; case CND_SUB: if (arity & 1) { if (arity & 2) x->eval = cndSub_1_1; else x->eval = cndSub_1_n; } else { if (arity & 2) x->eval = cndSub_n_1; else x->eval = cndSub_n_n; } break; case CND_MUL: if (arity & 1) { if (arity & 2) x->eval = cndMul_1_1; else x->eval = cndMul_1_n; } else { if (arity & 2) x->eval = cndMul_n_1; else x->eval = cndMul_n_n; } break; case CND_DIV: if (arity & 1) { if (arity & 2) x->eval = cndDiv_1_1; else x->eval = cndDiv_1_n; } else { if (arity & 2) x->eval = cndDiv_n_1; else x->eval = cndDiv_n_n; } break; case CND_EQ: if (arity & 1) { if (arity & 2) x->eval = cndEq_1_1; else x->eval = cndEq_1_n; } else { if (arity & 2) x->eval = cndEq_n_1; else x->eval = cndEq_n_n; } break; case CND_NEQ: if (arity & 1) { if (arity & 2) x->eval = cndNeq_1_1; else x->eval = cndNeq_1_n; } else { if (arity & 2) x->eval = cndNeq_n_1; else x->eval = cndNeq_n_n; } break; case CND_LT: if (arity & 1) { if (arity & 2) x->eval = cndLt_1_1; else x->eval = cndLt_1_n; } else { if (arity & 2) x->eval = cndLt_n_1; else x->eval = cndLt_n_n; } break; case CND_LTE: if (arity & 1) { if (arity & 2) x->eval = cndLte_1_1; else x->eval = cndLte_1_n; } else { if (arity & 2) x->eval = cndLte_n_1; else x->eval = cndLte_n_n; } break; case CND_GT: if (arity & 1) { if (arity & 2) x->eval = cndGt_1_1; else x->eval = cndGt_1_n; } else { if (arity & 2) x->eval = cndGt_n_1; else x->eval = cndGt_n_n; } break; case CND_GTE: if (arity & 1) { if (arity & 2) x->eval = cndGte_1_1; else x->eval = cndGte_1_n; } else { if (arity & 2) x->eval = cndGte_n_1; else x->eval = cndGte_n_n; } break; case CND_AND: if (arity & 1) { if (arity & 2) x->eval = cndAnd_1_1; else x->eval = cndAnd_1_n; } else { if (arity & 2) x->eval = cndAnd_n_1; else x->eval = cndAnd_n_n; } break; case CND_OR: if (arity & 1) { if (arity & 2) x->eval = cndOr_1_1; else x->eval = cndOr_1_n; } else { if (arity & 2) x->eval = cndOr_n_1; else x->eval = cndOr_n_n; } break; case CND_MATCH: case CND_NOMATCH: x->eval = cndMatch_inst; break; default: __pmNotifyErr(LOG_ERR, "findEval: internal error: bad op (%d)\n", x->op); dumpExpr(x); exit(1); } /* patch in fake actions for archive mode */ if (archives && (x->op == ACT_SHELL || x->op == ACT_ALARM || x->op == ACT_SYSLOG || x->op == ACT_PRINT || x->op == ACT_STOMP)) { x->eval = actFake; } } /* run evaluator */ void run(void) { Task *t; /* empty task queue */ if (taskq == NULL) return; /* initialize task scheduling */ t = taskq; while (t) { t->eval = t->epoch = start; t->retry = 0; t->tick = 0; t = t->next; } /* evaluate and reschedule */ t = taskq; for (;;) { if (t->retry && t->retry < t->eval) { now = t->retry; if (now > stop) break; sleepTight(t, SLEEP_RETRY); enable(t); t->retry = waiting(t) ? now + RETRY : 0; } else { now = t->eval; if (now > stop) break; reflectTime(t->delta); sleepTight(t, SLEEP_EVAL); eval(t); t->tick++; t->eval = t->epoch + t->tick * t->delta; if ((! t->retry) && waiting(t)) t->retry = now + RETRY; } taskq = t->next; if (taskq) taskq->prev = NULL; enque(t); t = taskq; } __pmNotifyErr(LOG_INFO, "evaluator exiting\n"); } /* invalidate all expressions being evaluated i.e. mark values as unknown */ void invalidate(void) { Task *t; Expr *x; Symbol *s; int i; t = taskq; while (t) { s = t->rules; for (i = 0; i < t->nrules; i++) { x = symValue(*s); clobber(x); s++; } t = t->next; } } pcp-3.8.12ubuntu1/src/pmie/src/systemlog.h0000664000000000000000000000003512272262501015307 0ustar void do_syslog_args(Expr *); pcp-3.8.12ubuntu1/src/pmie/src/show.c0000664000000000000000000006437712272262501014257 0ustar /*********************************************************************** * show.c - display expressions and their values *********************************************************************** * * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "show.h" #include "impl.h" #include "dstruct.h" #include "lexicon.h" #include "pragmatics.h" #if defined(HAVE_IEEEFP_H) #include #endif /*********************************************************************** * local declarations ***********************************************************************/ static struct { int op; char *str; } opstr[] = { { RULE, "->" }, { CND_FETCH, "" }, { CND_DELAY, "" }, { CND_RATE, "rate" }, { CND_NEG, "-" }, { CND_ADD, "+" }, { CND_SUB, "-" }, { CND_MUL, "*" }, { CND_DIV, "/" }, /* aggregation */ { CND_SUM_HOST, "sum_host" }, { CND_SUM_INST, "sum_inst" }, { CND_SUM_TIME, "sum_sample" }, { CND_AVG_HOST, "avg_host" }, { CND_AVG_INST, "avg_inst" }, { CND_AVG_TIME, "avg_sample" }, { CND_MAX_HOST, "max_host" }, { CND_MAX_INST, "max_inst" }, { CND_MAX_TIME, "max_sample" }, { CND_MIN_HOST, "min_host" }, { CND_MIN_INST, "min_inst" }, { CND_MIN_TIME, "min_sample" }, /* relational */ { CND_EQ, "==" }, { CND_NEQ, "!=" }, { CND_LT, "<" }, { CND_LTE, "<=" }, { CND_GT, ">" }, { CND_GTE, ">=" }, /* boolean */ { CND_NOT, "!" }, { CND_RISE, "rising" }, { CND_FALL, "falling" }, { CND_AND, "&&" }, { CND_OR, "||" }, { CND_MATCH, "match_inst" }, { CND_NOMATCH, "nomatch_inst" }, /* quantification */ { CND_ALL_HOST, "all_host" }, { CND_ALL_INST, "all_inst" }, { CND_ALL_TIME, "all_sample" }, { CND_SOME_HOST, "some_host" }, { CND_SOME_INST, "some_inst" }, { CND_SOME_TIME, "some_sample" }, { CND_PCNT_HOST, "pcnt_host" }, { CND_PCNT_INST, "pcnt_inst" }, { CND_PCNT_TIME, "pcnt_sample" }, { CND_COUNT_HOST, "count_host" }, { CND_COUNT_INST, "count_inst" }, { CND_COUNT_TIME, "count_sample" }, { ACT_SEQ, "&" }, { ACT_ALT, "|" }, { ACT_SHELL, "shell" }, { ACT_ALARM, "alarm" }, { ACT_SYSLOG, "syslog" }, { ACT_PRINT, "print" }, { ACT_STOMP, "stomp" }, { ACT_ARG, "" }, { NOP, "" }, { OP_VAR, "" }, }; static int numopstr = sizeof(opstr) / sizeof(opstr[0]); /*********************************************************************** * local utility functions ***********************************************************************/ /* Concatenate string1 to existing string2 whose original length is given. */ static size_t /* new length of *string2 */ concat(char *string1, size_t pos, char **string2) { size_t slen; size_t tlen; char *cat; char *dog; if ((slen = strlen(string1)) == 0) return pos; tlen = pos + slen; cat = (char *) ralloc(*string2, tlen + 1); dog = cat + pos; strcpy(dog, string1); dog += slen; *dog = '\0'; *string2 = cat; return tlen; } /*********************************************************************** * host and instance names ***********************************************************************/ /* Return host and instance name for nth value in expression *x */ static int lookupHostInst(Expr *x, int nth, char **host, char **inst) { Metric *m = NULL; int mi; int sts = 0; int pick = -1; int matchaggr = 0; int aggrop = NOP; double *aggrval = NULL; #if PCP_DEBUG static Expr *lastx = NULL; int dbg_dump = 0; #endif #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { if (x != lastx) { fprintf(stderr, "lookupHostInst(x=" PRINTF_P_PFX "%p, nth=%d, ...)\n", x, nth); lastx = x; dbg_dump = 1; } } #endif if (x->op == CND_MIN_HOST || x->op == CND_MAX_HOST || x->op == CND_MIN_INST || x->op == CND_MAX_INST || x->op == CND_MIN_TIME || x->op == CND_MAX_TIME) { /* * extrema operators ... value is here, but the host, instance, sample * context is in the child expression ... go one level deeper and try * to match the value */ aggrop = x->op; aggrval = (double *)x->smpls[0].ptr; matchaggr = 1; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "lookupHostInst look for extrema val=%f @ " PRINTF_P_PFX "%p\n", *aggrval, x); } x = x->arg1; #endif } /* check for no host and instance available e.g. constant expression */ if ((x->e_idom <= 0 && x->hdom <= 0) || ! x->metrics) { *host = NULL; *inst = NULL; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "lookupHostInst(x=" PRINTF_P_PFX "%p, nth=%d, ...) -> %%h and %%i undefined\n", x, nth); } #endif return sts; } /* find Metric containing the nth instance */ if (matchaggr == 0) { pick = nth; mi = 0; for (;;) { m = &x->metrics[mi]; #if PCP_DEBUG if ((pmDebug & DBG_TRACE_APPL2) && dbg_dump) { fprintf(stderr, "lookupHostInst: metrics[%d]\n", mi); dumpMetric(m); } #endif if (pick < m->m_idom) break; if (m->m_idom > 0) pick -= m->m_idom; mi++; } } else { if (aggrop == CND_MIN_HOST || aggrop == CND_MAX_HOST) { int k; #if PCP_DEBUG if ((pmDebug & DBG_TRACE_APPL2) && dbg_dump) { fprintf(stderr, "lookupHostInst [extrema_host]:\n"); } #endif for (k = 0; k < x->tspan; k++) { #if DESPERATE fprintf(stderr, "smpls[0][%d]=%g\n", k, *((double *)x->smpls[0].ptr+k)); #endif if (*aggrval == *((double *)x->smpls[0].ptr+k)) { m = &x->metrics[k]; goto done; } } fprintf(stderr, "Internal error: LookupHostInst: %s\n", opStrings(aggrop)); } else if (aggrop == CND_MIN_INST || aggrop == CND_MAX_INST) { int k; for (k = 0; k < x->tspan; k++) { #if DESPERATE fprintf(stderr, "smpls[0][%d]=%g\n", k, *((double *)x->smpls[0].ptr+k)); #endif if (*aggrval == *((double *)x->smpls[0].ptr+k)) { pick = k; m = &x->metrics[0]; #if PCP_DEBUG if ((pmDebug & DBG_TRACE_APPL2) && dbg_dump) { fprintf(stderr, "lookupHostInst [extrema_inst]:\n"); dumpMetric(m); } #endif goto done; } } fprintf(stderr, "Internal error: LookupHostInst: %s\n", opStrings(aggrop)); } else if (aggrop == CND_MIN_TIME || aggrop == CND_MAX_TIME) { int k; for (k = 0; k < x->nsmpls; k++) { #if DESPERATE fprintf(stderr, "smpls[%d][0]=%g\n", k, *((double *)x->smpls[k].ptr)); #endif if (*aggrval == *((double *)x->smpls[k].ptr)) { pick = nth; m = &x->metrics[0]; #if PCP_DEBUG if ((pmDebug & DBG_TRACE_APPL2) && dbg_dump) { fprintf(stderr, "lookupHostInst [extrema_sample]:\n"); dumpMetric(m); } #endif goto done; } } fprintf(stderr, "Internal error: LookupHostInst: %s\n", opStrings(aggrop)); } } done: /* host and instance names */ if (m == NULL) { *host = NULL; *inst = NULL; } else { *host = symName(m->hname); sts++; if (pick >= 0 && x->e_idom > 0 && m->inames) { *inst = m->inames[pick]; sts++; } else *inst = NULL; } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "lookupHostInst(x=" PRINTF_P_PFX "%p, nth=%d, ...) -> sts=%d %%h=%s %%i=%s\n", x, nth, sts, *host, *inst == NULL ? "undefined" : *inst); } #endif return sts; } /*********************************************************************** * expression value ***********************************************************************/ #define TRUTH_SPACE 7 static size_t showTruth(Expr *x, int nth, size_t length, char **string) { int smpl; size_t tlen; char *cat; char *dog; int val; tlen = length + (x->nsmpls * TRUTH_SPACE); cat = (char *)ralloc(*string, tlen + 1); dog = cat + length; for (smpl = 0; smpl < x->nsmpls; smpl++) { if (smpl > 0) { strcpy(dog, " "); dog += 1; } if (x->valid == 0) { strncpy(dog, "?", TRUTH_SPACE); dog++; continue; } val = *((char *)x->smpls[smpl].ptr + nth); if (val == FALSE) { strncpy(dog, "false", TRUTH_SPACE); dog += 5; } else if (val == TRUE) { strncpy(dog, "true", TRUTH_SPACE); dog += 4; } else if (val == DUNNO) { strncpy(dog, "?", TRUTH_SPACE); dog++; } else { sprintf(dog, "0x%02x?", val & 0xff); dog += 5; } } *dog = '\0'; *string = cat; return dog - cat; } static size_t showString(Expr *x, size_t length, char **string) { size_t slen; size_t tlen; char *cat; char *dog; slen = strlen((char *)x->smpls[0].ptr); tlen = length + slen + 2; cat = (char *)ralloc(*string, tlen + 1); dog = cat + length; *dog++ = '"'; strcpy(dog, (char *)x->smpls[0].ptr); dog += slen; *dog++ = '"'; *dog = '\0'; *string = cat; return tlen; } #define DBL_SPACE 24 static size_t showNum(Expr *x, int nth, size_t length, char **string) { int smpl; size_t tlen; char *cat; char *dog; char *fmt; double v; double abs_v; int sts; tlen = length + (x->nsmpls * DBL_SPACE); cat = (char *)ralloc(*string, tlen + 1); dog = cat + length; for (smpl = 0; smpl < x->nsmpls; smpl++) { int noval = 0; if (smpl > 0) { strcpy(dog, " "); dog += 1; } if (x->valid <= smpl) noval = 1; else { #ifdef HAVE_FPCLASSIFY noval = fpclassify(*((double *)x->smpls[smpl].ptr + nth)) == FP_NAN; #else #ifdef HAVE_ISNAN noval = isnan(*((double *)x->smpls[smpl].ptr + nth)); #endif #endif } if (noval) { strcpy(dog, "?"); dog += 1; } else { v = *((double *)x->smpls[smpl].ptr+nth); if (v == (int)v) sts = sprintf(dog, "%d", (int)v); else { abs_v = v < 0 ? -v : v; if (abs_v < 0.5) fmt = "%g"; else if (abs_v < 5) fmt = "%.2f"; else if (abs_v < 50) fmt = "%.1f"; else fmt = "%.0f"; sts = sprintf(dog, fmt, v); } if (sts > 0) dog += sts; else { strcpy(dog, "!"); dog += 1; } } } *dog = '\0'; *string = cat; return dog - cat; } static char * showConst(Expr *x) { char *string = NULL; size_t length = 0; int i; int first = 1; /* construct string representation */ if (x->nvals > 0) { for (i = 0; i < x->tspan; i++) { if (first) first = 0; else length = concat(" ", length, &string); if (x->sem == SEM_TRUTH) length = showTruth(x, i, length, &string); else if (x->sem == SEM_REGEX) { /* regex is compiled, cannot recover original string */ length = concat("//", length, &string); } else if (x->sem == SEM_CHAR) { length = showString(x, length, &string); /* tspan is string length, not an iterator in this case */ break; } else length = showNum(x, i, length, &string); } } return string; } /*********************************************************************** * expression syntax ***********************************************************************/ static void showSyn(FILE *f, Expr *x) { char *s; char *c; Metric *m; char **n; int i; int paren; if (x->op == NOP) { /* constant */ s = showConst(x); if (s) { c = s; while(isspace((int)*c)) c++; fputs(c, f); free(s); } } else if ((x->op == CND_FETCH) || (x->op == CND_DELAY)) { /* fetch expression (perhaps with delay) */ m = x->metrics; fprintf(f, "%s", symName(m->mname)); for (i = 0; i < x->hdom; i++) { fprintf(f, " :%s", symName(m->hname)); m++; } m = x->metrics; if (m->inames) { n = m->inames; for (i = 0; i < m->m_idom; i++) { fprintf(f, " #%s", *n); n++; } } if (x->op == CND_FETCH) { if (x->tdom > 1) fprintf(f, " @0..%d", x->tdom - 1); } else { if (x->tdom == x->arg1->tdom - 1) fprintf(f, " @%d", x->tdom); else fprintf(f, " @%d..%d", x->tdom, x->tdom + x->arg1->tdom - 1); } } else if (x->arg1 && x->arg2) { /* binary operator */ if (x->op == ACT_SHELL || x->op == ACT_ALARM || x->op == ACT_PRINT || x->op == ACT_STOMP) { fputs(opStrings(x->op), f); fputc(' ', f); showSyn(f, x->arg2); fputc(' ', f); showSyn(f, x->arg1); } else if (x->op == ACT_ARG && x->parent->op == ACT_SYSLOG) { int *ip; char *cp; ip = x->arg2->ring; cp = (char *)&ip[1]; fprintf(f, "[level=%d tag=\"%s\"]", *ip, cp); fputc(' ', f); showSyn(f, x->arg1); } else if (x->op == CND_PCNT_HOST || x->op == CND_PCNT_INST || x->op == CND_PCNT_TIME) { int pcnt; fputs(opStrings(x->op), f); fputc(' ', f); /* * used to showSyn(f, x->arg2) here, but formatting is a little * better if we punt on there being a single double representation * of the % value at the end of arg2 */ pcnt = (int)(*((double *)x->arg2->smpls[0].ptr)*100+0.5); fprintf(f, "%d%%", pcnt); fputc(' ', f); if (x->arg1->op == NOP || x->arg1->op == CND_DELAY || x->arg1->op == CND_FETCH) showSyn(f, x->arg1); else { fputc('(', f); showSyn(f, x->arg1); fputc(')', f); } } else if (x->op == CND_MATCH || x->op == CND_NOMATCH) { fputs(opStrings(x->op), f); fputc(' ', f); showSyn(f, x->arg2); fputc(' ', f); fputc('(', f); showSyn(f, x->arg1); fputc(')', f); } else { paren = 1 - (x->arg1->op == NOP || x->arg1->op == CND_DELAY || x->arg1->op == CND_FETCH || x->arg1->op == CND_RATE || x->arg1->op == CND_SUM_HOST || x->arg1->op == CND_SUM_INST || x->arg1->op == CND_SUM_TIME || x->arg1->op == CND_AVG_HOST || x->arg1->op == CND_AVG_INST || x->arg1->op == CND_AVG_TIME || x->arg1->op == CND_MAX_HOST || x->arg1->op == CND_MAX_INST || x->arg1->op == CND_MAX_TIME || x->arg1->op == CND_MIN_HOST || x->arg1->op == CND_MIN_INST || x->arg1->op == CND_MIN_TIME || x->arg1->op == CND_COUNT_HOST || x->arg1->op == CND_COUNT_INST || x->arg1->op == CND_COUNT_TIME || x->arg1->op == CND_RATE || x->op == RULE); if (paren) fputc('(', f); showSyn(f, x->arg1); if (paren) fputc(')', f); fputc(' ', f); fputs(opStrings(x->op), f); fputc(' ', f); paren = 1 - (x->arg2->op == NOP || x->arg2->op == CND_DELAY || x->arg2->op == CND_FETCH || x->arg2->op == CND_RATE || x->arg2->op == CND_SUM_HOST || x->arg2->op == CND_SUM_INST || x->arg2->op == CND_SUM_TIME || x->arg2->op == CND_AVG_HOST || x->arg2->op == CND_AVG_INST || x->arg2->op == CND_AVG_TIME || x->arg2->op == CND_MAX_HOST || x->arg2->op == CND_MAX_INST || x->arg2->op == CND_MAX_TIME || x->arg2->op == CND_MIN_HOST || x->arg2->op == CND_MIN_INST || x->arg2->op == CND_MIN_TIME || x->arg2->op == CND_COUNT_HOST || x->arg2->op == CND_COUNT_INST || x->arg2->op == CND_COUNT_TIME || x->arg2->op == CND_RATE || x->op == RULE); if (paren) fputc('(', f); showSyn(f, x->arg2); if (paren) fputc(')', f); } } else { /* unary operator */ assert(x->arg1 != NULL); if (x->op == ACT_ARG) { /* parameters for an action */ Expr *y = x->arg1; while (y != NULL) { if (y != x->arg1) fputc(' ', f); showSyn(f, y); // fprintf(f, "\"%s\"", (char *)y->smpls[0].ptr); y = y->arg1; } } else { fputs(opStrings(x->op), f); fputc(' ', f); paren = 1 - (x->arg1->op == ACT_SEQ || x->arg1->op == ACT_ALT || x->op == ACT_SHELL || x->op == ACT_ALARM || x->op == ACT_SYSLOG || x->op == ACT_PRINT || x->op == ACT_STOMP || x->op == CND_DELAY); if (paren) fputc('(', f); showSyn(f, x->arg1); if (paren) fputc(')', f); } } } /* * recursive descent to find a conjunct from the root of * the expression that has associated metrics (not constants) */ static Expr * findMetrics(Expr *y) { Expr *z; if (y == NULL) return NULL; if (y->metrics) return y; /* success */ /* give up if not a conjunct */ if (y->op != CND_AND) return NULL; /* recurse left and then right */ z = findMetrics(y->arg1); if (z != NULL) return z; return findMetrics(y->arg2); } /*********************************************************************** * satisfying bindings and values ***********************************************************************/ /* Find sub-expression that reveals host and instance bindings that satisfy the given expression *x. */ static Expr * findBindings(Expr *x) { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "call findBindings(x=" PRINTF_P_PFX "%p)\n", x); } #endif if (x->metrics == NULL) { /* * this Expr node has no metrics (involves only constants) * ... try and find a conjunct at the top level that has * associated metrics */ Expr *y = findMetrics(x->arg1); if (y != NULL) x = y; } while (x->metrics && (x->e_idom <= 0 || x->hdom <= 0)) { if (x->op == CND_SUM_HOST || x->op == CND_SUM_INST || x->op == CND_SUM_TIME || x->op == CND_AVG_HOST || x->op == CND_AVG_INST || x->op == CND_AVG_TIME || x->op == CND_MAX_HOST || x->op == CND_MAX_INST || x->op == CND_MAX_TIME || x->op == CND_MIN_HOST || x->op == CND_MIN_INST || x->op == CND_MIN_TIME || x->op == CND_COUNT_HOST || x->op == CND_COUNT_INST || x->op == CND_COUNT_TIME) { /* * don't descend below an aggregation operator with a singular * value, ... value you seek is right here */ #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "findBindings: found %s @ x=" PRINTF_P_PFX "%p\n", opStrings(x->op), x); } #endif break; } if (x->arg1 && x->metrics == x->arg1->metrics) { x = x->arg1; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "findBindings: try x->arg1=" PRINTF_P_PFX "%p\n", x); } #endif } else if (x->arg2) { x = x->arg2; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "findBindings: try x->arg2=" PRINTF_P_PFX "%p\n", x); } #endif } else break; } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "findBindings finish @ " PRINTF_P_PFX "%p\n", x); dumpTree(x); } #endif return x; } /* Find sub-expression that reveals the values that satisfy the given expression *x. */ static Expr * findValues(Expr *x) { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "call findValues(x=" PRINTF_P_PFX "%p)\n", x); } #endif while (x->sem == SEM_TRUTH && x->metrics) { if (x->metrics == x->arg1->metrics) { x = x->arg1; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "findValues: try x->arg1=" PRINTF_P_PFX "%p\n", x); } #endif } else { x = x->arg2; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "findValues: try x->arg2=" PRINTF_P_PFX "%p\n", x); } #endif } } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "findValues finish @ " PRINTF_P_PFX "%p\n", x); dumpTree(x); } #endif return x; } /*********************************************************************** * format string ***********************************************************************/ /* Locate next %h, %i or %v in format string. */ static int /* 0 -> not found, 1 -> host, 2 -> inst, 3 -> value */ findFormat(char *format, char **pos) { for (;;) { if (*format == '\0') return 0; if (*format == '%') { switch (*(format + 1)) { case 'h': *pos = format; return 1; case 'i': *pos = format; return 2; case 'v': *pos = format; return 3; } } format++; } } /*********************************************************************** * exported functions ***********************************************************************/ void showSyntax(FILE *f, Symbol s) { char *name = symName(s); Expr *x = symValue(s); fprintf(f, "%s =\n", name); showSyn(f, x); fprintf(f, ";\n\n"); } void showSubsyntax(FILE *f, Symbol s) { char *name = symName(s); Expr *x = symValue(s); Expr *x1; Expr *x2; fprintf(f, "%s (subexpression for %s, %s and %s bindings) =\n", name, "%h", "%i", "%v"); x1 = findBindings(x); x2 = findValues(x1); showSyn(f, x2); fprintf(f, "\n\n"); } /* Print value of expression */ void showValue(FILE *f, Expr *x) { char *string = NULL; string = showConst(x); if (string) { fputs(string, f); free(string); } else fputs("?", f); } /* Print value of expression together with any host and instance bindings */ void showAnnotatedValue(FILE *f, Expr *x) { char *string = NULL; size_t length = 0; char *host; char *inst; int i; /* no annotation possible */ if ((x->e_idom <= 0 && x->hdom <= 0) || x->sem == SEM_CHAR || x->metrics == NULL || x->valid == 0) { showValue(f, x); return; } /* construct string representation */ for (i = 0; i < x->tspan; i++) { length = concat("\n ", length, &string); lookupHostInst(x, i, &host, &inst); length = concat(host, length, &string); if (inst) { length = concat(": [", length, &string); length = concat(inst, length, &string); length = concat("] ", length, &string); } else length = concat(": ", length, &string); if (x->sem == SEM_TRUTH) length = showTruth(x, i, length, &string); else /* numeric value */ length = showNum(x, i, length, &string); } /* print string representation */ if (string) { fputs(string, f); free(string); } } void showTime(FILE *f, RealTime rt) { time_t t = (time_t)rt; char bfr[26]; pmCtime(&t, bfr); bfr[24] = '\0'; fprintf(f, "%s", bfr); } void showFullTime(FILE *f, RealTime rt) { time_t t = (time_t)rt; char bfr[26]; pmCtime(&t, bfr); bfr[24] = '\0'; fprintf(f, "%s.%06d", bfr, (int)((rt-t)*1000000)); } void showSatisfyingValue(FILE *f, Expr *x) { char *string = NULL; size_t length = 0; char *host; char *inst; int i; Expr *x1; Expr *x2; /* no satisfying values possible */ if (x->metrics == NULL || x->valid == 0) { showValue(f, x); return; } if (x->sem != SEM_TRUTH) { showAnnotatedValue(f, x); return; } x1 = findBindings(x); x2 = findValues(x1); if (!x1->valid) { /* * subexpression for %h, %i and %v is not valid but rule is * true, return string without substitution ... rare case * for || rule */ concat(" ", length, &string); goto done; } /* construct string representation */ for (i = 0; i < x1->tspan; i++) { if ((x1->sem == SEM_TRUTH && *((char *)x1->smpls[0].ptr + i) == TRUE) || (x1->sem != SEM_TRUTH && x1->sem != SEM_UNKNOWN)) { length = concat("\n ", length, &string); lookupHostInst(x1, i, &host, &inst); length = concat(host, length, &string); if (inst) { length = concat(": [", length, &string); length = concat(inst, length, &string); length = concat("] ", length, &string); } else length = concat(": ", length, &string); if (x2->sem == SEM_TRUTH) length = showTruth(x2, i, length, &string); else /* numeric value */ length = showNum(x2, i, length, &string); } } done: /* print string representation */ if (string) { fputs(string, f); free(string); } } /* * Instantiate format string for each satisfying binding and value * of the current rule ... enumerate and insert %h, %v and %v values * * WARNING: This is not thread safe, it dinks with the format string. */ size_t /* new length of string */ formatSatisfyingValue(char *format, size_t length, char **string) { char *host; char *inst; char *first; char *prev; char *next; int i; Expr *x1; Expr *x2; int sts1; int sts2; /* no formatting present? */ if ((sts1 = findFormat(format, &first)) == 0) return concat(format, length, string); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "formatSatisfyingValue: curr=" PRINTF_P_PFX "%p\n", curr); dumpExpr(curr); } #endif x1 = findBindings(curr); x2 = findValues(x1); if (!x1->valid) /* * subexpression for %h, %i and %v is not valid but rule is * true, return string without substitution ... rare case * for || rule */ return concat(format, length, string); for (i = 0; i < x1->tspan; i++) { if ((x1->sem == SEM_TRUTH && *((char *)x1->smpls[0].ptr + i) == TRUE) || (x1->sem != SEM_TRUTH && x1->sem != SEM_UNKNOWN)) { prev = format; next = first; sts2 = sts1; lookupHostInst(x1, i, &host, &inst); do { *next = '\0'; length = concat(prev, length, string); *next = '%'; switch (sts2) { case 1: if (host) length = concat(host, length, string); else length = concat("<%h undefined>", length, string); break; case 2: if (inst) length = concat(inst, length, string); else length = concat("<%i undefined>", length, string); break; case 3: if (x2->sem == SEM_TRUTH) length = showTruth(x2, i, length, string); else /* numeric value */ length = showNum(x2, i, length, string); break; } prev = next + 2; } while ((sts2 = findFormat(prev, &next))); length = concat(prev, length, string); } } return length; } char * opStrings(int op) { int i; /* * sizing of "eh" is a bit tricky ... * XXXXXXXXX is the number of digits in the largest possible value * for "op", to handle the default "" case, but also * "eh" must be long enough to accommodate the longest string from * opstr[i].str ... currently "" */ static char *eh = ""; for (i = 0; i < numopstr; i++) { if (opstr[i].op == op) break; } if (i < numopstr) return opstr[i].str; else { sprintf(eh, "", op); return eh; } } pcp-3.8.12ubuntu1/src/pmie/src/pragmatics.c0000664000000000000000000007024112272262501015414 0ustar /* * pragmatics.c - inference engine pragmatics analysis * * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2013 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * The analysis of how to organize the fetching of metrics (pragmatics), * and any other parts of the inference engine sensitive to details of * the PMAPI access are kept in this source file. */ #include #include #include "pmapi.h" #include "impl.h" #include "dstruct.h" #include "eval.h" #include "pragmatics.h" #if defined(HAVE_IEEEFP_H) #include #endif extern char *clientid; /* for initialization of pmUnits struct */ pmUnits noUnits; pmUnits countUnits = { .dimCount = 1 }; char * findsource(char *host) { static char buf[MAXPATHLEN+MAXHOSTNAMELEN+30]; if (archives) { Archive *a = archives; while (a) { /* find archive for host */ if (strcmp(host, a->hname) == 0) break; a = a->next; } if (a) snprintf(buf, sizeof(buf), "archive %s (host %s)", a->fname, host); else snprintf(buf, sizeof(buf), "host %s in unknown archive!", host); } else snprintf(buf, sizeof(buf), "host %s", host); return buf; } /*********************************************************************** * PMAPI context creation & destruction ***********************************************************************/ int /* > 0: context handle, -1: retry later */ newContext(char *host) { Archive *a; int sts = -1; if (archives) { a = archives; while (a) { /* find archive for host */ if (strcmp(host, a->hname) == 0) break; a = a->next; } if (a) { /* archive found */ if ((sts = pmNewContext(PM_CONTEXT_ARCHIVE, a->fname)) < 0) { fprintf(stderr, "%s: cannot open archive %s\n", pmProgname, a->fname); fprintf(stderr, "pmNewContext: %s\n", pmErrStr(sts)); exit(1); } } else { /* no archive for host */ fprintf(stderr, "%s: no archive for host %s\n", pmProgname, host); exit(1); } } else if ((sts = pmNewContext(PM_CONTEXT_HOST, host)) < 0) { if (host_state_changed(host, STATE_FAILINIT) == 1) { if (sts == -ECONNREFUSED) fprintf(stderr, "%s: warning - pmcd " "on host %s does not respond\n", pmProgname, host); else if (sts == PM_ERR_PERMISSION) fprintf(stderr, "%s: warning - host %s does not " "permit delivery of metrics to the local host\n", pmProgname, host); else if (sts == PM_ERR_CONNLIMIT) fprintf(stderr, "%s: warning - pmcd " "on host %s has exceeded its connection limit\n", pmProgname, host); else fprintf(stderr, "%s: warning - host %s is unreachable\n", pmProgname, host); } sts = -1; } else if (clientid != NULL) /* register client id with pmcd */ __pmSetClientId(clientid); return sts; } /*********************************************************************** * instance profile ***********************************************************************/ /* equality (not symmetric) of instance names */ static int eqinst(char *i1, char *i2) { int n1 = (int) strlen(i1); int n2 = (int) strlen(i2); /* test equality of first word */ if ((strncmp(i1, i2, n1) == 0) && ((n1 == n2) || isspace((int)i2[n1]))) return 1; do { /* skip over first word */ i2++; n2--; if (n2 < n1) return 0; } while (! isspace((int)*i2)); do { /* skip over spaces */ i2++; n2--; if (n2 < n1) return 0; } while (isspace((int)*i2)); /* test equality of second word */ if ((strncmp(i1, i2, n1) == 0) && ((n1 == n2) || isspace((int)i2[n1]))) return 1; return 0; } /*********************************************************************** * task queue ***********************************************************************/ /* find Task for new rule */ static Task * findTask(RealTime delta) { Task *t, *u; int n = 0; t = taskq; if (t) { while (t->next) { /* find last task in queue */ t = t->next; n++; } /* last task in queue has same delta */ if (t->delta == delta) return t; } u = newTask(delta, n); /* create new Task */ if (t) { t->next = u; u->prev = t; } else taskq = u; return u; } /*********************************************************************** * wait list ***********************************************************************/ /* put Metric onto wait list */ void waitMetric(Metric *m) { Host *h = m->host; m->next = h->waits; m->prev = NULL; if (h->waits) h->waits->prev = m; h->waits = m; } /* remove Metric from wait list */ void unwaitMetric(Metric *m) { if (m->prev) m->prev->next = m->next; else m->host->waits = m->next; if (m->next) m->next->prev = m->prev; } /*********************************************************************** * fetch list ***********************************************************************/ /* find Host for Metric */ static Host * findHost(Task *t, Metric *m) { Host *h; h = t->hosts; while (h) { /* look for existing host */ if (h->name == m->hname) return h; h = h->next; } h = newHost(t, m->hname); /* add new host */ if (t->hosts) { h->next = t->hosts; t->hosts->prev = h; } t->hosts = h; return h; } /* helper function for Extended Time Base */ static void getDoubleAsXTB(double *realtime, int *ival, int *mode) { #define SECS_IN_24_DAYS 2073600.0 if (*realtime > SECS_IN_24_DAYS) { *ival = (int)*realtime; *mode = (*mode & 0x0000ffff) | PM_XTB_SET(PM_TIME_SEC); } else { *ival = (int)(*realtime * 1000.0); *mode = (*mode & 0x0000ffff) | PM_XTB_SET(PM_TIME_MSEC); } } /* find Fetch bundle for Metric */ static Fetch * findFetch(Host *h, Metric *m) { Fetch *f; int sts; int i; int n; pmID pmid = m->desc.pmid; pmID *p; struct timeval tv; /* find existing Fetch bundle */ f = h->fetches; /* create new Fetch bundle */ if (! f) { f = newFetch(h); if ((f->handle = newContext(symName(h->name))) < 0) { free(f); h->down = 1; return NULL; } if (archives) { int tmp_ival; int tmp_mode = PM_MODE_INTERP; getDoubleAsXTB(&h->task->delta, &tmp_ival, &tmp_mode); tv.tv_sec = (time_t)start; tv.tv_usec = (int)((start - tv.tv_sec) * 1000000.0); if ((sts = pmSetMode(tmp_mode, &tv, tmp_ival)) < 0) { fprintf(stderr, "%s: pmSetMode failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "findFetch: fetch=0x%p host=0x%p delta=%.6f handle=%d\n", f, h, h->task->delta, f->handle); } #endif } f->next = NULL; f->prev = NULL; h->fetches = f; } /* look for existing pmid */ p = f->pmids; n = f->npmids; for (i = 0; i < n; i++) { if (*p == pmid) break; p++; } /* add new pmid */ if (i == n) { p = f->pmids; p = ralloc(p, (n+1) * sizeof(pmID)); p[n] = pmid; f->npmids = n + 1; f->pmids = p; } return f; } /* find Profile for Metric */ static Profile * findProfile(Fetch *f, Metric *m) { Profile *p; int sts; /* find existing Profile */ p = f->profiles; while (p) { if (p->indom == m->desc.indom) { m->next = p->metrics; if (p->metrics) p->metrics->prev = m; p->metrics = m; break; } p = p->next; } /* create new Profile */ if (p == NULL) { m->next = NULL; p = newProfile(f, m->desc.indom); p->next = f->profiles; if (f->profiles) f->profiles->prev = p; f->profiles = p; p->metrics = m; } /* add instances required by Metric to Profile */ if ((sts = pmUseContext(f->handle)) < 0) { fprintf(stderr, "%s: pmUseContext failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } /* * If any rule requires all instances, then ignore restricted * instance lists from all other rules */ if (m->specinst == 0 && p->need_all == 0) { sts = pmDelProfile(p->indom, 0, (int *)0); if (sts < 0) { fprintf(stderr, "%s: pmDelProfile failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } sts = pmAddProfile(p->indom, 0, (int *)0); p->need_all = 1; } else if (m->specinst > 0 && p->need_all == 0) sts = pmAddProfile(p->indom, m->m_idom, m->iids); else sts = 0; if (sts < 0) { fprintf(stderr, "%s: pmAddProfile failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } m->profile = p; return p; } /* organize fetch bundling for given expression */ static void bundle(Task *t, Expr *x) { Metric *m; Host *h; int i; if (x->op == CND_FETCH) { m = x->metrics; for (i = 0; i < x->hdom; i++) { h = findHost(t, m); m->host = h; if (m->conv) /* initialized Metric */ bundleMetric(h, m); else /* uninitialized Metric */ waitMetric(m); m++; } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "bundle: task " PRINTF_P_PFX "%p nth=%d prev=" PRINTF_P_PFX "%p next=" PRINTF_P_PFX "%p delta=%.3f nrules=%d\n", t, t->nth, t->prev, t->next, t->delta, t->nrules+1); __dumpExpr(1, x); m = x->metrics; for (i = 0; i < x->hdom; i++) { __dumpMetric(2, m); m++; } } #endif } else { if (x->arg1) { bundle(t, x->arg1); if (x->arg2) bundle(t, x->arg2); } } } /*********************************************************************** * secret agent mode support ***********************************************************************/ /* send pmDescriptor for the given Expr as a binary PDU */ static void sendDesc(Expr *x, pmValueSet *vset) { pmDesc d; d.pmid = vset->pmid; d.indom = PM_INDOM_NULL; switch (x->sem) { case PM_SEM_COUNTER: case PM_SEM_INSTANT: case PM_SEM_DISCRETE: /* these map directly to PMAPI semantics */ d.type = PM_TYPE_DOUBLE; d.sem = x->sem; d.units = x->units; break; case SEM_NUMVAR: case SEM_NUMCONST: case SEM_TRUTH: /* map to a numeric value */ d.type = PM_TYPE_DOUBLE; d.sem = PM_SEM_INSTANT; d.units = x->units; break; default: fprintf(stderr, "sendDesc(%s): botch sem=%d?\n", pmIDStr(d.pmid), x->sem); /* FALLTHROUGH */ case SEM_UNKNOWN: case SEM_CHAR: case SEM_REGEX: /* no mapping is possible */ d.type = PM_TYPE_NOSUPPORT; d.sem = PM_SEM_INSTANT; d.units = noUnits; break; } __pmSendDesc(STDOUT_FILENO, pmWhichContext(), &d); } /*********************************************************************** * exported functions ***********************************************************************/ /* initialize access to archive */ int initArchive(Archive *a) { pmLogLabel label; struct timeval tv; int sts; int handle; Archive *b; /* setup temorary context for the archive */ if ((sts = pmNewContext(PM_CONTEXT_ARCHIVE, a->fname)) < 0) { fprintf(stderr, "%s: cannot open archive %s\n" "pmNewContext failed: %s\n", pmProgname, a->fname, pmErrStr(sts)); return 0; } handle = sts; a->hname = strdup (pmGetContextHostName (handle)); /* get the goodies from archive label */ if ((sts = pmGetArchiveLabel(&label)) < 0) { fprintf(stderr, "%s: cannot read label from archive %s\n" "pmGetArchiveLabel failed: %s\n", pmProgname, a->fname, pmErrStr(sts)); pmDestroyContext(handle); return 0; } a->first = realize(label.ll_start); if ((sts = pmGetArchiveEnd(&tv)) < 0) { fprintf(stderr, "%s: archive %s is corrupted\n" "pmGetArchiveEnd failed: %s\n", pmProgname, a->fname, pmErrStr(sts)); pmDestroyContext(handle); return 0; } a->last = realize(tv); /* check for duplicate host */ b = archives; while (b) { if (strcmp(a->hname, b->hname) == 0) { fprintf(stderr, "%s: Error: archive %s not legal - archive %s is already open " "for host %s\n", pmProgname, a->fname, b->fname, b->hname); pmDestroyContext(handle); return 0; } b = b->next; } /* put archive record on the archives list */ a->next = archives; archives = a; /* update first and last available data points */ if (first == -1 || a->first < first) first = a->first; if (a->last > last) last = a->last; pmDestroyContext(handle); return 1; } /* initialize timezone */ void zoneInit(void) { int sts; int handle = -1; Archive *a; if (timeZone) { /* TZ from timezone string */ if ((sts = pmNewZone(timeZone)) < 0) fprintf(stderr, "%s: cannot set timezone to %s\n" "pmNewZone failed: %s\n", pmProgname, timeZone, pmErrStr(sts)); } else if (! archives && hostZone) { /* TZ from live host */ if ((handle = pmNewContext(PM_CONTEXT_HOST, dfltHostConn)) < 0) fprintf(stderr, "%s: cannot set timezone from %s\n" "pmNewContext failed: %s\n", pmProgname, findsource(dfltHostConn), pmErrStr(handle)); else if ((sts = pmNewContextZone()) < 0) fprintf(stderr, "%s: cannot set timezone from %s\n" "pmNewContextZone failed: %s\n", pmProgname, findsource(dfltHostConn), pmErrStr(sts)); else fprintf(stdout, "%s: timezone set to local timezone of host %s\n", pmProgname, dfltHostConn); if (handle >= 0) pmDestroyContext(handle); } else if (hostZone) { /* TZ from an archive */ a = archives; while (a) { if (strcmp(dfltHostName, a->hname) == 0) break; a = a->next; } if (! a) fprintf(stderr, "%s: no archive supplied for host %s\n", pmProgname, dfltHostName); else if ((handle = pmNewContext(PM_CONTEXT_ARCHIVE, a->fname)) < 0) fprintf(stderr, "%s: cannot set timezone from %s\npmNewContext failed: %s\n", pmProgname, findsource(dfltHostName), pmErrStr(handle)); else if ((sts = pmNewContextZone()) < 0) fprintf(stderr, "%s: cannot set timezone from %s\n" "pmNewContextZone failed: %s\n", pmProgname, findsource(dfltHostName), pmErrStr(sts)); else fprintf(stdout, "%s: timezone set to local timezone of host %s\n", pmProgname, dfltHostName); if (handle >= 0) pmDestroyContext(handle); } } /* convert to canonical units */ pmUnits canon(pmUnits in) { static pmUnits out; out = in; out.scaleSpace = PM_SPACE_BYTE; out.scaleTime = PM_TIME_SEC; out.scaleCount = 0; return out; } /* scale factor to canonical pmUnits */ double scale(pmUnits in) { double f; /* scale space to Mbyte */ f = pow(1024, in.dimSpace * (in.scaleSpace - PM_SPACE_BYTE)); /* scale time to seconds */ if (in.scaleTime > PM_TIME_SEC) f *= pow(60, in.dimTime * (in.scaleTime - PM_TIME_SEC)); else f *= pow(1000, in.dimTime * (in.scaleTime - PM_TIME_SEC)); /* scale events to millions of events */ f *= pow(10, in.dimCount * in.scaleCount); return f; } /* initialize Metric */ int /* 1: ok, 0: try again later, -1: fail */ initMetric(Metric *m) { char *hname = symName(m->hname); char *mname = symName(m->mname); char **inames; int *iids; int handle; int ret = 1; int sts; int i, j; /* set up temporary context */ if ((handle = newContext(hname)) < 0) return 0; host_state_changed(hname, STATE_RECONN); if ((sts = pmLookupName(1, &mname, &m->desc.pmid)) < 0) { fprintf(stderr, "%s: metric %s not in namespace for %s\n" "pmLookupName failed: %s\n", pmProgname, mname, findsource(hname), pmErrStr(sts)); ret = 0; goto end; } /* fill in performance metric descriptor */ if ((sts = pmLookupDesc(m->desc.pmid, &m->desc)) < 0) { fprintf(stderr, "%s: metric %s not currently available from %s\n" "pmLookupDesc failed: %s\n", pmProgname, mname, findsource(hname), pmErrStr(sts)); ret = 0; goto end; } if (m->desc.type == PM_TYPE_STRING || m->desc.type == PM_TYPE_AGGREGATE || m->desc.type == PM_TYPE_AGGREGATE_STATIC || m->desc.type == PM_TYPE_EVENT || m->desc.type == PM_TYPE_UNKNOWN) { fprintf(stderr, "%s: metric %s has non-numeric type\n", pmProgname, mname); ret = -1; } else if (m->desc.indom == PM_INDOM_NULL) { if (m->specinst != 0) { fprintf(stderr, "%s: metric %s has no instances\n", pmProgname, mname); ret = -1; } else m->m_idom = 1; } else { /* metric has instances, get full instance profile */ if (archives) { if ((sts = pmGetInDomArchive(m->desc.indom, &iids, &inames)) < 0) { fprintf(stderr, "Metric %s from %s - instance domain not " "available in archive\npmGetInDomArchive failed: %s\n", mname, findsource(hname), pmErrStr(sts)); ret = -1; } } else if ((sts = pmGetInDom(m->desc.indom, &iids, &inames)) < 0) { fprintf(stderr, "Instance domain for metric %s from %s not (currently) available\n" "pmGetIndom failed: %s\n", mname, findsource(hname), pmErrStr(sts)); ret = 0; } if (ret == 1) { /* got instance profile */ if (m->specinst == 0) { /* all instances */ m->iids = iids; m->m_idom = sts; m->inames = alloc(m->m_idom*sizeof(char *)); for (i = 0; i < m->m_idom; i++) { m->inames[i] = sdup(inames[i]); } } else { /* selected instances only */ m->m_idom = 0; for (i = 0; i < m->specinst; i++) { /* look for first matching instance name */ for (j = 0; j < sts; j++) { if (eqinst(m->inames[i], inames[j])) { m->iids[i] = iids[j]; m->m_idom++; break; } } if (j == sts) { __pmNotifyErr(LOG_ERR, "metric %s from %s does not " "(currently) have instance \"%s\"\n", mname, findsource(hname), m->inames[i]); m->iids[i] = PM_IN_NULL; ret = 0; } } if (sts > 0) { /* * pmGetInDom or pmGetInDomArchive returned some * instances above */ free(iids); } /* * if specinst != m_idom, then some not found ... move these * to the end of the list */ for (j = m->specinst-1; j >= 0; j--) { if (m->iids[j] != PM_IN_NULL) break; } for (i = 0; i < j; i++) { if (m->iids[i] == PM_IN_NULL) { /* need to swap */ char *tp; tp = m->inames[i]; m->inames[i] = m->inames[j]; m->iids[i] = m->iids[j]; m->inames[j] = tp; m->iids[j] = PM_IN_NULL; j--; } } } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { int numinst; fprintf(stderr, "initMetric: %s from %s: instance domain specinst=%d\n", mname, hname, m->specinst); if (m->m_idom < 1) fprintf(stderr, " %d instances!\n", m->m_idom); numinst = m->specinst == 0 ? m->m_idom : m->specinst; for (i = 0; i < numinst; i++) { fprintf(stderr, " indom[%d]", i); if (m->iids[i] == PM_IN_NULL) fprintf(stderr, " ?missing"); else fprintf(stderr, " %d", m->iids[i]); fprintf(stderr, " \"%s\"\n", m->inames[i]); } } #endif if (sts > 0) { /* * pmGetInDom or pmGetInDomArchive returned some instances * above */ free(inames); } } } if (ret == 1) { /* compute conversion factor into canonical units - non-zero conversion factor flags initialized metric */ m->conv = scale(m->desc.units); /* automatic rate computation */ if (m->desc.sem == PM_SEM_COUNTER) { m->vals = (double *) ralloc(m->vals, m->m_idom * sizeof(double)); for (j = 0; j < m->m_idom; j++) m->vals[j] = 0; } } end: /* destroy temporary context */ pmDestroyContext(handle); /* retry not meaningful for archives */ if (archives && (ret == 0)) ret = -1; return ret; } /* reinitialize Metric - only for live host */ int /* 1: ok, 0: try again later, -1: fail */ reinitMetric(Metric *m) { char *hname = symName(m->hname); char *mname = symName(m->mname); char **inames; int *iids; int handle; int ret = 1; int sts; int i, j; /* set up temporary context */ if ((handle = newContext(hname)) < 0) return 0; host_state_changed(hname, STATE_RECONN); if ((sts = pmLookupName(1, &mname, &m->desc.pmid)) < 0) { ret = 0; goto end; } /* fill in performance metric descriptor */ if ((sts = pmLookupDesc(m->desc.pmid, &m->desc)) < 0) { ret = 0; goto end; } if (m->desc.type == PM_TYPE_STRING || m->desc.type == PM_TYPE_AGGREGATE || m->desc.type == PM_TYPE_AGGREGATE_STATIC || m->desc.type == PM_TYPE_EVENT || m->desc.type == PM_TYPE_UNKNOWN) { fprintf(stderr, "%s: metric %s has non-numeric type\n", pmProgname, mname); ret = -1; } else if (m->desc.indom == PM_INDOM_NULL) { if (m->specinst != 0) { fprintf(stderr, "%s: metric %s has no instances\n", pmProgname, mname); ret = -1; } else m->m_idom = 1; } else { if ((sts = pmGetInDom(m->desc.indom, &iids, &inames)) < 0) { /* full profile */ ret = 0; } else { if (m->specinst == 0) { /* all instances */ m->iids = iids; m->m_idom = sts; m->inames = alloc(m->m_idom*sizeof(char *)); for (i = 0; i < m->m_idom; i++) { m->inames[i] = sdup(inames[i]); } } else { /* explicit instance profile */ m->m_idom = 0; for (i = 0; i < m->specinst; i++) { /* look for first matching instance name */ for (j = 0; j < sts; j++) { if (eqinst(m->inames[i], inames[j])) { m->iids[i] = iids[j]; m->m_idom++; break; } } if (j == sts) { m->iids[i] = PM_IN_NULL; ret = 0; } } if (sts > 0) { /* * pmGetInDom or pmGetInDomArchive returned some * instances above */ free(iids); } /* * if specinst != m_idom, then some not found ... move these * to the end of the list */ for (j = m->specinst-1; j >= 0; j--) { if (m->iids[j] != PM_IN_NULL) break; } for (i = 0; i < j; i++) { if (m->iids[i] == PM_IN_NULL) { /* need to swap */ char *tp; tp = m->inames[i]; m->inames[i] = m->inames[j]; m->iids[i] = m->iids[j]; m->inames[j] = tp; m->iids[j] = PM_IN_NULL; j--; } } } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { int numinst; fprintf(stderr, "reinitMetric: %s from %s: instance domain specinst=%d\n", mname, hname, m->specinst); if (m->m_idom < 1) fprintf(stderr, " %d instances!\n", m->m_idom); if (m->specinst == 0) numinst = m->m_idom; else numinst = m->specinst; for (i = 0; i < numinst; i++) { fprintf(stderr, " indom[%d]", i); if (m->iids[i] == PM_IN_NULL) fprintf(stderr, " ?missing"); else fprintf(stderr, " %d", m->iids[i]); fprintf(stderr, " \"%s\"\n", m->inames[i]); } } #endif if (sts > 0) { /* * pmGetInDom or pmGetInDomArchive returned some instances * above */ free(inames); } } } if (ret == 1) { /* compute conversion factor into canonical units - non-zero conversion factor flags initialized metric */ m->conv = scale(m->desc.units); /* automatic rate computation */ if (m->desc.sem == PM_SEM_COUNTER) { m->vals = (double *) ralloc(m->vals, m->m_idom * sizeof(double)); for (j = 0; j < m->m_idom; j++) m->vals[j] = 0; } } if (ret >= 0) { /* * re-shape, starting here are working up the expression until * we reach the top of the tree or the designated metrics * associated with the node are not the same */ Expr *x = m->expr; while (x) { /* * only re-shape expressions that may have set values */ if (x->op == CND_FETCH || x->op == CND_NEG || x->op == CND_ADD || x->op == CND_SUB || x->op == CND_MUL || x->op == CND_DIV || x->op == CND_SUM_HOST || x->op == CND_SUM_INST || x->op == CND_SUM_TIME || x->op == CND_AVG_HOST || x->op == CND_AVG_INST || x->op == CND_AVG_TIME || x->op == CND_MAX_HOST || x->op == CND_MAX_INST || x->op == CND_MAX_TIME || x->op == CND_MIN_HOST || x->op == CND_MIN_INST || x->op == CND_MIN_TIME || x->op == CND_EQ || x->op == CND_NEQ || x->op == CND_LT || x->op == CND_LTE || x->op == CND_GT || x->op == CND_GTE || x->op == CND_NOT || x->op == CND_AND || x->op == CND_OR || x->op == CND_RISE || x->op == CND_FALL || x->op == CND_MATCH || x->op == CND_NOMATCH) { instFetchExpr(x); findEval(x); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "reinitMetric: re-shaped ...\n"); dumpExpr(x); } #endif } if (x->parent) { x = x->parent; if (x->metrics == m) continue; } break; } } end: /* destroy temporary context */ pmDestroyContext(handle); return ret; } /* put initialised Metric onto fetch list */ void bundleMetric(Host *h, Metric *m) { Fetch *f = findFetch(h, m); if (f == NULL) { /* * creating new fetch bundle and pmNewContext failed ... * not much choice here */ waitMetric(m); } else /* usual case */ findProfile(findFetch(h, m), m); } /* reconnect attempt to host */ int reconnect(Host *h) { Fetch *f; f = h->fetches; while (f) { if (pmReconnectContext(f->handle) < 0) return 0; if (clientid != NULL) /* re-register client id with pmcd */ __pmSetClientId(clientid); f = f->next; } return 1; } /* pragmatics analysis */ void pragmatics(Symbol rule, RealTime delta) { Expr *x = symValue(rule); Task *t; if (x->op != NOP) { t = findTask(delta); bundle(t, x); t->nrules++; t->rules = (Symbol *) ralloc(t->rules, t->nrules * sizeof(Symbol)); t->rules[t->nrules-1] = symCopy(rule); perf->eval_expected += (float)1/delta; } } /* * find all expressions for a host that has just been marked "down" * and invalidate them */ static void mark_all(Host *hdown) { Task *t; Symbol *s; Metric *m; Expr *x; int i; for (t = taskq; t != NULL; t = t->next) { s = t->rules; for (i = 0; i < t->nrules; i++, s++) { x = (Expr *)symValue(*s); for (m = x->metrics; m != NULL; m = m->next) { if (m->host == hdown) clobber(x); } } } } /* execute fetches for given Task */ void taskFetch(Task *t) { Host *h; Fetch *f; Profile *p; Metric *m; pmResult *r; pmValueSet **v; int i; int sts; /* do all fetches, quick as you can */ h = t->hosts; while (h) { f = h->fetches; while (f) { if (f->result) pmFreeResult(f->result); if (! h->down) { pmUseContext(f->handle); if ((sts = pmFetch(f->npmids, f->pmids, &f->result)) < 0) { if (! archives) { __pmNotifyErr(LOG_ERR, "pmFetch from %s failed: %s\n", symName(f->host->name), pmErrStr(sts)); host_state_changed(symName(f->host->name), STATE_LOSTCONN); h->down = 1; mark_all(h); } f->result = NULL; } } else f->result = NULL; f = f->next; } h = h->next; } /* sort and distribute pmValueSets to requesting Metrics */ h = t->hosts; while (h) { if (! h->down) { f = h->fetches; while (f && (r = f->result)) { /* sort all vlists in result r */ v = r->vset; for (i = 0; i < r->numpmid; i++) { if ((*v)->numval > 0) { qsort((*v)->vlist, (size_t)(*v)->numval, sizeof(pmValue), compair); } v++; } /* distribute pmValueSets to Metrics */ p = f->profiles; while (p) { m = p->metrics; while (m) { for (i = 0; i < r->numpmid; i++) { if (m->desc.pmid == r->vset[i]->pmid) { if (r->vset[i]->numval > 0) { m->vset = r->vset[i]; m->stamp = realize(r->timestamp); } break; } } m = m->next; } p = p->next; } f = f->next; } } h = h->next; } } /* send pmDescriptors for all expressions in given task */ void sendDescs(Task *task) { Symbol *s; int i; s = task->rules; for (i = 0; i < task->nrules; i++) { sendDesc(symValue(*s), task->rslt->vset[i]); s++; } } /* convert Expr value to pmValueSet value */ void fillVSet(Expr *x, pmValueSet *vset) { if (x->valid > 0) { if (finite(*((double *)x->ring))) { /* copy value */ vset->numval = 1; memcpy(&vset->vlist[0].value.pval->vbuf, x->ring, sizeof(double)); } else /* value not representable */ vset->numval = 0; } else { /* value not available */ vset->numval = PM_ERR_VALUE; } } pcp-3.8.12ubuntu1/src/pmie/src/lexicon.c0000664000000000000000000004647012272262501014732 0ustar /*********************************************************************** * lexicon.c - lexical scanner * * There is enough lookahead to enable use of '/' as both an arithmetic * and units operator. Nested macro expansion is supported using a stack * of input contexts (see definition of LexIn in file syntax.y). *********************************************************************** * * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include "dstruct.h" #include "syntax.h" #include "grammar.h" #include "lexicon.h" #include "pragmatics.h" /*********************************************************************** * type definitions ***********************************************************************/ /* for table of lexical items */ typedef struct { char *key; int token; } LexEntry1; /* for another table of lexical items */ typedef struct { char *key; int token; int scale; } LexEntry2; /*********************************************************************** * constants ***********************************************************************/ static LexEntry1 domtab[] = { {"host", HOST_DOM}, {"inst", INST_DOM}, {"sample", TIME_DOM}, {NULL, 0} }; static LexEntry1 quantab[] = { {"sum", SUM_AGGR}, {"avg", AVG_AGGR}, {"max", MAX_AGGR}, {"min", MIN_AGGR}, {"count", COUNT_AGGR}, {"all", ALL_QUANT}, {"some", SOME_QUANT}, {"%", PCNT_QUANT}, {NULL, 0} }; static LexEntry1 optab[] = { {"true", TRU}, {"false", FALS}, {"rate", RATE}, {"shell", SHELL}, {"alarm", ALARM}, {"syslog", SYSLOG}, {"print", PRINT}, {"stomp", STOMP}, {"rising", RISE}, {"falling", FALL}, {"match_inst", MATCH}, {"nomatch_inst",NOMATCH}, {NULL, 0} }; static LexEntry2 unitab[] = { {"byte", SPACE_UNIT, PM_SPACE_BYTE}, {"Kbyte", SPACE_UNIT, PM_SPACE_KBYTE}, {"Mbyte", SPACE_UNIT, PM_SPACE_MBYTE}, {"Gbyte", SPACE_UNIT, PM_SPACE_GBYTE}, {"Tbyte", SPACE_UNIT, PM_SPACE_TBYTE}, {"nsec", TIME_UNIT, PM_TIME_NSEC}, {"usec", TIME_UNIT, PM_TIME_USEC}, {"msec", TIME_UNIT, PM_TIME_MSEC}, {"sec", TIME_UNIT, PM_TIME_SEC}, {"min", TIME_UNIT, PM_TIME_MIN}, {"hour", TIME_UNIT, PM_TIME_HOUR}, {"count", EVENT_UNIT, 0}, {"Kcount", EVENT_UNIT, 3}, {"Mcount", EVENT_UNIT, 6}, {"nanosec", TIME_UNIT, PM_TIME_NSEC}, {"nanosecond", TIME_UNIT, PM_TIME_NSEC}, {"microsec", TIME_UNIT, PM_TIME_USEC}, {"microsecond", TIME_UNIT, PM_TIME_USEC}, {"millisec", TIME_UNIT, PM_TIME_MSEC}, {"millisecond", TIME_UNIT, PM_TIME_MSEC}, {"second", TIME_UNIT, PM_TIME_SEC}, {"minute", TIME_UNIT, PM_TIME_MIN}, {NULL, 0, 0} }; /*********************************************************************** * variables ***********************************************************************/ LexIn *lin; /* current input context */ static char *token; /* current token buffer */ /*********************************************************************** * local functions ***********************************************************************/ /* unwind input context */ static void unwind(void) { LexIn *tmp; if (lin->name) { free(lin->name); if (! lin->macro) fclose(lin->stream); } tmp = lin; lin = lin->prev; free(tmp); } /* next input character */ static int nextc(void) { int c = '\0'; if (lin) { if (lin->lookin != lin->lookout) { c = lin->look[lin->lookout++]; if (lin->lookout >= LEX_MAX + 2) lin->lookout = 0; } else { if (lin->macro) c = *lin->macro++; else { c = getc(lin->stream); if (c == EOF) c = '\0'; } if (c == '\0') { unwind(); return nextc(); } lin->cno++; if (c == '\n') { lin->lno++; lin->cno = 0; } } #if PCP_DEBUG && PCP_DESPERATE if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "nextc() -> \'%c\'\n", c); #endif return c; } return EOF; } /* new file input context */ static int inFile(char *name) { FILE *f; LexIn *t; t = (LexIn *) zalloc(sizeof(LexIn)); if (name == NULL) f = stdin; else { if ((f = fopen(name, "r")) == NULL) { fprintf(stderr, "%s: cannot open config file %s\n", pmProgname, name); free(t); return 0; } t->name = (char *) alloc(strlen(name) + 1); strcpy(t->name, name); } t->stream = f; t->lno = 1; t->cno = 0; t->prev = lin; lin = t; return 1; } #define DEREF_ERROR 0 #define DEREF_STRING 1 #define DEREF_BOOL 2 #define DEREF_NUMBER 3 /* * dereference macro ... return one of the DEREF_* values * for DEREF_ERROR, error is reported here */ static int varDeref(char *name) { Symbol s; Expr *x; LexIn *t; /* lookup macro name */ if ((s = symLookup(&vars, name)) == NULL) { fprintf(stderr, "undefined macro name $%s\n", name); return DEREF_ERROR; } x = symValue(s); /* string macro */ if (x->sem == SEM_CHAR) { t = (LexIn *) zalloc(sizeof(LexIn)); t->prev = lin; lin = t; lin->name = (char *) alloc(strlen(name) + 1); strcpy(lin->name, name); lin->macro = (char *) x->ring; lin->lno = 1; lin->cno = 0; return DEREF_STRING; } /* truth valued macro */ if (x->sem == SEM_TRUTH) { yylval.x = x; return DEREF_BOOL; } /* constant numeric valued macro */ if (x->sem == SEM_NUMCONST) { /* * need to copy the Expr as the one returned here may be freed * later after constant folding, and we need the real macro's * value to be available for use in later rules */ yylval.x = newExpr(NOP, NULL, NULL, -1, -1, -1, 1, SEM_NUMCONST); yylval.x->smpls[0].ptr = x->smpls[0].ptr; yylval.x->valid = 1; return DEREF_NUMBER; } /* variable numeric valued macro */ if (x->sem == SEM_NUMVAR) { yylval.x = x; return DEREF_NUMBER; } fprintf(stderr, "varDeref(%s): internal botch sem=%d?\n", name, x->sem); dumpExpr(x); exit(1); } /* push character into lookahead queue */ static void prevc(int c) { if (lin) { lin->look[lin->lookin++] = c; if (lin->lookin >= LEX_MAX + 2) lin->lookin = 0; } } /* push string into lookahead queue */ static void prevs(char *s) { while (*s != '\0') { lin->look[lin->lookin++] = *s++; if (lin->lookin >= LEX_MAX + 2) lin->lookin = 0; } } /* get IDENT after '$' ... match rules for IDENT in main scanner */ static int get_ident(char *namebuf) { int c; int d = 0; int i; char *namebuf_start = namebuf; c = nextc(); if (c == '\'') { d = c; c = nextc(); } if (!isalpha(c)) { fprintf(stderr, "macro name must begin with an alphabetic (not '%c')\n", c); lexSync(); return 0; } i = 0; do { if (c == '\\') c = nextc(); *namebuf++ = c; i++; c = nextc(); } while (i < LEX_MAX && c != EOF && (isalpha(c) || isdigit(c) || c == '_' || (d && c != d))); if (i == LEX_MAX) { namebuf_start[20] = '\0'; fprintf(stderr, "macro name too long: $%s...\n", namebuf_start); lexSync(); return 0; } if (c == EOF) { *namebuf = '\0'; fprintf(stderr, "unexpected end of file in macro name: $%s\n", namebuf_start); lexSync(); return 0; } if (!d) prevc(c); *namebuf = '\0'; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "get_ident() -> macro name \"%s\"\n", namebuf_start); #endif return 1; } /*********************************************************************** * exported functions ***********************************************************************/ /* initialize scan of new input stream */ int lexInit(char *fname) { lin = NULL; if (! inFile(fname)) return 0; token = (char *) alloc(LEX_MAX + 1); return 1; } /* finalize scan of input stream */ void lexFinal(void) { free(token); } /* not end of input stream? */ int lexMore(void) { return (lin != NULL); } /* discard input to next ';' or EOF */ void lexSync(void) { int c; do c = nextc(); while ((c != ';') && (c != EOF)); prevc(c); } /* scanner main function */ int yylex(void) { int c, d; /* current character */ int esc = 0; /* for escape processing */ static int ahead = 0; /* lookahead token */ int behind = 0; /* lookbehind token */ LexEntry1 *lt1; /* scans through lexbuf1 */ LexEntry2 *lt2; /* scans through lexbuf2 */ char *p, *q; int i; char nbuf[LEX_MAX+1]; /* for getting macro name */ /* token from previous invocation */ if (ahead) { c = ahead; ahead = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> TOKEN (ahead) \'%c\'\n", c); #endif return c; } /* scan token from input */ c = nextc(); while (c != EOF) { /* skip blanks */ while (isspace(c)) c = nextc(); /* scan C style comment */ if (c == '/') { if ((d = nextc()) != '*') prevc(d); else { c = nextc(); while (c != EOF) { d = nextc(); if ((c == '*') && (d == '/')) { c = nextc(); break; } c = d; } continue; } } /* scan C++ style comment */ if (c == '/') { if ((d = nextc()) != '/') prevc(d); else { do c = nextc(); while (( c != '\n') && (c != EOF)); continue; } } /* scan alphanumeric */ if (isalpha(c) || (c == '\'') || (c == '%')) { d = c; if (d == '\'') c = nextc(); i = 0; do { if (c == '$') { /* macro embedded in identifier */ int sts; if (!get_ident(nbuf)) return EOF; sts = varDeref(nbuf); if (sts == DEREF_ERROR) { /* error reporting in varDeref() */ lexSync(); return EOF; } else if (sts != DEREF_STRING) { synerr(); fprintf(stderr, "macro $%s not string valued as expected\n", nbuf); lexSync(); return EOF; } c = nextc(); } else { if (c == '\\') c = nextc(); token[i++] = c; c = nextc(); } } while ((isalpha(c) || isdigit(c) || c == '.' || c == '_' || c == '\\' || c == '$' || (d == '\'' && c != d)) && (i < LEX_MAX)); token[i] = '\0'; if (d == '\'') c = nextc(); /* * recognize keywords associated with units of space, time * and count, see unitab[] */ if (d != '\'') { lt2 = &unitab[0]; if (i > 0 && token[i-1] == 's') i--; do { if (strlen(lt2->key) == i && strncmp(token, lt2->key, i) == 0) { /* if looking ahead after '/', return UNIT_SLASH */ if (behind == '/') { prevs(&token[0]); prevc(c); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \"/\"\n"); #endif return UNIT_SLASH; } prevc(c); yylval.u = noUnits; switch (lt2->token) { case SPACE_UNIT: yylval.u.dimSpace = 1; yylval.u.scaleSpace = lt2->scale; break; case TIME_UNIT: yylval.u.dimTime = 1; yylval.u.scaleTime = lt2->scale; break; case EVENT_UNIT: yylval.u.dimCount = 1; yylval.u.scaleCount = lt2->scale; break; } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> UNITS \"%s\"\n", pmUnitsStr(&yylval.u)); #endif return lt2->token; } lt2++; } while (lt2->key); } /* if looking ahead, return previous token */ if (behind) { prevs(&token[0]); prevc(c); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> TOKEN (behind) \'%c\'\n", behind); #endif return behind; } prevc(c); /* recognize aggregation and quantification */ if (d != '\'') { if ((p = strchr(token, '_')) != NULL) { *p = '\0'; lt1 = &quantab[0]; do { if (strcmp(&token[0], lt1->key) == 0) { c = lt1->token; q = p + 1; lt1 = &domtab[0]; do { if (strcmp(q, lt1->key) == 0) { ahead = lt1->token; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \"%s\'\n", token); #endif return c; } lt1++; } while (lt1->key); break; } lt1++; } while (lt1->key); *p = '_'; } /* recognize other reserved word */ lt1 = &optab[0]; do { if (strcmp(&token[0], lt1->key) == 0) { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> RESERVED-WORD \"%s\"\n", token); #endif return lt1->token; } lt1++; } while (lt1->key); } /* recognize identifier */ yylval.s = (char *) alloc(strlen(&token[0]) + 1); strcpy(yylval.s, &token[0]); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> IDENT \"%s\"\n", token); #endif return IDENT; } /* if looking ahead, return preceding token */ if (behind) { prevc(c); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> TOKEN (behind) \'%c\'\n", behind); #endif return behind; } /* special case for .[0-9]... number without leading [0-9] */ if (c == '.') { c = nextc(); if (isdigit(c)) { /* note prevc() implements a FIFO, not a stack! */ prevc('.'); /* push back period */ prevc(c); /* push back digit */ c = '0'; /* start with fake leading zero */ } else prevc(c); /* not a digit after period, push back */ } /* scan NUMBER */ if (isdigit(c)) { int flote = 0; i = 0; do { token[i++] = c; c = nextc(); if ((flote == 0) && (c == '.') && (i < LEX_MAX)) { c = nextc(); if (c == '.') prevc(c); /* INTERVAL token */ else { flote = 1; token[i++] = '.'; } } if ((flote <= 1) && (i < LEX_MAX) && ((c == 'e') || (c == 'E'))) { flote = 2; token[i++] = c; c = nextc(); } if ((flote <= 2) && (c == '-') && (i < LEX_MAX)) { flote = 3; token[i++] = c; c = nextc(); } } while (isdigit(c) && (i < LEX_MAX)); prevc(c); token[i] = '\0'; yylval.d = strtod(&token[0], NULL); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> NUMBER %g\n", yylval.d); #endif return NUMBER; } /* scan string */ if (c == '"') { yylval.s = NULL; i = 0; c = nextc(); while ((c != '"') && (c != EOF) && (i < LEX_MAX)) { /* escape character */ if (c == '\\') { esc = 1; c = nextc(); switch (c) { case 'n': c = '\n'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; case 'b': c = '\b'; break; case 'r': c = '\r'; break; case 'f': c = '\f'; break; case 'a': c = '\a'; break; } } else esc = 0; /* macro embedded in string */ if (c == '$' && !esc) { int sts; if (!get_ident(nbuf)) return EOF; sts = varDeref(nbuf); if (sts == DEREF_ERROR) { /* error reporting in varDeref() */ lexSync(); return EOF; } else if (sts != DEREF_STRING) { synerr(); fprintf(stderr, "macro $%s not string valued as expected\n", nbuf); lexSync(); return EOF; } c = nextc(); } /* add character to string */ yylval.s = (char *) ralloc(yylval.s, i+2); yylval.s[i++] = c; c = nextc(); } if (i == 0) { /* special case for null string */ yylval.s = (char *) ralloc(yylval.s, 1); } yylval.s[i++] = '\0'; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> STRING \"%s\"\n", yylval.s); #endif return STRING; } /* scan operator */ switch (c) { case ';': do d = nextc(); while (isspace(d)); if (d == '.') { while (lin) unwind(); } else prevc(d); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> END-OF-RULE\n"); #endif return EOF; case '$': if (!get_ident(nbuf)) return EOF; switch (varDeref(nbuf)) { case DEREF_ERROR: lexSync(); return EOF; case DEREF_STRING: c = nextc(); continue; case DEREF_BOOL: #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> (boolean) macro $%s\n", nbuf); #endif return VAR; case DEREF_NUMBER: #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> (numeric) macro $%s\n", nbuf); #endif return VAR; } /*NOTREACHED*/ break; case '/': behind = c; c = nextc(); continue; case '-': if ((d = nextc()) == '>') { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \"->\"\n"); #endif return ARROW; } prevc(d); break; case '=': if ((d = nextc()) == '=') { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \"==\"\n"); #endif return EQ_REL; } prevc(d); break; case '!': if ((d = nextc()) == '=') { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \"!=\"\n"); #endif return NEQ_REL; } prevc(d); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \"!\"\n"); #endif return NOT; case '<': if ((d = nextc()) == '=') { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \"<=\"\n"); #endif return LEQ_REL; } prevc(d); break; case '>': if ((d = nextc()) == '=') { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \">=\"\n"); #endif return GEQ_REL; } prevc(d); break; case '&': if ((d = nextc()) == '&') { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \"&&\"\n"); #endif return AND; } prevc(d); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \"&\"\n"); #endif return SEQ; case '|': if ((d = nextc()) == '|') { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \"||\"\n"); #endif return OR; } prevc(d); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \"|\"\n"); #endif return ALT; case '.': if ((d = nextc()) == '.') { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> OPERATOR \"..\"\n"); #endif return INTERVAL; } prevc(d); break; } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { if (c == EOF) fprintf(stderr, "yylex() -> EOF\n"); else fprintf(stderr, "yylex() -> TOKEN \'%c\' (0x%x)\n", c, c & 0xff); } #endif return c; } #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "yylex() -> EOF\n"); #endif return EOF; } pcp-3.8.12ubuntu1/src/pmie/src/dstruct.c0000664000000000000000000010053512272262501014752 0ustar /*********************************************************************** * dstruct.c - central data structures and associated operations *********************************************************************** * * Copyright (c) 2013 Red Hat. * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include #include #include #ifdef HAVE_SYS_WAIT_H #include #endif #include "dstruct.h" #include "symbol.h" #include "pragmatics.h" #include "fun.h" #include "eval.h" #include "show.h" #if defined(HAVE_VALUES_H) #include #endif #if defined(HAVE_IEEEFP_H) #include #endif /*********************************************************************** * constants ***********************************************************************/ double mynan; /* not-a-number run time initialized */ /*********************************************************************** * user supplied parameters ***********************************************************************/ char *pmnsfile = PM_NS_DEFAULT; /* alternate name space */ Archive *archives; /* list of open archives */ RealTime first = -1; /* archive starting point */ RealTime last = 0.0; /* archive end point */ char *dfltHostConn; /* default host connection string */ char *dfltHostName; /* default host name */ RealTime dfltDelta = DELTA_DFLT; /* default sample interval */ char *startFlag; /* start time specified? */ char *stopFlag; /* end time specified? */ char *alignFlag; /* align time specified? */ char *offsetFlag; /* offset time specified? */ RealTime runTime; /* run time interval */ int hostZone; /* timezone from host? */ char *timeZone; /* timezone from command line */ int verbose; /* verbosity 0, 1 or 2 */ int interactive; /* interactive mode, -d */ int isdaemon; /* run as a daemon */ int agent; /* secret agent mode? */ int applet; /* applet mode? */ int dowrap; /* counter wrap? default no */ int noDnsFlag; /* do a default name lookup? */ pmiestats_t *perf; /* live performance data */ pmiestats_t instrument; /* used if no mmap (archive) */ /*********************************************************************** * this is where the action is ***********************************************************************/ Task *taskq = NULL; /* evaluator task queue */ Expr *curr; /* current executing rule expression */ SymbolTable hosts; /* currently known hosts */ SymbolTable metrics; /* currently known metrics */ SymbolTable rules; /* currently known rules */ SymbolTable vars; /* currently known variables */ /*********************************************************************** * time ***********************************************************************/ RealTime now; /* current time */ RealTime start; /* start evaluation time */ RealTime stop; /* stop evaluation time */ Symbol symDelta; /* current sample interval */ Symbol symMinute; /* minutes after the hour 0..59 */ Symbol symHour; /* hours since midnight 0..23 */ Symbol symDay; /* day of the month 1..31 */ Symbol symMonth; /* month of the year 1..12 */ Symbol symYear; /* year 1996.. */ Symbol symWeekday; /* days since Sunday 0..6 */ static double delta; /* current sample interval */ static double second; /* seconds after the minute 0..59 */ static double minute; /* minutes after the hour 0..59 */ static double hour; /* hours since midnight 0..23 */ static double day; /* day of the month 1..31 */ static double month; /* month of the year 1..12 */ static double year; /* year 1996.. */ static double weekday; /* days since Sunday 0..6 */ /*********************************************************************** * process creation control ***********************************************************************/ int need_wait; /* return real time */ RealTime getReal(void) { struct timeval t; __pmtimevalNow(&t); return realize(t); } /* update time variables to reflect current time */ void reflectTime(RealTime d) { static time_t then = 0; /* previous time */ int skip = now - then; struct tm tm; then = (time_t)now; /* sample interval */ delta = d; /* try short path for current time */ if (skip >= 0 && skip < 24 * 60 * 60) { second += skip; if (second < 60) return; skip = (int)(second / 60); second -= (double)(60 * skip); minute += (double)skip; if (minute < 60) return; skip = (int)(minute / 60); minute -= (double)(60 * skip); hour += (double)skip; if (hour < 24) return; } /* long path for current time */ pmLocaltime(&then, &tm); second = (double) tm.tm_sec; minute = (double) tm.tm_min; hour = (double) tm.tm_hour; day = (double) tm.tm_mday; month = (double) tm.tm_mon; /* tm_year is years since 1900, so this is Y2K safe */ year = (double) tm.tm_year + 1900; weekday = (double) tm.tm_wday; } /* convert RealTime to timeval */ void unrealize(RealTime rt, struct timeval *tv) { tv->tv_sec = (time_t)rt; tv->tv_usec = (int)(1000000 * (rt - tv->tv_sec)); } /* convert RealTime to timespec */ void unrealizenano(RealTime rt, struct timespec *ts) { ts->tv_sec = (time_t)rt; ts->tv_nsec = (int)(1000000000 * (rt - ts->tv_sec)); } #define SLEEP_EVAL 0 #define SLEEP_RETRY 1 /* sleep until eval or retry RealTime */ void sleepTight(Task *t, int type) { RealTime sched; RealTime delay; /* interval to sleep */ int sts; RealTime cur_entry = getReal(); #ifdef HAVE_WAITPID pid_t pid; if (need_wait) { /* harvest terminated children */ while ((pid = waitpid(-1, &sts, WNOHANG)) > (pid_t)0) { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "sleepTight: wait: pid=%" FMT_PID " done status=0x%x", pid, sts); if (WIFEXITED(sts)) fprintf(stderr, " exit=%d", WEXITSTATUS(sts)); if (WIFSIGNALED(sts)) fprintf(stderr, " signal=%d", WTERMSIG(sts)); fprintf(stderr, "\n"); } #endif ; } need_wait = 0; } #endif if (!archives) { struct timespec ts, tleft; static RealTime last_sched = -1; static Task *last_t; static int last_type; RealTime cur = getReal(); sched = type == SLEEP_EVAL ? t->eval : t->retry; delay = sched - cur; if (delay < 0) { int show_detail = 0; if (delay <= -1) { fprintf(stderr, "sleepTight: negative delay (%f). sched=%f, cur=%f\n", delay, sched, cur); show_detail = 1; } #if PCP_DEBUG else { if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "sleepTight: small negative delay (%f). sched=%f, cur=%f\n", delay, sched, cur); show_detail = 1; } } #endif if (show_detail) { if (last_sched > 0) { fprintf(stderr, "Last sleepTight (%s) until: ", last_type == SLEEP_EVAL ? "eval" : "retry"); showFullTime(stderr, last_sched); fputc('\n', stderr); fprintf(stderr, "Last "); dumpTask(last_t); } fprintf(stderr, "This sleepTight() entry: "); showFullTime(stderr, cur_entry); fputc('\n', stderr); fprintf(stderr, "Harvest children done: "); showFullTime(stderr, cur); fputc('\n', stderr); fprintf(stderr, "Want sleepTight (%s) until: ", type == SLEEP_EVAL ? "eval" : "retry"); showFullTime(stderr, sched); fputc('\n', stderr); fprintf(stderr, "This "); dumpTask(t); } } else { unrealizenano(delay, &ts); for (;;) { /* loop to catch early wakeup from nanosleep */ if (ts.tv_sec < 0 || ts.tv_nsec > 999999999) { fprintf(stderr, "sleepTight: invalid args: %ld %ld\n", ts.tv_sec, ts.tv_nsec); break; } sts = nanosleep(&ts, &tleft); if (sts == 0 || (sts < 0 && oserror() != EINTR)) break; ts = tleft; } } last_t = t; last_type = type; last_sched = sched; } } /*********************************************************************** * ring buffer management ***********************************************************************/ void newRingBfr(Expr *x) { size_t sz; char *p; int i; sz = ((x->sem == SEM_TRUTH) || (x->sem == SEM_CHAR)) ? sizeof(char) * x->tspan : sizeof(double) * x->tspan; if (x->ring) free(x->ring); x->ring = alloc(x->nsmpls * sz); p = (char *) x->ring; for (i = 0; i < x->nsmpls; i++) { x->smpls[i].ptr = (void *) p; p += sz; } } void newStringBfr(Expr *x, size_t length, char *bfr) { if (x->e_idom != (int)length) { x->e_idom = (int)length; x->tspan = (int)length; x->nvals = (int)length; } if (x->ring) free(x->ring); x->ring = bfr; x->smpls[0].ptr = (void *) bfr; } /* Rotate ring buffer - safe to call only if x->nsmpls > 1 */ void rotate(Expr *x) { int n = x->nsmpls-1; Sample *q = &x->smpls[n]; Sample *p = q - 1; void *t = q->ptr; int i; for (i = n; i > 0; i--) *q-- = *p--; x->smpls[0].ptr = t; } /*********************************************************************** * memory allocation ***********************************************************************/ void * alloc(size_t size) { void *p; if ((p = malloc(size)) == NULL) { __pmNoMem("pmie.alloc", size, PM_FATAL_ERR); } return p; } void * zalloc(size_t size) { void *p; if ((p = calloc(1, size)) == NULL) { __pmNoMem("pmie.zalloc", size, PM_FATAL_ERR); } return p; } void * aalloc(size_t align, size_t size) { void *p; int sts = 0; #ifdef HAVE_POSIX_MEMALIGN sts = posix_memalign(&p, align, size); #else #ifdef HAVE_MEMALIGN p = memalign(align, size); if (p == NULL) sts = -1; #else p = malloc(size); if (p == NULL) sts = -1; #endif #endif if (sts != 0) { __pmNoMem("pmie.aalloc", size, PM_FATAL_ERR); } return p; } void * ralloc(void *p, size_t size) { void *q; if ((q = realloc(p, size)) == NULL) { __pmNoMem("pmie.ralloc", size, PM_FATAL_ERR); } return q; } char * sdup(char *p) { char *q; if ((q = strdup(p)) == NULL) { __pmNoMem("pmie.sdup", strlen(p), PM_FATAL_ERR); } return q; } Expr * newExpr(int op, Expr *arg1, Expr *arg2, int hdom, int idom, int tdom, int nsmpls, int sem) { Expr *x; Expr *arg; x = (Expr *) zalloc(sizeof(Expr) + (nsmpls - 1) * sizeof(Sample)); x->op = op; if (arg1) { x->arg1 = arg1; arg1->parent = x; } if (arg2) { x->arg2 = arg2; arg2->parent = x; } x->hdom = hdom; x->e_idom = idom; x->tdom = tdom; x->nsmpls = nsmpls; x->tspan = (x->e_idom >= 0) ? x->e_idom : abs(x->hdom); x->nvals = x->tspan * nsmpls; if (arg1) { arg = primary(arg1, arg2); x->metrics = arg->metrics; } if (sem == SEM_NUMVAR || sem == SEM_NUMCONST || sem == SEM_TRUTH || sem == SEM_CHAR || sem == SEM_REGEX) x->units = noUnits; else { x->units = noUnits; SET_UNITS_UNKNOWN(x->units); } x->sem = sem; return x; } Profile * newProfile(Fetch *owner, pmInDom indom) { Profile *p = (Profile *) zalloc(sizeof(Profile)); p->indom = indom; p->fetch = owner; return p; } Fetch * newFetch(Host *owner) { Fetch *f = (Fetch *) zalloc(sizeof(Fetch)); f->host = owner; return f; } Host * newHost(Task *owner, Symbol name) { Host *h = (Host *) zalloc(sizeof(Host)); h->name = symCopy(name); h->task = owner; return h; } Task * newTask(RealTime delta, int nth) { Task *t = (Task *) zalloc(sizeof(Task)); t->nth = nth; t->delta = delta; return t; } /* translate new metric name to internal pmid for agent mode */ static pmID agentId(char *name) { int sts; pmID pmid; if ((sts = pmLookupName(1, &name, &pmid)) < 0) { fprintf(stderr, "%s: agentId: metric %s not found in namespace: %s\n", pmProgname, name, pmErrStr(sts)); exit(1); } return pmid; } void newResult(Task *t) { pmResult *rslt; Symbol *sym; pmValueSet *vset; pmValueBlock *vblk; int i; int len; /* allocate pmResult */ rslt = (pmResult *) zalloc(sizeof(pmResult) + (t->nrules - 1) * sizeof(pmValueSet *)); rslt->numpmid = t->nrules; /* allocate pmValueSet's */ sym = t->rules; for (i = 0; i < t->nrules; i++) { vset = (pmValueSet *)alloc(sizeof(pmValueSet)); vset->pmid = agentId(symName(*sym)); vset->numval = 0; vset->valfmt = PM_VAL_DPTR; vset->vlist[0].inst = PM_IN_NULL; len = PM_VAL_HDR_SIZE + sizeof(double); vblk = (pmValueBlock *)zalloc(len); vblk->vlen = len; vblk->vtype = PM_TYPE_DOUBLE; vset->vlist[0].value.pval = vblk; rslt->vset[i] = vset; sym++; } t->rslt = rslt; } /*********************************************************************** * memory deallocation * * IMPORTANT: These functions free the argument structure plus any * structures it owns below it in the expression tree. ***********************************************************************/ void freeTask(Task *t) { if ((t->hosts == NULL) && (t->rules == NULL)) { if (t->next) t->next->prev = t->prev; if (t->prev) t->prev->next = t->next; else taskq = t->next; free(t); } } void freeHost(Host *h) { if ((h->fetches == NULL) && (h->waits == NULL)) { if (h->next) h->next->prev = h->prev; if (h->prev) h->prev->next = h->next; else { h->task->hosts = h->next; freeTask(h->task); } symFree(h->name); free(h); } } void freeFetch(Fetch *f) { if (f->profiles == NULL) { if (f->next) f->next->prev = f->prev; if (f->prev) f->prev->next = f->next; else { f->host->fetches = f->next; freeHost(f->host); } pmDestroyContext(f->handle); if (f->result) pmFreeResult(f->result); if (f->pmids) free(f->pmids); free(f); } } void FreeProfile(Profile *p) { if (p->metrics == NULL) { if (p->next) p->next->prev = p->prev; if (p->prev) p->prev->next = p->next; else { p->fetch->profiles = p->next; freeFetch(p->fetch); } free(p); } } void freeMetric(Metric *m) { int numinst; /* Metric is on fetch list */ if (m->profile) { if (m->prev) { m->prev->next = m->next; if (m->next) m->next->prev = m->prev; } else { m->host->waits = m->next; if (m->next) m->next->prev = NULL; } if (m->host) freeHost(m->host); } symFree(m->hname); numinst = m->specinst == 0 ? m->m_idom : m->specinst; if (numinst > 0 && m->inames) { int i; for (i = 0; i < numinst; i++) { if (m->inames[i] != NULL) free(m->inames[i]); } free(m->inames); } if (numinst && m->iids) free(m->iids); if (m->vals) free(m->vals); } void freeExpr(Expr *x) { Metric *m; int i; if (x) { if (x->arg1 && x->arg1->parent == x) freeExpr(x->arg1); if (x->arg2 && x->arg2->parent == x) freeExpr(x->arg2); if (x->metrics && x->op == CND_FETCH) { for (m = x->metrics, i = 0; i < x->hdom; m++, i++) freeMetric(m); /* * x->metrics allocated in a block, one element per host, so * free as one after all other freeing has been done. */ free(x->metrics); } if (x->ring) free(x->ring); free(x); } } /*********************************************************************** * comparison functions (for use by qsort) ***********************************************************************/ /* Compare two instance identifiers. - This function is passed as an argument to qsort, hence the casts. */ int /* -1 less, 0 equal, 1 greater */ compid(const void *i1, const void *i2) { if (*(int *)i1 < *(int *)i2) return -1; if (*(int *)i1 > *(int *)i2) return 1; return 0; } /* Compare two pmValue's on their inst fields - This function is passed as an argument to qsort, hence the casts. */ int /* -1 less, 0 equal, 1 greater */ compair(const void *pmv1, const void *pmv2) { if (((pmValue *)pmv1)->inst < ((pmValue *)pmv2)->inst) return -1; if (((pmValue *)pmv1)->inst > ((pmValue *)pmv2)->inst) return 1; return 0; } /*********************************************************************** * Expr manipulation ***********************************************************************/ /* Decide primary argument for inheritance of Expr attributes */ Expr * primary(Expr *arg1, Expr *arg2) { if (arg2 == NULL || arg1->nvals > 1) return arg1; if (arg2->nvals > 1) return arg2; if (arg1->metrics && (arg1->hdom != -1 || arg1->e_idom != -1 || arg1->tdom != -1)) return arg1; if (arg2->metrics && (arg2->hdom != -1 || arg2->e_idom != -1 || arg2->tdom != -1)) return arg2; return arg1; } /* change number of samples allocated in ring buffer */ void changeSmpls(Expr **p, int nsmpls) { Expr *x = *p; Metric *m; int i; if (nsmpls == x->nsmpls) return; *p = x = (Expr *) ralloc(x, sizeof(Expr) + (nsmpls - 1) * sizeof(Sample)); x->nsmpls = nsmpls; x->nvals = x->tspan * nsmpls; x->valid = 0; if (x->op == CND_FETCH) { m = x->metrics; for (i = 0; i < x->hdom; i++) { m->expr = x; m++; } } newRingBfr(x); } /* propagate instance domain, semantics and units from argument expressions to parents */ static void instExpr(Expr *x) { int up = 0; Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Expr *arg = primary(arg1, arg2); /* semantics ... */ if (x->sem == SEM_UNKNOWN) { if (arg2 == NULL) { /* unary expression */ if (arg1->sem != SEM_UNKNOWN) { up = 1; x->sem = arg1->sem; } } else if ((arg1->sem != SEM_UNKNOWN) && (arg2->sem != SEM_UNKNOWN)) { /* binary expression with known args */ up = 1; x->sem = arg->sem; } /* binary expression with unknown arg */ else return; } /* units ... */ if (UNITS_UNKNOWN(x->units)) { if (arg2 == NULL) { /* unary expression */ if (!UNITS_UNKNOWN(arg1->units)) { up = 1; x->units = arg1->units; } } else if (!UNITS_UNKNOWN(arg1->units) && !UNITS_UNKNOWN(arg2->units)) { /* binary expression with known args */ up = 1; x->units = arg->units; if (x->op == CND_MUL) { x->units.dimSpace = arg1->units.dimSpace + arg2->units.dimSpace; x->units.dimTime = arg1->units.dimTime + arg2->units.dimTime; x->units.dimCount = arg1->units.dimCount + arg2->units.dimCount; } else if (x->op == CND_DIV) { x->units.dimSpace = arg1->units.dimSpace - arg2->units.dimSpace; x->units.dimTime = arg1->units.dimTime - arg2->units.dimTime; x->units.dimCount = arg1->units.dimCount - arg2->units.dimCount; } } } /* instance domain */ if ((x->e_idom != -1) && (x->e_idom != arg->e_idom)) { up = 1; x->e_idom = arg->e_idom; x->tspan = (x->e_idom >= 0) ? x->e_idom : abs(x->hdom); x->nvals = x->tspan * x->nsmpls; x->valid = 0; newRingBfr(x); } if (up && x->parent) instExpr(x->parent); } /* propagate instance domain, semantics and units from given fetch expression to its parents */ void instFetchExpr(Expr *x) { Metric *m; int ninst; int up = 0; int i; /* update semantics and units */ if (x->sem == SEM_UNKNOWN) { m = x->metrics; for (i = 0; i < x->hdom; i++) { if (m->desc.sem != SEM_UNKNOWN) { if (m->desc.sem == PM_SEM_COUNTER) { x->sem = PM_SEM_INSTANT; x->units = canon(m->desc.units); x->units.dimTime--; } else { x->sem = m->desc.sem; x->units = canon(m->desc.units); } up = 1; break; } } } /* * update number of instances ... need to be careful because may be more * than one host, and instances may not be fully available ... * m_idom < 0 => no idea how many instances there might be (cannot * contact pmcd, unknown metric, can't get indom, ...) * m_idom == 0 => no values, but otherwise OK * m_idom > 0 => have this many values (and hence instances) */ m = x->metrics; ninst = -1; for (i = 0; i < x->hdom; i++) { m->offset = ninst; if (m->m_idom >= 0) { if (ninst == -1) ninst = m->m_idom; else ninst += m->m_idom; } m++; } if (x->e_idom != ninst) { /* number of instances is different */ x->e_idom = ninst; x->tspan = (x->e_idom >= 0) ? x->e_idom : abs(x->hdom); x->nvals = x->nsmpls * x->tspan; x->valid = 0; newRingBfr(x); up = 1; } if (x->parent) { /* do we need to propagate changes? */ if (up || (UNITS_UNKNOWN(x->parent->units) && !UNITS_UNKNOWN(x->units))) { instExpr(x->parent); } } } /*********************************************************************** * compulsory initialization ***********************************************************************/ void dstructInit(void) { Expr *x; double zero = 0.0; /* not-a-number initialization */ mynan = zero / zero; /* don't initialize dfltHost*; let pmie.c do it after getopt. */ /* set up symbol tables */ symSetTable(&hosts); symSetTable(&metrics); symSetTable(&rules); symSetTable(&vars); /* set yp inter-sample interval (delta) symbol */ symDelta = symIntern(&vars, "delta"); x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR); x->smpls[0].ptr = δ x->valid = 1; symValue(symDelta) = x; /* set up time symbols */ symMinute = symIntern(&vars, "minute"); x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR); x->smpls[0].ptr = &minute; x->valid = 1; symValue(symMinute) = x; symHour = symIntern(&vars, "hour"); x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR); x->smpls[0].ptr = &hour; x->valid = 1; symValue(symHour) = x; symDay = symIntern(&vars, "day"); x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR); x->smpls[0].ptr = &day; x->valid = 1; symValue(symDay) = x; symMonth = symIntern(&vars, "month"); x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR); x->smpls[0].ptr = &month; x->valid = 1; symValue(symMonth) = x; symYear = symIntern(&vars, "year"); x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR); x->smpls[0].ptr = &year; x->valid = 1; symValue(symYear) = x; symWeekday = symIntern(&vars, "day_of_week"); x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR); x->smpls[0].ptr = &weekday; x->valid = 1; symValue(symWeekday) = x; } /* get ready to run evaluator */ void agentInit(void) { Task *t; int sts; /* Set up local name space for agent */ /* Only load PMNS if it's default and hence not already loaded */ if (pmnsfile == PM_NS_DEFAULT && (sts = pmLoadNameSpace(pmnsfile)) < 0) { fprintf(stderr, "%s: agentInit: cannot load metric namespace: %s\n", pmProgname, pmErrStr(sts)); exit(1); } /* allocate pmResult's and send pmDescs for secret agent mode */ t = taskq; while (t) { newResult(t); sendDescs(t); t = t->next; } } /* * useful for diagnostics and with dbx */ static struct { void (*addr)(Expr *); char *name; } fn_map[] = { { actAlarm, "actAlarm" }, { actAnd, "actAnd" }, { actArg, "actArg" }, { actFake, "actFake" }, { actOr, "actOr" }, { actPrint, "actPrint" }, { actShell, "actShell" }, { actStomp, "actStomp" }, { actSyslog, "actSyslog" }, { cndAdd_1_1, "cndAdd_1_1" }, { cndAdd_1_n, "cndAdd_1_n" }, { cndAdd_n_1, "cndAdd_n_1" }, { cndAdd_n_n, "cndAdd_n_n" }, { cndAll_host, "cndAll_host" }, { cndAll_inst, "cndAll_inst" }, { cndAll_time, "cndAll_time" }, { cndAnd_1_1, "cndAnd_1_1" }, { cndAnd_1_n, "cndAnd_1_n" }, { cndAnd_n_1, "cndAnd_n_1" }, { cndAnd_n_n, "cndAnd_n_n" }, { cndAvg_host, "cndAvg_host" }, { cndAvg_inst, "cndAvg_inst" }, { cndAvg_time, "cndAvg_time" }, { cndCount_host, "cndCount_host" }, { cndCount_inst, "cndCount_inst" }, { cndCount_time, "cndCount_time" }, { cndDelay_1, "cndDelay_1" }, { cndDelay_n, "cndDelay_n" }, { cndDiv_1_1, "cndDiv_1_1" }, { cndDiv_1_n, "cndDiv_1_n" }, { cndDiv_n_1, "cndDiv_n_1" }, { cndDiv_n_n, "cndDiv_n_n" }, { cndEq_1_1, "cndEq_1_1" }, { cndEq_1_n, "cndEq_1_n" }, { cndEq_n_1, "cndEq_n_1" }, { cndEq_n_n, "cndEq_n_n" }, { cndFall_1, "cndFall_1" }, { cndFall_n, "cndFall_n" }, { cndFetch_1, "cndFetch_1" }, { cndFetch_all, "cndFetch_all" }, { cndFetch_n, "cndFetch_n" }, { cndGt_1_1, "cndGt_1_1" }, { cndGt_1_n, "cndGt_1_n" }, { cndGt_n_1, "cndGt_n_1" }, { cndGt_n_n, "cndGt_n_n" }, { cndGte_1_1, "cndGte_1_1" }, { cndGte_1_n, "cndGte_1_n" }, { cndGte_n_1, "cndGte_n_1" }, { cndGte_n_n, "cndGte_n_n" }, { cndLt_1_1, "cndLt_1_1" }, { cndLt_1_n, "cndLt_1_n" }, { cndLt_n_1, "cndLt_n_1" }, { cndLt_n_n, "cndLt_n_n" }, { cndLte_1_1, "cndLte_1_1" }, { cndLte_1_n, "cndLte_1_n" }, { cndLte_n_1, "cndLte_n_1" }, { cndLte_n_n, "cndLte_n_n" }, { cndMax_host, "cndMax_host" }, { cndMax_inst, "cndMax_inst" }, { cndMax_time, "cndMax_time" }, { cndMin_host, "cndMin_host" }, { cndMin_inst, "cndMin_inst" }, { cndMin_time, "cndMin_time" }, { cndMul_1_1, "cndMul_1_1" }, { cndMul_1_n, "cndMul_1_n" }, { cndMul_n_1, "cndMul_n_1" }, { cndMul_n_n, "cndMul_n_n" }, { cndNeg_1, "cndNeg_1" }, { cndNeg_n, "cndNeg_n" }, { cndNeq_1_1, "cndNeq_1_1" }, { cndNeq_1_n, "cndNeq_1_n" }, { cndNeq_n_1, "cndNeq_n_1" }, { cndNeq_n_n, "cndNeq_n_n" }, { cndNot_1, "cndNot_1" }, { cndNot_n, "cndNot_n" }, { cndOr_1_1, "cndOr_1_1" }, { cndOr_1_n, "cndOr_1_n" }, { cndOr_n_1, "cndOr_n_1" }, { cndOr_n_n, "cndOr_n_n" }, { cndPcnt_host, "cndPcnt_host" }, { cndPcnt_inst, "cndPcnt_inst" }, { cndPcnt_time, "cndPcnt_time" }, { cndRate_1, "cndRate_1" }, { cndRate_n, "cndRate_n" }, { cndRise_1, "cndRise_1" }, { cndRise_n, "cndRise_n" }, { cndSome_host, "cndSome_host" }, { cndSome_inst, "cndSome_inst" }, { cndSome_time, "cndSome_time" }, { cndSub_1_1, "cndSub_1_1" }, { cndSub_1_n, "cndSub_1_n" }, { cndSub_n_1, "cndSub_n_1" }, { cndSub_n_n, "cndSub_n_n" }, { cndSum_host, "cndSum_host" }, { cndSum_inst, "cndSum_inst" }, { cndSum_time, "cndSum_time" }, { rule, "rule" }, { NULL, NULL }, }; static struct { int val; char *name; } sem_map[] = { { SEM_UNKNOWN, "UNKNOWN" }, { SEM_NUMVAR, "NUMVAR" }, { SEM_NUMCONST, "NUMCONST" }, { SEM_TRUTH, "TRUTH" }, { SEM_CHAR, "CHAR" }, { SEM_REGEX, "REGEX" }, { PM_SEM_COUNTER, "COUNTER" }, { PM_SEM_INSTANT, "INSTANT" }, { PM_SEM_DISCRETE, "DISCRETE" }, { 0, NULL }, }; void __dumpExpr(int level, Expr *x) { int i; int j; int k; for (i = 0; i < level; i++) fprintf(stderr, ".. "); fprintf(stderr, "Expr dump @ " PRINTF_P_PFX "%p\n", x); if (x == NULL) return; for (i = 0; i < level; i++) fprintf(stderr, ".. "); fprintf(stderr, " op=%d (%s) arg1=" PRINTF_P_PFX "%p arg2=" PRINTF_P_PFX "%p parent=" PRINTF_P_PFX "%p\n", x->op, opStrings(x->op), x->arg1, x->arg2, x->parent); for (i = 0; i < level; i++) fprintf(stderr, ".. "); fprintf(stderr, " eval="); for (j = 0; fn_map[j].addr; j++) { if (x->eval == fn_map[j].addr) { fprintf(stderr, "%s", fn_map[j].name); break; } } if (fn_map[j].addr == NULL) fprintf(stderr, "" PRINTF_P_PFX "%p()", x->eval); fprintf(stderr, " metrics=" PRINTF_P_PFX "%p ring=" PRINTF_P_PFX "%p\n", x->metrics, x->ring); for (i = 0; i < level; i++) fprintf(stderr, ".. "); fprintf(stderr, " valid=%d cardinality[H,I,T]=[%d,%d,%d] tspan=%d\n", x->valid, x->hdom, x->e_idom, x->tdom, x->tspan); for (i = 0; i < level; i++) fprintf(stderr, ".. "); fprintf(stderr, " nsmpls=%d nvals=%d sem=", x->nsmpls, x->nvals); for (j = 0; sem_map[j].name; j++) { if (x->sem == sem_map[j].val) { fprintf(stderr, "%s", sem_map[j].name); break; } } if (sem_map[j].name == NULL) fprintf(stderr, "%d", x->sem); if (UNITS_UNKNOWN(x->units)) fprintf(stderr, " units=UNKNOWN\n"); else fprintf(stderr, " units=%s\n", pmUnitsStr(&x->units)); if (x->valid > 0) { if (x->sem == SEM_TRUTH || x->sem == SEM_CHAR || x->sem == SEM_NUMVAR || x->sem == SEM_NUMCONST || x->sem == PM_SEM_COUNTER || x->sem == PM_SEM_INSTANT || x->sem == PM_SEM_DISCRETE) { for (j = 0; j < x->nsmpls; j++) { for (i = 0; i < level; i++) fprintf(stderr, ".. "); fprintf(stderr, " smpls[%d].ptr " PRINTF_P_PFX "%p ", j, x->smpls[j].ptr); for (k = 0; k < x->tspan; k++) { if (x->tspan > 1 && x->sem != SEM_CHAR) { if (k > 0) fprintf(stderr, ", "); fprintf(stderr, "{%d} ", k); } if (x->sem == SEM_TRUTH) { char c = *((char *)x->smpls[j].ptr+k); if ((int)c == TRUE) fprintf(stderr, "true"); else if ((int)c == FALSE) fprintf(stderr, "false"); else if ((int)c == DUNNO) fprintf(stderr, "unknown"); else fprintf(stderr, "bogus (0x%x)", c & 0xff); } else if (x->sem == SEM_CHAR) { if (k == 0) fprintf(stderr, "\"%s\"", (char *)x->smpls[j].ptr); } else { double v = *((double *)x->smpls[j].ptr+k); int fp_bad = 0; #ifdef HAVE_FPCLASSIFY fp_bad = fpclassify(v) == FP_NAN; #else #ifdef HAVE_ISNAN fp_bad = isnan(v); #endif #endif if (fp_bad) fputc('?', stderr); else fprintf(stderr, "%g", v); } } fputc('\n', stderr); } } else if (x->sem == SEM_REGEX) { for (i = 0; i < level; i++) fprintf(stderr, ".. "); fprintf(stderr, " handle=" PRINTF_P_PFX "%p\n", x->ring); } } } void __dumpMetric(int level, Metric *m) { int i; int j; int numinst; for (i = 0; i < level; i++) fprintf(stderr, ".. "); fprintf(stderr, "Metric dump @ " PRINTF_P_PFX "%p\n", m); for (i = 0; i < level; i++) fprintf(stderr, ".. "); fprintf(stderr, "expr=" PRINTF_P_PFX "%p profile=" PRINTF_P_PFX "%p host=" PRINTF_P_PFX "%p next=" PRINTF_P_PFX "%p prev=" PRINTF_P_PFX "%p\n", m->expr, m->profile, m->host, m->next, m->prev); for (i = 0; i < level; i++) fprintf(stderr, ".. "); fprintf(stderr, "metric=%s host=%s conv=%g specinst=%d m_indom=%d\n", symName(m->mname), symName(m->hname), m->conv, m->specinst, m->m_idom); if (m->desc.indom != PM_INDOM_NULL) { numinst = m->specinst == 0 ? m->m_idom : m->specinst; for (j = 0; j < numinst; j++) { for (i = 0; i < level; i++) fprintf(stderr, ".. "); fprintf(stderr, "[%d] iid=", j); if (m->iids[j] == PM_IN_NULL) fprintf(stderr, "?missing"); else fprintf(stderr, "%d", m->iids[j]); fprintf(stderr, " iname=\"%s\"\n", m->inames[j]); } } for (i = 0; i < level; i++) fprintf(stderr, ".. "); fputc('\n', stderr); #if 0 pmDesc desc; /* pmAPI metric description */ RealTime stamp; /* time stamp for current values */ pmValueSet *vset; /* current values */ RealTime stomp; /* previous time stamp for rate calculation */ double *vals; /* vector of values for rate computation */ int offset; /* offset within sample in expr ring buffer */ ... Metric; #endif } void __dumpTree(int level, Expr *x) { __dumpExpr(level, x); if (x->arg1 != NULL) __dumpTree(level+1, x->arg1); if (x->arg2 != NULL) __dumpTree(level+1, x->arg2); } void dumpTree(Expr *x) { __dumpTree(0, x); } void dumpRules(void) { Task *t; Symbol *s; int i; for (t = taskq; t != NULL; t = t->next) { s = t->rules; for (i = 0; i < t->nrules; i++, s++) { fprintf(stderr, "\nRule: %s\n", symName(*s)); dumpTree((Expr *)symValue(*s)); } } } void dumpExpr(Expr *x) { __dumpExpr(0, x); } void dumpMetric(Metric *m) { __dumpMetric(0, m); } void dumpTask(Task *t) { int i; fprintf(stderr, "Task dump @ " PRINTF_P_PFX "%p\n", t); fprintf(stderr, " nth=%d delta=%.3f tick=%d next=" PRINTF_P_PFX "%p prev=" PRINTF_P_PFX "%p\n", t->nth, t->delta, t->tick, t->next, t->prev); fprintf(stderr, " eval time: "); showFullTime(stderr, t->eval); fputc('\n', stderr); fprintf(stderr, " retry time: "); showFullTime(stderr, t->retry); fputc('\n', stderr); if (t->hosts == NULL) fprintf(stderr, " host=\n"); else fprintf(stderr, " host=%s (%s)\n", symName(t->hosts->name), t->hosts->down ? "down" : "up"); fprintf(stderr, " rules:\n"); for (i = 0; i < t->nrules; i++) { fprintf(stderr, " %s\n", symName(t->rules[i])); } } pcp-3.8.12ubuntu1/src/pmie/src/hdr.sk0000664000000000000000000000234112272262501014226 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*********************************************************************** * fun.c * * These functions are generated from skeletons .sk * by the shell-script './meta'. ***********************************************************************/ #include "pmapi.h" #include "impl.h" #if defined(HAVE_SYS_WAIT_H) #include #endif #include "dstruct.h" #include "pragmatics.h" #include "fun.h" #include "show.h" #include "stomp.h" pcp-3.8.12ubuntu1/src/pmie/src/syntax.h0000664000000000000000000000566512272262501014625 0ustar /*********************************************************************** * syntax.h - inference rule language parser *********************************************************************** * * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef SYNTAX_H #define SYNTAX_H /*********************************************************************** * ONLY FOR USE BY: lexicon.c grammar.y ***********************************************************************/ typedef struct { int n; /* number of elements */ char **ss; /* dynamically allocated array */ } StringArray; typedef struct { int t1; /* start of interval */ int t2; /* end of interval */ } Interval; /* parser stack entry */ typedef union { int i; char *s; double d; StringArray sa; Interval t; pmUnits u; Metric *m; Expr *x; Symbol *z; } YYSTYPE; #define YYSTYPE_IS_DECLARED 1 extern YYSTYPE yylval; /* error reporting */ extern int errs; /* error count */ void yyerror(char *); void synerr(void); void synwarn(void); /* parser actions */ Symbol statement(char *, Expr *); Expr *ruleExpr(Expr *, Expr *); Expr *relExpr(int, Expr *, Expr *); Expr *binaryExpr(int, Expr *, Expr *); Expr *unaryExpr(int, Expr *); Expr *domainExpr(int, int, Expr *); Expr *percentExpr(double, int, Expr *); Expr *numMergeExpr(int, Expr *); Expr *boolMergeExpr(int, Expr *); Expr *fetchExpr(char *, StringArray, StringArray, Interval); Expr *numConst(double, pmUnits); Expr *strConst(char *); Expr *boolConst(Truth); Expr *numVar(Expr *); Expr *boolVar(Expr *); Expr *actExpr(int, Expr *, Expr *); Expr *actArgExpr(Expr *, Expr *); Expr *actArgList(Expr *, char *); /* parse tree */ extern Symbol parse; /*********************************************************************** * public ***********************************************************************/ /* Initialization to be called at the start of new input file. */ int synInit(char *); /* parse single statement */ Symbol syntax(void); #endif /* SYNTAX_H */ pcp-3.8.12ubuntu1/src/pmie/src/eval.h0000664000000000000000000000273312272262501014217 0ustar /*********************************************************************** * eval.h *********************************************************************** * * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef EVAL_H #define EVAL_H #include "dstruct.h" /* fill in apprpriate evaluator function for given Expr */ void findEval(Expr *); /* run evaluator until specified time reached */ void run(void); /* invalidate one expression (and descendents) */ void clobber(Expr *); /* invalidate all expressions being evaluated */ void invalidate(void); /* report changes in pmcd connection state */ #define STATE_INIT 0 #define STATE_FAILINIT 1 #define STATE_RECONN 2 #define STATE_LOSTCONN 3 int host_state_changed(char *, int); #endif /* EVAL_H */ pcp-3.8.12ubuntu1/src/pmie/src/binary.sk0000664000000000000000000001014612272262501014737 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*********************************************************************** * skeleton: binary.sk - binary operator ***********************************************************************/ /* * operator: @FUN */ #define @OP void @FUN_n_n(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg2->smpls[0]; Sample *os = &x->smpls[0]; @ITYPE *ip1; @ITYPE *ip2; @OTYPE *op; int n; int i; EVALARG(arg1) EVALARG(arg2) ROTATE(x) if (arg1->valid && arg2->valid && x->tspan > 0 && x->tspan == arg1->tspan && x->tspan == arg2->tspan) { ip1 = (@ITYPE *)is1->ptr; ip2 = (@ITYPE *)is2->ptr; op = (@OTYPE *)os->ptr; n = x->tspan; for (i = 0; i < n; i++) { *op++ = OP(*ip1, *ip2); ip1++; ip2++; } os->stamp = (is1->stamp > is2->stamp) ? is1->stamp : is2->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "@FUN_n_n(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void @FUN_n_1(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg2->smpls[0]; Sample *os = &x->smpls[0]; @ITYPE *ip1; @ITYPE iv2; @OTYPE *op; int n; int i; EVALARG(arg1) EVALARG(arg2) ROTATE(x) if (arg1->valid && arg2->valid && x->tspan > 0 && x->tspan == arg1->tspan) { ip1 = (@ITYPE *)is1->ptr; iv2 = *(@ITYPE *)is2->ptr; op = (@OTYPE *)os->ptr; n = x->tspan; for (i = 0; i < n; i++) { *op++ = OP(*ip1, iv2); ip1++; } os->stamp = (is1->stamp > is2->stamp) ? is1->stamp : is2->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "@FUN_n_1(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void @FUN_1_n(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg2->smpls[0]; Sample *os = &x->smpls[0]; @ITYPE iv1; @ITYPE *ip2; @OTYPE *op; int n; int i; EVALARG(arg1) EVALARG(arg2) ROTATE(x) if (arg1->valid && arg2->valid && x->tspan > 0 && x->tspan == arg2->tspan) { iv1 = *(@ITYPE *)is1->ptr; ip2 = (@ITYPE *)is2->ptr; op = (@OTYPE *)os->ptr; n = x->tspan; for (i = 0; i < n; i++) { *op++ = OP(iv1, *ip2); ip2++; } os->stamp = (is1->stamp > is2->stamp) ? is1->stamp : is2->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "@FUN_1_n(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } void @FUN_1_1(Expr *x) { Expr *arg1 = x->arg1; Expr *arg2 = x->arg2; Sample *is1 = &arg1->smpls[0]; Sample *is2 = &arg2->smpls[0]; Sample *os = &x->smpls[0]; EVALARG(arg1) EVALARG(arg2) ROTATE(x) if (arg1->valid && arg2->valid) { *(@OTYPE *)os->ptr = OP(*(@ITYPE *)is1->ptr, *(@ITYPE *)is2->ptr); os->stamp = (is1->stamp > is2->stamp) ? is1->stamp : is2->stamp; x->valid++; } else x->valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "@FUN_1_1(" PRINTF_P_PFX "%p) ...\n", x); dumpExpr(x); } #endif } #undef OP pcp-3.8.12ubuntu1/src/pmie/src/fun.h0000664000000000000000000000660712272262501014064 0ustar /*********************************************************************** * fun.h - expression evaluator functions *********************************************************************** * * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FUN_H #define FUN_H #include "dstruct.h" #include "andor.h" #define ROTATE(x) if ((x)->nsmpls > 1) rotate(x); #define EVALARG(x) if ((x)->op < NOP) ((x)->eval)(x); /* expression evaluator function prototypes */ void rule(Expr *); void cndFetch_all(Expr *); void cndFetch_n(Expr *); void cndFetch_1(Expr *); void cndDelay_n(Expr *); void cndDelay_1(Expr *); void cndRate_n(Expr *); void cndRate_1(Expr *); void cndSum_host(Expr *); void cndSum_inst(Expr *); void cndSum_time(Expr *); void cndAvg_host(Expr *); void cndAvg_inst(Expr *); void cndAvg_time(Expr *); void cndMax_host(Expr *); void cndMax_inst(Expr *); void cndMax_time(Expr *); void cndMin_host(Expr *); void cndMin_inst(Expr *); void cndMin_time(Expr *); void cndNeg_n(Expr *); void cndNeg_1(Expr *); void cndAdd_n_n(Expr *); void cndAdd_1_n(Expr *); void cndAdd_n_1(Expr *); void cndAdd_1_1(Expr *); void cndSub_n_n(Expr *); void cndSub_1_n(Expr *); void cndSub_n_1(Expr *); void cndSub_1_1(Expr *); void cndMul_n_n(Expr *); void cndMul_1_n(Expr *); void cndMul_n_1(Expr *); void cndMul_1_1(Expr *); void cndDiv_n_n(Expr *); void cndDiv_1_n(Expr *); void cndDiv_n_1(Expr *); void cndDiv_1_1(Expr *); void cndEq_n_n(Expr *); void cndEq_1_n(Expr *); void cndEq_n_1(Expr *); void cndEq_1_1(Expr *); void cndNeq_n_n(Expr *); void cndNeq_1_n(Expr *); void cndNeq_n_1(Expr *); void cndNeq_1_1(Expr *); void cndLt_n_n(Expr *); void cndLt_1_n(Expr *); void cndLt_n_1(Expr *); void cndLt_1_1(Expr *); void cndLte_n_n(Expr *); void cndLte_1_n(Expr *); void cndLte_n_1(Expr *); void cndLte_1_1(Expr *); void cndGt_n_n(Expr *); void cndGt_1_n(Expr *); void cndGt_n_1(Expr *); void cndGt_1_1(Expr *); void cndGte_n_n(Expr *); void cndGte_1_n(Expr *); void cndGte_n_1(Expr *); void cndGte_1_1(Expr *); void cndNot_n(Expr *); void cndNot_1(Expr *); void cndRise_n(Expr *); void cndRise_1(Expr *); void cndFall_n(Expr *); void cndFall_1(Expr *); void cndMatch_inst(Expr *); void cndAll_host(Expr *); void cndAll_inst(Expr *); void cndAll_time(Expr *); void cndSome_host(Expr *); void cndSome_inst(Expr *); void cndSome_time(Expr *); void cndPcnt_host(Expr *); void cndPcnt_inst(Expr *); void cndPcnt_time(Expr *); void cndCount_host(Expr *); void cndCount_inst(Expr *); void cndCount_time(Expr *); void actAnd(Expr *); void actOr(Expr *); void actShell(Expr *); void actAlarm(Expr *); void actSyslog(Expr *); void actPrint(Expr *); void actStomp(Expr *); void actArg(Expr *); void actFake(Expr *); #endif /* FUN_H */ pcp-3.8.12ubuntu1/src/pmie/src/dstruct.h0000664000000000000000000004045312272262501014761 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /*********************************************************************** * dstruct.h - central data structures snd associated operations ***********************************************************************/ #ifndef DSTRUCT_H #define DSTRUCT_H #include #include #include "pmapi.h" #include "impl.h" #include "symbol.h" #include "stats.h" /*********************************************************************** * forward reference ***********************************************************************/ struct expr; struct metric; struct profile; struct fetch; struct host; struct task; /*********************************************************************** * numeric and truth value constants ***********************************************************************/ typedef char Truth; #define FALSE 0 #define TRUE 1 #define DUNNO 2 extern double mynan; /* definitely not-a-number */ /*********************************************************************** * time ***********************************************************************/ typedef unsigned int TickTime; /* time counted in deltas */ /* following in usec */ typedef double RealTime; /* wall clock time or interval */ #define MINUTE 60 /* one minute of real time */ #define DELAY_MAX 32 /* maximum initial evaluation delay */ #define RETRY 5 /* retry interval */ #define DELTA_DFLT 10 /* default sample interval */ #define DELTA_MIN 0.1 /* minimum sample interval */ /*********************************************************************** * evaluator functions ***********************************************************************/ /* evaluator function */ typedef void (Eval)(struct expr *); /*********************************************************************** * internal representation of rule expressions and their values ***********************************************************************/ /* pointer to and timestamp for sample in ring buffer */ typedef struct { void *ptr; /* pointer into value ring buffer */ RealTime stamp; /* timestamp for sample */ } Sample; /* Expression Tree Node: * The parser fills in most of the fields, pragmatics analysis * fills in the rest. The parser may leave 0 in e_idom or nvals * and NULL in ring to indicate it did not have enough information * to fill in the correct values. These values are then patched * up during pragmatics analysis and dynamically if/when the number * of instances changes. * * Warning: The semantics of the hdom, e_idom and tdom fields are * quite subtle. A value of 1 or greater is the cardinality of * the corresponding domain. -1 indicates that the corresponding * domain has collapsed, and there is one value. 0 indicates * that there is no value (only used for e_idom to indicate an * empty instance domain). */ typedef struct expr { /* expression syntax */ int op; /* operator */ struct expr *arg1; /* NULL || (Expr *) */ struct expr *arg2; /* NULL || (Expr *) */ struct expr *parent; /* parent of this Expr */ /* evaluator */ Eval *eval; /* evaluator function */ int valid; /* number of valid samples */ /* description of value matrix */ int hdom; /* cardinality of host dimension */ int e_idom; /* cardinality of instance dimension */ int tdom; /* cardinality of time dimension */ int tspan; /* number of values per sample */ int nsmpls; /* number of samples in ring buffer */ int nvals; /* total number of values in ring buffer */ struct metric *metrics; /* array of per host metric info */ /* description of single value */ int sem; /* value semantics, see below */ pmUnits units; /* value units, as in pmDesc */ /* value buffer */ void *ring; /* base address of value ring buffer */ Sample smpls[1]; /* array dynamically allocated */ } Expr; /* per-host description of a performance metric */ typedef struct metric { struct expr *expr; /* Expr owning this Metric */ struct profile *profile; /* Profile owning this Metric */ struct host *host; /* Host owning this Metric */ struct metric *next; /* fetch/wait list forward pointer */ struct metric *prev; /* fetch/wait list backward pointer */ Symbol mname; /* metric name */ Symbol hname; /* host name */ pmDesc desc; /* pmAPI metric description */ double conv; /* conversion factor into canonical units */ int specinst; /* count of specific instances in rule and */ /* 0 if all instances are to be considered */ int m_idom; /* cardinality of available instance domain */ char **inames; /* array of instance names */ int *iids; /* array of instance ids */ RealTime stamp; /* time stamp for current values */ pmValueSet *vset; /* current values */ RealTime stomp; /* previous time stamp for rate calculation */ double *vals; /* vector of values for rate computation */ int offset; /* offset within sample in expr ring buffer */ } Metric; /* * Note on instances in Metric: * * if specinst == 0, then m_idom, inames[] and iids[] are the * currently available instances * otherwise, m_idom is the number of the specified instances currently * available (and identified in inames[] and iids[] for 0 .. m_idom-1) * and the unavailable instances are after that, i.e. elements * m_idom ... specinst-1 of inames[] and iids[] */ /* per instance-domain part of bundled fetch request */ typedef struct profile { struct metric *metrics; /* list of Metrics for this Profile */ struct fetch *fetch; /* Fetch bundle owning this Profile */ struct profile *next; /* Profile list forward link */ struct profile *prev; /* Profile list backward link */ pmInDom indom; /* instance domain */ int need_all; /* all instances required */ } Profile; /* bundled fetch request for multiple metrics */ typedef struct fetch { struct profile *profiles; /* list of Profiles for this Fetch */ struct host *host; /* Host owning this Fetch */ struct fetch *next; /* fetch list forward pointer */ struct fetch *prev; /* fetch list backward pointer */ int handle; /* PMCS context handle */ int npmids; /* number of metrics in fetch */ pmID *pmids; /* array of metric ids to fetch */ pmResult *result; /* result of fetch */ } Fetch; /* set of bundled fetches for single host (may be archive or live): The field waits contains a list of Metrics for which descriptors were not available during pragmatics analysis. */ typedef struct host { struct fetch *fetches; /* list of Fetches for this Host */ struct task *task; /* Task owning this host */ struct host *next; /* Host list forward pointer */ struct host *prev; /* Host list backward pointer */ Symbol name; /* host machine */ int down; /* host is not delivering metrics */ Metric *waits; /* wait list of Metrics */ Metric *duds; /* bad Metrics discovered during evaluation */ } Host; /* element of evaluator task queue */ typedef struct task { int nth; /* initial (syntactic) position in task queue */ struct task *next; /* task list forward link */ struct task *prev; /* task list backward link */ RealTime epoch; /* bottom-line for timing calculations */ RealTime delta; /* sample interval */ TickTime tick; /* count up deltas */ RealTime eval; /* scheduled evaluation time */ RealTime retry; /* scheduled retry down Hosts and Metrics */ int nrules; /* number of rules in this task */ Symbol *rules; /* array of rules to be evaluated */ Host *hosts; /* fetches to be executed and waiting */ pmResult *rslt; /* for secret agent mode */ } Task; /* value semantics - as in pmDesc plus following */ #define SEM_UNKNOWN 0 /* semantics not yet available */ #define SEM_NUMVAR 10 /* numeric variable value */ #define SEM_TRUTH 11 /* truth value */ #define SEM_CHAR 12 /* character (string) */ #define SEM_NUMCONST 13 /* numeric constant value */ #define SEM_REGEX 14 /* compiled regular expression */ /* Expr operator (op) tokens */ typedef int Op; #define RULE 0 /* basic conditions */ #define CND_FETCH 1 #define CND_DELAY 2 #define CND_RATE 3 /* arithmetic */ #define CND_NEG 4 #define CND_ADD 5 #define CND_SUB 6 #define CND_MUL 7 #define CND_DIV 8 /* aggregation */ #define CND_SUM_HOST 10 #define CND_SUM_INST 11 #define CND_SUM_TIME 12 #define CND_AVG_HOST 13 #define CND_AVG_INST 14 #define CND_AVG_TIME 15 #define CND_MAX_HOST 16 #define CND_MAX_INST 17 #define CND_MAX_TIME 18 #define CND_MIN_HOST 19 #define CND_MIN_INST 20 #define CND_MIN_TIME 21 /* relational */ #define CND_EQ 30 #define CND_NEQ 31 #define CND_LT 32 #define CND_LTE 33 #define CND_GT 34 #define CND_GTE 35 /* boolean */ #define CND_NOT 40 #define CND_RISE 41 #define CND_FALL 42 #define CND_AND 43 #define CND_OR 44 #define CND_MATCH 45 #define CND_NOMATCH 46 /* quantification */ #define CND_ALL_HOST 50 #define CND_ALL_INST 51 #define CND_ALL_TIME 52 #define CND_SOME_HOST 53 #define CND_SOME_INST 54 #define CND_SOME_TIME 55 #define CND_PCNT_HOST 56 #define CND_PCNT_INST 57 #define CND_PCNT_TIME 58 #define CND_COUNT_HOST 59 #define CND_COUNT_INST 60 #define CND_COUNT_TIME 61 /* actions */ #define ACT_SEQ 70 #define ACT_ALT 71 #define ACT_SHELL 72 #define ACT_ALARM 73 #define ACT_SYSLOG 74 #define ACT_PRINT 75 #define ACT_ARG 76 #define ACT_STOMP 77 /* no operation (extension) */ #define NOP 80 /* dereferenced variable */ #define OP_VAR 90 int unary(Op); /* unary operator */ int binary(Op); /* binary operator */ /*********************************************************************** * archives ***********************************************************************/ typedef struct archive { struct archive *next; /* list link */ char *fname; /* file name */ char *hname; /* host name */ RealTime first; /* timestamp for first pmResult */ RealTime last; /* timestamp for last pmResult */ } Archive; /*********************************************************************** * memory allocation / deallocation ***********************************************************************/ void *alloc(size_t); void *zalloc(size_t); void *ralloc(void *, size_t); void *aalloc(size_t, size_t); char *sdup(char *); Expr *newExpr(int, Expr *, Expr *, int, int, int, int, int); Profile *newProfile(Fetch *, pmInDom); Fetch *newFetch(Host *); Host *newHost(Task *, Symbol); Task *newTask(RealTime, int); void newResult(Task *); void freeExpr(Expr *); void freeMetric(Metric *); void FreeProfile(Profile *); void freeFetch(Fetch *); void freeTask(Task *); /*********************************************************************** * ring buffer management ***********************************************************************/ void newRingBfr(Expr *); void newStringBfr(Expr *, size_t, char *); void rotate(Expr *); /*********************************************************************** * Expr manipulation ***********************************************************************/ Expr *primary(Expr *, Expr *); void changeSmpls(Expr **, int); void instFetchExpr(Expr *); /*********************************************************************** * time methods ***********************************************************************/ /* convert timeval to RealTime */ #define realize(t) (1.0e-6 * (RealTime)(t).tv_usec + (RealTime)(t).tv_sec) /* convert RealTime to timeval */ void unrealize(RealTime, struct timeval *); RealTime getReal(void); /* return current time */ void reflectTime(RealTime); /* update time vars to reflect now */ #define SLEEP_EVAL 0 #define SLEEP_RETRY 1 void sleepTight(Task *, int); /* sleep until retry or eval time */ /* * diagnostic tracing */ void dumpRules(void); void dumpExpr(Expr *); void dumpTree(Expr *); void dumpMetric(Metric *); void dumpTask(Task *); void __dumpExpr(int, Expr *); void __dumpTree(int, Expr *); void __dumpMetric(int, Metric *); /*********************************************************************** * comparison functions (for use by qsort) ***********************************************************************/ /* compare two instance identifiers. */ int compid(const void *, const void *); /* compare two pmValue's on their inst fields */ int compair(const void *, const void *); /*********************************************************************** * global data structures ***********************************************************************/ extern char *pmnsfile; /* alternate namespace */ extern Archive *archives; /* archives given on command line */ extern RealTime first; /* archive starting point */ extern RealTime last; /* archive end point */ extern char *dfltHostConn; /* default PM_CONTEXT_HOST parameter */ extern char *dfltHostName; /* pmContextGetHostName of host name */ extern RealTime dfltDelta; /* default sample interval */ extern char *startFlag; /* start time specified? */ extern char *stopFlag; /* end time specified? */ extern char *alignFlag; /* align time specified? */ extern char *offsetFlag; /* offset time specified? */ extern RealTime runTime; /* run time interval */ extern int hostZone; /* timezone from host? */ extern char *timeZone; /* timezone from command line */ extern int verbose; /* verbosity 0, 1 or 2 */ extern int interactive; /* interactive mode, -d */ extern int isdaemon; /* run as a daemon */ extern int agent; /* secret agent mode? */ extern int applet; /* applet mode? */ extern int dowrap; /* counter wrap? default no */ extern int noDnsFlag; /* hostname DNS lookup needed? */ extern pmiestats_t *perf; /* pmie performance data ptr */ extern pmiestats_t instrument; /* pmie performance data struct */ extern SymbolTable rules; /* currently known rules */ extern SymbolTable vars; /* currently known variables */ extern SymbolTable hosts; /* currently known hosts */ extern SymbolTable metrics; /* currently known metrics */ extern Task *taskq; /* evaluator task queue */ extern Expr *curr; /* current executing rule expression */ extern RealTime now; /* current time */ extern RealTime start; /* start evaluation */ extern RealTime stop; /* stop evaluation */ /*********************************************************************** * reserved symbols ***********************************************************************/ extern Symbol symDelta; /* current sample interval */ extern Symbol symMinute; /* minutes after the hour 0..59 */ extern Symbol symHour; /* hours since midnight 0..23 */ extern Symbol symDay; /* day of the month 1..31 */ extern Symbol symMonth; /* month of the year 1..12 */ extern Symbol symYear; /* year 1996.. */ extern Symbol symWeekday; /* days since Sunday 0..6 */ /*********************************************************************** * compulsory initialization ***********************************************************************/ void dstructInit(void); /* initialize central data structures */ void timeInit(void); /* initialize time keeping data structures */ void agentInit(void); /* initialize evaluation parameters */ /*********************************************************************** * unknown units handling * We don't have a good sentinal value, but 1 / count x 10 ^ 7 does * not appear in any PMDA and cannot come from the pmie lexical scanner ***********************************************************************/ #define SET_UNITS_UNKNOWN(u) { u.dimCount = -1; u.scaleCount = 7; } #define UNITS_UNKNOWN(u) (u.dimCount == -1 && u.scaleCount == 7) #endif /* DSTRUCT_H */ pcp-3.8.12ubuntu1/src/pmie/src/show.h0000664000000000000000000000246412272262501014251 0ustar /*********************************************************************** * show.h - output syntax and values *********************************************************************** * * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "dstruct.h" char *opStrings(int); void showSyntax(FILE *,Symbol); void showSubsyntax(FILE *, Symbol); void showValue(FILE *, Expr *); void showAnnotatedValue(FILE *, Expr *); void showSatisfyingValue(FILE *, Expr *); void showTime(FILE *, RealTime); void showFullTime(FILE *, RealTime); size_t formatSatisfyingValue(char *, size_t, char **); pcp-3.8.12ubuntu1/src/pmie/pmie_check.sh0000664000000000000000000003622712272262501014760 0ustar #! /bin/sh # # Copyright (c) 2013 Red Hat. # Copyright (c) 1998-2000,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Administrative script to check pmie processes are alive, and restart # them as required. # # Get standard environment . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/rc-proc.sh PMIE=pmie PMIECONF="$PCP_BIN_DIR/pmieconf" # error messages should go to stderr, not the GUI notifiers unset PCP_STDERR # added to handle problem when /var/log/pcp is a symlink, as first # reported by Micah_Altman@harvard.edu in Nov 2001 # _unsymlink_path() { [ -z "$1" ] && return __d=`dirname $1` __real_d=`cd $__d 2>/dev/null && $PWDCMND` if [ -z "$__real_d" ] then echo $1 else echo $__real_d/`basename $1` fi } # constant setup # tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 status=0 echo >$tmp/lock trap "rm -rf \`[ -f $tmp/lock ] && cat $tmp/lock\` $tmp; exit \$status" 0 1 2 3 15 prog=`basename $0` # control file for pmie administration ... edit the entries in this # file to reflect your local configuration # CONTROL=$PCP_PMIECONTROL_PATH # NB: FQDN cleanup; don't guess a 'real name for localhost', and # definitely don't truncate it a la `hostname -s`. Instead now # we use such a string only for the default log subdirectory, ie. # for substituting LOCALHOSTNAME in the third column of $CONTROL. # determine path for pwd command to override shell built-in PWDCMND=`which pwd 2>/dev/null | $PCP_AWK_PROG ' BEGIN { i = 0 } / not in / { i = 1 } / aliased to / { i = 1 } { if ( i == 0 ) print } '` [ -z "$PWDCMND" ] && PWDCMND=/bin/pwd eval $PWDCMND -P >/dev/null 2>&1 [ $? -eq 0 ] && PWDCMND="$PWDCMND -P" # determine whether we can automatically enable any events sinks CONFARGS="-cF" if which esplogger >/dev/null 2>&1 then CONFARGS='m global syslog_prefix $esp_prefix$' fi # option parsing # SHOWME=false MV=mv RM=rm CP=cp KILL=pmsignal TERSE=false VERBOSE=false VERY_VERBOSE=false CHECK_RUNLEVEL=false START_PMIE=true usage="Usage: $prog [-CNsTV] [-c control]" while getopts c:CNsTV? c do case $c in c) CONTROL="$OPTARG" ;; C) CHECK_RUNLEVEL=true ;; N) SHOWME=true MV="echo + mv" RM="echo + rm" CP="echo + cp" KILL="echo + kill" ;; s) START_PMIE=false ;; T) TERSE=true ;; V) if $VERBOSE then VERY_VERBOSE=true else VERBOSE=true fi ;; ?) echo "$usage" status=1 exit ;; esac done shift `expr $OPTIND - 1` if [ $# -ne 0 ] then echo "$usage" status=1 exit fi _error() { echo "$prog: [$CONTROL:$line]" echo "Error: $1" echo "... automated performance reasoning for host \"$host\" unchanged" touch $tmp/err } _warning() { echo "$prog [$CONTROL:$line]" echo "Warning: $1" } _message() { case $1 in 'restart') $PCP_ECHO_PROG $PCP_ECHO_N "Restarting pmie for host \"$host\" ...""$PCP_ECHO_C" ;; esac } _lock() { # demand mutual exclusion # rm -f $tmp/stamp delay=200 # tenths of a second while [ $delay -ne 0 ] do if pmlock -v $logfile.lock >$tmp/out then echo $logfile.lock >$tmp/lock break else if [ ! -f $tmp/stamp ] then touch -t `pmdate -30M %Y%m%d%H%M` $tmp/stamp fi if [ -n "`find $logfile.lock ! -newer $tmp/stamp -print 2>/dev/null`" ] then _warning "removing lock file older than 30 minutes" ls -l $logfile.lock rm -f $logfile.lock fi fi pmsleep 0.1 delay=`expr $delay - 1` done if [ $delay -eq 0 ] then # failed to gain mutex lock # if [ -f $logfile.lock ] then _warning "is another PCP cron job running concurrently?" ls -l $logfile.lock else echo "$prog: `cat $tmp/out`" fi _warning "failed to acquire exclusive lock ($logfile.lock) ..." continue fi } _unlock() { rm -f $logfile.lock echo >$tmp/lock } _check_logfile() { if [ ! -f $logfile ] then echo "$prog: Error: cannot find pmie output file at \"$logfile\"" if $TERSE then : else logdir=`dirname $logfile` echo "Directory (`cd $logdir; $PWDCMND`) contents:" LC_TIME=POSIX ls -la $logdir fi else echo "Contents of pmie output file \"$logfile\" ..." cat $logfile fi } _check_pmie() { $VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N " [process $1] ""$PCP_ECHO_C" # wait until pmie process starts, or exits # delay=5 [ ! -z "$PMCD_CONNECT_TIMEOUT" ] && delay=$PMCD_CONNECT_TIMEOUT x=5 [ ! -z "$PMCD_REQUEST_TIMEOUT" ] && x=$PMCD_REQUEST_TIMEOUT # wait for maximum time of a connection and 20 requests # delay=`expr \( $delay + 20 \* $x \) \* 10` # tenths of a second while [ $delay -ne 0 ] do if [ -f $logfile ] then # $logfile was previously removed, if it has appeared again then # we know pmie has started ... if not just sleep and try again # if ls "$PCP_TMP_DIR/pmie/$1" >$tmp/out 2>&1 then if grep "No such file or directory" $tmp/out >/dev/null then : else $VERBOSE && echo " done" return 0 fi fi _plist=`_get_pids_by_name pmie` _found=false for _p in `echo $_plist` do [ $_p -eq $1 ] && _found=true done if $_found then # process still here, just hasn't created its status file # yet, try again : else $VERBOSE || _message restart echo " process exited!" if $TERSE then : else echo "$prog: Error: failed to restart pmie" echo "Current pmie processes:" $PCP_PS_PROG $PCP_PS_ALL_FLAGS | tee $tmp/tmp | sed -n -e 1p for _p in `echo $_plist` do sed -n -e "/^[ ]*[^ ]* [ ]*$_p /p" < $tmp/tmp done echo fi _check_logfile return 1 fi fi pmsleep 0.1 delay=`expr $delay - 1` $VERBOSE && [ `expr $delay % 10` -eq 0 ] && \ $PCP_ECHO_PROG $PCP_ECHO_N ".""$PCP_ECHO_C" done $VERBOSE || _message restart echo " timed out waiting!" if $TERSE then : else sed -e 's/^/ /' $tmp/out fi _check_logfile return 1 } _get_configfile() { # extract the pmie configuration file (-c) from a list of arguments # echo $@ | sed -n \ -e 's/^/ /' \ -e 's/[ ][ ]*/ /g' \ -e 's/-c /-c/' \ -e 's/.* -c\([^ ]*\).*/\1/p' } _configure_pmie() { # update a pmie configuration file if it should be created/modified # configfile="$1" if [ -f "$configfile" ] then # look for "magic" string at start of file, and ensure we created it sed 1q "$configfile" | grep '^// pmieconf-pmie [0-9]' >/dev/null magic=$? grep '^// Auto-generated by pmieconf' "$configfile" >/dev/null owned=$? if [ $magic -eq 0 -a $owned -eq 0 ] then # pmieconf file, see if re-generation is needed cp "$configfile" $tmp/pmie if $PMIECONF -f $tmp/pmie $CONFARGS >$tmp/diag 2>&1 then grep -v "generated by pmieconf" "$configfile" >$tmp/old grep -v "generated by pmieconf" $tmp/pmie >$tmp/new if ! diff $tmp/old $tmp/new >/dev/null then if [ -w $configfile ] then $VERBOSE && echo "Reconfigured: \"$configfile\" (pmieconf)" eval $CP $tmp/pmie "$configfile" else _warning "no write access to pmieconf file \"$configfile\", skip reconfiguration" ls -l "$configfile" fi fi else _warning "pmieconf failed to reconfigure \"$configfile\"" cat "s;$tmp/pmie;$configfile;g" $tmp/diag echo "=== start pmieconf file ===" cat $tmp/pmie echo "=== end pmieconf file ===" fi fi elif [ ! -e "$configfile" ] then # file does not exist, generate it, if possible if $SHOWME then echo "+ $PMIECONF -f $configfile $CONFARGS" elif ! $PMIECONF -f "$configfile" $CONFARGS >$tmp/diag 2>&1 then _warning "pmieconf failed to generate \"$configfile\"" cat $tmp/diag echo "=== start pmieconf file ===" cat "$configfile" echo "=== end pmieconf file ===" else ( id pcp && chown pcp:pcp "$configfile" ) >/dev/null 2>&1 fi fi } QUIETLY=false if [ $CHECK_RUNLEVEL = true ] then # determine whether to start/stop based on runlevel settings - we # need to do this when running unilaterally from cron, else we'll # always start pmie up (even when we shouldn't). # QUIETLY=true if is_chkconfig_on pmie then START_PMIE=true else START_PMIE=false fi fi if [ $START_PMIE = false ] then # if pmie has never been started, there's no work to do to stop it [ ! -d "$PCP_TMP_DIR/pmie" ] && exit $QUIETLY || $PCP_BINADM_DIR/pmpost "stop pmie from $prog" fi if [ ! -f "$CONTROL" ] then echo "$prog: Error: cannot find control file ($CONTROL)" status=1 exit fi # 1.0 is the first release, and the version is set in the control file # with a $version=x.y line # version=1.0 eval `grep '^version=' "$CONTROL" | sort -rn` if [ $version != "1.0" ] then _error "unsupported version (got $version, expected 1.0)" status=1 exit fi echo >$tmp/dir rm -f $tmp/err $tmp/pmies line=0 cat "$CONTROL" \ | sed -e "s;PCP_LOG_DIR;$PCP_LOG_DIR;g" \ | while read host socks logfile args do # NB: FQDN cleanup: substitute the LOCALHOSTNAME marker in the config line # differently for the directory and the pcp -h HOST arguments. logfile_hostname=`hostname || echo localhost` logfile=`echo $logfile | sed -e "s;LOCALHOSTNAME;$logfile_hostname;"` logfile=`_unsymlink_path $logfile` if [ "x$host" = "xLOCALHOSTNAME" ] then host=local: fi line=`expr $line + 1` case "$host" in \#*|'') # comment or empty continue ;; \$*) # in-line variable assignment $SHOWME && echo "# $host $socks $logfile $args" cmd=`echo "$host $socks $logfile $args" \ | sed -n \ -e "/='/s/\(='[^']*'\).*/\1/" \ -e '/="/s/\(="[^"]*"\).*/\1/' \ -e '/=[^"'"'"']/s/[;&<>|].*$//' \ -e '/^\\$[A-Za-z][A-Za-z0-9_]*=/{ s/^\\$// s/^\([A-Za-z][A-Za-z0-9_]*\)=/export \1; \1=/p }'` if [ -z "$cmd" ] then # in-line command, not a variable assignment _warning "in-line command is not a variable assignment, line ignored" else case "$cmd" in 'export PATH;'*) _warning "cannot change \$PATH, line ignored" ;; 'export IFS;'*) _warning "cannot change \$IFS, line ignored" ;; *) $SHOWME && echo "+ $cmd" eval $cmd ;; esac fi continue ;; esac if [ -z "$socks" -o -z "$logfile" -o -z "$args" ] then _error "insufficient fields in control file record" continue fi [ $VERY_VERBOSE = "true" ] && echo "Check pmie -h $host -l $logfile ..." # make sure output directory exists # dir=`dirname $logfile` if [ ! -d "$dir" ] then mkdir -p "$dir" >$tmp/err 2>&1 if [ ! -d "$dir" ] then cat $tmp/err _error "cannot create directory ($dir) for pmie log file" fi chown pcp:pcp "$dir" 2>/dev/null fi [ ! -d "$dir" ] && continue cd "$dir" dir=`$PWDCMND` $SHOWME && echo "+ cd $dir" if [ ! -w "$dir" ] then _warning "no write access in $dir, skip lock file processing" ls -ld "$dir" else _lock fi # match $logfile from control file to running pmies pid="" for file in $PCP_TMP_DIR/pmie/[0-9]* do [ "$file" = "$PCP_TMP_DIR/pmie/[0-9]*" ] && continue $VERY_VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N "... try $file: ""$PCP_ECHO_C" p_id=`echo $file | sed -e 's,.*/,,'` p_logfile="" p_pmcd_host="" # throw away stderr in case $file has been removed by now eval `$PCP_BINADM_DIR/pmiestatus $file 2>/dev/null | $PCP_AWK_PROG ' NR == 2 { printf "p_logfile=\"%s\"\n", $0; next } NR == 3 { printf "p_pmcd_host=\"%s\"\n", $0; next } { next }'` p_logfile=`_unsymlink_path $p_logfile` if [ "$p_logfile" != $logfile ] then $VERY_VERBOSE && echo "different logfile, skip" $VERY_VERBOSE && echo " $p_logfile differs to $logfile" elif _get_pids_by_name pmie | grep "^$p_id\$" >/dev/null then $VERY_VERBOSE && echo "pmie process $p_id identified, OK" pid=$p_id break else $VERY_VERBOSE && echo "pmie process $p_id not running, skip" $VERY_VERBOSE && _get_pids_by_name pmie fi done if $VERY_VERBOSE then if [ -z "$pid" ] then echo "No current pmie process exists for:" else echo "Found pmie process $pid monitoring:" fi echo " host = $host" echo " log file = $logfile" fi if [ -z "$pid" -a $START_PMIE = true ] then configfile=`_get_configfile $args` if [ ! -z "$configfile" ] then # if this is a relative path and not relative to cwd, # substitute in the default pmie search location. # if [ ! -f "$configfile" -a "`basename $configfile`" = "$configfile" ] then configfile="$PCP_SYSCONF_DIR/pmie/$configfile" fi # check configuration file exists and is up to date _configure_pmie "$configfile" "$host" fi args="-h $host -l $logfile $args" $VERBOSE && _message restart sock_me='' if [ "$socks" = y ] then # only check for pmsocks if it's specified in the control file have_pmsocks=false if which pmsocks >/dev/null 2>&1 then # check if pmsocks has been set up correctly if pmsocks ls >/dev/null 2>&1 then have_pmsocks=true fi fi if $have_pmsocks then sock_me="pmsocks " else echo "$prog: Warning: no pmsocks available, would run without" sock_me="" fi fi [ -f "$logfile" ] && eval $MV -f "$logfile" "$logfile.prior" if $SHOWME then $VERBOSE && echo echo "+ ${sock_me}$PMIE -b $args" _unlock continue else # since this is launched as a sort of daemon, any output should # go on pmie's stderr, i.e. $logfile ... use -b for this # $VERY_VERBOSE && ( echo; $PCP_ECHO_PROG $PCP_ECHO_N "+ ${sock_me}$PMIE -b $args""$PCP_ECHO_C"; echo "..." ) $PCP_BINADM_DIR/pmpost "start pmie from $prog for host $host" ${sock_me}$PMIE -b $args & pid=$! fi # wait for pmie to get started, and check on its health _check_pmie $pid elif [ ! -z "$pid" -a $START_PMIE = false ] then # Send pmie a SIGTERM, which is noted as a pending shutdown. # Add pid to list of pmies sent SIGTERM - may need SIGKILL later. # $VERY_VERBOSE && echo "+ $KILL -s TERM $pid" eval $KILL -s TERM $pid $PCP_ECHO_PROG $PCP_ECHO_N "$pid ""$PCP_ECHO_C" >> $tmp/pmies fi _unlock done # check all the SIGTERM'd pmies really died - if not, use a bigger hammer. # if $SHOWME then : elif [ $START_PMIE = false -a -s $tmp/pmies ] then pmielist=`cat $tmp/pmies` if ps -p "$pmielist" >/dev/null 2>&1 then $VERY_VERBOSE && ( echo; $PCP_ECHO_PROG $PCP_ECHO_N "+ $KILL -KILL `cat $tmp/pmies` ...""$PCP_ECHO_C" ) eval $KILL -s KILL $pmielist >/dev/null 2>&1 delay=30 # tenths of a second while ps -f -p "$pmielist" >$tmp/alive 2>&1 do if [ $delay -gt 0 ] then pmsleep 0.1 delay=`expr $delay - 1` continue fi echo "$prog: Error: pmie process(es) will not die" cat $tmp/alive status=1 break done fi fi [ -f $tmp/err ] && status=1 exit pcp-3.8.12ubuntu1/src/pmie/rc_pmie0000664000000000000000000001536312272262501013674 0ustar #!/bin/sh # # Copyright (c) 2012 Red Hat. # Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # The following is for chkconfig on RedHat based systems # chkconfig: 2345 94 06 # description: pmie is a performance inference engine for the Performance Co-Pilot (PCP) # # The following is for insserv(1) based systems, # e.g. SuSE, where chkconfig is a perl script. ### BEGIN INIT INFO # Provides: pmie # Required-Start: $remote_fs # Should-Start: $local_fs $network $syslog $time $pmcd # Required-Stop: $remote_fs # Should-Stop: $local_fs $network $syslog $pmcd # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Control pmie (performance inference engine for PCP) # Description: Configure and control pmie (the performance inference engine for the Performance Co-Pilot) ### END INIT INFO . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/rc-proc.sh PMIECTRL=$PCP_PMIECONTROL_PATH RUNDIR=$PCP_LOG_DIR/pmie pmprog=$PCP_RC_DIR/pmie prog=$PCP_RC_DIR/`basename $0` # search for your mail agent of choice ... # MAIL='' for try in Mail mail email do if which $try >/dev/null 2>&1 then MAIL=$try break fi done tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1 status=1 trap "rm -rf $tmp; exit \$status" 0 1 2 3 15 if [ $pmprog = $prog ] then VERBOSE_CTL=on else VERBOSE_CTL=off fi id=`id | sed -e "s/(.*//" -e "s/.*=//"` if [ "$id" != 0 -a "$1" != "status" ] then if [ -n "$PCP_DIR" ] then : running in a non-default installation, do not need to be root else echo "$prog:"' Error: You must be root (uid 0) to start or stop pmie.' exit fi fi _usage() { echo "Usage: $pmprog [-v] {start|restart|condrestart|stop|status|reload|force-reload}" } _reboot_setup() { # base directories and house-keeping for pmie instances # if [ ! -d "$PCP_TMP_DIR/pmie" ] then mkdir -p -m 0775 "$PCP_TMP_DIR/pmie" chown $PCP_USER:$PCP_GROUP "$PCP_TMP_DIR/pmie" else rm -rf $tmp/ent $tmp/pid here=`pwd` cd "$PCP_TMP_DIR/pmie" _get_pids_by_name pmie | sort >$tmp/pid ls [0-9]* 2>&1 | sed -e '/\[0-9]\*/d' \ | sed -e 's/[ ][ ]*//g' | sort >$tmp/ent # remove entries without a pmie process rm -f `comm -23 $tmp/ent $tmp/pid` rm -f $tmp/ent $tmp/pid cd "$here" fi } # Note: _start_pmie is running in the background, in parallel with # the rest of the script. It might complete well after the caller # so tmpfile handling is especially problematic. Goal is to speed # bootup by starting potentially slow (remote monitoring) processes # in the background. # _start_pmie() { bgstatus=0 bgtmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1 trap "rm -rf $bgtmp; exit \$bgstatus" 0 1 2 3 15 wait_option='' [ ! -z "$PMCD_WAIT_TIMEOUT" ] && wait_option="-t $PMCD_WAIT_TIMEOUT" if pmcd_wait $wait_option then pmie_check >$bgtmp/pmie 2>&1 bgstatus=$? if [ -s $bgtmp/pmie ] then $PCP_BINADM_DIR/pmpost "pmie_check start failed in $prog, mailing output to root" if [ ! -z "$MAIL" ] then $MAIL -s "pmie_check start failed in $prog" root <$bgtmp/pmie >/dev/null 2>&1 else echo "$prog: pmie_check start failed ..." cat $bgtmp/pmie fi fi else bgstatus=$? $PCP_BINADM_DIR/pmpost "pmcd_wait failed in $prog: exit status: $bgstatus" if [ ! -z "$MAIL" ] then echo "pmcd_wait: exit status: $bgstatus" | $MAIL -s "pmcd_wait failed in $prog" root else echo "$prog: pmcd_wait failed ..." echo "pmcd_wait: exit status: $bgstatus" fi fi exit $bgstatus # co-process is now complete } _shutdown() { _get_pids_by_name pmie >$tmp/pmies 2>&1 if [ ! -s $tmp/pmies ] then [ "$1" = verbose ] && echo "$pmprog: PMIE not running" return 0 fi [ "$1" = quietly ] || \ $ECHO $PCP_ECHO_N "Waiting for pmie process(es) to terminate ..." "$PCP_ECHO_C" pmie_check -s >$tmp/pmie 2>&1 if [ -s $tmp/pmie ] then $PCP_BINADM_DIR/pmpost "pmie_check stop failed in $prog, mailing output to root" if [ ! -z "$MAIL" ] then $MAIL -s "pmie_check stop failed in $prog" root <$tmp/pmie else echo "$prog: pmie_check stop failed ..." cat $tmp/pmie fi fi true $RC_STATUS -v rm -fr "$tmp/pmie" "$PCP_TMP_DIR/pmie" $PCP_BINADM_DIR/pmpost "stop pmie from $pmprog" } while getopts v c do case $c in v) # force verbose VERBOSE_CTL=on ;; *) _usage exit 1 ;; esac done shift `expr $OPTIND - 1` if [ $VERBOSE_CTL = on ] then # For a verbose startup and shutdown ECHO=$PCP_ECHO_PROG else # For a quiet startup and shutdown ECHO=: fi case "$1" in 'start'|'restart'|'condrestart'|'reload'|'force-reload') if [ "$1" = "condrestart" ] && ! is_chkconfig_on pmie then status=0 exit fi _shutdown quietly # messages should go to stderr, not the GUI notifiers # unset PCP_STDERR _reboot_setup if which pmie >/dev/null 2>&1 then if is_chkconfig_on pmie then if [ ! -d "$RUNDIR" ] then # Should not happen, but needs to match permissions # from package, as defined in src/pmie/GNUmakefile # mkdir -p -m 775 "$RUNDIR" chown $PCP_USER:$PCP_GROUP "$RUNDIR" fi cd $RUNDIR if which pmie_check >/dev/null 2>&1 then if [ ! -f $PMIECTRL ] then echo "$prog:"' Error: PCP inference engine control file '$PMIECTRL' is missing! Cannot start any Performance Co-Pilot inference engine(s).' else $ECHO $PCP_ECHO_N "Starting pmie ..." "$PCP_ECHO_C" _start_pmie & $RC_STATUS -v fi fi elif [ "$0" = "$PCP_RC_DIR/pmie" ] then echo "$prog: Warning: Performance Co-Pilot Inference Engine (pmie) is disabled." chkconfig_on_msg pmie fi fi status=0 ;; 'stop') _shutdown verbose status=0 ;; 'status') # NOTE: $RC_CHECKPROC returns LSB compliant status values. $ECHO $PCP_ECHO_N "Checking for pmie:" "$PCP_ECHO_C" if [ -r /etc/rc.status ] then # SuSE $RC_CHECKPROC pmie $RC_STATUS -v status=$? else # not SuSE $RC_CHECKPROC pmie status=$? if [ $status -eq 0 ] then $ECHO running else $ECHO stopped fi fi ;; *) _usage ;; esac pcp-3.8.12ubuntu1/src/pmie/GNUmakefile0000664000000000000000000000360312272262501014377 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs SUBDIRS = src examples OTHERS = control stomp rc_pmie pmie2col pmie_check.sh pmie_daily.sh LSRCFILES = $(OTHERS) crontab.in LDIRT = crontab ifeq ($(TARGET_OS),linux) CRONTAB_USER = $(PCP_USER) CRONTAB_PATH = $(PCP_ETC_DIR)/cron.d/pcp-pmie else CRONTAB_USER = CRONTAB_PATH = $(PCP_SYSCONF_DIR)/pmie/crontab endif default:: crontab default:: $(SUBDIRS) $(SUBDIRS_MAKERULE) install:: $(SUBDIRS) $(SUBDIRS_MAKERULE) install:: default $(INSTALL) -m 775 -o $(PCP_USER) -g $(PCP_GROUP) -d $(PCP_SYSCONF_DIR)/pmie $(INSTALL) -m 664 -o $(PCP_USER) -g $(PCP_GROUP) control $(PCP_PMIECONTROL_PATH) $(INSTALL) -m 755 pmie_check.sh $(PCP_BINADM_DIR)/pmie_check $(INSTALL) -m 755 pmie_daily.sh $(PCP_BINADM_DIR)/pmie_daily $(INSTALL) -m 755 pmie2col $(PCP_BIN_DIR)/pmie2col $(INSTALL) -m 755 rc_pmie $(PCP_RC_DIR)/pmie $(INSTALL) -m 775 -o $(PCP_USER) -g $(PCP_GROUP) -d $(PCP_LOG_DIR)/pmie $(INSTALL) -m 775 -o $(PCP_USER) -g $(PCP_GROUP) -d $(PCP_TMP_DIR)/pmie ifeq ($(TARGET_OS),linux) $(INSTALL) -m 755 -d `dirname $(CRONTAB_PATH)` endif $(INSTALL) -m 644 crontab $(CRONTAB_PATH) include $(BUILDRULES) default_pcp : default install_pcp : install crontab: crontab.in $(SED) -e 's;@user@;'$(CRONTAB_USER)';' -e 's;@path@;'$(PCP_BINADM_DIR)';g' $< > $@ pcp-3.8.12ubuntu1/src/pmie/stomp0000664000000000000000000000070412272262501013411 0ustar # # Sample STOMP configuration file, parameters affecting connection # between pmie and a JMS server for the "stomp" rule action. # host=foo.bar.com # this is the JMS server (required) port=61616 # and its listening here (required) timeout=2 # seconds to wait for server (optional) topic=PMIE # JMS topic for pmie messages (optional) username=joe # required password=j03ST0MP # required pcp-3.8.12ubuntu1/src/pmie/pmie_daily.sh0000664000000000000000000002700212272262501014774 0ustar #! /bin/sh # # Copyright (c) 1995-2000,2003 Silicon Graphics, Inc. All Rights Reserved. # Portions Copyright (c) 2007 Aconex. All Rights Reserved. # Copyright (c) 2013 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Daily administrative script for pmie logfiles # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/rc-proc.sh # added to handle problem when /var/log/pcp is a symlink, as first # reported by Micah_Altman@harvard.edu in Nov 2001 # _unsymlink_path() { [ -z "$1" ] && return __d=`dirname $1` __real_d=`cd $__d 2>/dev/null && $PWDCMND` if [ -z "$__real_d" ] then echo $1 else echo $__real_d/`basename $1` fi } # error messages should go to stderr, not the GUI notifiers # unset PCP_STDERR # constant setup # tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 status=0 echo >$tmp/lock trap "rm -rf \`[ -f $tmp/lock ] && cat $tmp/lock\` $tmp; exit \$status" 0 1 2 3 15 prog=`basename $0` if is_chkconfig_on pmie then PMIE_CTL=on else PMIE_CTL=off fi # control file for pmie administration ... edit the entries in this # file to reflect your local configuration (see also -c option below) # CONTROL=$PCP_PMIECONTROL_PATH # default number of days to keep pmie logfiles # CULLAFTER=14 # default compression program # COMPRESS=bzip2 COMPRESSAFTER="" COMPRESSREGEX=".meta$|.index$|.Z$|.gz$|.bz2$|.zip$" # mail addresses to send daily logfile summary to # MAILME="" # search for your mail agent of choice ... # MAIL='' for try in Mail mail email do if which $try >/dev/null 2>&1 then MAIL=$try break fi done # NB: FQDN cleanup; don't guess a 'real name for localhost', and # definitely don't truncate it a la `hostname -s`. Instead now # we use such a string only for the default log subdirectory, ie. # for substituting LOCALHOSTNAME in the third column of $CONTROL. # determine path for pwd command to override shell built-in # (see BugWorks ID #595416). PWDCMND=`which pwd 2>/dev/null | $PCP_AWK_PROG ' BEGIN { i = 0 } / not in / { i = 1 } / aliased to / { i = 1 } { if ( i == 0 ) print } '` if [ -z "$PWDCMND" ] then # Looks like we have no choice here... # force it to a known IRIX location PWDCMND=/bin/pwd fi eval $PWDCMND -P >/dev/null 2>&1 [ $? -eq 0 ] && PWDCMND="$PWDCMND -P" _usage() { cat - <$tmp/lock } # filter for pmie log files in working directory - # pass in the number of days to skip over (backwards) from today # # pv:821339 too many sed commands for IRIX ... split into groups # of at most 200 days # _date_filter() { # start with all files whose names match the patterns used by # the PCP pmie log file management scripts ... this list may be # reduced by the sed filtering later on # ls | sed -n >$tmp/in -e '/[-.][12][0-9][0-9][0-9][0-1][0-9][0-3][0-9]/p' i=0 while [ $i -le $1 ] do dmax=`expr $i + 200` [ $dmax -gt $1 ] && dmax=$1 echo "/[-.][12][0-9][0-9][0-9][0-1][0-9][0-3][0-9]/{" >$tmp/sed1 while [ $i -le $dmax ] do x=`pmdate -${i}d %Y%m%d` echo "/[-.]$x/d" >>$tmp/sed1 i=`expr $i + 1` done echo "p" >>$tmp/sed1 echo "}" >>$tmp/sed1 # cull file names with matching dates, keep other file names # sed -n -f $tmp/sed1 <$tmp/in >$tmp/tmp mv $tmp/tmp $tmp/in done cat $tmp/in } rm -f $tmp/err $tmp/mail line=0 version='' cat $CONTROL \ | sed -e "s;PCP_LOG_DIR;$PCP_LOG_DIR;g" \ | while read host socks logfile args do # NB: FQDN cleanup: substitute the LOCALHOSTNAME marker in the config line # differently for the directory and the pcp -h HOST arguments. logfile_hostname=`hostname || echo localhost` logfile=`echo $logfile | sed -e "s;LOCALHOSTNAME;$logfile_hostname;"` logfile=`_unsymlink_path $logfile` if [ "x$host" = "xLOCALHOSTNAME" ] then host=local: fi line=`expr $line + 1` $VERY_VERBOSE && echo "[control:$line] host=\"$host\" socks=\"$socks\" log=\"$logfile\" args=\"$args\"" case "$host" in \#*|'') # comment or empty continue ;; \$*) # in-line variable assignment $SHOWME && echo "# $host $socks $logfile $args" cmd=`echo "$host $socks $logfile $args" \ | sed -n \ -e "/='/s/\(='[^']*'\).*/\1/" \ -e '/="/s/\(="[^"]*"\).*/\1/' \ -e '/=[^"'"'"']/s/[;&<>|].*$//' \ -e '/^\\$[A-Za-z][A-Za-z0-9_]*=/{ s/^\\$// s/^\([A-Za-z][A-Za-z0-9_]*\)=/export \1; \1=/p }'` if [ -z "$cmd" ] then # in-line command, not a variable assignment _warning "in-line command is not a variable assignment, line ignored" else case "$cmd" in 'export PATH;'*) _warning "cannot change \$PATH, line ignored" ;; 'export IFS;'*) _warning "cannot change \$IFS, line ignored" ;; *) $SHOWME && echo "+ $cmd" eval $cmd ;; esac fi continue ;; esac if [ -z "$socks" -o -z "$logfile" -o -z "$args" ] then _error "insufficient fields in control file record" continue fi dir=`dirname $logfile` if $VERY_VERBOSE then echo "Check pmie -h $host ... in $dir ..." fi if [ ! -d "$dir" ] then if [ "$PMIE_CTL" = "on" ] then _error "logfile directory ($dir) does not exist" fi continue fi cd $dir dir=`$PWDCMND` $SHOWME && echo "+ cd $dir" if $VERBOSE then echo echo "=== daily maintenance of pmie log files for host $host ===" echo fi if [ ! -w $dir ] then echo "$prog: Warning: no write access in $dir, skip lock file processing" else # demand mutual exclusion # fail=true rm -f $tmp/stamp for try in 1 2 3 4 do if pmlock -v lock >$tmp/out then echo $dir/lock >$tmp/lock fail=false break else if [ ! -f $tmp/stamp ] then touch -t `pmdate -30M %Y%m%d%H%M` $tmp/stamp fi if [ ! -z "`find lock -newer $tmp/stamp -print 2>/dev/null`" ] then : else echo "$prog: Warning: removing lock file older than 30 minutes" LC_TIME=POSIX ls -l $dir/lock rm -f lock fi fi sleep 5 done if $fail then # failed to gain mutex lock # if [ -f lock ] then echo "$prog: Warning: is another PCP cron job running concurrently?" LC_TIME=POSIX ls -l $dir/lock else echo "$prog: `cat $tmp/out`" fi _warning "failed to acquire exclusive lock ($dir/lock) ..." continue fi fi # match $logfile from control file to running pmies pid="" $VERY_VERBOSE && echo "Looking for logfile=$logfile" for file in `ls "$PCP_TMP_DIR/pmie"` do p_id=$file file="$PCP_TMP_DIR/pmie/$file" p_logfile="" p_pmcd_host="" $VERY_VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N "Check p_id=$p_id ... ""$PCP_ECHO_C" if ps -p "$p_id" >/dev/null 2>&1 then eval `$PCP_BINADM_DIR/pmiestatus $file | $PCP_AWK_PROG ' NR == 2 { printf "p_logfile=\"%s\"\n", $0; next } NR == 3 { printf "p_pmcd_host=\"%s\"\n", $0; next } { next }'` $VERY_VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N "p_pmcd_host=$p_pmcd_host p_logfile=$p_logfile""$PCP_ECHO_C" p_logfile=`_unsymlink_path $p_logfile` $VERY_VERBOSE && $PCP_ECHO_PROG $PCP_ECHO_N "->$p_logfile ... ""$PCP_ECHO_C" if [ "$p_logfile" = $logfile ] then pid=$p_id $VERY_VERBOSE && $PCP_ECHO_PROG match break fi $VERY_VERBOSE && $PCP_ECHO_PROG "no match" else # ignore, its not a running process eval $RM -f $file $VERY_VERBOSE && $PCP_ECHO_PROG "process has vanished" fi done if [ -z "$pid" ] then if [ "$PMIE_CTL" = "on" ] then _error "no pmie instance running for host \"$host\"" fi else # now move current logfile name aside and SIGHUP to "roll the logs" # creating a new logfile with the old name in the process. # $SHOWME && echo "+ mv $logfile ${logfile}.{SUMMARY_LOGNAME}" if mv $logfile ${logfile}.${SUMMARY_LOGNAME} then $VERY_VERBOSE && echo "+ $KILL -s HUP $pid" eval $KILL -s HUP $pid echo ${logfile}.${SUMMARY_LOGNAME} >> $tmp/mail else _error "problems moving logfile \"$logfile\" for host \"$host\"" touch $tmp/err fi fi # and cull old logfiles # if [ X"$CULLAFTER" != X"forever" ] then _date_filter $CULLAFTER >$tmp/list if [ -s $tmp/list ] then if $VERBOSE then echo "Log files older than $CULLAFTER days being removed ..." fmt <$tmp/list | sed -e 's/^/ /' fi if $SHOWME then cat $tmp/list | xargs echo + rm -f else cat $tmp/list | xargs rm -f fi fi fi # finally, compress old log files # (after cull - don't compress unnecessarily) # if [ ! -z "$COMPRESSAFTER" ] then _date_filter $COMPRESSAFTER | egrep -v "$COMPRESSREGEX" >$tmp/list if [ -s $tmp/list ] then if $VERBOSE then echo "Log files older than $COMPRESSAFTER days being compressed ..." fmt <$tmp/list | sed -e 's/^/ /' fi if $SHOWME then cat $tmp/list | xargs echo + $COMPRESS else cat $tmp/list | xargs $COMPRESS fi fi fi _unlock done if [ -n "$MAILME" -a -s $tmp/mail ] then logs="" for file in `cat $tmp/mail` do [ -f $file ] && logs="$logs $file" done egrep -v '( OK | OK$|^$|^Log |^pmie: PID)' $logs > $tmp/logmail if [ ! -s "$tmp/logmail" ] then : elif [ ! -z "$MAIL" ] then egrep -v '( OK | OK$|^$)' $logs | \ $MAIL -s "PMIE summary for $LOCALHOSTNAME" $MAILME else echo "$prog: PMIE summary for $LOCALHOSTNAME ..." egrep -v '( OK | OK$|^$)' $logs fi rm -f $tmp/mail $tmp/logmail fi [ -f $tmp/err ] && status=1 exit pcp-3.8.12ubuntu1/src/pmie/examples/0000775000000000000000000000000012272262620014143 5ustar pcp-3.8.12ubuntu1/src/pmie/examples/uag.210000664000000000000000000000056412272262501015066 0ustar // // a rule expression with multiple actions and %-binding in the // arguments for the action methods ... use some creative string // composition for the final message // some_inst ( disk.dev.total > 50 ) -> syslog 10 mins "Busy disks: " "%i @ %v IOPS " & shell 1 hour "echo 'REALLY busy disks: " "%i @ %v I/Os per second " "' | Mail -s 'pmie alarm' sysadm"; pcp-3.8.12ubuntu1/src/pmie/examples/uag.300000664000000000000000000000065112272262501015063 0ustar // // intrinsic operators // m = mem.freemem; rate_m = rate mem.freemem; // At least 2 CPUs doing some reasonable amount of work // poke = ":moomba :'mac-larry' :bitbucket"; // note '' to escape - in host name u = kernel.percpu.cpu.user $poke; s = kernel.percpu.cpu.sys $poke; some_host ( count_inst ( kernel.percpu.cpu.user $poke + kernel.percpu.cpu.sys $poke > 0.7 ) >= 2 ) -> alarm "2 or more busy CPUs"; pcp-3.8.12ubuntu1/src/pmie/examples/filesys.100000664000000000000000000000072612272262501015766 0ustar // // Some read activity through the buffer cache and the cache read // hit ratio is less than 80% // (lots of file system reads causing physical I/O) // delta = 1 min; // check every minute blkio = "kernel.all.io"; poor_read_hits = (($blkio.lread - $blkio.bread) / $blkio.lread) < 0.8 && $blkio.lread > 100 -> alarm 20 min "poor buffer cache read hit ratio (%v)"; // Note: %v in alarm string is bound to the left most // expression in the predicate pcp-3.8.12ubuntu1/src/pmie/examples/webreport.010000664000000000000000000000030712272262501016314 0ustar // // Data throughput (Kbytes per minute) summaries // // you may replace the metric below with any of the other // web.allservers.bytes metrics data_rate = web.allservers.bytes.total * 60 / 1024; pcp-3.8.12ubuntu1/src/pmie/examples/uag.130000664000000000000000000000133412272262501015063 0ustar // // nested quantification // Servers = ":moomba :gonzo"; // change as desired // read and write rate per disk per host // rd = disk.dev.read $Servers; wr = disk.dev.write $Servers; // one value per host, true if 20% or more of the disks are doing // significant reading or writing // rd_20 = 20%_inst disk.dev.read $Servers > 40; wr_20 = 20%_inst disk.dev.write $Servers > 40; // single truth value: more than 20% of the disks busy reading or writing // on all hosts? // summary = all_host ( 20%_inst disk.dev.read $Servers > 40 || 20%_inst disk.dev.write $Servers > 40 ); // alternate form // summary2 = all_host ( 20%_inst ( disk.dev.read $Servers > 40 || disk.dev.write $Servers > 40 ) ); pcp-3.8.12ubuntu1/src/pmie/examples/cpu.000000664000000000000000000000041012272262501015064 0ustar // // Unusual usr-sys split when some CPU is more than 20% in usr mode // and sys mode is at least 1.5 times usr mode // cpu_usr_sys = some_inst ( $percpu.cpu.sys > $percpu.cpu.user * 1.5 && $percpu.cpu.user > 0.2 ) -> alarm "Unusual sys time: " "%i "; pcp-3.8.12ubuntu1/src/pmie/examples/upm.020000664000000000000000000000056312272262501015111 0ustar delta = 5 sec; // force evaluation once every 5 seconds from here on // If for any disk, for all 4 samples (20 seconds), the disk is performing // more than 40 I/Os per second, then print a message to standard output and // then launch dkvis(1) // some_inst all_sample disk.dev.total @0..3 > 40 count/sec -> print "disk busy for 20 sec" & shell 5 min "dkvis"; pcp-3.8.12ubuntu1/src/pmie/examples/webreport.000000664000000000000000000000031612272262501016313 0ustar // // Request rate throughput (requests per second) summaries // // you may replace the metric below with any of the other // web.allservers.requests metrics request_rate = web.allservers.requests.total; pcp-3.8.12ubuntu1/src/pmie/examples/README0000664000000000000000000000152012272262501015017 0ustar Example Expressions and Rules for pmie(1) The files in this directory contain a number of sample rules for the Performance Co-Pilot inference engine pmie(1). In some cases the rules could be used directly. In others the rules would require customization (host names, thresholds, rule evaluation frequency, choose a suitable alarm/action, etc) before they could be used at a particular site. Each file contains a set of related rules as follows: CPU general CPU utilization and saturation monitoring DISK general disk utilization and saturation monitoring FILESYS general file system monitoring RAS simple reliability and availability monitoring (see also the shping PMDA, pmdashping(1)) UAG examples from the Performance Co-Pilot User's and Administrator's Guide UPM examples from the Performance Co-Pilot Programmer's Guide pcp-3.8.12ubuntu1/src/pmie/examples/filesys.200000664000000000000000000000104112272262501015756 0ustar // // at least $threshold full and at the current rate of growth will fill // the file system in less than $lead_time // ie. used + $lead_time * growth-rate > capacity delta = 1 min; // check every minute threshold = 40; // must be at least this full now (percentage) lead_time = "15min"; // lead time before the filesystem will be full some_inst ( 100 * filesys.used / filesys.capacity > $threshold && filesys.used + $lead_time * ( rate filesys.used ) > filesys.capacity ) -> print "filesystem will be full within $lead_time:" " %i"; pcp-3.8.12ubuntu1/src/pmie/examples/upm.070000664000000000000000000000054112272262501015112 0ustar // // The following rule requires a machine that supports the PCP environment // metrics. If the machine environment temperature rises more than 2 // degrees over a 10 minute interval, write an entry in the system log // environ.temp @1 - environ.temp @0 > 2 -> alarm "temperature rising fast" & syslog "machine room temperature rise alarm"; pcp-3.8.12ubuntu1/src/pmie/examples/uag.040000664000000000000000000000256612272262501015073 0ustar // // perverse example to show all possible choices of units for numeric // constants // mem.freemem > 1 byte; mem.freemem > 1 Kbyte; mem.freemem > 1 Mbyte; mem.freemem > 1 Gbyte; mem.freemem > 1 Tbyte; disk.dev.blktotal > 1 Mbyte / nsec; disk.dev.blktotal > 1 Mbyte / nanosecond; disk.dev.blktotal > 1 Mbyte / usec; disk.dev.blktotal > 1 Mbyte / microsecond; disk.dev.blktotal > 1 Mbyte / msec; disk.dev.blktotal > 1 Mbyte / millisecond; disk.dev.blktotal > 1 Mbyte / sec; disk.dev.blktotal > 1 Mbyte / second; disk.dev.blktotal > 1 Mbyte / min; disk.dev.blktotal > 1 Mbyte / minute; disk.dev.blktotal > 1 Mbyte / hour; hinv.ncpu > 1 count; hinv.ncpu > 1 Kcount; hinv.ncpu > 1 count; hinv.ncpu > 1 Gcount; hinv.ncpu > 1 Tcount; mem.freemem > 1 bytes; mem.freemem > 1 Kbytes; mem.freemem > 1 Mbytes; mem.freemem > 1 Gbytes; mem.freemem > 1 Tbytes; disk.dev.blktotal > 1 Mbyte / nsecs; disk.dev.blktotal > 1 Mbyte / nanoseconds; disk.dev.blktotal > 1 Mbyte / usecs; disk.dev.blktotal > 1 Mbyte / microseconds; disk.dev.blktotal > 1 Mbyte / msecs; disk.dev.blktotal > 1 Mbyte / milliseconds; disk.dev.blktotal > 1 Mbyte / secs; disk.dev.blktotal > 1 Mbyte / seconds; disk.dev.blktotal > 1 Mbyte / mins; disk.dev.blktotal > 1 Mbyte / minutes; disk.dev.blktotal > 1 Mbyte / hours; hinv.ncpu > 1 counts; hinv.ncpu > 1 Kcounts; hinv.ncpu > 1 counts; hinv.ncpu > 1 Gcounts; hinv.ncpu > 1 Tcounts; pcp-3.8.12ubuntu1/src/pmie/examples/network.head0000664000000000000000000000053612272262501016461 0ustar // // Some Common Performance Monitoring Scenarios // // The Network Group // // replace with your hosts HOSTS = ":localhost :foo"; // replace this with your e-mail address MINDER = "root@localhost"; // 10 second rulesets in this group delta = 10 sec; // numbers are diff than strings DELTA_STR = "10 seconds"; // strings are diff than numbers pcp-3.8.12ubuntu1/src/pmie/examples/uag.100000664000000000000000000000137312272262501015063 0ustar // // metric expressions // all instances // enet = network.interface.total.packets; // restricted instance (loopback interface only) // enet_r = network.interface.total.packets #lo0; // restricted instances with weird instance names ... // note instance names are "identifiers" in the grammar, so single // quotes required for tricky characters, like /, spaces, etc, _not_ // double quotes // root_n_usr = filesys.free #'/dev/root' #'/dev/usr'; // multiple hosts // num_cpu = hinv.ncpu :babylon.engr.sgi.com :gonzo :sandpit; // multiple sample times // mem_trend = mem.freemem @0..3; // multi-dimension variations // // missing instance for non-singular instance domain, plus multiple hosts // net_view = network.interface.total.packets :gonzo :moomba; pcp-3.8.12ubuntu1/src/pmie/examples/webreport.head0000664000000000000000000000053112272262501016774 0ustar // // Some Common Performance Monitoring Scenarios // // The WEBREPORT Group // // Intended to be used with archive logs to produce summaries, e.g. // pmie -v -A 1hour -S @10:00am -T @2:00pm -a somearchive WEBREPORT // produces hourly summaries for the hours 10am to 2pm // delta = 1 hour; // change to suit, else use -t from the command line pcp-3.8.12ubuntu1/src/pmie/examples/uag.030000664000000000000000000000014112272262501015055 0ustar // // simple use of a macro // disk = "disk.all"; pct_wrt = ($disk.write / $disk.total) * 100; pcp-3.8.12ubuntu1/src/pmie/examples/disk.000000664000000000000000000000133412272262501015235 0ustar // // Any disk performing more than 40 I/Os per second, sustained over // at least 30 seconds is probably busy // delta = 30 seconds; disk_busy = some_inst ( $disk.dev.total > 40 count/sec ) -> shell 15 mins "Mail -s 'Heavy sustained disk traffic' sysadm 60 count/sec ) ) -> alarm 5 mins "Disk Burst? " "%i "; // any SCSI disk controller performing more than 3 Mbytes per sec is busy // some_inst $disk.ctl.blktotal * 0.5 > 3 Mbyte/sec -> alarm "Busy Disk Controller: " "%i "; pcp-3.8.12ubuntu1/src/pmie/examples/disk.head0000664000000000000000000000023712272262501015720 0ustar // // Some Common Performance Monitoring Scenarios // // The Disk Group // delta = 15 sec; // often enough for disks? // common prefixes // disk = "disk"; pcp-3.8.12ubuntu1/src/pmie/examples/upm.head0000664000000000000000000000014112272262501015561 0ustar // // Examples from the pmie(1) man page // delta = 1 sec; // force evaluation once per second pcp-3.8.12ubuntu1/src/pmie/examples/GNUmakefile0000664000000000000000000000562012272262501016216 0ustar # # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs UAG_SOURCE = uag.head $(sort $(wildcard uag.[0-9][0-9])) UPM_SOURCE = upm.head $(sort $(wildcard upm.[0-9][0-9])) CPU_SOURCE = cpu.head $(sort $(wildcard cpu.[0-9][0-9])) DISK_SOURCE = disk.head $(sort $(wildcard disk.[0-9][0-9])) FILESYS_SOURCE = filesys.head $(sort $(wildcard filesys.[0-9][0-9])) RAS_SOURCE = ras.head $(sort $(wildcard ras.[0-9][0-9])) SWAP_SOURCE = swap.head $(sort $(wildcard swap.[0-9][0-9])) NETWORK_SOURCE = network.head $(sort $(wildcard network.[0-9][0-9])) ENVIRON_SOURCE = environ.head $(sort $(wildcard environ.[0-9][0-9])) WEBREPORT_SOURCE= webreport.head $(sort $(wildcard webreport.[0-9][0-9])) TARGETS = UAG UPM CPU DISK FILESYS RAS SWAP NETWORK ENVIRON \ WEBREPORT LDIRT = $(TARGETS) LSRCFILES = README $(UAG_SOURCE) $(UPM_SOURCE) $(CPU_SOURCE) \ $(DISK_SOURCE) $(FILESYS_SOURCE) $(RAS_SOURCE) $(SWAP_SOURCE) \ $(NETWORK_SOURCE) $(ENVIRON_SOURCE) $(WEBREPORT_SOURCE) EX_DIR = $(PCP_SHARE_DIR)/examples/pmie default: $(TARGETS) README install: default $(INSTALL) -m 755 -d $(EX_DIR) $(INSTALL) -m 644 $(TARGETS) README $(EX_DIR) UAG: $(UAG_SOURCE) rm -f UAG for file in $(UAG_SOURCE); do cat $$file >>UAG; echo >>UAG; done UPM: $(UPM_SOURCE) rm -f UPM for file in $(UPM_SOURCE); do cat $$file >>UPM; echo >>UPM; done CPU: $(CPU_SOURCE) rm -f CPU for file in $(CPU_SOURCE); do cat $$file >>CPU; echo >>CPU; done DISK: $(DISK_SOURCE) rm -f DISK for file in $(DISK_SOURCE); do cat $$file >>DISK; echo >>DISK; done sed -i -e "s@/usr/pcp/bin/pmpost@$(PCP_BINADM_DIR)/pmpost@" DISK FILESYS: $(FILESYS_SOURCE) rm -f FILESYS for file in $(FILESYS_SOURCE); do cat $$file >>FILESYS; echo >>FILESYS; done RAS: $(RAS_SOURCE) rm -f RAS for file in $(RAS_SOURCE); do cat $$file >>RAS; echo >>RAS; done SWAP: $(SWAP_SOURCE) rm -f SWAP for file in $(SWAP_SOURCE); do cat $$file >>SWAP; echo >>SWAP; done NETWORK: $(NETWORK_SOURCE) rm -f NETWORK for file in $(NETWORK_SOURCE); do cat $$file >>NETWORK; echo >>NETWORK; done ENVIRON: $(ENVIRON_SOURCE) rm -f ENVIRON for file in $(ENVIRON_SOURCE); do cat $$file >>ENVIRON; echo >>ENVIRON; done WEBREPORT: $(WEBREPORT_SOURCE) rm -f WEBREPORT for file in $(WEBREPORT_SOURCE); do cat $$file >>WEBREPORT; echo >>WEBREPORT; done include $(BUILDRULES) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmie/examples/upm.090000664000000000000000000000051412272262501015114 0ustar // Busy disk? delta = 20 sec; // force evaluation once every 5 seconds from here on // If any disk is performing more than 60 I/Os per second, then // print a message to standard output and launch dkvis(1) // some_inst disk.dev.total > 60 count/sec -> print "disk busy for 20 sec" "%v IOPS %i@%h" & shell 5 min "dkvis"; pcp-3.8.12ubuntu1/src/pmie/examples/swap.head0000664000000000000000000000045012272262501015735 0ustar // // The Swap Group // // replace with your hosts HOSTS = ":localhost :foo"; // replace this with your e-mail address MINDER = "root@localhost"; // 20 second rulesets in this group delta = 20 sec; // numbers are diff than strings DELTA_STR = "20 seconds"; // strings are diff than numbers pcp-3.8.12ubuntu1/src/pmie/examples/uag.010000664000000000000000000000013012272262501015051 0ustar // // total disk write percentage // wrt_pct = (disk.all.write / disk.all.total) * 100; pcp-3.8.12ubuntu1/src/pmie/examples/cpu.020000664000000000000000000000047312272262501015077 0ustar // // the 1 minute load average exceeds 5 * number of CPUs on any host // hosts = ":gonzo :moomba"; // change as required delta = 1 minute; // no need to evaluate more often than this high_load = some_host ( $all.load $hosts #'1 minute' > 5 * hinv.ncpu $hosts ) -> alarm "High Load Average? " "%h: %v "; pcp-3.8.12ubuntu1/src/pmie/examples/uag.020000664000000000000000000000034012272262501015055 0ustar // // some varied expressions // pct_wrt = (disk.all.write / disk.all.total) * 100; busy_wrt = disk.dev.total > 10 && disk.dev.write > disk.dev.read; busy = some_inst disk.dev.total > 60 -> print "[%i] high disk i/o "; pcp-3.8.12ubuntu1/src/pmie/examples/network.000000664000000000000000000000051312272262501015772 0ustar // // Report when some interface has seen more than 15 errors per second // on at least 3 of the last 4 observations // // Rule donated by Kevin Wang at Silicon Graphics // some_host some_inst 75%_sample ( network.interface.total.errors $HOSTS @0..3 > 15 ) -> print 5 min "high network interface errors" "%h[%i] %v errors/sec "; pcp-3.8.12ubuntu1/src/pmie/examples/uag.200000664000000000000000000000045412272262501015063 0ustar // // a rule expression with multiple actions and %-binding in the // arguments for the action methods // some_inst ( disk.dev.total > 60 ) -> syslog 10 mins "[%i] busy, %v IOPS " & shell 1 hour "echo 'Disk %i is REALLY busy. Running at %v I/Os per second' | Mail -s 'pmie alarm' sysadm"; pcp-3.8.12ubuntu1/src/pmie/examples/uag.head0000664000000000000000000000012112272262501015532 0ustar // // Examples from the Performance Co-Pilot User's and Administrator's Guide // pcp-3.8.12ubuntu1/src/pmie/examples/environ.000000664000000000000000000000107012272262501015760 0ustar // // Absolute temperature ceiling. // // Rules donated by Kevin Wang at Silicon Graphics // some_host ( environ.temp $HOSTS > 33 ) -> print 10 min "absolute temperature alarm! " "%h: %v degrees "; // // Watch the machine room temperature. If it rises more than 2 degrees // every $delta, danger! // This is different from the absolute rule above ... this one // gives early warning of sustained temperature increases. // some_host ( environ.temp $HOSTS @0 - environ.temp $HOSTS @1 > 2 ) -> print "temperature rise alarm: " "%h: %v degree rise in $DELTA_STR "; pcp-3.8.12ubuntu1/src/pmie/examples/uag.110000664000000000000000000000024012272262501015054 0ustar // // relational (logical) expressions // hosts = ":gonzo"; intfs = "#ec0 #ec2"; all_intf = network.interface.in.packets $hosts $intfs @0..2 > 300 count/sec; pcp-3.8.12ubuntu1/src/pmie/examples/cpu.head0000664000000000000000000000031112272262501015546 0ustar // // Some Common Performance Monitoring Scenarios // // The CPU Group // delta = 2 sec; // more often for demonstration purposes // common prefixes // percpu = "kernel.percpu"; all = "kernel.all"; pcp-3.8.12ubuntu1/src/pmie/examples/swap.000000664000000000000000000000223212272262501015253 0ustar // // report when swap > 50-75% full and when swap > 75% full // // Rules donated by Kevin Wang at Silicon Graphics // // note: the sort hack '9999999' to keep the header first; later // removed by sed // note: -o option to ps(1) requires IRIX 6.2 or later ... for IRIX 5.3 // this would have to be re-written using ps -el SWAP="swap"; some_host ( ($SWAP.free $HOSTS / $SWAP.length $HOSTS) * 100 < 50 && ($SWAP.free $HOSTS / $SWAP.length $HOSTS) * 100 >= 25 ) -> print 10 min "swap more than half-full: " "%h: %v% free " & shell 10 min "rsh -n guest@%h /sbin/ps -eo 'ruser=UID,pid=PID,ppid=PPID,pcpu=%CPU,sz=9999999SZ,rss=RSS,stime=STIME,time=TIME,args=CMD' | sort +4 -nr | sed -e 's/9999999SZ / SZ:/' | /usr/sbin/Mail -s '%h swap more than half-full (%v% free)' $MINDER &"; some_host ( ($SWAP.free $HOSTS / $SWAP.length $HOSTS) * 100 < 25 ) -> print 10 min "swap almost full: " "%h: %v% free " & shell 10 min "rsh -n guest@%h /sbin/ps -eo 'ruser=UID,pid=PID,ppid=PPID,pcpu=%CPU,sz=9999999SZ,rss=RSS,stime=STIME,time=TIME,args=CMD' | sort +4 -nr | sed -e 's/9999999SZ / SZ:/' | /usr/sbin/Mail -s '%h swap almost full (%v% free)' $MINDER &"; pcp-3.8.12ubuntu1/src/pmie/examples/upm.010000664000000000000000000000015012272262501015100 0ustar all_sample (kernel.all.syscall @0..4 > 10 Kcount/sec * hinv.ncpu) -> shell 5 min "xwsh -e 'top'"; pcp-3.8.12ubuntu1/src/pmie/examples/filesys.000000664000000000000000000000060712272262501015763 0ustar // // Either the /tmp or the /usr filesystem being // more than 95% full // delta = 5 mins; // often enough for file system fullness? tmp_full = $fsys.free #'/dev/root' / $fsys.capacity #'/dev/root' < 0.05 -> syslog "/dev/root filesystem (almost) full"; usr_full = $fsys.free #'/dev/usr' / $fsys.capacity #'/dev/usr' < 0.05 -> syslog "/dev/usr filesystem (almost) full"; pcp-3.8.12ubuntu1/src/pmie/examples/cpu.010000664000000000000000000000054712272262501015100 0ustar // // Over all CPUs, syscall_rate > 1000 * no_of_cpus // cpu_syscall = $all.syscall > 1000 count/sec * hinv.ncpu -> print "high aggregate syscalls: %v"; // Sustained high syscall rate on a single CPU // delta = 30 sec; percpu_syscall = some_inst ( $percpu.syscall > 2000 count/sec ) -> syslog "Sustained syscalls per second? " "[%i] %v "; pcp-3.8.12ubuntu1/src/pmie/examples/uag.000000664000000000000000000000011312272262501015051 0ustar // // a simple expression, with multiple values // iops = disk.dev.total; pcp-3.8.12ubuntu1/src/pmie/examples/environ.head0000664000000000000000000000070612272262501016447 0ustar // // Some Common Performance Monitoring Scenarios // // The Environ Group // // Note: need environ PMDA installed on a Challenge L or XL for // required metrics to be available // replace with your hosts HOSTS = ":localhost :foo"; // replace this with your e-mail address MINDER = "root@localhost"; // 1 minute rulesets in this group delta = 1 min; // numbers are diff than strings DELTA_STR = "1 minute"; // strings are diff than numbers pcp-3.8.12ubuntu1/src/pmie/examples/ras.head0000664000000000000000000000014012272262501015544 0ustar // // Some System Reliability, Availability and Serviceability (RAS) Checks // delta = 20 sec; pcp-3.8.12ubuntu1/src/pmie/examples/upm.060000664000000000000000000000073112272262501015112 0ustar delta = 10 mins; // force evaluation once every 10 minutes from here on // If either the / or the /usr filesystem is more than 95% full, display // an alarm popup, but not if it has already been displayed during the last // 24 hours // filesys.free #'/dev/root' / filesys.capacity #'/dev/root' < 0.05 -> alarm 24 hour "root filesystem (almost) full"; filesys.free #'/dev/usr' / filesys.capacity #'/dev/usr' < 0.05 -> alarm 24 hour "/usr filesystem (almost) full"; pcp-3.8.12ubuntu1/src/pmie/examples/disk.100000664000000000000000000000126012272262501015234 0ustar // // A subset of the disks on a particular host are either busy // (more than 30 I/Os per second averaged over these disks) or one // disk is busy (more than 50 I/Os per second) with write-dominated // (more than 75%) activity delta = 10 sec; myhost = "moomba"; // the host of interest mydisks = "#dks1d1 #dks1d2 #dks3d2"; // the disks of interest on this host metric = "disk.dev"; disk_group_busy = ( avg_inst ( $metric.total :$myhost $mydisks ) > 10 count/sec || some_inst ( $metric.total :$myhost $mydisks > 50 count/sec && $metric.write :$myhost $mydisks > 3 * $metric.write :$myhost $mydisks ) ) -> alarm "Busy disks: $mydisks on host: $myhost)"; pcp-3.8.12ubuntu1/src/pmie/examples/upm.050000664000000000000000000000043512272262501015112 0ustar // // Macro for use ... // bc = "buffer_cache"; // Using the above macro; If the buffer cache is in use (more than 50 read // requests) with hit ratio less than 90%, then popup an alarm // $bc.getblks > 50 && $bc.getfound / $bc.getblks < 0.9 -> alarm "poor buffer cache hit rate"; pcp-3.8.12ubuntu1/src/pmie/examples/ras.000000664000000000000000000000055612272262501015075 0ustar // // For Origin systems, sequence number errors are not indicative of // a problem, but persistent checkbit and/or retry errors may indicate // a CrayLink interconnect problem. // some_inst ( all_sample ( hw.router.perport.cb_errors @0..2 > 0 || hw.router.perport.retry_errors @0..2 > 0 ) ) -> alarm 30mins "CrayLink SN and/or Retry errors: " "%i "; pcp-3.8.12ubuntu1/src/pmie/examples/upm.000000664000000000000000000000027512272262501015107 0ustar // // If total syscall rate exceeds 10000/second times number of CPUs, then // display an alarm notifier // kernel.all.syscall > 10 Kcount/sec * hinv.ncpu -> alarm "high syscall rate"; pcp-3.8.12ubuntu1/src/pmie/examples/upm.030000664000000000000000000000046112272262501015107 0ustar // // Refine the preceding rule to apply only between the hours of 9am and 5pm, // and to require that just 3 of the four samples exceed the threshold // $hour >= 9 && $hour <= 17 && some_inst 75 %_sample disk.dev.total @0..3 > 40 count/sec -> print "disk busy for 20 sec" & shell 5 min "dkvis"; pcp-3.8.12ubuntu1/src/pmie/examples/upm.040000664000000000000000000000040212272262501015103 0ustar // // Refine the preceding rule further to print the host name and disk name // for which the threshold is exceeded // $hour >= 9 && $hour <= 17 && some_inst 75 %_sample disk.dev.total @0..3 > 40 count/sec -> print "disk %i on host %h busy for 20 sec"; pcp-3.8.12ubuntu1/src/pmie/examples/filesys.head0000664000000000000000000000017412272262501016444 0ustar // // Some Common Performance Monitoring Scenarios // // The File System Group // // common prefixes // fsys = "filesys"; pcp-3.8.12ubuntu1/src/pmie/examples/upm.080000664000000000000000000000062612272262501015117 0ustar // // Something interesting if you have performance problems with // your Oracle data base ... // db = "oracle.ptg1"; host = ":moomba.melbourne.sgi.com"; lru = "#'cache buffers lru chain'"; gets = "$db.latch.gets $host $lru"; total = "$db.latch.gets $host $lru + $db.latch.misses $host $lru + $db.latch.immisses $host $lru"; $total > 100 && $gets / $total < 0.2 -> alarm "high LRU latch contention"; pcp-3.8.12ubuntu1/src/pmie/examples/uag.120000664000000000000000000000033712272262501015064 0ustar // // quantification examples // // some_instance all_intf = network.interface.in.packets #ec0 #ec2 @0..2 > 300 count/sec; any_sample = some_sample network.interface.in.packets #ec0 #ec2 @0..2 > 300 count/sec; pcp-3.8.12ubuntu1/src/pmie/examples/disk.200000664000000000000000000000102212272262501015231 0ustar // // Assume the / and /usr file systems are on different partitions // of the same disk (/dev/dsk0d1 in the example below). // Add an entry to the file $PCP_LOG_DIR/NOTICES when this disk is // busy and either of the file systems is more than 90% full. // // Suggestion from: Steve Daniels (steve@houdini.denver.sgi.com) delta = 60; ( filesys.full #'/dev/root' > 90 || filesys.full #'/dev/usr' > 90 ) && disk.dev.total #'dks0d1' > 40 count/sec -> shell 15min "/usr/pcp/bin/pmpost 'dks0d1 busy when / or /usr nearly full'"; pcp-3.8.12ubuntu1/src/pmie/pmie2col0000775000000000000000000000453112272262501013766 0ustar #!/bin/sh # # A crude ascii reporting tool, convert pmie to column output # # The pmie rules need to be of the form: # load_1 = kernel.all.load #'1 minute'; # idle = kernel.all.cpu.idle; # column_name=some other expression; # ... # # Each pmie expression has to produce a singular value. # # With timestamps (pmie -e or pmie output from a PCP archive), lines look like # metric (Tue Feb 13 05:01:19 2001): value # load_1 (Tue Dec 23 12:20:45 2003): 0.24 # the first sed step in the filter sorts this out. # # First e-mailed to Patrick Aland and pcp@oss.sgi.com # on Wed, 24 Jan 2001. # # Get standard environment . $PCP_DIR/etc/pcp.env # For interactive use, works better with line buffered output from sed(1) # and awk(1). # case "$PCP_PLATFORM" in linux|mingw|kfreebsd) SED="sed -u" ;; freebsd|darwin) SED="sed -l" ;; *) SED=sed ;; esac _usage() { echo "Usage: pmie2col [-w width] [-d delimiter] [-p precision]" exit 1 } pre=2 # floating point precision wid=7 # reporting column width delim=' ' while getopts "d:p:w:?" c do case "$c" in w) wid="$OPTARG" ;; p) pre="$OPTARG" ;; d) delim="$OPTARG" ;; *) _usage ;; esac done shift `expr $OPTIND - 1` if [ $# -ne 0 ] then _usage fi # culled output at the start is produced by pmie and/or pmafm $SED \ -e '/^pmie: timezone set to/d' \ -e '/^Note: running pmie serially, once per archive$/d' \ -e '/^Host: [A-Za-z0-9]* Archive: /d' \ -e '/^[^ ][^ ]* ([A-Z][a-z][a-z] [A-Z][a-z][a-z] *[0-9][0-9]* [0-2][0-9]:[0-5][0-9]:[0-5][0-9] [0-9][0-9][0-9][0-9]): /{ s/ (/|/ s/): /|/ }' \ -e '/^\([^ ][^ ]*\):/s//\1||/' \ | awk -F\| -v delim="$delim" ' NF == 0 { if (state == 0) { ncol = i print "" } if (stamp != "") printf "%24s ",stamp for (i = 0; i < ncol; i++) { if (v[i] == "?") # no value printf "%s%'$wid'.'$wid's",delim,"?" else if (v[i]+0 == v[i]) # number printf "%s%'$wid'.'$pre'f",delim,v[i] else # string printf "%s%'$wid'.'$wid's",delim,v[i] v[i] = "?" } print "" i = 0 stamp = "" state = 1 next } NF == 3 && stamp == "" { stamp = $2 } state == 0 { if (i == 0 && stamp != "") printf "%24s ","" printf "%s%'$wid'.'$wid's",delim,$1 } { v[i++] = $NF }' pcp-3.8.12ubuntu1/src/pmie/control0000664000000000000000000000330112272262501013723 0ustar # # PCP inference engine configuration/control # # This file is used by a number of the PCP inference engine administrative # tools to perform maintenance on the pmie instances running on the local host. # # This file contains one line per host to be monitored, fields are # Host name of host to be monitored # S(ocks)? should this pmie be launched with pmsocks? y or n # Log File full pathname to file where pmie activity log is to be # maintained ... note all scripts "cd" the directory housing # this file as a first step # Arguments optional additional arguments to pmie # # === VARIABLE ASSIGNMENTS === # $version=1.0 # if pmsocks is being used, edit the IP address for $SOCKS_SERVER and # uncomment the next line #$SOCKS_SERVER=123.456.789.123; export SOCKS_SERVER # if remote pmie instances are run over a WAN with potentially long delays, # adjust the following and uncomment #$PMCD_CONNECT_TIMEOUT=20; export PMCD_CONNECT_TIMEOUT #$PMCD_REQUEST_TIMEOUT=15; export PMCD_REQUEST_TIMEOUT # === PMIE CONTROL SPECIFICATIONS === # # Note: - if multiple pmie instances for the same host, then they MUST use # different log files; # - any occurence of LOCALHOSTNAME will be replaced by local hostname; # - pmie's configuration file search path is "./:$PCP_SYSCONF_DIR/pmie/", # and the working directory ('.') is the dirname of the Log File. # #Host S? Log File Arguments LOCALHOSTNAME n PCP_LOG_DIR/pmie/LOCALHOSTNAME/pmie.log -c config.default # remote host #remote n PCP_LOG_DIR/pmie/remote/pmie.log -c config.remote # thru the firewall via socks #distant y PCP_LOG_DIR/pmie/distant/pmie.log -c config.distant pcp-3.8.12ubuntu1/src/pmiestatus/0000775000000000000000000000000012272262620013571 5ustar pcp-3.8.12ubuntu1/src/pmiestatus/pmiestatus.c0000664000000000000000000000322512272262501016133 0ustar /* * Copyright (c) 2010 Max Matveev. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "impl.h" #include "stats.h" int main(int argc, char **argv) { int i; __pmSetProgname(argv[0]); for (i=1; i < argc; i++) { pmiestats_t ps; struct stat st; int f = open(argv[i], O_RDONLY, 0); if (f < 0) { fprintf(stderr, "%s: cannot open %s - %s\n", pmProgname, argv[i], osstrerror()); continue; } if (fstat(f, &st) < 0) { fprintf(stderr, "%s: cannot get size of %s - %s\n", pmProgname, argv[i], osstrerror()); goto closefile; } if (st.st_size != sizeof(ps)) { fprintf(stderr, "%s: %s is not a valid pmie stats file\n", pmProgname, argv[i]); goto closefile; } if (read(f, &ps, sizeof(ps)) != sizeof(ps)) { fprintf(stderr, "%s: cannot read %ld bytes from %s\n", pmProgname, (long)sizeof(ps), argv[i]); goto closefile; } if (ps.version != 1) { fprintf(stderr, "%s: unsupported version %d in %s\n", pmProgname, ps.version, argv[i]); goto closefile; } printf ("%s\n%s\n%s\n", ps.config, ps.logfile, ps.defaultfqdn); closefile: close(f); } return 0; } pcp-3.8.12ubuntu1/src/pmiestatus/GNUmakefile0000664000000000000000000000171312272262501015643 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2010 Max Matveev. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmiestatus.c CMDTARGET = pmiestatus$(EXECSUFFIX) LLDLIBS = $(PCPLIB) LCFLAGS = -I$(TOPDIR)/src/pmie/src default : $(CMDTARGET) include $(BUILDRULES) install : default $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BINADM_DIR)/$(CMDTARGET) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/libpcp_pmcd/0000775000000000000000000000000012272262617013655 5ustar pcp-3.8.12ubuntu1/src/libpcp_pmcd/GNUlocaldefs.320000664000000000000000000000014712272262501016323 0ustar LCFLAGS += -m32 -march=i386 LLDFLAGS += -m32 -march=i386 PCP_LIB_DIR=$(PCP_LIB32_DIR) LIBPCP_ABIDIR=32 pcp-3.8.12ubuntu1/src/libpcp_pmcd/src/0000775000000000000000000000000012272262617014444 5ustar pcp-3.8.12ubuntu1/src/libpcp_pmcd/src/trace.c0000664000000000000000000002035312272262501015701 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1995-2000,2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmcd.h" #include "config.h" #if HAVE_STATIC_PROBES #include "probes.h" #else #define PCP_PROBE_PMCD_PDU(type,who,p1,p2) #define PCP_PROBE_PMCD(type,who,p1,p2) #endif /* * Diagnostic event tracing support */ typedef struct { time_t t_stamp; /* timestamp */ int t_type; /* event type */ int t_who; /* originator or principal identifier */ int t_p1; /* optional event parameters */ int t_p2; } tracebuf; static tracebuf *trace; static unsigned int next; /* * by default, circular buffer last 20 events -- change by modify * pmcd.control.tracebufs * by default, tracing is disabled -- change by setting the following * to 1, pmcd.control.traceconn (trace connections) and/or * pmcd.control.tracepdu (trace PDUs) */ PMCD_INTERN int _pmcd_trace_nbufs = 20; PMCD_INTERN int _pmcd_trace_mask; void pmcd_init_trace(int n) { if (trace != NULL) free(trace); if ((trace = (tracebuf *)malloc(n * sizeof(tracebuf))) == NULL) { __pmNoMem("pmcd_init_trace", n * sizeof(tracebuf), PM_RECOV_ERR); return; } _pmcd_trace_nbufs = n; next = 0; } void pmcd_trace(int type, int who, int p1, int p2) { int p; switch (type) { case TR_XMIT_PDU: case TR_RECV_PDU: PCP_PROBE_PMCD_PDU(type, who, p1, p2); if ((_pmcd_trace_mask & TR_MASK_PDU) == 0) return; break; default: PCP_PROBE_PMCD(type, who, p1, p2); if ((_pmcd_trace_mask & TR_MASK_CONN) == 0) return; break; } if (trace == NULL) { pmcd_init_trace(_pmcd_trace_nbufs); if (trace == NULL) return; } p = (next++) % _pmcd_trace_nbufs; time(&trace[p].t_stamp); trace[p].t_type = type; trace[p].t_who = who; trace[p].t_p1 = p1; trace[p].t_p2 = p2; if (_pmcd_trace_mask & TR_MASK_NOBUF) /* unbuffered, dump it now */ pmcd_dump_trace(stderr); } void pmcd_dump_trace(FILE *f) { int i; int p; struct tm last = { 0, 0 }; struct tm *this; char strbuf[20]; if ((_pmcd_trace_mask & TR_MASK_NOBUF) == 0) fprintf(f, "\n->PMCD event trace: "); if (trace != NULL && next != 0) { if (next < _pmcd_trace_nbufs) i = 0; else i = next - _pmcd_trace_nbufs; if ((_pmcd_trace_mask & TR_MASK_NOBUF) == 0) { fprintf(f, "starting at %s", ctime(&trace[i % _pmcd_trace_nbufs].t_stamp)); last.tm_hour = -1; } else last.tm_hour = -2; for ( ; i < next; i++) { fprintf(f, "->"); p = i % _pmcd_trace_nbufs; this = localtime(&trace[p].t_stamp); if (this->tm_hour != last.tm_hour || this->tm_min != last.tm_min || this->tm_sec != last.tm_sec) { if (last.tm_hour == -1) fprintf(f, " "); else fprintf(f, "%02d:%02d:%02d ", this->tm_hour, this->tm_min, this->tm_sec); last = *this; /* struct assignment */ } else fprintf(f, " "); switch (trace[p].t_type) { case TR_ADD_CLIENT: { ClientInfo *cip; fprintf(f, "New client: [%d] ", trace[p].t_who); cip = GetClient(trace[p].t_who); if (cip == NULL) { fprintf(f, "-- unknown?\n"); } else { __pmSockAddr *saddr = (__pmSockAddr *)cip->addr; char *addrbuf; addrbuf = __pmSockAddrToString(saddr); if (addrbuf == NULL) fprintf(f, "invalid socket address"); else { fprintf(f, "addr=%s", addrbuf); free(addrbuf); } fprintf(f, ", fd=%d, seq=%u\n", cip->fd, cip->seq); } } break; case TR_DEL_CLIENT: fprintf(f, "End client: fd=%d", trace[p].t_who); if (trace[p].t_p1 != 0) fprintf(f, ", err=%d: %s", trace[p].t_p1, pmErrStr(trace[p].t_p1)); fputc('\n', f); break; case TR_ADD_AGENT: fprintf(f, "Add PMDA: domain=%d, ", trace[p].t_who); if (trace[p].t_p1 == -1 && trace[p].t_p2 == -1) fprintf(f, "DSO\n"); else fprintf(f, "infd=%d, outfd=%d\n", trace[p].t_p1, trace[p].t_p2); break; case TR_DEL_AGENT: fprintf(f, "Drop PMDA: domain=%d, ", trace[p].t_who); if (trace[p].t_p1 == -1 && trace[p].t_p2 == -1) fprintf(f, "DSO\n"); else fprintf(f, "infd=%d, outfd=%d\n", trace[p].t_p1, trace[p].t_p2); break; case TR_EOF: fprintf(f, "Premature EOF: expecting %s PDU, fd=%d\n", trace[p].t_p1 == -1 ? "NO" : __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who); break; case TR_WRONG_PDU: if (trace[p].t_p2 > 0) { fprintf(f, "Wrong PDU type: expecting %s PDU, fd=%d, got %s PDU\n", trace[p].t_p1 == -1 ? "NO" : __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who, trace[p].t_p2 == -1 ? "NO" : __pmPDUTypeStr_r(trace[p].t_p2, strbuf, sizeof(strbuf))); } else if (trace[p].t_p2 == 0) { fprintf(f, "Wrong PDU type: expecting %s PDU, fd=%d, got EOF\n", trace[p].t_p1 == -1 ? "NO" : __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who); } else { fprintf(f, "Wrong PDU type: expecting %s PDU, fd=%d, got err=%d: %s\n", trace[p].t_p1 == -1 ? "NO" : __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who, trace[p].t_p2, pmErrStr(trace[p].t_p2)); } break; case TR_XMIT_ERR: fprintf(f, "Send %s PDU failed: fd=%d, err=%d: %s\n", __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who, trace[p].t_p2, pmErrStr(trace[p].t_p2)); break; case TR_RECV_TIMEOUT: fprintf(f, "Recv timeout: expecting %s PDU, fd=%d\n", __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who); break; case TR_RECV_ERR: fprintf(f, "Recv error: expecting %s PDU, fd=%d, err=%d: %s\n", __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who, trace[p].t_p2, pmErrStr(trace[p].t_p2)); break; case TR_XMIT_PDU: fprintf(f, "Xmit: %s PDU, fd=%d", __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who); if (trace[p].t_p1 == PDU_ERROR) fprintf(f, ", err=%d: %s", trace[p].t_p2, pmErrStr(trace[p].t_p2)); else if (trace[p].t_p1 == PDU_RESULT) fprintf(f, ", numpmid=%d", trace[p].t_p2); else if (trace[p].t_p1 == PDU_TEXT_REQ || trace[p].t_p1 == PDU_TEXT) fprintf(f, ", id=0x%x", trace[p].t_p2); else if (trace[p].t_p1 == PDU_DESC_REQ || trace[p].t_p1 == PDU_DESC) fprintf(f, ", pmid=%s", pmIDStr_r((pmID)trace[p].t_p2, strbuf, sizeof(strbuf))); else if (trace[p].t_p1 == PDU_INSTANCE_REQ || trace[p].t_p1 == PDU_INSTANCE) fprintf(f, ", indom=%s", pmInDomStr_r((pmInDom)trace[p].t_p2, strbuf, sizeof(strbuf))); else if (trace[p].t_p1 == PDU_PMNS_NAMES) fprintf(f, ", numpmid=%d", trace[p].t_p2); else if (trace[p].t_p1 == PDU_PMNS_IDS) fprintf(f, ", numpmid=%d", trace[p].t_p2); else if (trace[p].t_p1 == PDU_CREDS) fprintf(f, ", numcreds=%d", trace[p].t_p2); fputc('\n', f); break; case TR_RECV_PDU: fprintf(f, "Recv: %s PDU, fd=%d, pdubuf=0x", __pmPDUTypeStr_r(trace[p].t_p1, strbuf, sizeof(strbuf)), trace[p].t_who); /* This will only work if sizeof (int) == sizeof (ptr). * On MIPS int is always 32 bits regardless the ABI, * and on Linux we're checking in configure if an int is * anything else but 32 bits, so if pointer is not * 32 bit, then .... */ #ifndef HAVE_32BIT_PTR fprintf(f, "..."); #endif fprintf(f, "%x\n", trace[p].t_p2); break; default: fprintf(f, "Type=%d who=%d p1=%d p2=%d\n", trace[p].t_type, trace[p].t_who, trace[p].t_p1, trace[p].t_p2); break; } } } else fprintf(f, "\n"); if ((_pmcd_trace_mask & TR_MASK_NOBUF) == 0) fputc('\n', f); next = 0; /* empty the circular buffer */ } pcp-3.8.12ubuntu1/src/libpcp_pmcd/src/data.c0000664000000000000000000000301412272262501015507 0ustar /* * Copyright (c) 2012 Red Hat. * Copyright (c) 1995-2001,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmcd.h" /* * Global data shared by pmcd and the pmcd PMDA DSO must reside * in a DSO as well, due to linkage oddities with Windows DLLs. */ PMCD_INTERN int pmcd_hi_openfds = -1; /* Highest open pmcd file descriptor */ PMCD_INTERN int _pmcd_done; /* flag from pmcd pmda */ PMCD_INTERN int _pmcd_timeout = 5; /* Timeout for hung agents */ PMCD_INTERN int nAgents; /* Number of active agents */ PMCD_INTERN AgentInfo *agent; /* Array of agent info structs */ PMCD_INTERN char *_pmcd_hostname; /* Explicitly requested hostname */ /* * File descriptors are used as an internal index with the advent * of NSPR in libpcp. We (may) need to first decode the index to * an internal representation and lookup the real file descriptor. * Note the use of on-stack fd overwrite, avoiding local variable. */ void pmcd_openfds_sethi(int fd) { if ((fd = __pmFD(fd)) > pmcd_hi_openfds) pmcd_hi_openfds = fd; } pcp-3.8.12ubuntu1/src/libpcp_pmcd/src/client.c0000664000000000000000000000333512272262501016062 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2001,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmcd.h" PMCD_INTERN ClientInfo *client; PMCD_INTERN int nClients; /* Number in array, (not all in use) */ PMCD_INTERN int this_client_id; void ShowClients(FILE *f) { int i; char *sbuf; char *hostName; fprintf(f, " fd client connection from ipc ver operations denied\n"); fprintf(f, " == ======================================== ======= =================\n"); for (i = 0; i < nClients; i++) { if (client[i].status.connected == 0) continue; fprintf(f, " %3d ", client[i].fd); hostName = __pmGetNameInfo(client[i].addr); if (hostName == NULL) { sbuf = __pmSockAddrToString(client[i].addr); fprintf(f, "%s", sbuf); free(sbuf); } else { fprintf(f, "%-40.40s", hostName); free(hostName); } fprintf(f, " %7d", __pmVersionIPC(client[i].fd)); if (client[i].denyOps != 0) { fprintf(f, " "); if (client[i].denyOps & PMCD_OP_FETCH) fprintf(f, "fetch "); if (client[i].denyOps & PMCD_OP_STORE) fprintf(f, "store "); } fputc('\n', f); } fputc('\n', f); } pcp-3.8.12ubuntu1/src/libpcp_pmcd/src/probes.d0000664000000000000000000000013612272262501016073 0ustar provider pcp_probe { probe PMCD_PDU(int, int, int, int); probe PMCD(int, int, int, int); }; pcp-3.8.12ubuntu1/src/libpcp_pmcd/src/GNUmakefile0000664000000000000000000000432512272262501016512 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2008 Aconex. All Rights Reserved. # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs CFILES = data.c trace.c client.c LSRCFILES = pmcd.stp.in probes.d LCFLAGS = -I$(TOPDIR)/src/pmcd/src -I$(TOPDIR)/src/libpcp/src -DPMCD_INTERNAL LLDLIBS = -lpcp ifeq "$(ENABLE_SECURE)" "true" LCFLAGS += $(NSSCFLAGS) $(NSPRCFLAGS) endif ifeq "$(ENABLE_PROBES)" "true" ifeq "$(TARGET_OS)" "linux" OBJECTS += probes.o endif LDIRT += probes.h pmcd.stp endif ifeq "$(TARGET_OS)" "mingw" LIBTARGET = libpcp_pmcd.$(DSOSUFFIX) LDIRT += libpcp_pmcd.a else STATICLIBTARGET = libpcp_pmcd.a LDIRT += libpcp_pmcd.$(DSOSUFFIX) endif default : $(LIBTARGET) $(STATICLIBTARGET) # Static probing for Linux, Mac OS X and Solaris. ifeq "$(ENABLE_PROBES)" "true" ifneq "$(findstring $(TARGET_OS),linux darwin)" "" trace.o: probes.h probes.h: probes.d pmcd.stp $(DTRACE) -h -s $< -o $@ probes.o: probes.d $(DTRACE) -G -s $< -o $@ endif ifeq "$(TARGET_OS)" "solaris" $(STATICLIBTARGET): rewrite trace.o: probes.h probes.h: probes.d $(DTRACE) -h -s $< -o $@ rewrite: trace.o $(DTRACE) -G -s probes.d trace.o touch rewrite LDIRT += rewrite endif endif pmcd.stp : pmcd.stp.in $(SED) -e 's;@path@;'$(PCP_BINADM_DIR)/pmcd';' $< > $@ include $(BUILDRULES) install : default ifeq "$(TARGET_OS)" "mingw" $(INSTALL) -m 755 $(LIBTARGET) $(PCP_LIB_DIR)/$(LIBTARGET) endif ifeq "$(ENABLE_PROBES)" "true" ifeq "$(TARGET_OS)" "linux" $(INSTALL) -m 755 -d $(PCP_SHARE_DIR)/../systemtap/tapset $(INSTALL) -m 444 pmcd.stp $(PCP_SHARE_DIR)/../systemtap/tapset/pmcd.stp endif endif default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/libpcp_pmcd/src/pmcd.stp.in0000664000000000000000000001641512272262501016523 0ustar // Performance CoPilot pmcd tapset // Copyright (C) 2013 Red Hat Inc. // // This file is part of SystemTap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General // Public License (GPL); either version 2, or (at your option) any // later version. global pmid_domain[2] global pmid_cluster[2] global pmid_item[2] global pmindom_domain[2] global pmindom_serial[2] global pdu_types[25] # from impl.h global PDU_ERROR = 0x7000 global PDU_RESULT = 0x7001 global PDU_PROFILE = 0x7002 global PDU_FETCH = 0x7003 global PDU_DESC_REQ = 0x7004 global PDU_DESC = 0x7005 global PDU_INSTANCE_REQ = 0x7006 global PDU_INSTANCE = 0x7007 global PDU_TEXT_REQ = 0x7008 global PDU_TEXT = 0x7009 global PDU_CONTROL_REQ = 0x700a global PDU_CREDS = 0x700c global PDU_PMNS_IDS = 0x700d global PDU_PMNS_NAMES = 0x700e global PDU_PMNS_CHILD = 0x700f global PDU_PMNS_TRAVERSE = 0x7010 global PDU_AUTH = 0x7011 global PDU_LOG_CONTROL = 0x8000 global PDU_LOG_STATUS = 0x8001 global PDU_LOG_REQUEST = 0x8002 global DYNAMIC_PMID = 511 global PM_INDOM_NULL = 0xffffffff global PM_ID_NULL = 0xffffffff # from pmcd.h global TR_ADD_CLIENT = 1 global TR_DEL_CLIENT = 2 global TR_ADD_AGENT = 3 global TR_DEL_AGENT = 4 global TR_EOF = 5 global TR_XMIT_PDU = 7 global TR_RECV_PDU = 8 global TR_WRONG_PDU = 9 global TR_XMIT_ERR = 10 global TR_RECV_TIMEOUT = 11 global TR_RECV_ERR = 12 # Use the same naming scheme as trace.c::tracebuf # We sadly eschew stap 2.0+ feature to make $argN more symbolic: # @define t_type %( $arg1 %) # @define t_who %( $arg2 %) # @define t_p1 %( $arg3 %) # @define t_p2 %( $arg4 %) probe begin { // [0]=bit start position [1]=bit length pmid_item[0] = 0 pmid_item[1] = 10 pmid_cluster[0] = 10 pmid_cluster[1] = 12 pmid_domain[0] = 22 pmid_domain[1] = 9 pmindom_serial[0] = 0 pmindom_serial[1] = 22 pmindom_domain[0] = 22 pmindom_domain[1] = 9 pdu_types[PDU_ERROR] = "ERROR"; pdu_types[PDU_RESULT] = "RESULT"; pdu_types[PDU_PROFILE] = "PROFILE"; pdu_types[PDU_FETCH] = "FETCH"; pdu_types[PDU_DESC_REQ] = "DESC_REQ"; pdu_types[PDU_DESC] = "DESC"; pdu_types[PDU_INSTANCE_REQ] = "INSTANCE_REQ"; pdu_types[PDU_INSTANCE] = "INSTANCE"; pdu_types[PDU_TEXT_REQ] = "TEXT_REQ"; pdu_types[PDU_TEXT] = "TEXT"; pdu_types[PDU_CONTROL_REQ] = "CONTROL_REQ"; pdu_types[PDU_CREDS] = "CREDS"; pdu_types[PDU_PMNS_IDS] = "PMNS_IDS"; pdu_types[PDU_PMNS_NAMES] = "PMNS_NAMES"; pdu_types[PDU_PMNS_CHILD] = "PMNS_CHILD"; pdu_types[PDU_PMNS_TRAVERSE] = "PMNS_TRAVERSE"; pdu_types[PDU_LOG_CONTROL] = "LOG_CONTROL"; pdu_types[PDU_LOG_STATUS] = "LOG_STATUS"; pdu_types[PDU_LOG_REQUEST] = "LOG_REQUEST"; pdu_types[PDU_AUTH] = "AUTH"; pdu_types[-1] = "NO"; } function bitextract (bits, start, length) { // HAVE_BITFIELDS_LTOR ? %( arch != "i386" && arch != "x86_64" %? // HAVE_BITFIELDS_RTOL start = 32 - start - length; %) return ((bits >> start) & ((1 << length) - 1)); } function pdu_type:string (type:long) { if (type in pdu_types) return pdu_types[type] else return sprint ("TYPE-",type,"?"); } /** * probe pmcd.* - Indicates the type of the pmcd trace * * @t_desc: Description of the trace * @t_type: Type of tracing that occurred * @t_who: File descriptor * @t_p1: Trace argument 1 * @t_p2: Trace argument 2 */ probe pmcd.add_client = process("@path@").mark("PMCD") { t_desc = "" if ($arg1 != TR_ADD_CLIENT) next t_desc = sprintf("New client: [%d]", $arg2) } probe pmcd.del_client = process("@path@").mark("PMCD") { t_desc = "" if ($arg1 != TR_DEL_CLIENT) next t_desc = sprintf("End client: fd=%d err=%d", $arg2, $arg3) } probe pmcd.add_agent = process("@path@").mark("PMCD") { t_desc = "" if ($arg1 != TR_ADD_AGENT) next t_desc = sprintf("Add PMDA: domain=%d ", $arg2) if ($arg3 == -1 && $arg4 == -1) t_desc = t_desc . "DSO" else t_desc = t_desc . sprintf("infd=%d, outfd=%d", $arg3, $arg4) } probe pmcd.del_agent = process("@path@").mark("PMCD") { t_desc = "" if ($arg1 != TR_DEL_AGENT) next t_desc = sprintf("Drop PMDA: domain=%d ", $arg2) if ($arg3 == -1 && $arg4 == -1) t_desc = t_desc . "DSO" else t_desc = t_desc . sprintf("infd=%d, outfd=%d", $arg3, $arg4) } probe pmcd.eof = process("@path@").mark("PMCD") { t_desc = "" if ($arg1 != TR_EOF) next; t_desc = sprintf("Premature EOF: expecting %s PDU, fd=%d", pdu_type($arg3), $arg2) } probe pmcd.wrong_pdu = process("@path@").mark("PMCD") { t_desc = "" if ($arg1 != TR_WRONG_PDU) next t_desc = sprintf("Wrong PDU type: expecting %s PDU, fd=%d, ", pdu_type($arg3), $arg2) if ($arg3 > 0) t_desc = t_desc . sprintf("got %s PDU", pdu_type($arg4)) else if ($arg3 == 0) t_desc = t_desc . "got EOF" else t_desc = t_desc . sprintf("got err=%d", $arg4) } probe pmcd.xmit_err = process("@path@").mark("PMCD") { t_desc = "" if ($arg1 != TR_XMIT_ERR) next t_desc = sprintf("Send %s PDU failed: fd=%d, err=%d", pdu_type($arg3), $arg2, $arg4) } probe pmcd.recv_timeout = process("@path@").mark("PMCD") { t_desc = "" if ($arg1 != TR_RECV_TIMEOUT) next t_desc = sprintf("Recv timeout: expecting %s PDU, fd=%d", pdu_type($arg3), $arg2) } probe pmcd.recv_err = process("@path@").mark("PMCD") { t_desc = "" if ($arg1 != TR_RECV_ERR) next; t_desc = sprintf("Recv error: expecting %s PDU, fd=%d, err=%d", pdu_type($arg3), $arg2, $arg4) } probe pmcd.pdu.xmit = process("@path@").mark("PMCD_PDU") { t_desc = "" if ($arg1 != TR_XMIT_PDU) next t_desc = sprintf("Xmit: %s PDU, fd=%d, ", pdu_type($arg3), $arg2) if ($arg3 == PDU_ERROR) t_desc = t_desc . sprintf(" err=%d", $arg4) else if ($arg3 == PDU_RESULT) t_desc = t_desc . sprintf("numpmid=%d", $arg4) else if ($arg3 == PDU_TEXT || $arg3 == PDU_TEXT_REQ) t_desc = t_desc . sprintf("id=%#lx", $arg4) else if ($arg3 == PDU_DESC || $arg3 == PDU_DESC_REQ) { domain = bitextract ($arg4, pmid_domain[0],pmid_domain[1]) cluster = bitextract ($arg4, pmid_cluster[0],pmid_cluster[1]) item = bitextract ($arg4, pmid_item[0],pmid_item[1]) if ($arg4 == PM_ID_NULL) t_desc = t_desc . sprintf("pmid=PM_ID_NULL") else if (domain == DYNAMIC_PMID && item == 0) t_desc = t_desc . sprintf("pmid=%d.*.*", $arg4) else t_desc = t_desc . sprintf("pmid=%d.%d.%d", domain, cluster, item) } else if ($arg3 == PDU_INSTANCE_REQ || $arg3 == PDU_INSTANCE) { domain = bitextract ($arg4, pmindom_domain[0],pmindom_domain[1]) serial = bitextract ($arg4, pmindom_serial[0],pmindom_serial[1]) if ($arg4 == PM_INDOM_NULL) t_desc = t_desc . sprintf("pmid=PM_INDOM_NULL") else t_desc = t_desc . sprintf("indom=%d.%d", domain, serial) } else if ($arg2 == PDU_PMNS_NAMES) t_desc = t_desc . sprintf("numpmid=%d", $arg4) else if ($arg2 == PDU_PMNS_IDS) t_desc = t_desc . sprintf("numpmid=%d", $arg4) else if ($arg2 == PDU_CREDS) t_desc = t_desc . sprintf("numcreds=%d", $arg4) } probe pmcd.pdu.recv = process("@path@").mark("PMCD_PDU") { t_desc = "" if ($arg1 != TR_RECV_PDU) next; t_desc = sprintf("Recv: %s PDU, fd=%d, pdubuf=%#x", pdu_type($arg3), $arg2, $arg4) } // Example Use # probe pmcd.* # { # println(t_desc) # } # probe pmcd.pdu.* # { # println(t_desc) # } pcp-3.8.12ubuntu1/src/libpcp_pmcd/GNUmakefile0000664000000000000000000000202412272262501015715 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This library is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published # by the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. # # This library is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public # License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with this library; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs LSRCFILES = GNUlocaldefs.32 SUBDIRS = src $(PCP_ALTLIBS) default install : $(SUBDIRS) $(SUBDIRS_MAKERULE) include $(BUILDRULES) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmconfig/0000775000000000000000000000000012272262620013175 5ustar pcp-3.8.12ubuntu1/src/pmconfig/pmconfig.c0000664000000000000000000000475112272262501015150 0ustar /* * Copyright (c) 2012 Red Hat. * Copyright (c) 2008 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" void env_formatter(char *var, char *prefix, char *val) { char *v; __pmNativeConfig(var, prefix, val); v = getenv(var); if (!v || v[0] == '\0') printf("%s=\n", var); else printf("%s=%s\n", var, v); } void api_formatter(const char *var, const char *val) { if (!val || val[0] == '\0') printf("%s=false\n", var); else printf("%s=%s\n", var, val); } int main(int argc, char **argv) { int c; int errflag = 0; int sflag = 0; int Lflag = 0; __pmSetProgname(argv[0]); while ((c = getopt(argc, argv, "alLs")) != EOF) { switch (c) { case 'a': /* show all, default (unmodified) list format */ case 'l': sflag = 0; break; case 's': /* show all, guarded format for shell expansion */ sflag = 1; break; case 'L': Lflag = 1; break; case '?': default: errflag++; break; } } if (errflag) { fprintf(stderr, "Usage: %s [options] [variable ...]\n\ \n\ Options:\n\ -a | -l show all, unmodified format (default)\n\ -L show library features instead of environment\n\ -s show all, quoted format for shell expansion\n", pmProgname); exit(1); } if (optind >= argc) { if (sflag) putenv("SHELL=/bin/sh"); if (Lflag) __pmAPIConfig(api_formatter); else __pmConfig(env_formatter); } else if (sflag) { putenv("SHELL=/bin/sh"); if (Lflag) for (c = optind; c < argc; c++) printf("export %s=${%s:-\"%s\"}\n", argv[c], argv[c], __pmGetAPIConfig(argv[c])); else for (c = optind; c < argc; c++) printf("export %s=${%s:-\"%s\"}\n", argv[c], argv[c], pmGetConfig(argv[c])); } else if (Lflag) for (c = optind; c < argc; c++) printf("%s=%s\n", argv[c], __pmGetAPIConfig(argv[c])); else for (c = optind; c < argc; c++) printf("%s=%s\n", argv[c], pmGetConfig(argv[c])); exit(0); } pcp-3.8.12ubuntu1/src/pmconfig/GNUmakefile0000664000000000000000000000155412272262501015252 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmconfig.c LLDLIBS = $(PCPLIB) CMDTARGET = pmconfig$(EXECSUFFIX) default: $(CMDTARGET) include $(BUILDRULES) install: $(CMDTARGET) $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/include/0000775000000000000000000000000012272262617013024 5ustar pcp-3.8.12ubuntu1/src/include/builddefs.in0000664000000000000000000004402112272262501015306 0ustar # # Copyright (c) 2012-2013 Red Hat. # Copyright (c) 2008 Aconex. All Rights Reserved. # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Common gmake macros for building # # @configure_input@ # ifndef _BUILDDEFS_INCLUDED_ _BUILDDEFS_INCLUDED_ = 1 ifndef _PCP_CONF_INCLUDED_ _PCP_CONF_INCLUDED_ = 1 include $(TOPDIR)/src/include/pcp.conf endif # General package information PACKAGE_VERSION ?= @PACKAGE_VERSION@ PACKAGE_MAJOR ?= @PACKAGE_MAJOR@ PACKAGE_MINOR ?= @PACKAGE_MINOR@ PACKAGE_REVISION ?= @PACKAGE_REVISION@ PACKAGE_BUILD ?= @PACKAGE_BUILD@ PACKAGE_NAME ?= pcp PACKAGE_CONFIGURE ?= @PACKAGE_CONFIGURE@ PACKAGE_DISTRIBUTION ?= @PACKAGE_DISTRIBUTION@ SGI_CHROOT_BUILD ?= 0 SGI_ISSP_BUILD ?= 0 BUILDRULES = $(TOPDIR)/src/include/buildrules # LCFLAGS, LLDFLAGS, LLDLIBS, LSRCFILES and LDIRT may be specified in # user Makefiles. Note: LSRCFILES is anything other than Makefile, # $(CXXFILES), $(CFILES), or $(HFILES) and is used to construct the # manifest list during the "dist" phase (packaging). # turn on all warnings by default ifeq "@cc_is_gcc@" "yes" WARN_OFF = -Wall else WARN_OFF = endif LIBPCP_ABIDIR ?= src PCPLIB_LDFLAGS = -L$(TOPDIR)/src/libpcp/$(LIBPCP_ABIDIR) \ -L$(TOPDIR)/src/libpcp_pmda/$(LIBPCP_ABIDIR) # backward compatibility PCP_LIBS = $(PCPLIB_LDFLAGS) # platform-specific CFLAGS, LDLIBS, and shared library extension # # Note: # Need PCFLAGS setting here to match the CFLAGS settings in # ../../configure.in (likewise for PLDFLAGS and LDFLAGS). # TARGET_OS = @target_os@ PCFLAGS = @PCFLAGS@ PLDFLAGS = @PLDFLAGS@ ifneq (, $(filter linux kfreebsd, $(TARGET_OS))) DSOSUFFIX = so endif ifeq "$(TARGET_OS)" "darwin" DSOSUFFIX = dylib CASE_INSENSITIVE_FS=1 endif ifeq "$(TARGET_OS)" "mingw" DSOSUFFIX = dll EXECSUFFIX = .exe SHELLSUFFIX = .sh PLDLIBS = -lwsock32 -L$$PCP_DIR/local/bin -L$$PCP_DIR/local/lib -L$$PCP_DIR/lib endif ifeq "$(TARGET_OS)" "solaris" PLDFLAGS += -fPIC PLDLIBS = -lnsl -lsocket -lresolv -ldl -lposix4 DSOSUFFIX = so endif ifeq "$(TARGET_OS)" "aix" DSOSUFFIX = so # -qcpluscmt # allow C++-style // as comment preamble # -brtl # use run-time linker # -bnoipath # do not use path to DSOs from the build, use default search path # rules # (and does not accept -Wall as a valid option) PLDFLAGS += -brtl -bnoipath WARN_OFF = endif ifeq "$(TARGET_OS)" "freebsd" DSOSUFFIX = so endif ifeq "$(TARGET_OS)" "netbsd" DSOSUFFIX = so endif CFLAGS_ABI = @cflags_abi@ CFLAGS_OPT = -O2 -g CFLAGS += $(PCFLAGS) $(LCFLAGS) $(WARN_OFF) $(CFLAGS_OPT) \ -DPCP_DEBUG -DPCP_VERSION=\"$(PCP_VERSION)\" \ -I$(TOPDIR)/src/include -I$(TOPDIR)/src/include/pcp PIECFLAGS = @PIECFLAGS@ PIELDFLAGS = @PIELDFLAGS@ INVISIBILITY = @INVISIBILITY@ # hide shared library symbols NSSCFLAGS = @NSSCFLAGS@ NSPRCFLAGS = @NSPRCFLAGS@ SASLCFLAGS = @SASLCFLAGS@ AVAHICFLAGS = @avahi_CFLAGS@ LDFLAGS += $(PLDFLAGS) $(WARN_OFF) $(PCP_LIBS) $(LLDFLAGS) SRCFILES = GNUmakefile $(HFILES) $(CFILES) $(CXXFILES) $(MFILES) \ $(LSRCFILES) $(LFILES) $(YFILES) $(PYFILES) LDLIBS = $(LLDLIBS) $(PLDLIBS) MAKEOPTS = --no-print-directory DIRT = $(LDIRT) dep dep.bak $(OBJECTS) $(CMDTARGET) $(CXXMDTARGET) \ $(LIBTARGET) $(STATICLIBTARGET) \ *.[1-9].gz *.[1-9].bz2 *.[1-9].lzma *.[1-9].xz *.[1-9].tmp DIRDIRT = $(LDIRDIRT) OBJECTS = $(ASFILES:.s=.o) \ $(CFILES:.c=.o) \ $(CXXFILES:.cxx=.o) \ $(FFILES:.f=.o) \ $(LFILES:.l=.o) \ $(YFILES:%.y=%.tab.o) #NB: don't override $(MAKE); gnumake sets it well, propagating -j etc. #MAKE = @make@ CC = @cc@ CXX = @cxx@ LD = @ld@ AWK = @awk@ SED = @sed@ CPP = @cpp@ LEX = @lex@ YACC = @yacc@ ECHO = @echo@ LN_S = @LN_S@ GREP = @grep@ GIT = @GIT@ PYTHON = @PYTHON@ DTRACE = @DTRACE@ INSTALL_SH = $(TOPDIR)/install-sh INSTALL = $(INSTALL_SH) -o $(PCP_USER_INSTALL) -g $(PCP_GROUP_INSTALL) CCF = $(CC) $(CFLAGS) CXXF = $(CXX) $(CFLAGS) $(CXXFLAGS) # NB: don't use $(MAKEF), since that suppresses gnumake's subdir parallelization #MAKEF = $(MAKE) $(MAKEOPTS) LDF = $(LD) $(LDFLAGS) MAKEDEPEND = @makedepend@ ZIP = @gzip@ BZIP2 = @bzip2@ LZMA = @lzma@ XZ = @xz@ TAR = @tar@ RPMPROG = @rpmprog@ PACKAGE_MAKER = @package_maker@ HDIUTIL = @hdiutil@ MKINSTALLP = @mkinstallp@ DLLTOOL = @dlltool@ RPMBUILD= @rpmbuild@ RPM = @rpm@ POD2MAN = @pod2man@ DPKG = @dpkg@ MAKEPKG = @makepkg@ GENPMDA = $(TOPDIR)/src/genpmda/genpmda PKGMK = @pkgmk@ MD5SUM = @md5sum@ HAVE_GZIPPED_MANPAGES = @have_gzipped_manpages@ HAVE_BZIP2ED_MANPAGES = @have_bzip2ed_manpages@ HAVE_LZMAED_MANPAGES = @have_lzmaed_manpages@ HAVE_XZED_MANPAGES = @have_xzed_manpages@ PCP_MAN_DIR = @pcp_man_dir@ NEED_OLD_TBL_HEADER = @need_old_tbl_header@ RDYNAMIC_FLAG = @rdynamic_flag@ ENABLE_SHARED = @enable_shared@ ENABLE_SECURE = @enable_secure@ ENABLE_PROBES = @enable_probes@ ENABLE_AVAHI = @enable_avahi@ # additional libraries needed for particular functions LIB_FOR_BASENAME = @lib_for_basename@ LIB_FOR_DLOPEN = @lib_for_dlopen@ LIB_FOR_REGEX = @lib_for_regex@ LIB_FOR_MATH = @lib_for_math@ LIB_FOR_READLINE = @lib_for_readline@ LIB_FOR_CURSES = @lib_for_curses@ LIB_FOR_PTHREADS = @lib_for_pthreads@ LIB_FOR_RT = @lib_for_rt@ LIB_FOR_NSS = @lib_for_nss@ LIB_FOR_NSPR = @lib_for_nspr@ LIB_FOR_SASL = @lib_for_sasl@ LIB_FOR_SSL = @lib_for_ssl@ LIB_FOR_AVAHI = @lib_for_avahi@ HAVE_LIBMICROHTTPD = @HAVE_LIBMICROHTTPD@ HAVE_RPMLIB = @HAVE_RPMLIB@ SHELL = /bin/sh IMAGES_DIR = $(TOPDIR)/all-images DIST_DIR = $(TOPDIR)/dist # env vars to be set before you can run a PCP binary in the build # environment ... needed for tools like newhelp # # default, then special case for different platforms # RUN_IN_BUILD_ENV = PCP_CONF=$(TOPDIR)/src/include/pcp.conf LD_LIBRARY_PATH=$(TOPDIR)/src/libpcp/src:$(TOPDIR)/src/libpcp_pmda/src:$$LD_LIBRARY_PATH HOME=`pwd` PCP_ALT_CPP=$(TOPDIR)/src/pmcpp/pmcpp ifeq "$(TARGET_OS)" "darwin" RUN_IN_BUILD_ENV = PCP_CONF=$(TOPDIR)/src/include/pcp.conf DYLD_LIBRARY_PATH=$(TOPDIR)/src/libpcp/src:$(TOPDIR)/src/libpcp_pmda/src:$$DYLD_LIBRARY_PATH HOME=`pwd` PCP_ALT_CPP=$(TOPDIR)/src/pmcpp/pmcpp endif ifeq "$(TARGET_OS)" "aix" RUN_IN_BUILD_ENV = PCP_CONF=$(TOPDIR)/src/include/pcp.conf LIBPATH=$(TOPDIR)/src/libpcp/src:$(TOPDIR)/src/libpcp_pmda/src:$$LIBPATH HOME=`pwd` PCP_ALT_CPP=$(TOPDIR)/src/pmcpp/pmcpp endif ifeq "$(TARGET_OS)" "mingw" RUN_IN_BUILD_ENV = PCP_CONF=$(TOPDIR)/src/include/pcp.conf PATH=$(TOPDIR)/src/libpcp/src:$(TOPDIR)/src/libpcp_pmda/src:$$PATH USERPROFILE=`pwd` PCP_ALT_CPP=`pwd`/$(TOPDIR)/src/pmcpp/pmcpp endif SUBDIRS_MAKERULE = \ +for d in `echo $^ `; do \ if test -d "$$d" -a -f "$$d/GNUmakefile"; then \ $(ECHO) === $$d ===; \ $(MAKE) $(MAKEOPTS) -C $$d $@ || exit $$?; \ fi; \ done # prepare symbols file for the GNU toolchain (linker) for DSO PMDAs VERSION_SCRIPT_MAKERULE = \ @rm -f $@; \ echo "{" >$@; \ echo " global: $(PMDAINIT);" >>$@; \ echo " local: *;" >>$@; \ echo "};" >>$@; \ # prepare domain.h used during the PMDA build process for each PMDA DOMAIN_MAKERULE = \ @rm -f $@; \ echo "/*" >$@; \ echo " * built from $<" >>$@; \ echo " */" >>$@; \ $(AWK) <$< '\ $$1=="\#define" && $$2 == "$(DOMAIN)" {\ print "\#define $(DOMAIN) " $$3 >>"$@"; found++ \ }\ END {\ if (found == 0) { \ print "Botch: no define for domain $(DOMAIN) in $<"; \ exit(1) \ }\ if (found > 1) { \ print "Botch: multiple defines for domain $(DOMAIN) in $<";\ print "... see $@ for details"; \ exit(1) \ }\ exit(0) \ }' DOMAIN_PERLRULE = \ @export perldomain=`sed -n \ -e '/PCP::PMDA->new/s/[^0-9]*$$//' \ -e '/PCP::PMDA->new/s/^[^0-9]*//p' pmda$(IAM).pl`; \ $(AWK) <$< '\ BEGIN {\ domain = toupper("$(IAM)") \ }\ $$1=="\#define" && $$2 == domain { \ pmd=$$3; found++ \ }\ END {\ if (found == 0) {\ print "Botch: no define for domain " domain " in $<"; \ exit(1) \ }\ if (found > 1) {\ print "Botch: multiple defines of domain " domain " in $<";\ exit(1) \ }\ if (pmd != "'"$$perldomain"'") {\ print "Botch: domain number in ../../pmns/stdpmid (" pmd ") does not match domain number in Perl source ("'"$$perldomain"'")"; \ exit(1) \ }\ exit(0) \ }' DOMAIN_PYTHONRULE = \ @export pythondomain=`sed -n \ -e '/PMDA(/s/[^0-9]*$$//' \ -e '/PMDA(/s/^[^0-9]*//p' $(PYSCRIPT)`; \ $(AWK) <$< '\ BEGIN {\ domain = toupper("$(IAM)") \ }\ $$1=="\#define" && $$2 == domain { \ pmd=$$3; found++ \ }\ END {\ if (found == 0) {\ print "Botch: no define for domain " domain " in $<"; \ exit(1) \ }\ if (found > 1) {\ print "Botch: multiple defines of domain " domain " in $<";\ exit(1) \ }\ if (pmd != "'"$$pythondomain"'") {\ print "Botch: domain number in ../../pmns/stdpmid (" pmd ") does not match domain number in Python source ("'"$$pythondomain"'")"; \ exit(1) \ }\ exit(0) \ }' POD_OPTIONS = --section=$(MAN_SECTION) --release=$(PCP_VERSION) \ --center="Performance Co-Pilot" --date="Performance Co-Pilot" POD_MAKERULE = $(POD2MAN) $(POD_OPTIONS) $^ $@ ifeq "$(TARGET_OS)" "mingw" INSTALL_MAN = else INSTALL_MAN = \ test -z "$$MAN_PAGES" && MAN_PAGES="$(MAN_PAGES)"; \ for d in `echo $$MAN_PAGES`; do \ echo "=== `pwd`/$$d ===" >>/tmp/eek.raw; \ first=true; \ base=`echo $$d | sed -e 's/\.[0-9]//g'`; \ $(AWK) <$$d ' \ BEGIN { state=0; print "'"$$base"'" } \ $$1==".ds" { ds["\\\\\\*\\("$$2] = $$3 } \ $$1==".SH" && $$2=="NAME" { state=1; next } \ $$1==".SH" && state==1 { exit } \ /^\./ { next } \ state==1 { for (i=1;i<=NF;i++) { \ if ($$i=="\\-" || $$i=="-") exit; \ gsub ("\\\\f3", "", $$i); gsub ("\\\\f1.*", "", $$i); \ for ( d in ds ) sub (d, ds[d], $$i); \ print $$i \ } \ }' \ | tee -a /tmp/eek.raw \ | LC_COLLATE=POSIX $(PCP_SORT_PROG) -u \ | while read m; do \ [ -z "$$m" -o "$$m" = "\\" ] && continue; \ t=$(MAN_DEST)/$$m.$(MAN_SECTION); \ if $$first; then \ _tfx= ;\ if $(NEED_OLD_TBL_HEADER) ; then \ $(SED) -e "1s/^'\\\\\"! tbl.*/'\\\\\" t/" $$d > $$d.tmp; _tfx=.tmp; \ fi; \ if $(HAVE_GZIPPED_MANPAGES) ; then \ $(ZIP) -c $$d$$_tfx > $$d.gz; _tfx=.gz; _sfx=.gz; \ fi; \ if $(HAVE_BZIP2ED_MANPAGES) ; then \ $(BZIP2) -c $$d$$_tfx > $$d.bz2; _tfx=.bz2; _sfx=.bz2; \ fi; \ if $(HAVE_LZMAED_MANPAGES) ; then \ $(LZMA) -c $$d$$_tfx > $$d.lzma; _tfx=.lzma; _sfx=.lzma; \ fi; \ if $(HAVE_XZED_MANPAGES) ; then \ $(XZ) -c $$d$$_tfx > $$d.xz; _tfx=.xz; _sfx=.xz; \ fi; \ u=$$m.$(MAN_SECTION)$$_sfx; \ echo $(INSTALL) -m 644 $${d}$$_tfx $${t}$$_sfx; \ $(INSTALL) -m 644 $${d}$$_tfx $${t}$$_sfx; \ else \ if test ! -z $(CASE_INSENSITIVE_FS) -a $(CASE_INSENSITIVE_FS); then \ if test "`echo $$u | tr 'a-z' 'A-Z'`" != "`basename $${t}$$_sfx | tr 'a-z' 'A-Z'`"; then \ echo $(INSTALL) -S $$u $${t}$$_sfx; \ $(INSTALL) -S $$u $${t}$$_sfx; \ fi \ else \ echo $(INSTALL) -S $$u $${t}$$_sfx; \ $(INSTALL) -S $$u $${t}$$_sfx; \ fi \ fi; \ first=false; \ done; \ done endif PERL_INSTALL_BASE = @perl_install_base@ PERL_INSTALLDIRS = @perl_installdirs@ # MakeMaker INSTALL_BASE needs to be unset for proper vendor_perl paths to be used for --prefix=/usr; ifeq "$(PERL_INSTALL_BASE)" "/usr" ifneq "$(TARGET_OS)" "darwin" MAKEMAKER_EXTRA_OPTIONS= else MAKEMAKER_EXTRA_OPTIONS=INSTALL_BASE=$(PERL_INSTALL_BASE) INSTALLBASE=$(PERL_INSTALL_BASE) endif else MAKEMAKER_EXTRA_OPTIONS=INSTALL_BASE=$(PERL_INSTALL_BASE) INSTALLBASE=$(PERL_INSTALL_BASE) endif PERL_MAKE_MAKEFILE = \ export PCP_TOPDIR=`cd $(TOPDIR) && pwd`; \ NSS_CFLAGS="$(NSS_CFLAGS)" NSPR_CFLAGS="$(NSPR_CFLAGS)" \ TARGET_OS="$(TARGET_OS)" CC="$(CC) $(CFLAGS_ABI)" perl Makefile.PL $(MAKEMAKER_EXTRA_OPTIONS) $(MAKEMAKER_OPTIONS) # Collect files from a Perl "make -f Makefile install" below # src/perl to build the PCP Perl packaging list, and also clean up # the installed files to remove unwanted files and make the DSO # executable # # Usage is $(call PERL_GET_FILELIST,listfile,base) # where listfile is something like $(TOPDIR)/perl-pcp-pmda.list and # base is the DSO basename like PMDA. # # We need different versions for the different installation and # packaging regimes. # ifeq "$(PACKAGE_DISTRIBUTION)" "debian" # For Debian packaging, this is not needed PERL_GET_FILELIST = else ifeq "$(PACKAGE_DISTRIBUTION)" "gentoo" # Gentoo cannot rely on the .packlist files from the install, so create # a temporary pack.list file PERL_GET_FILELIST = \ $(PERLMAKE) -f Makefile install DESTDIR=$$DIST_ROOT \ | tee pack.list; \ sed -n -e '/\.bs$$/d' -e 's/\.[0-9]pm$$/&.gz/' -e "s@^Installing $$DIST_ROOT@@p" $(1) || exit 1; \ if [ -s $(1) ]; then rm -f pack.list; \ else echo "Arrgh ... no files to include in package via $(1), see pack.list"; exit 1; \ fi; \ find $$DIST_ROOT/$(PERL_INSTALL_BASE) -name perllocal.pod -exec rm -f '{}' ';' ; \ find $$DIST_ROOT/$(PERL_INSTALL_BASE) -name \*.bs -exec rm -f '{}' ';' ; \ find $$DIST_ROOT/$(PERL_INSTALL_BASE) -name $(2).so -exec chmod 755 '{}' ';' else # Everyone else ... includes the RPM-based packaging platforms ifeq "$(PACKAGE_DISTRIBUTION)" "mandriva" man_suffix=lzma else man_suffix=gz endif PERL_GET_FILELIST = \ $(PERLMAKE) -f Makefile install DESTDIR=$$DIST_ROOT; \ find $$DIST_ROOT/$(PERL_INSTALL_BASE) -name .packlist -exec mv '{}' $(1) ';' ; \ if [ -s $(1) ] ; then \ _sfx=.gz; \ $(HAVE_BZIP2ED_MANPAGES) && _sfx=.bz2; \ $(HAVE_LZMAED_MANPAGES) && _sfx=.lzma; \ $(HAVE_XZED_MANPAGES) && _sfx=.xz; \ sed -n -e '/\.bs$$/d' -e 's/\.[0-9]pm$$/&'"$$_sfx/" -e "s@^$$DIST_ROOT@@p" $(1) >$(1).tmp; \ mv $(1).tmp $1; \ else echo "Arrgh ... no files to include in package via $(1)"; exit 1; \ fi; \ find $$DIST_ROOT/$(PERL_INSTALL_BASE) -name perllocal.pod -exec rm -f '{}' ';' ; \ find $$DIST_ROOT/$(PERL_INSTALL_BASE) -name \*.bs -exec rm -f '{}' ';' ; \ find $$DIST_ROOT/$(PERL_INSTALL_BASE) -name $(2).so -exec chmod 755 '{}' ';' endif endif # Create perl manifest files explicitly for some distributions ifeq "$(shell [ '$(PACKAGE_DISTRIBUTION)' = cocoa \ -o '$(PACKAGE_DISTRIBUTION)' = macosx \ -o '$(PACKAGE_DISTRIBUTION)' = gentoo \ -o '$(PACKAGE_DISTRIBUTION)' = solaris \ ] && echo 1)" "1" # Gather installed Perl files before packaging PERL_INSTALL = \ if [ -n "$(DIST_MANIFEST)" ]; then \ if [ "`echo $(TOPDIR)/perl-pcp-*.list`" != "$(TOPDIR)/perl-pcp-*.list" ]; then \ cat $(TOPDIR)/perl-pcp-*.list | while read f; do \ bn=`basename $$f .gz`; \ dn=`dirname $$f`; \ $(INSTALL) -d $$dn || exit 1; \ src=`find */blib -name $$bn`; \ if [ -x $$src ] ; then mode=0755; else mode=0644; fi; \ $(INSTALL) -m $$mode $$src $$dn/$$bn || exit 1; \ done; \ fi; \ fi else PERL_INSTALL = endif SYSTEMD_CFLAGS=@SYSTEMD_CFLAGS@ SYSTEMD_LIBS=@SYSTEMD_LIBS@ PMDA_SYSTEMD=@PMDA_SYSTEMD@ IB_LIBS=@IB_LIBS@ PMDA_INFINIBAND=@PMDA_INFINIBAND@ # # Python platform-specific installation quirks PYTHON_PREFIX=@python_prefix@ SETUP_PY_BUILD_OPTIONS = --include-dirs=$(TOPDIR)/src/include SETUP_PY_BUILD_OPTIONS += --library-dirs=$(TOPDIR)/src/libpcp/src:$(TOPDIR)/src/libpcp_pmda/src:$(TOPDIR)/src/libpcp_gui/src:$(TOPDIR)/src/libpcp_import/src:$(TOPDIR)/src/libpcp_mmv/src SETUP_PY_INSTALL_OPTIONS = --skip-build SETUP_PY_INSTALL_OPTIONS += --root=$${DIST_ROOT-/} SETUP_PY_INSTALL_OPTIONS += --record=$(TOPDIR)/python-pcp.list ifeq "$(PYTHON_PREFIX)" "/usr" ifeq "$(PACKAGE_DISTRIBUTION)" "debian" SETUP_PY_INSTALL_OPTIONS += --install-layout=deb endif else SETUP_PY_INSTALL_OPTIONS += --prefix=$(PYTHON_PREFIX) endif # RPM byte-compiles and installs results in our DIST_ROOT, cater for this: ifeq "$(shell [ '$(TARGET_OS)' = linux -a '$(PACKAGE_DISTRIBUTION)' != gentoo \ ] && echo 1)" "1" # Linux and not Gentoo (which needs tarball packaging) PYTHON_INSTALL = \ $(AWK) '{print} /.pyc$$/ {sub(/.pyc$$/,".pyo"); print}' \ < $(TOPDIR)/python-pcp.list > $(TOPDIR)/python-pcp.list.rpm; \ cat $(TOPDIR)/python-pcp.list.rpm | while read f; do \ touch $${DIST_ROOT-/}$$f; \ done else ifeq "$(shell [ '$(PACKAGE_DISTRIBUTION)' = cocoa \ -o '$(PACKAGE_DISTRIBUTION)' = macosx \ -o '$(PACKAGE_DISTRIBUTION)' = gentoo \ -o '$(PACKAGE_DISTRIBUTION)' = solaris \ ] && echo 1)" "1" # Gather installed Python files before packaging # Lines in python-pcp.list are like this # /usr/lib/python2.7/site-packages/pcp.py # /usr/lib/python2.7/site-packages/pcp.pyc # /usr/lib/python2.7/site-packages/pmapi.so # /usr/lib/python2.7/site-packages/pcp-0.2-py2.7.egg-info # # Matching build artifacts are below src/python/build # PYTHON_INSTALL = \ if [ -n "$(DIST_MANIFEST)" ]; then \ cat $(TOPDIR)/python-pcp.list \ | while read f; do \ bn=`basename $$f`; \ dn=`dirname $$f`; \ $(INSTALL) -d $$dn || exit 1; \ src=`find $(TOPDIR)/src/python/build -name $$bn`; \ $(INSTALL) $$src $$f || exit 1; \ done; \ fi else PYTHON_INSTALL = endif endif # # For targets that should always be rebuilt, # define a target that is never up-to-date. # Targets needing this should depend on $(_FORCE) _FORCE = __force_build PCP_USER = @pcp_user@ PCP_GROUP = @pcp_group@ PCP_USER_INSTALL = @pcp_user_install@ PCP_GROUP_INSTALL = @pcp_group_install@ PCPLIB = -lpcp ifneq "$(PCPLIB)" "$(LIB_FOR_BASENAME)" PCPLIB += $(LIB_FOR_BASENAME) endif ifeq "$(ENABLE_SHARED)" "no" PCPLIB += $(LIB_FOR_MATH) $(LIB_FOR_PTHREADS) $(LIB_FOR_DLOPEN) endif PCP_GUILIB = -lpcp_gui $(PCPLIB) PCP_PMDALIB = -lpcp_pmda $(PCPLIB) PCP_TRACELIB = -lpcp_trace $(PCPLIB) ifdef PCP_ALTLIBS ifeq ($(PCP_LIB_DIR),$(PCP_LIB32_DIR)) PCP_ALTLIBS = else ifneq "$(findstring $(MAKECMDGOALS),clean clobber src-pcp)" "" PCP_ALTLIBS = endif endif endif BUILD_PMMGR=@BUILD_PMMGR@ endif # _BUILDDEFS_INCLUDED_ pcp-3.8.12ubuntu1/src/include/pcp.mingw0000664000000000000000000000454412272262501014650 0ustar # # Copyright (c) 2000,2003 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2010 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # This file is sourced by PCP scripts to set the environment # variables defined in the file named $PCP_CONF (or /etc/pcp.conf # if $PCP_CONF is not defined). Any variable already defined in # the environment is not changed. # # Note: any variables NOT starting with PCP_ will be ignored. # This is a security issue so don't change it. # Note also, this variant of pcp.env is *only* used on Windows. # if [ -z "$PCP_ENV_DONE" ] then __CONF=${PCP_CONF-/etc/pcp.conf} if [ ! -f "$__CONF" ] then echo "pcp.env: Fatal Error: \"$__CONF\" not found" >&2 exit 1 fi export PCP_DIR=/c/MinGW/sys/1.0 export PCP_CONF=$PCP_DIR/etc/pcp.conf eval export `PATH=/lib:$PATH $PCP_DIR/bin/pmconfig.exe -s` export PATH="/sbin:/bin:/lib:/etc:${PCP_BIN_DIR}:${PCP_BINADM_DIR}:${PCP_SHARE_DIR}/bin:${PCP_SHARE_DIR}/lib:${PCP_PLATFORM_PATHS}" export PCP_ENV_DONE=y fi mkaf() { mkaf.sh $@ } pmafm() { pmafm.sh $@ } pmsignal() { pmsignal.sh $@ } _get_pids_by_name() { if [ $# -ne 1 ] then echo "Usage: _get_pids_by_name process-name" >&2 exit 1 fi # Algorithm ... all ps(1) variants have a time of the form MM:SS # or HH:MM:SS or HH:MM.SS before the psargs field, so we're using # this as the search anchor. # # Matches with $1 (process-name) occur if the first psarg is $1 # or ends in /$1 ... the matching uses sed's regular expressions, # so passing a regex into $1 will work. $PCP_PS_PROG $PCP_PS_ALL_FLAGS \ | sed -n \ -e 's/$/ /' \ -e 's/[ ][ ]*/ /g' \ -e 's/^ //' \ -e 's/^[^ ]* //' \ -e "/[0-9][:\.][0-9][0-9] *[^ ]*\\$1\.exe /s/ .*//p" \ -e "/[0-9][:\.][0-9][0-9] *[^ ]*\/$1 /s/ .*//p" \ -e "/[0-9][:\.][0-9][0-9] *$1\.exe /s/ .*//p" \ -e "/[0-9][:\.][0-9][0-9] *$1 /s/ .*//p" } pcp-3.8.12ubuntu1/src/include/buildrules0000664000000000000000000001255712272262501015123 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Common build rules for gmake # ifndef _BUILDRULES_INCLUDED_ _BUILDRULES_INCLUDED_ = 1 ifndef _BUILDDEFS_INCLUDED_ include $(TOPDIR)/src/include/builddefs endif # # Standard targets # ifdef CMDTARGET $(CMDTARGET) : $(SUBDIRS) $(OBJECTS) $(CCF) -o $(CMDTARGET) $(LDFLAGS) $(OBJECTS) $(LDLIBS) endif ifdef CXXMDTARGET $(CXXMDTARGET) : $(SUBDIRS) $(OBJECTS) $(CXXF) -o $(CXXMDTARGET) $(LDFLAGS) $(OBJECTS) $(LDLIBS) endif # GNU make has a built-in recipe for .cc / .C / .cpp, but not for .cxx -> .o .cxx.o: $(CXXF) $(CXXFLAGS) -c $< -o $@ .SUFFIXES: .cxx ifdef LIBTARGET ifneq (, $(filter linux freebsd kfreebsd netbsd mingw, $(TARGET_OS))) _SHAREDOPTS = -shared -Wl,-soname,$(LIBTARGET) endif ifeq ($(TARGET_OS), solaris) _SHAREDOPTS = -shared -fpic endif ifeq ($(TARGET_OS), darwin) # libtool doesnt understand -dynamiclib so we need both _SHAREDOPTS = -fPIC -dynamic -dynamiclib -flat_namespace -undefined suppress -headerpad_max_install_names -arch i386 ifeq ($(PACKAGE_DISTRIBUTION), cocoa) _SHAREDOPTS += -arch x86_64 endif endif ifeq ($(TARGET_OS), aix) _SHAREDOPTS = -qmkshrobj endif ifdef VERSION_SCRIPT ifneq ($(INVISIBILITY),) ifeq ($(TARGET_OS), darwin) # Mac OS X ld(1) takes a different format for the symbols file # _SHAREDOPTS += -Wl,-exported_symbols_list $(VERSION_SCRIPT) else _SHAREDOPTS += -Wl,--version-script=$(VERSION_SCRIPT) endif endif endif $(LIBTARGET) : $(SUBDIRS) $(OBJECTS) $(CC) $(LDFLAGS) $(_SHAREDOPTS) -o $(LIBTARGET) $(OBJECTS) $(LDLIBS) $(LIB_FOR_DLOPEN) $(LIB_FOR_BASENAME) endif ifdef STATICLIBTARGET $(STATICLIBTARGET) : $(SUBDIRS) $(OBJECTS) ifeq ($(TARGET_OS), darwin) libtool -static -o $(STATICLIBTARGET) $? else $(AR) cr $(STATICLIBTARGET) $? endif endif # Suffix rule to support transition for YFILES to OBJECTS %.tab.h : %.y $(YACC) -d -b `basename $< .y` $< %.tab.c : %.y $(YACC) -d -b `basename $< .y` $< # Dealing with quirks of the various packaging mechanisms %.py: %.python $(LN_S) $< $@ %.pl: %.perl $(LN_S) $< $@ ifeq ($(TARGET_OS), mingw) # # .exe rule for Windows # .SUFFIXES: .exe .o.exe: $(CCF) -o $* $(LDFLAGS) $(OBJECTS) $(LDLIBS) endif clean clobber :: $(SUBDIRS) $(PRO_SUBDIRS) $(SNIA_SUBDIRS) rm -rf $(DIRT) @rm -fr $(DIRDIRT) $(SUBDIRS_MAKERULE) realclean distclean: clean rm -f $(TOPDIR)/src/include/builddefs \ $(TOPDIR)/src/include/pcp.conf \ $(TOPDIR)/src/include/pcp/config.h \ $(TOPDIR)/src/include/pcp/platform_defs.h \ $(TOPDIR)/src/include/pcp/pmdbg.h rm -f $(TOPDIR)/build/GNUlocaldefs rm -f $(TOPDIR)/pcp.lsm # # Never blow away subdirs # ifdef SUBDIRS .PRECIOUS: $(SUBDIRS) endif src-pcp : $(SRCFILES) $(SUBDIRS) @test ! -z "$$SRC_ROOT" || ( echo '$$SRC_ROOT not set ... bozo!' ; echo "... generally unsafe to run make src-pcp outside the Makepkgs script"; exit 1 ) @test -z "$$DIR" && DIR="."; \ for f in `echo $^`; do \ if test -d $$f ; then \ $(MAKE) $(MAKEOPTS) -j 1 DIR=$$DIR/$$f -C $$f $@ || exit $$?; \ else \ $(ECHO) $$DIR/$$f; \ fi; \ done src-link-pcp : $(SRCFILES) $(CONFFILES) $(SUBDIRS) @test ! -z "$$SRCLINK_ROOT" || ( echo '$$SRCLINK_ROOT not set ... bozo!' ; echo "... generally unsafe to run make src-link-pcp outside the Makepkgs script"; exit 1 ) @test -z "$$DIR" && DIR="."; \ for f in `echo $^`; do \ if test -d $$f ; then \ echo "=== $$DIR/$$f ==="; \ mkdir $$SRCLINK_ROOT/$$DIR/$$f || exit $$?; \ $(MAKE) $(MAKEOPTS) -j 1 DIR=$$DIR/$$f -C $$f $@ || exit $$?; \ else \ ln $$f $$SRCLINK_ROOT/$$DIR/$$f || exit $$?; \ fi; \ done endif $(_FORCE): # The depend target does not depend on any other targets (even though it # actually depends on CFILES and HFILES). This is because there are several # places where we generate header files (e.g. domain.h is generated for each # subdir below src/pmdas, and domain.h in turn depends on src/pmns/stdpmid, # which itself a generated file ...). As a result, you can't run make # depend after make clobber, because the generated files will be missing. # # So running makedepend is for development use when you change a header # somewhere and you need to be sure everything that depends on that header # will be remade properly. .PHONY : depend $(_FORCE) depend : $(SUBDIRS) $(SUBDIRS_MAKERULE) touch dep $(MAKEDEPEND) -fdep -- $(CFLAGS) -- $(CFILES) # # include dep, but only if it exists -include dep # Support for building multiple versions of the same library ifneq ($(PCP_ALTLIBS),) $(PCP_ALTLIBS): rm -rf $@ mkdir $@ cp GNUlocaldefs.$@ $@/GNUlocaldefs $(MAKE) -C src SLDEST=../$@ SLSRC=../src libsrc_symlinks endif libsrc_symlinks: test -n "$(SLDEST)" -a -d $(SLDEST) for f in $(SRCFILES); do \ if [ -e $(SLDEST)/$$f -a ! -L $(SLDEST)/$$f ] ; then \ echo "$$f exists in $(SLDEST) and not a symlink"; exit 1; \ fi; \ rm -f $(SLDEST)/$$f; $(LN_S) $(SLSRC)/$$f $(SLDEST)/$$f || exit 1; \ done pcp-3.8.12ubuntu1/src/include/pcp.env0000664000000000000000000000533612272262501014317 0ustar # # Copyright (c) 2000,2003 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2010 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # This file is sourced by PCP scripts to set the environment # variables defined in the file named $PCP_CONF (or /etc/pcp.conf # if $PCP_CONF is not defined). Any variable already defined in # the environment is not changed. # # Note: any variables NOT starting with PCP_ will be ignored. # This is a security issue so don't change it. # Note also, this (variant of this) file is not used on Windows. # if [ -z "$PCP_ENV_DONE" ] then if [ -n "$PCP_CONF" ] then __CONF="$PCP_CONF" elif [ -n "$PCP_DIR" ] then __CONF="$PCP_DIR/etc/pcp.conf" else __CONF=/etc/pcp.conf fi if [ ! -f "$__CONF" ] then echo "pcp.env: Fatal Error: \"$__CONF\" not found" >&2 exit 1 fi eval `sed -e 's/"//g' $__CONF \ | awk -F= ' /^PCP_/ && NF == 2 { exports=exports" "$1 printf "%s=${%s:-\"%s\"}\n", $1, $1, $2 } END { print "export", exports }'` export PCP_ENV_DONE=y fi # Always need to set $PATH ... sudo -E leaves $PCP_ENV_DONE set, but # clears/resets $PATH. Note that order is important: any paths with # pcp-specific binaries should end up ahead of more generic paths in # the final $PATH to avoid conflicts on names of non-pcp binaries. # for dir in ${PCP_BIN_DIR} ${PCP_PLATFORM_PATHS} ${PCP_BINADM_DIR} \ ${PCP_SHARE_DIR}/bin ${PCP_SHARE_DIR}/lib /usr/gnu/bin do if [ -d $dir ] then if echo ":$PATH:" | grep ":$dir:" >/dev/null 2>&1 then : else PATH="$dir:$PATH" fi fi done export PATH _get_pids_by_name() { if [ $# -ne 1 ] then echo "Usage: _get_pids_by_name process-name" >&2 exit 1 fi # Algorithm ... all ps(1) variants have a time of the form MM:SS # or HH:MM:SS or HH:MM.SS before the psargs field, so we're using # this as the search anchor. # # Matches with $1 (process-name) occur if the first psarg is $1 # or ends in /$1 ... the matching uses sed's regular expressions, # so passing a regex into $1 will work. $PCP_PS_PROG $PCP_PS_ALL_FLAGS \ | sed -n \ -e 's/$/ /' \ -e 's/[ ][ ]*/ /g' \ -e 's/^ //' \ -e 's/^[^ ]* //' \ -e "/[0-9][:\.][0-9][0-9] *[^ ]*\/$1 /s/ .*//p" \ -e "/[0-9][:\.][0-9][0-9] *$1 /s/ .*//p" } pcp-3.8.12ubuntu1/src/include/pcp.conf.in0000664000000000000000000001365012272262501015057 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000-2001,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # This file defines the directories and paths used by PCP # and is installed as the file /etc/pcp.conf for use at run-time. # # Note: the syntax of this file must allow processing to generate # correct variable assignments for both sh and make, # hence there should be no spaces immediately before or after # the equals in each assignment, no quoting on the right of the # equals although the value may contain embedded spaces. # # Shell scripts should never source this file directly, rather they # should use this file indirectly by sourcing /etc/pcp.env, i.e. # . $PCP_DIR/etc/pcp.env # this will handle the quoting and white space issues and set all # "variables" beginning with PCP_ in this file into the environment. # The defaults may be over-ridden by setting $PCP_CONF in the environment # as the full path to an alternate version of this file. # # The "standard paths" reflect the directory structure that is used by # default on the platform on which this file is installed. # # directory for _this_ file ... useful in the build # Standard path: /etc PCP_ETC_DIR=@pcp_etc_dir@ # directory for PCP configuration files # Standard path: /etc/pcp PCP_SYSCONF_DIR=@pcp_sysconf_dir@ # directory for rc/startup scripts # Standard path: /etc/init.d PCP_RC_DIR=@pcp_rc_dir@ # directory for sysconfig controls # Standard path: /etc/sysconf (Redhat-specific) # if no sysconfig support PCP_SYSCONFIG_DIR=@pcp_sysconfig_dir@ # directory for public binaries # Standard path: /usr/bin PCP_BIN_DIR=@pcp_bin_dir@ # directory for private PCP binaries (not run directly by users) # Standard path is platform dependent, but generally one of # /usr/libexec/pcp/bin or /usr/lib/pcp/bin or /usr/share/pcp/bin PCP_BINADM_DIR=@pcp_binadm_dir@ # directory for runtime shared libraries, libpcp.so, etc. # Standard path: /usr/lib PCP_LIB_DIR=@pcp_lib_dir@ PCP_LIB32_DIR=@pcp_lib32_dir@ # directory for shared PCP files (shareable for diskless) # Standard path: /usr/share/pcp # Subdirectories: bin lib PCP_SHARE_DIR=@pcp_share_dir@ # directory for headers # Standard path: /usr/include/pcp PCP_INC_DIR=@pcp_inc_dir@ # parent directory of man pages # Standard path: /usr/man # Subdirectories: man1 man3 man5 PCP_MAN_DIR=@pcp_man_dir@ # directory for non-shared (i.e. system local) PCP files # Standard path: /var/lib/pcp # Subdirectories: config pmns (note see $PCP_PMDAS_DIR) for pmdas PCP_VAR_DIR=@pcp_var_dir@ # path to pmcd config file # Standard path: $PCP_SYSCONF_DIR/pmcd/pmcd.conf PCP_PMCDCONF_PATH=@pcp_pmcdconf_path@ # path to pmcd options file # Standard path: $PCP_SYSCONF_DIR/pmcd/pmcd.options PCP_PMCDOPTIONS_PATH=@pcp_pmcdoptions_path@ # path to site-local pmcd startup script # Standard path: $PCP_SYSCONF_DIR/pmcd/rc.local PCP_PMCDRCLOCAL_PATH=@pcp_pmcdrclocal_path@ # path to pmproxy options file # Standard path: $PCP_SYSCONF_DIR/pmproxy/pmproxy.options PCP_PMPROXYOPTIONS_PATH=@pcp_pmproxyoptions_path@ # path to pmwebd options file # Standard path: $PCP_SYSCONF_DIR/pmwebd/pmwebd.options PCP_PMWEBDOPTIONS_PATH=@pcp_pmwebdoptions_path@ # path to pmmgr options file # Standard path: $PCP_SYSCONF_DIR/pmmgr/pmmgr.options PCP_PMMGROPTIONS_PATH=@pcp_pmmgroptions_path@ # path to pmie control file # Standard path: $PCP_SYSCONF_DIR/pmie/control PCP_PMIECONTROL_PATH=@pcp_pmiecontrol_path@ # path to pmsnap control file # Standard path: $PCP_SYSCONF_DIR/pmsnap/control PCP_PMSNAPCONTROL_PATH=@pcp_pmsnapcontrol_path@ # path to pmlogger control file # Standard path: $PCP_SYSCONF_DIR/pmlogger/control PCP_PMLOGGERCONTROL_PATH=@pcp_pmloggercontrol_path@ # directory for PCP PMDAs # Standard path: /var/lib/pcp/pmdas # Subdirectories: one per PMDA PCP_PMDAS_DIR=@pcp_pmdas_dir@ # directory for PCP pid files # Standard path: /var/run/pcp PCP_RUN_DIR=@pcp_run_dir@ # directory for PCP logs # Standard path: /var/log/pcp # Subdirectories: pmcd pmlogger pmie PCP_LOG_DIR=@pcp_log_dir@ # directory for PCP temp status files # Standard path: /var/lib/pcp/tmp # Subdirectories: pmie pmlogger PCP_TMP_DIR=@pcp_tmp_dir@ # directory for PCP temp work files # Standard path: /var/tmp PCP_TMPFILE_DIR=@pcp_tmpfile_dir@ # directory for PCP documentation # Standard path: /usr/share/doc/pcp # Subdirectories: Tutorial pcpweb ... PCP_DOC_DIR=@pcp_doc_dir@ # directory for PCP demos and examples # Standard path: /usr/share/pcp/demos # Subdirectories: assorted PCP_DEMOS_DIR=@pcp_demos_dir@ # awk PCP_AWK_PROG="@awk@" # unix-like sort PCP_SORT_PROG=@sort@ # tools needed to rebuild things on the target platform PCP_MAKE_PROG=@make@ PCP_CC_PROG="@cc@ @cflags_abi@" # echo # for lines without newline, use # $PCP_ECHO_PROG $PCP_ECHO_N "string""$PCP_ECHO_C" PCP_ECHO_PROG=@echo@ PCP_ECHO_N=@echo_n@ PCP_ECHO_C=@echo_c@ # write to the system log PCP_SYSLOG_PROG=@pcp_syslog_prog@ # running process list PCP_PS_PROG=@pcp_ps_prog@ PCP_PS_HAVE_BSD=@pcp_ps_have_bsd@ PCP_PS_ALL_FLAGS=@pcp_ps_all_flags@ # locate executables PCP_WHICH_PROG=@which@ # host operating system PCP_PLATFORM=@target_os@ PCP_PLATFORM_PATHS=@pcp_platform_paths@ # PCP version PCP_VERSION=@PACKAGE_VERSION@ # confirmation dialog PCP_XCONFIRM_PROG=@ac_xconfirm_prog@ # mpi PCP_MPI_DIRS=@pcp_mpi_dirs@ # default account for running daemons (preferably unprivileged) # Standard user: "pcp" and group: "pcp" PCP_USER=@pcp_user@ PCP_GROUP=@pcp_group@ # directory for SASL configuration files # Standard path: /etc/sasl2 PCP_SASLCONF_DIR=@pcp_saslconf_dir@ pcp-3.8.12ubuntu1/src/include/GNUmakefile0000664000000000000000000000360112272262501015066 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs CONFFILES = builddefs pcp.conf LSRCFILES = builddefs.in buildrules \ pcp.conf.in pcp.env pcp.mingw LDIRT = builddefs.install SUBDIRS = pcp default :: default_pcp default_pcp : $(SUBDIRS) pcp.conf builddefs.install $(SUBDIRS_MAKERULE) include $(BUILDRULES) install :: default_pcp install_pcp install_pcp : $(SUBDIRS) default_pcp $(INSTALL) -m 644 pcp.conf $(PCP_ETC_DIR)/pcp.conf ifeq "$(TARGET_OS)" "mingw" $(INSTALL) -m 644 pcp.mingw $(PCP_ETC_DIR)/pcp.env else $(INSTALL) -m 644 pcp.env $(PCP_ETC_DIR)/pcp.env endif $(INSTALL) -m 644 buildrules $(PCP_INC_DIR)/buildrules $(INSTALL) -m 644 builddefs.install $(PCP_INC_DIR)/builddefs $(SUBDIRS_MAKERULE) builddefs.install : builddefs sed -e 's;^include .*pcp.conf;include $$(PCP_DIR)/etc/pcp.conf;' \ -e 's;^BUILDRULES.*=.*buildrules;BUILDRULES = $$\(PCP_INC_DIR\)/buildrules;' \ -e 's;^INSTALL_SH.*=.*install-sh;INSTALL_SH = $$\(PCP_BINADM_DIR\)/install-sh;' \ -e 's;^GENPMDA.*=.*genpmda;GENPMDA = $$\(PCP_BIN_DIR\)/genpmda;' \ < builddefs > builddefs.install pcp-3.8.12ubuntu1/src/include/pcp/0000775000000000000000000000000012272262617013606 5ustar pcp-3.8.12ubuntu1/src/include/pcp/config.h.in0000664000000000000000000003573412272262501015635 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2003 Moser, Inc. All Rights Reserved. * Copyright (c) 2000-2004,2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _PCP_CONFIG_H #define _PCP_CONFIG_H #ifdef __cplusplus extern "C" { #endif #include /* * The type of timestamps in struct stat: either HAVE_STAT_TIMESPEC, * HAVE_STAT_TIMESPEC_T, HAVE_STAT_TIMESTRUC or HAVE_STAT_TIME_T */ #undef HAVE_STAT_TIMESPEC_T #undef HAVE_STAT_TIMESTRUC #undef HAVE_STAT_TIMESPEC #undef HAVE_STAT_TIME_T /* HAVE_ST_MTIME if stat.st_mtime has a ``spec'' on the end */ #undef HAVE_ST_MTIME_WITH_SPEC /* HAVE_ST_MTIME if stat.st_mtime has an ``e'' on the end */ #undef HAVE_ST_MTIME_WITH_E /* if your compiler supports LL sufix on 64 bit int constants */ #undef HAVE_CONST_LONGLONG /* * HAVE_UNDERBAR_ENVIRON if extern char **_environ is defined * (else extern char **environ will be used) */ #undef HAVE_UNDERBAR_ENVIRON /* * If the pointer-to-function arguments to scandir() * are (*scanfn)(const struct dirent *dep) * Otherwise ``const'' will be omitted. */ #undef HAVE_CONST_DIRENT /* * If the dirent structure contains a directory offset field. */ #undef HAVE_DIRENT_D_OFF /* * If getopt() needs $POSIXLY_CORRECT set in the environment to work * correctly, specifically to not treat -x as an option when foo is * invoked with the arguments "arg -x" */ #undef HAVE_GETOPT_NEEDS_POSIXLY_CORRECT /* Defined if printf %p -> 0x prefix for value */ #undef HAVE_PRINTF_P_PFX #ifdef HAVE_PRINTF_P_PFX #define PRINTF_P_PFX "" #else #define PRINTF_P_PFX "0x" #endif /* Defined if bit fields are allocated left-to-right within a word */ #undef HAVE_BITFIELDS_LTOR /* if compiler can cast __uint64_t to double */ #undef HAVE_CAST_U64_DOUBLE /* long and pointer must be either 32 bit or 64 bit */ #undef HAVE_64BIT_LONG #undef HAVE_32BIT_LONG #undef HAVE_32BIT_PTR #undef HAVE_64BIT_PTR /* Define if header file is available */ #undef HAVE_FCNTL_H #undef HAVE_LIMITS_H #undef HAVE_MALLOC_H #undef HAVE_STRINGS_H #undef HAVE_SYSLOG_H #undef HAVE_UNISTD_H #undef HAVE_STDDEF_H #undef HAVE_SCHED_H #undef HAVE_DLFCN_H #undef HAVE_DL_H #undef HAVE_SYS_TIME_H #undef HAVE_SYS_TIMEB_H #undef HAVE_SYS_TIMES_H #undef HAVE_SYS_SYSINFO_H #undef HAVE_SYS_SYSTEMINFO_H #undef HAVE_SYS_RESOURCE_H #undef HAVE_SYS_PRCTL_H #undef HAVE_ENDIAN_H #undef HAVE_STANDARDS_H #undef HAVE_SYS_BYTEORDER_H #undef HAVE_PTHREAD_H #undef HAVE_GETOPT_H #undef HAVE_LIBGEN_H #undef HAVE_SYS_PARAM_H #undef HAVE_SYS_MMAN_H #undef HAVE_SYS_UN_H #undef HAVE_STDINT_H #undef HAVE_VALUES_H #undef HAVE_IEEEFP_H #undef HAVE_MATH_H #undef HAVE_PWD_H #undef HAVE_GRP_H #undef HAVE_REGEX_H #undef HAVE_TERMIO_H #undef HAVE_TERMIOS_H #undef HAVE_SYS_TERMIOS_H #undef HAVE_SYS_IOCTL_H #undef HAVE_SYS_WAIT_H #undef HAVE_WINDOWS_H #undef HAVE_WINSOCK2_H #undef HAVE_WS2TCPIP_H #undef HAVE_EXECINFO_H #undef HAVE_IPTYPES_H #undef HAVE_NETDB_H #undef HAVE_SYS_SOCKET_H #undef HAVE_NETINET_IN_H #undef HAVE_NETINET_TCP_H #undef HAVE_ARPA_INET_H #undef HAVE_SYS_ENDIAN_H #undef HAVE_SYS_MACHINE_H #undef HAVE_MACHINE_ENDIAN_H #undef HAVE_AI_ADDRCONFIG #if defined(HAVE_MALLOC_H) #include #endif #if defined(HAVE_STDDEF_H) #include #endif #if defined(HAVE_SYSLOG_H) #include #endif #if defined(HAVE_WINDOWS_H) #include #endif #if defined(HAVE_WINSOCK2_H) #include #endif #if defined(HAVE_WS2TCPIP_H) #include #endif #if defined(HAVE_SYS_TIMEB_H) #include #endif /* HAVE_NETWORK_BYTEORDER for big endian systems (not Intel) */ #if defined(HAVE_ENDIAN_H) #include #elif defined(HAVE_SYS_ENDIAN_H) #include #elif defined(HAVE_MACHINE_ENDIAN_H) #include #endif #if defined(HAVE_ENDIAN_H) || defined(HAVE_SYS_ENDIAN_H) || defined(HAVE_MACHINE_ENDIAN_H) #if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN #define HAVE_NETWORK_BYTEORDER #endif #endif #if defined(HAVE_SYS_BYTEORDER_H) #include #if defined(_BIG_ENDIAN) #define HAVE_NETWORK_BYTEORDER #endif #endif #if defined(HAVE_SYS_MACHINE_H) #include #if defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN #define HAVE_NETWORK_BYTEORDER #endif #endif /* define which libraries are available */ #undef HAVE_SECURE_SOCKETS #undef HAVE_STATIC_PROBES #undef HAVE_SERVICE_DISCOVERY #undef HAVE_AVAHI #undef HAVE_LIBREGEX #undef HAVE_READLINE /* define which libc functions are available */ #undef HAVE_WAIT3 #undef HAVE_MKTIME #undef HAVE_UNSETENV #undef HAVE_SELECT #undef HAVE_SOCKET #undef HAVE_GETHOSTNAME #undef HAVE_GETPEERUCRED #undef HAVE_GETPEEREID #undef HAVE_UNAME #undef HAVE_SYSLOG #undef HAVE___CLONE #undef HAVE_PIPE2 #undef HAVE_FCNTL #undef HAVE_PRCTL #undef HAVE_SETLINEBUF #undef HAVE_WAITPID #undef HAVE_ATEXIT #undef HAVE_KILL #undef HAVE_CHOWN #undef HAVE_GETCWD #undef HAVE_SCANDIR #undef HAVE_MKSTEMP #undef HAVE_GETGRENT #undef HAVE_GETGRENT_R #undef HAVE_GETGRNAM #undef HAVE_GETGRNAM_R #undef HAVE_GETGRGID #undef HAVE_GETGRGID_R #undef HAVE_GETPWENT #undef HAVE_GETPWENT_R #undef HAVE_GETPWNAM #undef HAVE_GETPWNAM_R #undef HAVE_GETPWUID #undef HAVE_GETPWUID_R #undef HAVE_BRK #undef HAVE_SBRK #undef HAVE_POSIX_MEMALIGN #undef HAVE_MEMALIGN #undef HAVE_VALLOC #undef HAVE_NANOSLEEP #undef HAVE_USLEEP #undef HAVE_SIGNAL #undef HAVE_SIGHOLD #undef HAVE_SIGRELSE #undef HAVE_TCGETATTR #undef GWINSZ_IN_SYS_IOCTL #undef HAVE_REGEX #undef HAVE_REGCMP #undef HAVE_REGEXEC #undef HAVE_REGCOMP #undef HAVE_STRTOD #undef HAVE_STRTOL #undef HAVE_STRTOLL #undef HAVE_STRTOULL #undef HAVE_STRNDUP #undef HAVE_DLOPEN #undef HAVE_FPCLASSIFY #undef HAVE_ISNAN #undef HAVE_ISNANF #undef HAVE_FLOG10 #undef HAVE_POW #undef HAVE_DIRNAME #undef HAVE_BASENAME #undef HAVE_SYSINFO #undef HAVE_TRACE_BACK_STACK #undef HAVE_BACKTRACE #undef HAVE_READDIR64 /* if termio signals are supported */ #ifdef HAVE_TERMIOS_H #ifdef HAVE_TCGETATTR #define HAVE_TERMIO_SIGNALS #endif #endif /* if the /proc pseudo filesystem exists */ #undef HAVE_PROCFS /* Infiniband API version information */ #undef HAVE_PORT_PERFORMANCE_QUERY_VIA #ifndef ULONGLONG_MAX #define ULONGLONG_MAX (__uint64_t)18446744073709551615ULL #endif #ifndef LONGLONG_MAX #define LONGLONG_MAX (__int64_t)9223372036854775807LL #endif /* some types only known by some compilers */ #undef uint_t #undef __int32_t #undef __uint32_t #undef __int64_t #undef __uint64_t /* Check if __psint_t is set to something meaningful */ #undef HAVE___PSINT_T #ifndef HAVE___PSINT_T #ifdef HAVE_32BIT_PTR typedef int __psint_t; #elif defined HAVE_64BIT_PTR #ifdef HAVE_64BIT_LONG typedef long __psint_t; #else /* This is a very strange architecture, which has 64 bit pointers but * not 64 bit longs. So, I'd just punt here and assume long long is Ok */ typedef long long __psint_t; #endif #else #error Unknown pointer size - not 32 and not 64 #endif #endif /* Check if ptrdiff_t type is available */ #undef HAVE_PTRDIFF_T #ifndef HAVE_PTRDIFF_T #define ptrdiff_t long #endif /* * User and group accounts - POSIX uid_t/gid_t combo or Win32 SID */ #undef HAVE_UID_T #undef HAVE_GID_T #undef HAVE_SID #if defined(HAVE_UID_T) && defined(HAVE_GID_T) typedef uid_t __pmUserID; typedef gid_t __pmGroupID; #elif defined(HAVE_SID) typedef SID __pmUserID; typedef SID __pmGroupID; #else bozo! unclear how to represent users and groups for this platform #endif /* * socklen_t is not always defined, so use __pmSockLen abstraction */ #undef HAVE_SOCKLEN_T #ifdef HAVE_SOCKLEN_T #include #include typedef socklen_t __pmSockLen; #else typedef int __pmSockLen; #endif /* * MAXNAMELEN hides in may places and may have alias names ... */ #ifndef MAXNAMELEN #include #ifdef HAVE_SYS_PARAM_H #include #endif #if !defined(MAXNAMELEN) && defined(FILENAME_MAX) /* posix version of the bsd MAXNAMELEN macro */ #define MAXNAMELEN FILENAME_MAX #endif #endif #ifndef MAXNAMELEN bozo! need to find where MAXNAMELEN is defined for this platform #endif /* * MAXPATHLEN hides in many places and may have alias names ... */ #ifndef MAXPATHLEN #ifdef HAVE_SYS_PARAM_H #include #endif #ifdef HAVE_LIMITS_H #include #endif #if !defined(MAXPATHLEN) && defined(PATH_MAX) /* posix version of the bsd MAXPATHLEN macro */ #define MAXPATHLEN PATH_MAX #endif #endif #ifndef MAXPATHLEN bozo! need to find where MAXPATHLEN is defined for this platform #endif /* * MAXHOSTNAMELEN hides in many places and may also have aliases ... */ #ifndef MAXHOSTNAMELEN #ifdef HAVE_SYS_PARAM_H #include #endif #endif #ifndef MAXHOSTNAMELEN #ifdef HAVE_LIMITS_H #include #endif #endif #ifndef MAXHOSTNAMELEN #ifdef HAVE_NETDB_H #include #endif #endif #ifndef MAXHOSTNAMELEN #ifdef HAVE_IPTYPES_H #include #define MAXHOSTNAMELEN MAX_HOSTNAME_LEN #endif #endif #ifndef MAXHOSTNAMELEN bozo! need to find where MAXHOSTNAMELEN is defined for this platform #endif #ifndef HAVE_FLOG10 #if !defined(flog10) #define flog10(x) (float)log10((double)x) #endif #endif #if !defined(WORD_BIT) #define WORD_BIT 32 #endif #undef RETSIGTYPE #ifndef RETSIGTYPE #define RETSIGTYPE void #endif #undef HAVE_SIGPF #ifndef HAVE_SIGPF /* The return type of signal() */ typedef void (*SIG_PF) (int); #endif #undef HAVE_SA_SIGINFO #undef HAVE_SIGPIPE #undef HAVE_SIGHUP #undef HAVE_WAIT_INCLUDES_SIGNAL #ifndef HAVE_WAIT_INCLUDES_SIGNAL #include #endif #undef HAVE_PR_TERMCHILD #undef HAVE_PR_SET_PDEATHSIG #ifdef HAVE_LIBGEN_H #include #endif /* thread support options */ #undef HAVE_PTHREAD_MUTEX_T #undef HAVE_PTHREAD_BARRIER_T #undef HAVE___THREAD #undef HAVE_FNDELAY #if !defined(HAVE_FNDELAY) /* Only Solaris is known to need this so far */ #ifndef FNDELAY #define FNDELAY O_NDELAY #endif #endif #undef HAVE_ALTZONE #undef HAVE_STRFTIME_z #undef HAVE_STRERROR_R_PTR #undef HAVE_STRUCT_TIMESPEC #undef HAVE_STRUCT_SOCKADDR_UN #undef HAVE_STRUCT_UCRED #ifndef HAVE_VALLOC #define valloc(x) malloc(x) #endif /* Determine if we are on a Linux box */ #undef IS_LINUX /* Determine if we are on a Solaris box */ #undef IS_SOLARIS /* Determine if we are on an AIX box */ #undef IS_AIX /* Determine if we are on a FreeBSD box */ #undef IS_FREEBSD /* Determine if we are on a NetBSD box */ #undef IS_NETBSD /* Determine if we are on a Mac OS X box */ #undef IS_DARWIN #ifdef IS_DARWIN #define DLOPEN_NO_WARN #define st_atim st_atimespec /* workaround */ #define st_mtim st_mtimespec /* workaround */ #define st_ctim st_ctimespec /* workaround */ #endif /* Determine if we are on Windows with MinGW compiler */ #undef IS_MINGW #ifdef IS_MINGW #ifdef PCP_VERSION /* used to reduce namespace pollution */ #define EINPROGRESS WSAEINPROGRESS #define ENETDOWN WSAENETDOWN #define ENETUNREACH WSAENETUNREACH #define ECONNRESET WSAECONNRESET #define ETIMEDOUT WSAETIMEDOUT #define ECONNREFUSED WSAECONNREFUSED #define EHOSTDOWN WSAEHOSTDOWN #define EHOSTUNREACH WSAEHOSTUNREACH #define EOPNOTSUPP WSAEOPNOTSUPP #define EADDRINUSE WSAEADDRINUSE #define EPROTO WSAEPROTONOSUPPORT #define EMSGSIZE WSAEMSGSIZE #define ENODATA WSANO_DATA extern const char *wsastrerror(int); #define HAVE_PIPE1 #define HAVE_MKDIR2 #define HAVE_RENAME2 #define HAVE_DLOPEN #define HAVE_FNDELAY #define MAP_FAILED NULL #define O_NDELAY 0 #define SIGHUP (NSIG+1) #define SIGUSR1 (NSIG+2) #define SIGBUS (NSIG+3) #define S_IRGRP 0 #define S_IROTH 0 #define S_IRWXG 0 #define S_IRWXO 0 #define S_ISVTX 0 #define fcntl(f, cmd, ...) 0 #define mkdir2(path, mode) mkdir(path) #define rename2(a, b) (unlink(b), rename(a,b)) #define realpath(path, pp) strcpy(pp, path) #define pipe1(fds) _pipe(fds, 4096, O_BINARY) extern void setlinebuf(FILE *); extern char *index(const char *, int); extern char *rindex(const char *, int); extern long int lrand48(void); extern void srand48(long int); #ifdef HAVE_STRUCT_TIMESPEC /* * This is a bit odd ... but for MinGW, struct timespec is not in * but _is_ in ... the structure (sec, nanosec) * is what we want, so include */ #include #endif extern int nanosleep(const struct timespec *, struct timespec *); extern unsigned int sleep(unsigned int); enum { RTLD_NOW, RTLD_LAZY }; extern void *dlopen(const char *, int); extern char *dlerror(void); extern void *dlsym(void *, const char *); extern int dlclose(void *); extern void openlog(const char *, int, int); extern void syslog(int, const char *, ...); extern void closelog(void); #endif enum { LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG, LOG_PID, LOG_CONS, LOG_DAEMON }; #ifdef LIBPCP_INTERNAL #define INTERN __declspec(dllexport) #define EXTERN #else #define INTERN #define EXTERN __declspec(dllimport) #endif #define setoserror(n) (errno = (n)) /* not SetLastError() */ #define oserror() errno /* not GetLastError() */ #define neterror() WSAGetLastError() #define hosterror() WSAGetLastError() #define osstrerror() strerror(GetLastError()) #define osstrerror_r(buf, len) pmErrStr_r(-GetLastError(), buf, len) #define netstrerror() strerror(WSAGetLastError()) #define netstrerror_r(buf, len) pmErrStr_r(-WSAGetLastError(), buf, len) #define hoststrerror() strerror(WSAGetLastError()) #else /*!MINGW*/ #define INTERN #define EXTERN extern #define setoserror(n) (errno = (n)) #define oserror() errno #define neterror() errno #define hosterror() h_errno #define osstrerror() strerror(errno) #define osstrerror_r(buf, len) pmErrStr_r(-errno, buf, len) #define netstrerror() strerror(errno) #define netstrerror_r(buf, len) pmErrStr_r(-errno, buf, len) #define hoststrerror() hstrerror(h_errno) #endif #ifndef O_CLOEXEC #define O_CLOEXEC 0 #endif #ifndef FD_CLOEXEC #define FD_CLOEXEC 0 #endif /* * run-time environment that is in libc for most platforms, but for some * we need to provide our own implementation */ #ifndef HAVE_DIRNAME extern char *dirname(char *); #endif #ifndef HAVE_BASENAME extern char *basename(char *); #endif #ifndef HAVE_STRNDUP extern char *strndup(const char *, size_t n); #endif #ifdef HAVE_CONST_DIRENT #define const_dirent const struct dirent #else #define const_dirent struct dirent #endif #ifndef HAVE_SCANDIR struct dirent; extern int scandir(const char *, struct dirent ***, int(*filter)(const_dirent *), int(*compare)(const_dirent **, const_dirent **)); extern int alphasort(const_dirent **, const_dirent **); #endif #ifndef HAVE_MKDIR2 #define mkdir2(path,mode) mkdir(path,mode) #endif #ifndef HAVE_RENAME2 #define rename2(path,target) rename(path,target) #endif #ifndef HAVE_PIPE1 #define pipe1(fds) pipe(fds) #endif #ifdef __cplusplus } #endif #endif /* _PCP_CONFIG_H */ pcp-3.8.12ubuntu1/src/include/pcp/pmapi.h0000664000000000000000000006146512272262501015071 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1997,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _PMAPI_H #define _PMAPI_H #include #include #include #include #include #include #include #include /* * Platform and environment customization */ #include "platform_defs.h" #ifdef __cplusplus extern "C" { #endif #define PMAPI_VERSION_2 2 #define PMAPI_VERSION PMAPI_VERSION_2 /* * -------- Naming Services -------- */ typedef unsigned int pmID; /* Metric Identifier */ #define PM_ID_NULL 0xffffffff typedef unsigned int pmInDom; /* Instance-Domain */ #define PM_INDOM_NULL 0xffffffff #define PM_IN_NULL 0xffffffff #define PM_NS_DEFAULT NULL /* default name */ /* * Encoding for the units (dimensions Time and Space) and scale * for Performance Metric Values * * For example, a pmUnits struct of * { 1, -1, 0, PM_SPACE_MBYTE, PM_TIME_SEC, 0 } * represents Mbytes/sec, while * { 0, 1, -1, 0, PM_TIME_HOUR, 6 } * represents hours/million-events */ typedef struct { #ifdef HAVE_BITFIELDS_LTOR signed int dimSpace : 4; /* space dimension */ signed int dimTime : 4; /* time dimension */ signed int dimCount : 4; /* event dimension */ unsigned int scaleSpace : 4; /* one of PM_SPACE_* below */ unsigned int scaleTime : 4; /* one of PM_TIME_* below */ signed int scaleCount : 4; /* one of PM_COUNT_* below */ unsigned int pad : 8; #else unsigned int pad : 8; signed int scaleCount : 4; /* one of PM_COUNT_* below */ unsigned int scaleTime : 4; /* one of PM_TIME_* below */ unsigned int scaleSpace : 4; /* one of PM_SPACE_* below */ signed int dimCount : 4; /* event dimension */ signed int dimTime : 4; /* time dimension */ signed int dimSpace : 4; /* space dimension */ #endif } pmUnits; /* dimensional units and scale of value */ /* pmUnits.scaleSpace */ #define PM_SPACE_BYTE 0 /* bytes */ #define PM_SPACE_KBYTE 1 /* Kilobytes (1024) */ #define PM_SPACE_MBYTE 2 /* Megabytes (1024^2) */ #define PM_SPACE_GBYTE 3 /* Gigabytes (1024^3) */ #define PM_SPACE_TBYTE 4 /* Terabytes (1024^4) */ #define PM_SPACE_PBYTE 5 /* Petabytes (1024^5) */ #define PM_SPACE_EBYTE 6 /* Exabytes (1024^6) */ /* pmUnits.scaleTime */ #define PM_TIME_NSEC 0 /* nanoseconds */ #define PM_TIME_USEC 1 /* microseconds */ #define PM_TIME_MSEC 2 /* milliseconds */ #define PM_TIME_SEC 3 /* seconds */ #define PM_TIME_MIN 4 /* minutes */ #define PM_TIME_HOUR 5 /* hours */ /* * pmUnits.scaleCount (e.g. count events, syscalls, interrupts, etc.) * -- these are simply powers of 10, and not enumerated here, * e.g. 6 for 10^6, or -3 for 10^-3 */ #define PM_COUNT_ONE 0 /* 1 */ /* Performance Metric Descriptor */ typedef struct { pmID pmid; /* unique identifier */ int type; /* base data type (see below) */ pmInDom indom; /* instance domain */ int sem; /* semantics of value (see below) */ pmUnits units; /* dimension and units */ } pmDesc; /* pmDesc.type -- data type of metric values */ #define PM_TYPE_NOSUPPORT -1 /* not implemented in this version */ #define PM_TYPE_32 0 /* 32-bit signed integer */ #define PM_TYPE_U32 1 /* 32-bit unsigned integer */ #define PM_TYPE_64 2 /* 64-bit signed integer */ #define PM_TYPE_U64 3 /* 64-bit unsigned integer */ #define PM_TYPE_FLOAT 4 /* 32-bit floating point */ #define PM_TYPE_DOUBLE 5 /* 64-bit floating point */ #define PM_TYPE_STRING 6 /* array of char */ #define PM_TYPE_AGGREGATE 7 /* arbitrary binary data (aggregate) */ #define PM_TYPE_AGGREGATE_STATIC 8 /* static pointer to aggregate */ #define PM_TYPE_EVENT 9 /* packed pmEventArray */ #define PM_TYPE_UNKNOWN 255 /* used in pmValueBlock, not pmDesc */ /* pmDesc.sem -- semantics/interpretation of metric values */ #define PM_SEM_COUNTER 1 /* cumulative counter (monotonic increasing) */ /* was PM_SEM_RATE, no longer used now */ #define PM_SEM_INSTANT 3 /* instantaneous value, continuous domain */ #define PM_SEM_DISCRETE 4 /* instantaneous value, discrete domain */ #define PM_ERR_BASE2 12345 #define PM_ERR_BASE PM_ERR_BASE2 /* PMAPI Error Conditions */ #define PM_ERR_GENERIC (-PM_ERR_BASE-0) /* Generic error, already reported above */ #define PM_ERR_PMNS (-PM_ERR_BASE-1) /* Problems parsing PMNS definitions */ #define PM_ERR_NOPMNS (-PM_ERR_BASE-2) /* PMNS not accessible */ #define PM_ERR_DUPPMNS (-PM_ERR_BASE-3) /* Attempt to reload the PMNS */ #define PM_ERR_TEXT (-PM_ERR_BASE-4) /* Oneline or help text is not available */ #define PM_ERR_APPVERSION (-PM_ERR_BASE-5) /* Metric not supported by this version of monitored application */ #define PM_ERR_VALUE (-PM_ERR_BASE-6) /* Missing metric value(s) */ /* retired PM_ERR_LICENSE (-PM_ERR_BASE-7) Current PCP license does not permit this operation */ #define PM_ERR_TIMEOUT (-PM_ERR_BASE-8) /* Timeout waiting for a response from PMCD */ #define PM_ERR_NODATA (-PM_ERR_BASE-9) /* Empty archive log file */ #define PM_ERR_RESET (-PM_ERR_BASE-10) /* pmcd reset or configuration changed */ /* retired PM_ERR_FILE (-PM_ERR_BASE-11) Cannot locate a file */ #define PM_ERR_NAME (-PM_ERR_BASE-12) /* Unknown metric name */ #define PM_ERR_PMID (-PM_ERR_BASE-13) /* Unknown or illegal metric identifier */ #define PM_ERR_INDOM (-PM_ERR_BASE-14) /* Unknown or illegal instance domain identifier */ #define PM_ERR_INST (-PM_ERR_BASE-15) /* Unknown or illegal instance identifier */ #define PM_ERR_UNIT (-PM_ERR_BASE-16) /* Illegal pmUnits specification */ #define PM_ERR_CONV (-PM_ERR_BASE-17) /* Impossible value or scale conversion */ #define PM_ERR_TRUNC (-PM_ERR_BASE-18) /* Truncation in value conversion */ #define PM_ERR_SIGN (-PM_ERR_BASE-19) /* Negative value in conversion to unsigned */ #define PM_ERR_PROFILE (-PM_ERR_BASE-20) /* Explicit instance identifier(s) required */ #define PM_ERR_IPC (-PM_ERR_BASE-21) /* IPC protocol failure */ /* retired PM_ERR_NOASCII (-PM_ERR_BASE-22) ASCII format not supported for this PDU */ #define PM_ERR_EOF (-PM_ERR_BASE-23) /* IPC channel closed */ #define PM_ERR_NOTHOST (-PM_ERR_BASE-24) /* Operation requires context with host source of metrics */ #define PM_ERR_EOL (-PM_ERR_BASE-25) /* End of PCP archive log */ #define PM_ERR_MODE (-PM_ERR_BASE-26) /* Illegal mode specification */ #define PM_ERR_LABEL (-PM_ERR_BASE-27) /* Illegal label record at start of a PCP archive log file */ #define PM_ERR_LOGREC (-PM_ERR_BASE-28) /* Corrupted record in a PCP archive log */ #define PM_ERR_NOTARCHIVE (-PM_ERR_BASE-29) /* Operation requires context with archive source of metrics */ #define PM_ERR_LOGFILE (-PM_ERR_BASE-30) /* Missing archive file */ #define PM_ERR_NOCONTEXT (-PM_ERR_BASE-31) /* Attempt to use an illegal context */ #define PM_ERR_PROFILESPEC (-PM_ERR_BASE-32) /* NULL pmInDom with non-NULL instlist */ #define PM_ERR_PMID_LOG (-PM_ERR_BASE-33) /* Metric not defined in the PCP archive log */ #define PM_ERR_INDOM_LOG (-PM_ERR_BASE-34) /* Instance domain identifier not defined in the PCP archive log */ #define PM_ERR_INST_LOG (-PM_ERR_BASE-35) /* Instance identifier not defined in the PCP archive log */ #define PM_ERR_NOPROFILE (-PM_ERR_BASE-36) /* Missing profile - protocol botch */ #define PM_ERR_NOAGENT (-PM_ERR_BASE-41) /* No pmcd agent for domain of request */ #define PM_ERR_PERMISSION (-PM_ERR_BASE-42) /* No permission to perform requested operation */ #define PM_ERR_CONNLIMIT (-PM_ERR_BASE-43) /* PMCD connection limit for this host exceeded */ #define PM_ERR_AGAIN (-PM_ERR_BASE-44) /* try again. Info not currently available */ #define PM_ERR_ISCONN (-PM_ERR_BASE-45) /* already connected */ #define PM_ERR_NOTCONN (-PM_ERR_BASE-46) /* not connected */ #define PM_ERR_NEEDPORT (-PM_ERR_BASE-47) /* port name required */ /* retired PM_ERR_WANTACK (-PM_ERR_BASE-48) can not send due to pending acks */ #define PM_ERR_NONLEAF (-PM_ERR_BASE-49) /* PMNS node is not a leaf node */ /* retired PM_ERR_OBJSTYLE (-PM_ERR_BASE-50) user/kernel object style mismatch */ /* retired PM_ERR_PMCDLICENSE (-PM_ERR_BASE-51) PMCD is not licensed to accept connections */ #define PM_ERR_TYPE (-PM_ERR_BASE-52) /* Unknown or illegal metric type */ #define PM_ERR_THREAD (-PM_ERR_BASE-53) /* Operation not supported for multi-threaded applications */ /* retired PM_ERR_CTXBUSY (-PM_ERR_BASE-97) Context is busy */ #define PM_ERR_TOOSMALL (-PM_ERR_BASE-98) /* Insufficient elements in list */ #define PM_ERR_TOOBIG (-PM_ERR_BASE-99) /* Result size exceeded */ #define PM_ERR_FAULT (-PM_ERR_BASE-100) /* QA fault injected */ #define PM_ERR_PMDAREADY (-PM_ERR_BASE-1048) /* now ready to respond */ #define PM_ERR_PMDANOTREADY (-PM_ERR_BASE-1049) /* not yet ready to respond */ #define PM_ERR_NYI (-PM_ERR_BASE-8999) /* Functionality not yet implemented [end-of-range mark] */ /* * Report PMAPI errors messages */ extern char *pmErrStr(int); /* NOT thread-safe */ extern char *pmErrStr_r(int, char *, int); /* safe size for a pmErrStr_r buffer to accommodate all error messages */ #define PM_MAXERRMSGLEN 128 /* * Load a Performance Metrics Name Space */ extern int pmLoadNameSpace(const char *); extern int pmLoadASCIINameSpace(const char *, int); extern void pmUnloadNameSpace(void); /* * Where is PMNS located - added for distributed PMNS. */ extern int pmGetPMNSLocation(void); #define PMNS_LOCAL 1 #define PMNS_REMOTE 2 #define PMNS_ARCHIVE 3 /* * Trim a name space with respect to the current context * (usually from an archive, or after processing an archive) */ extern int pmTrimNameSpace(void); /* * Expand a list of names to a list of metrics ids */ extern int pmLookupName(int, char **, pmID *); /* * Find the names of descendent nodes in the PMNS * and in the latter case get the status of each child. */ extern int pmGetChildren(const char *, char ***); extern int pmGetChildrenStatus(const char *, char ***, int **); #define PMNS_LEAF_STATUS 0 /* leaf node in PMNS tree */ #define PMNS_NONLEAF_STATUS 1 /* non-terminal node in PMNS tree */ /* * Reverse Lookup: find name(s) given a metric id */ extern int pmNameID(pmID, char **); /* one */ extern int pmNameAll(pmID, char ***); /* all */ /* * Handy recursive descent of the PMNS */ extern int pmTraversePMNS(const char *, void(*)(const char *)); extern int pmTraversePMNS_r(const char *, void(*)(const char *, void *), void *); /* * Given a metric, find it's descriptor (caller supplies buffer for desc), * from the current context. */ extern int pmLookupDesc(pmID, pmDesc *); /* * Return the internal instance identifier, from the current context, * given an instance domain and the external instance name. * Archive variant scans the union of the indom entries in the archive * log. */ extern int pmLookupInDom(pmInDom, const char *); extern int pmLookupInDomArchive(pmInDom, const char *); /* * Return the external instance name, from the current context, * given an instance domain and the internal instance identifier. * Archive variant scans the union of the indom entries in the archive * log. */ extern int pmNameInDom(pmInDom, int, char **); extern int pmNameInDomArchive(pmInDom, int, char **); /* * Return all of the internal instance identifiers (instlist) and external * instance names (namelist) for the given instance domain in the current * context. * Archive variant returns the union of the indom entries in the archive * log. */ extern int pmGetInDom(pmInDom, int **, char ***); extern int pmGetInDomArchive(pmInDom, int **, char ***); /* * Given context ID, return a host name, associated with the id * or empty string if no name can be found */ extern const char *pmGetContextHostName(int); /* * return the handle of the current context */ extern int pmWhichContext(void); /* * destroy a context and close it's connection */ extern int pmDestroyContext(int); /* * Establish a new context (source of performance data + instance profile) * for the named host */ extern int pmNewContext(int, const char *); #define PM_CONTEXT_UNDEF -1 /* current context is undefined */ #define PM_CONTEXT_HOST 1 /* host via pmcd */ #define PM_CONTEXT_ARCHIVE 2 /* PCP archive */ #define PM_CONTEXT_LOCAL 3 /* local host, no pmcd connection */ #define PM_CONTEXT_TYPEMASK 0xff /* mask to separate types / flags */ /* #define PM_CTXFLAG_SHALLOW (1U<<8) -- don't actually connect to host */ /* #define PM_CTXFLAG_EXCLUSIVE (1U<<9) -- don't share socket among ctxts */ #define PM_CTXFLAG_SECURE (1U<<10)/* encrypted socket comms channel */ #define PM_CTXFLAG_COMPRESS (1U<<11)/* compressed socket host channel */ #define PM_CTXFLAG_RELAXED (1U<<12)/* encrypted if possible else not */ #define PM_CTXFLAG_AUTH (1U<<13)/* make authenticated connection */ /* * Duplicate current context -- returns handle to new one for pmUseContext() */ extern int pmDupContext(void); /* * Restore (previously established or duplicated) context */ extern int pmUseContext(int); /* * Reconnect an existing context (when pmcd dies, etc). All existing context * settings are preserved and the previous context settings are restored. */ extern int pmReconnectContext(int); /* * Add to instance profile. * If pmInDom == PM_INDOM_NULL, then all instance domains are selected. * If no inst parameters are given, then all instances are selected. * e.g. to select all available instances in all domains, * then use pmAddProfile(PM_INDOM_NULL, 0, NULL). */ extern int pmAddProfile(pmInDom, int, int *); /* * Delete from instance profile. * Similar (but negated) functional semantics to pmProfileAdd. * E.g. to disable all instances in all domains then use * pmDelProfile(PM_INDOM_NULL, 0, NULL). */ extern int pmDelProfile(pmInDom, int, int *); /* * ---------- Collection services ---------- * * Result from pmFetch is encoded as a timestamp and vector of pointers * to pmValueSet instances (one per PMID in the result). * Each pmValueSet has a PMID, a value count, a value format, and a vector of * instance-value pairs. Aggregate, string and non-int values are returned * via one further level of indirection using pmValueBlocks. * * timeStamp * ->pmID * value format * instance, value * instance, value * ... etc * * ->pmID * value format * instance, value * ... etc * * * Notes on pmValueBlock * 0. may be used for arbitrary binary data * 1. only ever allocated dynamically, and vbuf expands to accommodate * an arbitrary value (don't believe the [1] size!) * 2. len is the length of the len field + the real size of vbuf * (which includes the null-byte terminator if there is one) */ typedef struct { #ifdef HAVE_BITFIELDS_LTOR unsigned int vtype : 8; /* value type */ unsigned int vlen : 24; /* bytes for vtype/vlen + vbuf */ #else unsigned int vlen : 24; /* bytes for vtype/vlen + vbuf */ unsigned int vtype : 8; /* value type */ #endif char vbuf[1]; /* the value */ } pmValueBlock; #define PM_VAL_HDR_SIZE 4 /* bytes for the vtype/vlen header */ #define PM_VAL_VLEN_MAX 0x00ffffff /* maximum vbuf[] size */ typedef struct { int inst; /* instance identifier */ union { pmValueBlock *pval; /* pointer to value-block */ int lval; /* integer value insitu (lval 'cuz it WAS a long) */ } value; } pmValue; typedef struct { pmID pmid; /* metric identifier */ int numval; /* number of values */ int valfmt; /* value style */ pmValue vlist[1]; /* set of instances/values */ } pmValueSet; /* values for valfmt */ #define PM_VAL_INSITU 0 /* value.lval is it */ #define PM_VAL_DPTR 1 /* value.pval->vbuf is it, and dynamic alloc */ #define PM_VAL_SPTR 2 /* value.pval->vbuf is it, and static alloc */ /* Result returned by pmFetch() */ typedef struct { struct timeval timestamp; /* time stamped by collector */ int numpmid; /* number of PMIDs */ pmValueSet *vset[1]; /* set of value sets, one per PMID */ } pmResult; /* Generic Union for Value-Type conversions */ typedef union { __int32_t l; /* 32-bit signed */ __uint32_t ul; /* 32-bit unsigned */ __int64_t ll; /* 64-bit signed */ __uint64_t ull; /* 64-bit unsigned */ float f; /* 32-bit floating point */ double d; /* 64-bit floating point */ char *cp; /* char ptr */ pmValueBlock *vbp; /* pmValueBlock ptr */ } pmAtomValue; /* * Fetch metrics. Value/instances returned depends on current instance profile. * By default, all available instances for each requested metric id are * returned. The metrics argument is terminated with PM_NULL_ID * * The value sets returned are in the same order as the metrics argument, * and the number of value sets returned is guaranteed to be the same as * the number of metrics in the agument. */ extern int pmFetch(int, pmID *, pmResult **); /* * PMCD state changes returned as pmFetch function result for PM_CONTEXT_HOST * contexts, i.e. when communicating with PMCD */ #define PMCD_NO_CHANGE 0 #define PMCD_ADD_AGENT 1 #define PMCD_RESTART_AGENT 2 #define PMCD_DROP_AGENT 4 /* * variant that is used to return a pmResult from an archive */ extern int pmFetchArchive(pmResult **); /* * struct timeval is sometimes 2 x 64-bit ... we use a 2 x 32-bit format for * PDUs, internally within libpcp and for (external) archive logs */ typedef struct { __int32_t tv_sec; /* seconds since Jan. 1, 1970 */ __int32_t tv_usec; /* and microseconds */ } __pmTimeval; /* * Label Record at the start of every log file - as exported above * the PMAPI ... * NOTE MAXHOSTNAMELEN is a bad choice here for ll_hostname[], as * it may vary on different hosts ... we use PM_LOG_MAXHOSTLEN instead, and * size this to be the same as MAXHOSTNAMELEN in IRIX 5.3 * NOTE that the struct timeval means we have another struct (__pmLogLabel) * for internal use that has a __pmTimeval in place of the struct timeval. */ #define PM_TZ_MAXLEN 40 #define PM_LOG_MAXHOSTLEN 64 #define PM_LOG_MAGIC 0x50052600 #define PM_LOG_VERS02 0x2 #define PM_LOG_VOL_TI -2 /* temporal index */ #define PM_LOG_VOL_META -1 /* meta data */ typedef struct { int ll_magic; /* PM_LOG_MAGIC | log format version no. */ pid_t ll_pid; /* PID of logger */ struct timeval ll_start; /* start of this log */ char ll_hostname[PM_LOG_MAXHOSTLEN]; /* name of collection host */ char ll_tz[PM_TZ_MAXLEN]; /* $TZ at collection host */ } pmLogLabel; /* * get the label record from the current archive context, and discover * when the archive ends */ extern int pmGetArchiveLabel(pmLogLabel *); extern int pmGetArchiveEnd(struct timeval *); /* Free result buffer */ extern void pmFreeResult(pmResult *); /* Value extract from pmValue and type conversion */ extern int pmExtractValue(int, const pmValue *, int, pmAtomValue *, int); /* Print single pmValue */ extern void pmPrintValue(FILE *, int, int, const pmValue *, int); /* Scale conversion, based on value format, value type and scale */ extern int pmConvScale(int, const pmAtomValue *, const pmUnits *, pmAtomValue *, const pmUnits *); /* Sort instances for each metric within a pmResult */ extern void pmSortInstances(pmResult *); /* Adjust collection time and/or mode for pmFetch */ extern int pmSetMode(int, const struct timeval *, int); #define PM_MODE_LIVE 0 #define PM_MODE_INTERP 1 #define PM_MODE_FORW 2 #define PM_MODE_BACK 3 /* Modify the value of one or more metrics */ extern int pmStore(const pmResult *); /* Get help and descriptive text */ extern int pmLookupText(pmID, int, char **); extern int pmLookupInDomText(pmInDom, int, char **); #define PM_TEXT_ONELINE 1 #define PM_TEXT_HELP 2 /* * some handy formatting routines for messages, and other output */ extern const char *pmIDStr(pmID); /* NOT thread-safe */ extern char *pmIDStr_r(pmID, char *, int); extern const char *pmInDomStr(pmInDom); /* NOT thread-safe */ extern char *pmInDomStr_r(pmInDom, char *, int); extern const char *pmTypeStr(int); /* NOT thread-safe */ extern char *pmTypeStr_r(int, char *, int); extern const char *pmUnitsStr(const pmUnits *); /* NOT thread-safe */ extern char *pmUnitsStr_r(const pmUnits *, char *, int); extern const char *pmAtomStr(const pmAtomValue *, int); /* NOT thread-safe */ extern char *pmAtomStr_r(const pmAtomValue *, int, char *, int); extern const char *pmNumberStr(double); /* NOT thread-safe */ extern char *pmNumberStr_r(double, char *, int); extern const char *pmEventFlagsStr(int); /* NOT thread-safe */ extern char *pmEventFlagsStr_r(int, char *, int); /* Extended time base definitions and macros */ #define PM_XTB_FLAG 0x1000000 #define PM_XTB_SET(type) (PM_XTB_FLAG | ((type) << 16)) #define PM_XTB_GET(x) (((x) & PM_XTB_FLAG) ? (((x) & 0xff0000) >> 16) : -1) /* parse -t, -S, -T, -A and -O options */ extern int pmParseInterval(const char *, struct timeval *, char **); extern int pmParseTimeWindow( const char *, const char *, const char *, const char *, const struct timeval *, const struct timeval *, struct timeval *, struct timeval *, struct timeval *, char **); /* reporting timezone */ extern int pmUseZone(const int); extern int pmNewZone(const char *); extern int pmNewContextZone(void); extern int pmWhichZone(char **); extern char *pmCtime(const time_t *, char *); extern struct tm *pmLocaltime(const time_t *, struct tm *); /* Parse host:metric[instances] or archive/metric[instances] */ typedef struct { int isarch; /* source type: 0 -> live host, 1 -> archive, 2 -> local context */ char *source; /* name of source host or archive */ char *metric; /* name of metric */ int ninst; /* number of instances, 0 -> all */ char *inst[1]; /* array of instance names */ } pmMetricSpec; /* parsing of host:metric[instances] or archive/metric[instances] */ extern int pmParseMetricSpec(const char *, int, char *, pmMetricSpec **, char **); extern void pmFreeMetricSpec(pmMetricSpec *p); /* * configurable error reporting */ #ifdef __GNUC__ # define __PM_PRINTFLIKE(idx,cnt) __attribute__ ((format (printf, idx,cnt))) #else # define __PM_PRINTFLIKE(idx,cnt) #endif extern int pmprintf(const char *, ...) __PM_PRINTFLIKE(1,2); extern int pmflush(void); /* * Wrapper for config/environment variables. Warning: this will exit() with * a FATAL error if /etc/pcp.conf does not exist and $PCP_CONF is not set. * Return values point to strings in the environment. */ extern char *pmGetConfig(const char *); /* * Derived Metrics support */ extern int pmLoadDerivedConfig(const char *); extern char *pmRegisterDerived(const char *, const char *); extern char *pmDerivedErrStr(void); /* * Event Record support */ typedef struct { pmID ep_pmid; /* vtype and vlen fields the format same as for pmValueBlock */ #ifdef HAVE_BITFIELDS_LTOR unsigned int ep_type : 8; /* value type */ unsigned int ep_len : 24; /* bytes for type/len + vbuf */ #else unsigned int ep_len : 24; /* bytes for type/len + vbuf */ unsigned int ep_type : 8; /* value type */ #endif /* actual value (vbuf) goes here ... */ } pmEventParameter; typedef struct { __pmTimeval er_timestamp; /* must be 2 x 32-bit format */ unsigned int er_flags; /* event record characteristics */ int er_nparams; /* number of er_param[] entries */ pmEventParameter er_param[1]; } pmEventRecord; /* potential flags bits set in er_flags (above) */ #define PM_EVENT_FLAG_POINT (1U<<0) /* an observation, default type */ #define PM_EVENT_FLAG_START (1U<<1) /* marking start of a new event */ #define PM_EVENT_FLAG_END (1U<<2) /* completion of a traced event */ #define PM_EVENT_FLAG_ID (1U<<3) /* 1st parameter is a trace ID */ #define PM_EVENT_FLAG_PARENT (1U<<4) /* 2nd parameter is parents ID */ #define PM_EVENT_FLAG_MISSED (1U<<31)/* nparams shows #missed events */ typedef struct { /* align initial declarations with start of pmValueBlock */ #ifdef HAVE_BITFIELDS_LTOR unsigned int ea_type : 8; /* value type */ unsigned int ea_len : 24; /* bytes for type/len + vbuf */ #else unsigned int ea_len : 24; /* bytes for type/len + vbuf */ unsigned int ea_type : 8; /* value type */ #endif /* real event records start here */ int ea_nrecords; /* number of ea_record[] entries */ pmEventRecord ea_record[1]; } pmEventArray; /* unpack a PM_TYPE_EVENT value into a set on pmResults */ extern int pmUnpackEventRecords(pmValueSet *, int, pmResult ***); /* Free set of pmResults from pmUnpackEventRecords */ extern void pmFreeEventResult(pmResult **); /* Service discovery, for clients. */ #define PM_SERVER_SERVICE_SPEC "pmcd" extern int pmDiscoverServices(const char *, const char *, char ***); #ifdef __cplusplus } #endif #endif /* _PMAPI_H */ pcp-3.8.12ubuntu1/src/include/pcp/trace.h0000664000000000000000000000755212272262501015056 0ustar /* * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _TRACE_H #define _TRACE_H /* * Transaction monitoring PMDA (trace) public interface. * * An example program using this interface can be found at * $PCP_DEMOS_DIR/trace/demo.c and contains further doumentation. * Also refer to the pmdatrace(1) and pmdatrace(3) man pages and * the Performance Co-Pilot Programmer's Guide. */ #ifdef __cplusplus extern "C" { #endif /* * Add a new entry to the table of transactions currently being monitored, * or update an existing entry. */ extern int pmtracebegin(const char *); /* * Make measurements recorded for the given transaction tag available * through the trace PMDA. */ extern int pmtraceend(const char *); /* * Cancel a transaction which began from an earlier call to pmtracebegin, * without exporting new data through the trace PMDA. */ extern int pmtraceabort(const char *); /* * An alternate form of measurement can be obtained using pmtracepoint. * This is a count-only measurement, and will result in the trace PMDA * exporting the number of times a given code point is passed (ie. the * the number of times a particular label has been passed to pmtracepoint. */ extern int pmtracepoint(const char *); /* * An extension to pmtracepoint is pmtraceobs, with similar semantics to * pmtracepoint except allowing an arbitrary numeric value (double) to be * exported up through the PMAPI. */ extern int pmtraceobs(const char *, double); /* * Similar to pmtraceobs is pmtracecounter, with the only difference * being the way the trace PMDA exports the given numeric value to * PMAPI clients (exported with counter semantics, rather than with * instantaneous semantics which is the case with pmtraceobs). */ extern int pmtracecounter(const char *, double); /* * Should any of these routines return a negative value, the return value * can be passed to pmtraceerrstr for the associated error message. * This performs a lookup into a static error message table, so the returned * pointer must not be freed. */ extern char *pmtraceerrstr(int); #define PMTRACE_ERR_BASE 12000 #define PMTRACE_ERR_TAGNAME (-PMTRACE_ERR_BASE-0) #define PMTRACE_ERR_INPROGRESS (-PMTRACE_ERR_BASE-1) #define PMTRACE_ERR_NOPROGRESS (-PMTRACE_ERR_BASE-2) #define PMTRACE_ERR_NOSUCHTAG (-PMTRACE_ERR_BASE-3) #define PMTRACE_ERR_TAGTYPE (-PMTRACE_ERR_BASE-4) #define PMTRACE_ERR_TAGLENGTH (-PMTRACE_ERR_BASE-5) #define PMTRACE_ERR_IPC (-PMTRACE_ERR_BASE-6) #define PMTRACE_ERR_ENVFORMAT (-PMTRACE_ERR_BASE-7) #define PMTRACE_ERR_TIMEOUT (-PMTRACE_ERR_BASE-8) #define PMTRACE_ERR_VERSION (-PMTRACE_ERR_BASE-9) #define PMTRACE_ERR_PERMISSION (-PMTRACE_ERR_BASE-10) #define PMTRACE_ERR_CONNLIMIT (-PMTRACE_ERR_BASE-11) /* * Diagnostic and state switching */ extern int pmtracestate(int code); #define PMTRACE_STATE_NONE 0 /* default: synchronous and no diagnostics */ #define PMTRACE_STATE_API 1 /* debug: processing just below the API */ #define PMTRACE_STATE_COMMS 2 /* debug: shows network-related activity */ #define PMTRACE_STATE_PDU 4 /* debug: shows app<->PMDA IPC traffic */ #define PMTRACE_STATE_PDUBUF 8 /* debug: internal IPC buffer management */ #define PMTRACE_STATE_NOAGENT 16 /* debug: no PMDA communications at all */ #define PMTRACE_STATE_ASYNC 32 /* control: use asynchronous PDU protocol */ #ifdef __cplusplus } #endif #endif /* _TRACE_H */ pcp-3.8.12ubuntu1/src/include/pcp/mmv_dev.h0000664000000000000000000000601412272262501015405 0ustar /* * Copyright (C) 2001,2009 Silicon Graphics, Inc. All Rights Reserved. * Copyright (C) 2009 Aconex. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #ifndef _MMV_DEV_H #define _MMV_DEV_H #define MMV_VERSION 1 typedef enum { MMV_TOC_INDOMS = 1, /* mmv_disk_indom_t */ MMV_TOC_INSTANCES = 2, /* mmv_disk_instance_t */ MMV_TOC_METRICS = 3, /* mmv_disk_metric_t */ MMV_TOC_VALUES = 4, /* mmv_disk_value_t */ MMV_TOC_STRINGS = 5, /* mmv_disk_string_t */ } mmv_toc_type_t; /* The way the Table Of Contents is written into the file */ typedef struct { mmv_toc_type_t type; /* What is it? */ __int32_t count; /* Number of entries */ __uint64_t offset; /* Offset of section from file start */ } mmv_disk_toc_t; typedef struct { __uint32_t serial; /* Unique identifier */ __uint32_t count; /* Number of instances */ __uint64_t offset; /* Offset of first instance */ __uint64_t shorttext; /* Offset of short help text string */ __uint64_t helptext; /* Offset of long help text string */ } mmv_disk_indom_t; typedef struct { __uint64_t indom; /* Offset into files indom section */ __uint32_t padding; /* zero filled, alignment bits */ __int32_t internal; /* Internal instance ID */ char external[MMV_NAMEMAX]; /* External instance ID */ } mmv_disk_instance_t; typedef struct { char payload[MMV_STRINGMAX]; /* NULL terminated string */ } mmv_disk_string_t; typedef struct { char name[MMV_NAMEMAX]; __uint32_t item; /* Unique identifier */ mmv_metric_type_t type; mmv_metric_sem_t semantics; pmUnits dimension; __int32_t indom; /* Instance domain number */ __uint32_t padding; /* zero filled, alignment bits */ __uint64_t shorttext; /* Offset of short help text string */ __uint64_t helptext; /* Offset of long help text string */ } mmv_disk_metric_t; typedef struct { pmAtomValue value; /* Union of all possible value types */ __int64_t extra; /* INTEGRAL(starttime)/STRING(offset) */ __uint64_t metric; /* Offset into the metric section */ __uint64_t instance; /* Offset into the instance section */ } mmv_disk_value_t; typedef struct { char magic[4]; /* MMV\0 */ __int32_t version; /* version */ __uint64_t g1; /* Generation numbers */ __uint64_t g2; __int32_t tocs; /* Number of toc entries */ mmv_stats_flags_t flags; __int32_t process; /* client process identifier (flags) */ __int32_t cluster; /* preferred PMDA cluster identifier */ } mmv_disk_header_t; #endif /* _MMV_DEV_H */ pcp-3.8.12ubuntu1/src/include/pcp/fault.h0000664000000000000000000000327312272262501015067 0ustar /* * Copyright (c) 2011 Ken McDonell. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #ifndef _FAULT_H #define _FAULT_H #ifdef __cplusplus extern "C" { #endif /* * Routines to support fault injection infrastructure * * Build libpcp with -DPM_FAULT_INJECTION to enable all of this. */ extern void __pmFaultInject(const char *, int); extern void __pmFaultSummary(FILE *f); #ifdef PM_FAULT_INJECTION extern int __pmFault_arm; #define PM_FAULT_POINT(ident, class) __pmFaultInject(ident, class) #ifdef malloc #undef malloc #endif #define malloc(x) __pmFault_malloc(x) extern void *__pmFault_malloc(size_t); #ifdef realloc #undef realloc #endif #define realloc(x,y) __pmFault_realloc(x,y) extern void *__pmFault_realloc(void *, size_t); #ifdef strdup #undef strdup #endif #define strdup(x) __pmFault_strdup(x) extern char *__pmFault_strdup(const char *); #define PM_FAULT_CHECK(class) if (__pmFault_arm == PM_FAULT_PMAPI) { __pmFault_arm = 0; return PM_ERR_FAULT; } #else #define PM_FAULT_POINT(ident, class) #define PM_FAULT_CHECK(class) #endif /* * Classes of fault types (second arg to __pmFaultInject()) */ #define PM_FAULT_ALLOC 100 #define PM_FAULT_PMAPI 101 #ifdef __cplusplus } #endif #endif /* _FAULT_H */ pcp-3.8.12ubuntu1/src/include/pcp/GNUmakefile0000664000000000000000000000231012272262501015644 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs HFILES = pmapi.h impl.h pmda.h pmtime.h pmafm.h import.h \ trace.h trace_dev.h mmv_stats.h mmv_dev.h GENERATED_HFILES = pmdbg.h platform_defs.h config.h CONFFILES = config.h platform_defs.h LSRCFILES = config.h.in platform_defs.h.in mk_pmdbg fault.h LDIRT = $(GENERATED_HFILES) default :: default_pcp default_pcp : $(HEADERS) $(GENERATED_HFILES) include $(BUILDRULES) install :: default_pcp install_pcp install_pcp : default_pcp $(INSTALL) -m 644 $(HFILES) $(GENERATED_HFILES) $(PCP_INC_DIR) pmdbg.h : pmapi.h impl.h ./mk_pmdbg pcp-3.8.12ubuntu1/src/include/pcp/mk_pmdbg0000775000000000000000000000250412272262501015305 0ustar #!/bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Create pmdbg.h from impl.h if [ -f ../pcp.conf ] then # needed for $PCP_SORT_PROG . ../pcp.conf else echo "mk_pmdbg: cannot find pcp.conf" exit 1 fi if [ ! -f impl.h ] then echo "mk_pmdbg: cannot find impl.h" exit 1 fi rm -f pmdbg.h cat <pmdbg.h /* * Built from impl.h by mk_pmdbg. Any modifications will be lost. */ typedef const struct { const char *name; const int bit; } debug_map_t; static const debug_map_t debug_map[] = { End-of-File sed -n >pmdbg.h cat <>pmdbg.h }; static const int num_debug = sizeof(debug_map) / sizeof(debug_map[0]); End-of-File exit 0 pcp-3.8.12ubuntu1/src/include/pcp/trace_dev.h0000664000000000000000000000515012272262501015704 0ustar /* * Copyright (c) 1997-2001,2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _TRACE_DEV_H #define _TRACE_DEV_H #ifndef _PLATFORM_DEFS_H #include "platform_defs.h" #endif #ifdef _cplusplus extern "C" { #endif #define MAXTAGNAMELEN 256 #define TRACE_ENV_HOST "PCP_TRACE_HOST" #define TRACE_ENV_PORT "PCP_TRACE_PORT" #define TRACE_ENV_TIMEOUT "PCP_TRACE_TIMEOUT" #define TRACE_ENV_NOAGENT "PCP_TRACE_NOAGENT" #define TRACE_ENV_REQTIMEOUT "PCP_TRACE_REQTIMEOUT" #define TRACE_ENV_RECTIMEOUT "PCP_TRACE_RECONNECT" #define TRACE_PORT 4323 #define TRACE_PDU_VERSION 1 #define TRACE_TYPE_TRANSACT 1 #define TRACE_TYPE_POINT 2 #define TRACE_TYPE_OBSERVE 3 #define TRACE_TYPE_COUNTER 4 #define TRACE_FIRST_TYPE TRACE_TYPE_TRANSACT #define TRACE_LAST_TYPE TRACE_TYPE_COUNTER /* * Protocol data unit (PDU) support snarfed from impl.h, pdu.c and pdubuf.c */ typedef struct { int len; /* length of pdu_header + PDU */ int type; /* PDU type */ int from; /* pid of PDU originator */ } __pmTracePDUHdr; typedef __uint32_t __pmTracePDU; extern int __pmtracexmitPDU(int, __pmTracePDU *); extern int __pmtracegetPDU(int, int, __pmTracePDU **); /* for __pmtracegetPDU */ #define TRACE_TIMEOUT_NEVER 0 #define TRACE_TIMEOUT_DEFAULT -1 /* unit of space allocation for PDU buffer. */ #define TRACE_PDU_CHUNK 1024 extern __pmTracePDU *__pmtracefindPDUbuf(int); extern void __pmtracepinPDUbuf(void *); extern int __pmtraceunpinPDUbuf(void *); extern int __pmtracemoreinput(int); extern void __pmtracenomoreinput(int); #define TRACE_PDU_BASE 0x7050 #define TRACE_PDU_ACK 0x7050 #define TRACE_PDU_DATA 0x7051 #define TRACE_PDU_MAX 2 extern int __pmtracesendack(int, int); extern int __pmtracedecodeack(__pmTracePDU *, int *); extern int __pmtracesenddata(int, char *, int, int, double); extern int __pmtracedecodedata(__pmTracePDU *, char **, int *, int *, int *, double *); #define TRACE_PROTOCOL_FINAL -1 #define TRACE_PROTOCOL_QUERY 0 #define TRACE_PROTOCOL_ASYNC 1 #define TRACE_PROTOCOL_SYNC 2 extern int __pmtraceprotocol(int); extern int __pmstate; #ifdef __cplusplus } #endif #endif /* _TRACE_DEV_H */ pcp-3.8.12ubuntu1/src/include/pcp/platform_defs.h.in0000664000000000000000000000034212272262501017200 0ustar /* * @configure_input@ */ #ifndef _PCP_PLATFORM_DEFS_H #define _PCP_PLATFORM_DEFS_H #include "config.h" /* printf candy ... */ #define FMT_PID @fmt_pid@ #define FMT_PTHREAD @fmt_pthread@ #endif /* _PCP_PLATFORM_DEFS_H */ pcp-3.8.12ubuntu1/src/include/pcp/pmda.h0000664000000000000000000005356612272262501014707 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1995,2005 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _PMDA_H #define _PMDA_H #include #ifdef __cplusplus extern "C" { #endif /* * libpcp_pmda interface versions */ #define PMDA_INTERFACE_2 2 /* new function arguments */ #define PMDA_INTERFACE_3 3 /* 3-state return from fetch callback */ #define PMDA_INTERFACE_4 4 /* dynamic pmns */ #define PMDA_INTERFACE_5 5 /* client context in pmda and */ /* 4-state return from fetch callback */ #define PMDA_INTERFACE_6 6 /* client security attributes in pmda */ #define PMDA_INTERFACE_LATEST 6 /* * Type of I/O connection to PMCD (pmdaUnknown defaults to pmdaPipe) */ typedef enum {pmdaPipe, pmdaInet, pmdaUnix, pmdaUnknown, pmdaIPv6} pmdaIoType; /* * Instance description: index and name */ typedef struct { int i_inst; /* internal instance identifier */ char *i_name; /* external instance identifier */ } pmdaInstid; /* * Instance domain description: unique instance id, number of instances in * this domain, and the list of instances (not null terminated). */ typedef struct { pmInDom it_indom; /* indom, filled in */ int it_numinst; /* number of instances */ pmdaInstid *it_set; /* instance identifiers */ } pmdaIndom; /* * Metric description: handle for extending description, and the description. */ typedef struct { void *m_user; /* for users external use */ pmDesc m_desc; /* metric description */ } pmdaMetric; /* * Type of function call back used by pmdaFetch. */ typedef int (*pmdaFetchCallBack)(pmdaMetric *, unsigned int, pmAtomValue *); /* * return values for a pmdaFetchCallBack method */ #define PMDA_FETCH_NOVALUES 0 #define PMDA_FETCH_STATIC 1 #define PMDA_FETCH_DYNAMIC 2 /* free avp->vp after __pmStuffValue */ /* * Type of function call back used by pmdaMain to clean up a pmResult structure * after a fetch. */ typedef void (*pmdaResultCallBack)(pmResult *); /* * Type of function call back used by pmdaMain on receipt of each PDU to check * availability, etc. */ typedef int (*pmdaCheckCallBack)(void); /* * Type of function call back used by pmdaMain after each PDU has been * processed. */ typedef void (*pmdaDoneCallBack)(void); /* * Type of function call back used by pmdaMain when a client context is * closed by PMCD. */ typedef void (*pmdaEndContextCallBack)(int); /* * Forward declarations of structures so that inclusion of (internal) impl.h * header file is not mandated if this header file is included. */ typedef struct __pmnsTree pmdaNameSpace; typedef struct __pmHashCtl pmdaHashTable; typedef struct __pmProfile pmdaInProfile; typedef struct __pmInResult pmdaInResult; /* * libpcp_pmda extension structure. * * The fields of this structure are initialised using pmdaDaemon() or pmdaDSO() * (if the agent is a daemon or a DSO respectively), pmdaGetOpt() and * pmdaInit(). * */ typedef struct { unsigned int e_flags; /* PMDA_EXT_FLAG_* bit field */ void *e_ext; /* used internally within libpcp_pmda */ char *e_sockname; /* socket name to pmcd */ char *e_name; /* name of this pmda */ char *e_logfile; /* path to log file */ char *e_helptext; /* path to help text */ int e_status; /* =0 is OK */ int e_infd; /* input file descriptor from pmcd */ int e_outfd; /* output file descriptor to pmcd */ int e_port; /* port to pmcd */ int e_singular; /* =0 for singular values */ int e_ordinal; /* >=0 for non-singular values */ int e_direct; /* =1 if pmid map to meta table */ int e_domain; /* metrics domain */ int e_nmetrics; /* number of metrics */ int e_nindoms; /* number of instance domains */ int e_help; /* help text comes via this handle */ pmdaInProfile *e_prof; /* last received profile */ pmdaIoType e_io; /* connection type to pmcd */ pmdaIndom *e_indoms; /* instance domain table */ pmdaIndom *e_idp; /* used in instance domain expansion */ pmdaMetric *e_metrics; /* metric description table */ pmdaResultCallBack e_resultCallBack; /* callback to clean up pmResult after fetch */ pmdaFetchCallBack e_fetchCallBack; /* callback to assign metric values in fetch */ pmdaCheckCallBack e_checkCallBack; /* callback on receipt of a PDU */ pmdaDoneCallBack e_doneCallBack; /* callback after PDU has been processed */ /* added for PMDA_INTERFACE_5 */ int e_context; /* client context id from pmcd */ pmdaEndContextCallBack e_endCallBack; /* callback after client context closed */ } pmdaExt; #define PMDA_EXT_FLAG_DIRECT 0x1 /* direct mapped PMID metric table */ #define PMDA_EXT_FLAG_HASHED 0x2 /* hashed PMID metric table lookup */ /* * Optionally restrict symbol visibility for DSO PMDAs * * When compiled with -fvisibility=hidden this directive can be used * to set up the init routine so that it is the only symbol exported * by the DSO PMDA. This gives the compiler opportunity to generate * more optimal code as well as ensuring that just the one symbol is * exported (which is a good idea in itself). */ #ifdef __GNUC__ # define __PMDA_INIT_CALL __attribute__ ((visibility ("default"))) #else # define __PMDA_INIT_CALL #endif /* * Interface Definitions for PMDA DSO Interface * The new interface structure makes use of a union to manage new revisions * cleanly. The structure for each new version must be backward compatible * to all of the previous versions (i.e. contain earlier fields unchanged). * * The domain field is set by pmcd(1) in the case of a DSO PMDA, and by * pmdaDaemon and pmdaGetOpt in the case of a Daemon PMDA. It should not be * modified. */ typedef struct { int domain; /* performance metrics domain id */ struct { unsigned int pmda_interface : 8; /* PMDA DSO interface version */ unsigned int pmapi_version : 8; /* PMAPI version */ unsigned int flags : 16; /* optional feature flags */ } comm; /* set/return communication and version info */ int status; /* return initialization status here */ union { /* * Interface Version 2 and 3 (PCP 2.0) * PMDA_INTERFACE_2 and PMDA_INTERFACE_3 */ struct { pmdaExt *ext; int (*profile)(pmdaInProfile *, pmdaExt *); int (*fetch)(int, pmID *, pmResult **, pmdaExt *); int (*desc)(pmID, pmDesc *, pmdaExt *); int (*instance)(pmInDom, int, char *, pmdaInResult **, pmdaExt *); int (*text)(int, int, char **, pmdaExt *); int (*store)(pmResult *, pmdaExt *); } any, two, three; /* * Interface Version 4 (dynamic pmns support) and Version 5 (client context * in PMDA). * PMDA_INTERFACE_4, PMDA_INTERFACE_5 */ struct { pmdaExt *ext; int (*profile)(pmdaInProfile *, pmdaExt *); int (*fetch)(int, pmID *, pmResult **, pmdaExt *); int (*desc)(pmID, pmDesc *, pmdaExt *); int (*instance)(pmInDom, int, char *, pmdaInResult **, pmdaExt *); int (*text)(int, int, char **, pmdaExt *); int (*store)(pmResult *, pmdaExt *); int (*pmid)(const char *, pmID *, pmdaExt *); int (*name)(pmID, char ***, pmdaExt *); int (*children)(const char *, int, char ***, int **, pmdaExt *); } four, five; /* * Interface Version 6 (client context security attributes in PMDA). * PMDA_INTERFACE_6 */ struct { pmdaExt *ext; int (*profile)(pmdaInProfile *, pmdaExt *); int (*fetch)(int, pmID *, pmResult **, pmdaExt *); int (*desc)(pmID, pmDesc *, pmdaExt *); int (*instance)(pmInDom, int, char *, pmdaInResult **, pmdaExt *); int (*text)(int, int, char **, pmdaExt *); int (*store)(pmResult *, pmdaExt *); int (*pmid)(const char *, pmID *, pmdaExt *); int (*name)(pmID, char ***, pmdaExt *); int (*children)(const char *, int, char ***, int **, pmdaExt *); int (*attribute)(int, int, const char *, int, pmdaExt *); } six; } version; } pmdaInterface; /* * PM_CONTEXT_LOCAL support */ typedef struct { int domain; char *name; char *init; void *handle; pmdaInterface dispatch; } __pmDSO; extern __pmDSO *__pmLookupDSO(int /*domain*/); /* Macro that can be used to create each metrics' PMID. */ #define PMDA_PMID(x,y) (((x)<<10)|(y)) /* macro for pmUnits bitmap in a pmDesc declaration */ #ifdef HAVE_BITFIELDS_LTOR #define PMDA_PMUNITS(a,b,c,d,e,f) {a,b,c,d,e,f,0} #else #define PMDA_PMUNITS(a,b,c,d,e,f) {0,f,e,d,c,b,a} #endif /* * PMDA Setup Routines. * * pmdaGetOpt * Replacement for getopt(3) which strips out the standard PMDA flags * before returning the next command line option. The standard PMDA * flags are "D:d:i:l:pu:" which will initialise the pmdaExt structure * with the IPC details, path to the log file and domain number. * err will be incremented if there was an error parsing these options. * * pmdaDaemon * Setup the pmdaInterface structure for a daemon and initialise * the pmdaExt structure with the PMDA's name, domain and path to * the log file and help file. The libpcp internal state is also * initialised. * * pmdaDSO * Setup the pmdaInterface structure for a DSO and initialise the * pmdaExt structure with the PMDA's name and help file. * * pmdaOpenLog * Redirects stderr to the logfile. * * pmdaSetFlags * Allow behaviour flags to be set to enable features, such as to request * libpcp_pmda internally use direct or hashed PMID metric table mapping. * Can be called multiple times - effects are cumulative - no flag can be * cleared, although libpcp_pmda may disable a flag later on if it cannot * enact the requested behaviour. * * pmdaInit * Further initialises the pmdaExt structure with the instance domain and * metric structures. Unique identifiers are applied to each instance * domain and metric. Also open the help text file and checks whether the * metrics can be directly mapped. * * pmdaConnect * Connect to the PMCD process using the method set in the pmdaExt e_io * field. * * pmdaMain * Loop which receives PDUs and dispatches the callbacks. Must be called * by a daemon PMDA. * * pmdaSetResultCallBack * Allows an application specific routine to be specified for cleaning up * a pmResult after a fetch. Most PMDAs should not use this. * * pmdaSetFetchCallBack * Allows an application specific routine to be specified for completing a * pmAtom structure with a metrics value. This must be set if pmdaFetch is * used as the fetch callback. * * pmdaSetCheckCallBack * Allows an application specific routine to be called upon receipt of any * PDU. For all PDUs except PDU_PROFILE, a result less than zero * indicates an error. If set to zero (which is also the default), * the callback is ignored. * * pmdaSetDoneCallBack * Allows an application specific routine to be called after each PDU is * processed. The result is ignored. If set to zero (which is also * the default), the callback is ignored. * * pmdaSetEndContextCallBack * Allows an application specific routine to be called when a * PMCD context is closed, so any per-context state can be cleaned * up. If set to zero (which is also the default), the callback * is ignored. */ extern int pmdaGetOpt(int, char *const *, const char *, pmdaInterface *, int *); extern void pmdaDaemon(pmdaInterface *, int, char *, int , char *, char *); extern void pmdaDSO(pmdaInterface *, int, char *, char *); extern void pmdaOpenLog(pmdaInterface *); extern void pmdaSetFlags(pmdaInterface *, int); extern void pmdaInit(pmdaInterface *, pmdaIndom *, int, pmdaMetric *, int); extern void pmdaConnect(pmdaInterface *); extern void pmdaMain(pmdaInterface *); extern void pmdaSetResultCallBack(pmdaInterface *, pmdaResultCallBack); extern void pmdaSetFetchCallBack(pmdaInterface *, pmdaFetchCallBack); extern void pmdaSetCheckCallBack(pmdaInterface *, pmdaCheckCallBack); extern void pmdaSetDoneCallBack(pmdaInterface *, pmdaDoneCallBack); extern void pmdaSetEndContextCallBack(pmdaInterface *, pmdaEndContextCallBack); /* * Callbacks to PMCD which should be adequate for most PMDAs. * NOTE: if pmdaFetch is used, e_callback must be specified in the pmdaExt * structure. * * pmdaProfile * Store the instance profile away for the next fetch. * * pmdaFetch * Resize the pmResult and call e_callback in the pmdaExt structure * for each metric instance required by the profile. * * pmdaInstance * Return description of instances and instance domains. * * pmdaDesc * Return the metric desciption. * * pmdaText * Return the help text for the metric. * * pmdaStore * Store a value into a metric. This is a no-op. * * pmdaPMID * Return the PMID for a named metric within a dynamic subtree * of the PMNS. * * pmdaName * Given a PMID, return the names of all matching metrics within a * dynamic subtree of the PMNS. * * pmdaChildren * If traverse == 0, return the names of all the descendent children * and their status, given a named metric in a dynamic subtree of * the PMNS (this is the pmGetChildren or pmGetChildrenStatus variant). * If traverse == 1, return the full names of all descendent metrics * (this is the pmTraversePMNS variant, with the status added) * * pmdaAttribute * Inform the agent about security aspects of a client connection, * such as the authenticated userid. Passed in a client identifier, * numeric PCP_ATTR, pointer to the associated value, and the length * of the value. */ extern int pmdaProfile(pmdaInProfile *, pmdaExt *); extern int pmdaFetch(int, pmID *, pmResult **, pmdaExt *); extern int pmdaInstance(pmInDom, int, char *, pmdaInResult **, pmdaExt *); extern int pmdaDesc(pmID, pmDesc *, pmdaExt *); extern int pmdaText(int, int, char **, pmdaExt *); extern int pmdaStore(pmResult *, pmdaExt *); extern int pmdaPMID(const char *, pmID *, pmdaExt *); extern int pmdaName(pmID, char ***, pmdaExt *); extern int pmdaChildren(const char *, int, char ***, int **, pmdaExt *); extern int pmdaAttribute(int, int, const char *, int, pmdaExt *); /* * PMDA "help" text manipulation */ extern int pmdaOpenHelp(char *); extern void pmdaCloseHelp(int); extern char *pmdaGetHelp(int, pmID, int); extern char *pmdaGetInDomHelp(int, pmInDom, int); /* * Dynamic metric table manipulation * * pmdaDynamicPMNS * Register a new dynamic namespace sub-tree associated with one or more * PMID clusters. Callbacks are passed in to deal with PMDA-specific * components (names, help text, metric duplication, and table sizing). * * pmdaDynamicLookupName * Perform PMDA name lookup operations for the name callback, for dynamic * metrics. * * pmdaDynamicLookupPMID * Perform PMDA reverse name lookup operations for the PMID callback, for * dynamic metrics. * * pmdaDynamicLookupText * Perform PMDA help text lookup operations for dynamic metrics. * * pmdaDynamicMetricTable * Install a new metric table for the PMDA, after changes to the set of * metrics which the PMDA must export (IOW, dynamic metrics are in use). * * pmdaRehash * Update the metrictable within the pmdaExt structure with new (dynamic) * metrics and recompute the hash table used for optimised lookup. Aids * PMDAs with large numbers of metrics to get closer to directly mapped * PMID lookup time, rather than multiple linear table scans per fetch. * [NOTE: can be used by any interface version, not only dynamic metrics] */ typedef int (*pmdaUpdatePMNS)(pmdaExt *, pmdaNameSpace **); typedef int (*pmdaUpdateText)(pmdaExt *, pmID, int, char **); typedef void (*pmdaUpdateMetric)(pmdaMetric *, pmdaMetric *, int); typedef void (*pmdaCountMetrics)(int *, int *); extern void pmdaDynamicPMNS(const char *, int *, int, pmdaUpdatePMNS, pmdaUpdateText, pmdaUpdateMetric, pmdaCountMetrics, pmdaMetric *, int); extern pmdaNameSpace *pmdaDynamicLookupName(pmdaExt *, const char *); extern pmdaNameSpace *pmdaDynamicLookupPMID(pmdaExt *, pmID); extern int pmdaDynamicLookupText(pmID, int, char **, pmdaExt *); extern void pmdaDynamicMetricTable(pmdaExt *); extern void pmdaRehash(pmdaExt *, pmdaMetric *, int); /* * Dynamic names interface (version 4) helper routines. * * pmdaTreePMID * when a pmdaNameSpace is being used, this provides * an implementation for the four.pmid() interface. * * pmdaTreeName * when a pmdaNameSpace is being used, this provides * an implementation for the four.name() interface. * * pmdaTreeChildren * when a pmdaNameSpace is being used, this provides * an implementation for the four.children() interface. * * pmdaTreeRebuildHash * iterate over a pmdaNameSpace and (re)build the hash * for any subsequent PMID -> name (reverse) lookups * * pmdaTreeSize * returns the numbers of entries in a pmdaNameSpace. */ extern int pmdaTreePMID(pmdaNameSpace *, const char *, pmID *); extern int pmdaTreeName(pmdaNameSpace *, pmID, char ***); extern int pmdaTreeChildren(pmdaNameSpace *, const char *, int, char ***, int **); extern void pmdaTreeRebuildHash(pmdaNameSpace *, int); extern int pmdaTreeSize(pmdaNameSpace *); /* * PMDA instance domain cache support * * pmdaCacheStore * add entry into the cache, or change state, assigns internal * instance identifier * * pmdaCacheStoreKey * add entry into the cache, or change state, caller provides "hint" * for internal instance identifier * * pmdaCacheLookup * fetch entry based on internal instance identifier * * pmdaCacheLookupName * fetch entry based on external instance name * * pmdaCacheLookupKey * fetch entry based on key as "hint", like pmdaCacheStoreKey() * * pmdaCacheOp * service routines to load, unload, mark as write-thru, purge, * count entries, etc * * pmdaCachePurge * cull inactive entries */ extern int pmdaCacheStore(pmInDom, int, const char *, void *); extern int pmdaCacheStoreKey(pmInDom, int, const char *, int, const void *, void *); extern int pmdaCacheLookup(pmInDom, int, char **, void **); extern int pmdaCacheLookupName(pmInDom, const char *, int *, void **); extern int pmdaCacheLookupKey(pmInDom, const char *, int, const void *, char **, int *, void **); extern int pmdaCacheOp(pmInDom, int); extern int pmdaCachePurge(pmInDom, time_t); #define PMDA_CACHE_LOAD 1 #define PMDA_CACHE_ADD 2 #define PMDA_CACHE_HIDE 3 #define PMDA_CACHE_CULL 4 #define PMDA_CACHE_EMPTY 5 #define PMDA_CACHE_SAVE 6 #define PMDA_CACHE_STRINGS 7 #define PMDA_CACHE_ACTIVE 8 #define PMDA_CACHE_INACTIVE 9 #define PMDA_CACHE_SIZE 10 #define PMDA_CACHE_SIZE_ACTIVE 11 #define PMDA_CACHE_SIZE_INACTIVE 12 #define PMDA_CACHE_REUSE 13 #define PMDA_CACHE_WALK_REWIND 14 #define PMDA_CACHE_WALK_NEXT 15 #define PMDA_CACHE_CHECK 16 #define PMDA_CACHE_REORG 17 #define PMDA_CACHE_SYNC 18 #define PMDA_CACHE_DUMP 19 #define PMDA_CACHE_DUMP_ALL 20 /* * Internal libpcp_pmda routines. * * __pmdaCntInst * Returns the number of instances for an entry in the instance domain * table. * * __pmdaStartInst * Setup for __pmdaNextInst to iterate over an instance domain. * * __pmdaNextInst * Step through an instance domain, returning instances one at a * time. * * __pmdaMainPDU * Use this when you need to override pmdaMain and construct * your own loop. * Call this function in the _body_ of your loop. * See pmdaMain code for an example. * Returns negative int on failure, 0 otherwise. * * __pmdaInFd * This returns the file descriptor that is used to get the * PDU from pmcd. * One may use the fd to do a select call in a custom main loop. * Returns negative int on failure, file descriptor otherwise. * * __pmdaCacheDumpAll and __pmdaCacheDump * print out cache contents */ extern int __pmdaCntInst(pmInDom, pmdaExt *); extern void __pmdaStartInst(pmInDom, pmdaExt *); extern int __pmdaNextInst(int *, pmdaExt *); extern int __pmdaMainPDU(pmdaInterface *); extern int __pmdaInFd(pmdaInterface *); extern void __pmdaCacheDumpAll(FILE *, int); extern void __pmdaCacheDump(FILE *, pmInDom, int); /* * Client Context support */ extern int pmdaGetContext(void); extern void __pmdaSetContext(int); /* * Event Record support */ extern int pmdaEventNewArray(void); extern int pmdaEventResetArray(int); extern int pmdaEventReleaseArray(int); extern int pmdaEventAddRecord(int, struct timeval *, int); extern int pmdaEventAddMissedRecord(int, struct timeval *, int); extern int pmdaEventAddParam(int, pmID, int, pmAtomValue *); extern pmEventArray *pmdaEventGetAddr(int); /* * Event Queue support */ extern int pmdaEventNewQueue(const char *, size_t); extern int pmdaEventNewActiveQueue(const char *, size_t, unsigned int); extern int pmdaEventQueueHandle(const char *); extern int pmdaEventQueueAppend(int, void *, size_t, struct timeval *); extern int pmdaEventQueueClients(int, pmAtomValue *); extern int pmdaEventQueueCounter(int, pmAtomValue *); extern int pmdaEventQueueBytes(int, pmAtomValue *); extern int pmdaEventQueueMemory(int, pmAtomValue *); typedef int (*pmdaEventDecodeCallBack)(int, void *, size_t, struct timeval *, void *); extern int pmdaEventQueueRecords(int, pmAtomValue *, int, pmdaEventDecodeCallBack, void *); extern int pmdaEventNewClient(int); extern int pmdaEventEndClient(int); extern int pmdaEventClients(pmAtomValue *); typedef int (*pmdaEventApplyFilterCallBack)(void *, void *, size_t); typedef void (*pmdaEventReleaseFilterCallBack)(void *); extern int pmdaEventSetFilter(int, int, void *, pmdaEventApplyFilterCallBack, pmdaEventReleaseFilterCallBack); extern int pmdaEventSetAccess(int, int, int); extern char *__pmdaEventPrint(const char *, int, char *, int); #ifdef __cplusplus } #endif #endif /* _PMDA_H */ pcp-3.8.12ubuntu1/src/include/pcp/import.h0000664000000000000000000000544012272262501015264 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2010 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _IMPORT_H #define _IMPORT_H #ifdef __cplusplus extern "C" { #endif /* core libpcp_import API routines */ extern int pmiStart(const char *, int); extern int pmiUseContext(int); extern int pmiEnd(void); extern int pmiSetHostname(const char *); extern int pmiSetTimezone(const char *); extern int pmiAddMetric(const char *, pmID, int, pmInDom, int, pmUnits); extern int pmiAddInstance(pmInDom, const char *, int); extern int pmiPutValue(const char *, const char *, const char *); extern int pmiGetHandle(const char *, const char *); extern int pmiPutValueHandle(int, const char *); extern int pmiWrite(int, int); extern int pmiPutResult(const pmResult *); /* helper routines */ extern pmID pmiID(int, int, int); extern pmInDom pmiInDom(int, int); extern pmUnits pmiUnits(int, int, int, int, int, int); /* diagnostic routines */ #define PMI_MAXERRMSGLEN 128 /* safe size to accomodate any error message */ extern char *pmiErrStr_r(int, char *, int); extern const char *pmiErrStr(int); /* cannot ever be made thread-safe */ extern void pmiDump(void); /* libpcp_import error codes */ #define PMI_ERR_BASE 20000 #define PMI_ERR_DUPMETRICNAME (-PMI_ERR_BASE-1) /* Metric name already defined */ #define PMI_ERR_DUPMETRICID (-PMI_ERR_BASE-2) /* Metric pmID already defined */ #define PMI_ERR_DUPINSTNAME (-PMI_ERR_BASE-3) /* External instance name already defined */ #define PMI_ERR_DUPINSTID (-PMI_ERR_BASE-4) /* Internal instance identifer already defined */ #define PMI_ERR_INSTNOTNULL (-PMI_ERR_BASE-5) /* Non-null instance expected for a singular metric */ #define PMI_ERR_INSTNULL (-PMI_ERR_BASE-6) /* Null instance not allowed for a non-singular metric */ #define PMI_ERR_BADHANDLE (-PMI_ERR_BASE-7) /* Illegal handle */ #define PMI_ERR_DUPVALUE (-PMI_ERR_BASE-8) /* Value already assigned for singular metric */ #define PMI_ERR_BADTYPE (-PMI_ERR_BASE-9) /* Illegal metric type */ #define PMI_ERR_BADSEM (-PMI_ERR_BASE-10) /* Illegal metric semantics */ #define PMI_ERR_NODATA (-PMI_ERR_BASE-11) /* No data to output */ #define PMI_ERR_BADMETRICNAME (-PMI_ERR_BASE-12) /* Illegal metric name */ #define PMI_ERR_BADTIMESTAMP (-PMI_ERR_BASE-13) /* Illegal result timestamp */ #ifdef __cplusplus } #endif #endif /* _IMPORT_H */ pcp-3.8.12ubuntu1/src/include/pcp/pmtime.h0000664000000000000000000000634312272262501015250 0ustar /* * Copyright (C) 2006-2007 Aconex. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #ifndef PMTIME_H #define PMTIME_H #include typedef enum { PM_TCTL_SET = (1<<0), // client -> server PM_TCTL_STEP = (1<<1), // server -> clients PM_TCTL_TZ = (1<<2), // server -> clients PM_TCTL_VCRMODE = (1<<3), // server -> clients PM_TCTL_VCRMODE_DRAG= (1<<4), // server -> clients PM_TCTL_GUISHOW = (1<<5), // client -> server PM_TCTL_GUIHIDE = (1<<6), // client -> server PM_TCTL_BOUNDS = (1<<7), // client -> server PM_TCTL_ACK = (1<<8), // client -> server (except handshake) } pm_tctl_command; typedef enum { PM_STATE_STOP = 0, PM_STATE_FORWARD = 1, PM_STATE_BACKWARD = 2, } pm_tctl_state; typedef enum { PM_MODE_STEP = 0, PM_MODE_NORMAL = 1, PM_MODE_FAST = 2, } pm_tctl_mode; typedef enum { PM_SOURCE_NONE = -1, PM_SOURCE_HOST = 0, PM_SOURCE_ARCHIVE = 1, } pm_tctl_source; #define PMTIME_MAGIC 0x54494D45 /* "TIME" */ typedef struct { unsigned int magic; unsigned int length; pm_tctl_command command; pm_tctl_source source; pm_tctl_state state; pm_tctl_mode mode; struct timeval delta; struct timeval position; struct timeval start; /* archive only */ struct timeval end; /* archive only */ char data[0]; /* arbitrary length info (e.g. $TZ) */ } pmTime; extern int pmTimeSendAck(int, struct timeval *); extern int pmTimeConnect(int, pmTime *); extern int pmTimeShowDialog(int, int); extern int pmTimeRecv(int, pmTime **); /* * Time state management API for simple clients */ typedef void (*pmTimeStateResume)(void); typedef void (*pmTimeStateRewind)(void); typedef void (*pmTimeStateExited)(void); typedef void (*pmTimeStateBoundary)(void); typedef void (*pmTimeStatePosition)(struct timeval); typedef void (*pmTimeStateInterval)(struct timeval); typedef void (*pmTimeStateStepped)(struct timeval); typedef void (*pmTimeStateNewZone)(char *, char *); typedef struct { pmTimeStateResume resume; pmTimeStateRewind rewind; pmTimeStateExited exited; pmTimeStateBoundary boundary; pmTimeStatePosition position; pmTimeStateInterval interval; pmTimeStateStepped stepped; pmTimeStateNewZone newzone; struct timeval delta; int fd; int showgui; int context; int padding; } pmTimeControls; extern pmTime *pmTimeStateSetup(pmTimeControls *, int, int, struct timeval, struct timeval, struct timeval, struct timeval, char *, char *); extern void pmTimeStateAck(pmTimeControls *, pmTime *); extern void pmTimeStateMode(int, struct timeval, struct timeval *); extern int pmTimeStateVector(pmTimeControls *, pmTime *); extern void pmTimeStateBounds(pmTimeControls *, pmTime *); #endif /* PMTIME_H */ pcp-3.8.12ubuntu1/src/include/pcp/mmv_stats.h0000664000000000000000000000763412272262501015776 0ustar /* * Copyright (C) 2013 Red Hat. * Copyright (C) 2009 Aconex. All Rights Reserved. * Copyright (C) 2001,2009 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #ifndef _MMV_STATS_H #define _MMV_STATS_H #ifdef __cplusplus extern "C" { #endif #define MMV_NAMEMAX 64 #define MMV_STRINGMAX 256 typedef enum mmv_metric_type { MMV_TYPE_NOSUPPORT = PM_TYPE_NOSUPPORT, MMV_TYPE_I32 = PM_TYPE_32, /* 32-bit signed integer */ MMV_TYPE_U32 = PM_TYPE_U32, /* 32-bit unsigned integer */ MMV_TYPE_I64 = PM_TYPE_64, /* 64-bit signed integer */ MMV_TYPE_U64 = PM_TYPE_U64, /* 64-bit unsigned integer */ MMV_TYPE_FLOAT = PM_TYPE_FLOAT, /* 32-bit floating point */ MMV_TYPE_DOUBLE = PM_TYPE_DOUBLE,/* 64-bit floating point */ MMV_TYPE_STRING = PM_TYPE_STRING,/* NULL-terminate string */ MMV_TYPE_ELAPSED = 9, /* 64-bit elapsed time */ } mmv_metric_type_t; typedef enum mmv_metric_sem { MMV_SEM_COUNTER = PM_SEM_COUNTER, MMV_SEM_INSTANT = PM_SEM_INSTANT, MMV_SEM_DISCRETE = PM_SEM_DISCRETE, } mmv_metric_sem_t; typedef struct mmv_instances { __int32_t internal; /* Internal instance ID */ char external[MMV_NAMEMAX]; /* External instance ID */ } mmv_instances_t; typedef struct mmv_indom { __uint32_t serial; /* Unique identifier */ __uint32_t count; /* Number of instances */ mmv_instances_t * instances; /* Internal/external IDs */ char * shorttext; /* Short help text string */ char * helptext; /* Long help text string */ } mmv_indom_t; typedef struct mmv_metric { char name[MMV_NAMEMAX]; __uint32_t item; /* Unique identifier */ mmv_metric_type_t type; mmv_metric_sem_t semantics; pmUnits dimension; __uint32_t indom; /* Indom serial */ char * shorttext; /* Short help text string */ char * helptext; /* Long help text string */ } mmv_metric_t; #ifdef HAVE_BITFIELDS_LTOR #define MMV_UNITS(a,b,c,d,e,f) {a,b,c,d,e,f,0} #else #define MMV_UNITS(a,b,c,d,e,f) {0,f,e,d,c,b,a} #endif typedef enum mmv_stats_flags { MMV_FLAG_NOPREFIX = 0x1, /* Don't prefix metric names by filename */ MMV_FLAG_PROCESS = 0x2, /* Indicates process check on PID needed */ } mmv_stats_flags_t; extern void * mmv_stats_init(const char *, int, mmv_stats_flags_t, const mmv_metric_t *, int, const mmv_indom_t *, int); extern void mmv_stats_stop(const char *, void *); extern pmAtomValue * mmv_lookup_value_desc(void *, const char *, const char *); extern void mmv_inc_value(void *, pmAtomValue *, double); extern void mmv_set_value(void *, pmAtomValue *, double); extern void mmv_set_string(void *, pmAtomValue *, const char *, int); extern void mmv_stats_add(void *, const char *, const char *, double); extern void mmv_stats_inc(void *, const char *, const char *); extern void mmv_stats_set(void *, const char *, const char *, double); extern void mmv_stats_add_fallback(void *, const char *, const char *, const char *, double); extern void mmv_stats_inc_fallback(void *, const char *, const char *, const char *); extern pmAtomValue * mmv_stats_interval_start(void *, pmAtomValue *, const char *, const char *); extern void mmv_stats_interval_end(void *, pmAtomValue *); extern void mmv_stats_set_string(void *, const char *, const char *, const char *); extern void mmv_stats_set_strlen(void *, const char *, const char *, const char *, size_t); #ifdef __cplusplus } #endif #endif /* _MMV_STATS_H */ pcp-3.8.12ubuntu1/src/include/pcp/impl.h0000664000000000000000000013663212272262501014723 0ustar /* * Copyright (c) 2012-2014 Red Hat. * Copyright (c) 2008-2009 Aconex. All Rights Reserved. * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _IMPL_H #define _IMPL_H #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif #ifdef HAVE_NETINET_IN_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_NETDB_H #include #endif /* * Thread-safe support ... #define to enable thread-safe protection of * global data structures and mutual exclusion when required. * * We require pthread.h and working mutex, the rest can be faked * by the libpcp itself. */ #if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_MUTEX_T) #define PM_MULTI_THREAD 1 #include typedef pthread_mutex_t __pmMutex; #else typedef void * __pmMutex; #endif #ifdef __cplusplus extern "C" { #endif /* * This defines the routines, macros and data structures that are used * in the Performance Metrics Collection Subsystem (PMCS) below the * PMAPI. */ /* * internal libpcp state ... PM_STATE_APPL means we are at or above the * PMAPI in a state where PMAPI calls can safely be made ... PM_STATE_PMCS * means we are in the PMCD, or a PMDA, or low-level PDU code, and * PMAPI calls are a bad idea. */ #define PM_STATE_APPL 0 #define PM_STATE_PMCS 1 extern void __pmSetInternalState(int); extern int __pmGetInternalState(void); /* * PMCD connections come here by default, over-ride with $PMCD_PORT in * environment */ #define SERVER_PORT 44321 /* * port that clients connect to pmproxy(1) on by default, over-ride with * $PMPROXY_PORT in environment */ #define PROXY_PORT 44322 /* * port that clients connect to pmwebd(1) by default */ #define PMWEBD_PORT 44323 /* * Internally, this is how to decode a PMID! * - flag is to denote state internally in some operations * - domain is usually the unique domain number of a PMDA, but DYNAMIC_PMID * (number 511) is reserved for PMIDs representing the root of a * dynamic subtree in the PMNS (and in this case the real domain number * is encoded in the cluster field) * - cluster and item together uniquely identify a metric within a domain */ #define DYNAMIC_PMID 511 typedef struct { #ifdef HAVE_BITFIELDS_LTOR unsigned int flag : 1; unsigned int domain : 9; unsigned int cluster : 12; unsigned int item : 10; #else unsigned int item : 10; unsigned int cluster : 12; unsigned int domain : 9; unsigned int flag : 1; #endif } __pmID_int; static inline __pmID_int * __pmid_int(pmID *idp) { /* avoid gcc's warning about dereferencing type-punned pointers */ return (__pmID_int *)idp; } static inline unsigned int pmid_item(pmID id) { return __pmid_int(&id)->item; } static inline unsigned int pmid_cluster(pmID id) { return __pmid_int(&id)->cluster; } static inline unsigned int pmid_domain(pmID id) { return __pmid_int(&id)->domain; } static inline pmID pmid_build(unsigned int domain, unsigned int cluster, unsigned int item) { pmID id = 0; __pmid_int(&id)->domain = domain; __pmid_int(&id)->cluster = cluster; __pmid_int(&id)->item = item; return id; } /* * Internally, this is how to decode an Instance Domain Identifier * - flag is to denote state internally in some operations * - domain is usually the unique domain number of a PMDA, but DYNAMIC_PMID * (number 511) is reserved (see above for PMID encoding rules) * - serial uniquely identifies an InDom within a domain */ typedef struct { #ifdef HAVE_BITFIELDS_LTOR int flag : 1; unsigned int domain : 9; unsigned int serial : 22; #else unsigned int serial : 22; unsigned int domain : 9; int flag : 1; #endif } __pmInDom_int; static inline __pmInDom_int * __pmindom_int(pmInDom *idp) { /* avoid gcc's warning about dereferencing type-punned pointers */ return (__pmInDom_int *)idp; } static inline unsigned int pmInDom_domain(pmInDom id) { return __pmindom_int(&id)->domain; } static inline unsigned int pmInDom_serial(pmInDom id) { return __pmindom_int(&id)->serial; } static inline pmInDom pmInDom_build (unsigned int domain, unsigned int serial) { pmInDom ind = 0; __pmindom_int(&ind)->domain = domain; __pmindom_int(&ind)->serial = serial; return (ind); } /* * internal structure of a PMNS node */ typedef struct __pmnsNode { struct __pmnsNode *parent; struct __pmnsNode *next; struct __pmnsNode *first; struct __pmnsNode *hash; /* used as "last" in build, then pmid hash synonym */ char *name; pmID pmid; } __pmnsNode; /* * internal structure of a PMNS tree */ typedef struct __pmnsTree { __pmnsNode *root; /* root of tree structure */ __pmnsNode **htab; /* hash table of nodes keyed on pmid */ int htabsize; /* number of nodes in the table */ char *symbol; /* store all names contiguously */ int contiguous; /* is data stored contiguously ? */ int mark_state; /* the total mark value for trimming */ } __pmnsTree; /* used by pmnsmerge... */ extern __pmnsTree *__pmExportPMNS(void); /* for PMNS in archives */ extern int __pmNewPMNS(__pmnsTree **); extern void __pmFreePMNS(__pmnsTree *); extern void __pmUsePMNS(__pmnsTree *); /* for debugging */ extern int __pmFixPMNSHashTab(__pmnsTree *, int, int); extern int __pmAddPMNSNode(__pmnsTree *, int, const char *); /* return true if the named pmns file has changed */ extern int __pmHasPMNSFileChanged(const char *); /* standard log file set up */ extern FILE *__pmOpenLog(const char *, const char *, FILE *, int *); extern FILE *__pmRotateLog(const char *, const char *, FILE *, int *); /* make __pmNotifyErr also add entries to syslog */ extern void __pmSyslog(int); /* standard error, warning and info wrapper for syslog(3C) */ extern void __pmNotifyErr(int, const char *, ...) __PM_PRINTFLIKE(2,3); /* * These are for debugging only (but are present in the shipped libpcp) */ EXTERN int pmDebug; #define DBG_TRACE_PDU 1 /* PDU send and receive */ #define DBG_TRACE_FETCH 2 /* dump pmFetch results */ #define DBG_TRACE_PROFILE 4 /* trace profile changes */ #define DBG_TRACE_VALUE 8 /* metric value conversions */ #define DBG_TRACE_CONTEXT 16 /* trace PMAPI context changes */ #define DBG_TRACE_INDOM 32 /* instance domain operations */ #define DBG_TRACE_PDUBUF 64 /* PDU buffer management */ #define DBG_TRACE_LOG 128 /* generic archive log operations */ #define DBG_TRACE_LOGMETA (1<<8) /* meta data in archives */ #define DBG_TRACE_OPTFETCH (1<<9) /* optFetch tracing */ #define DBG_TRACE_AF (1<<10) /* trace async timer events */ #define DBG_TRACE_APPL0 (1<<11) /* reserved for applications */ #define DBG_TRACE_APPL1 (1<<12) /* reserved for applications */ #define DBG_TRACE_APPL2 (1<<13) /* reserved for applications */ #define DBG_TRACE_PMNS (1<<14) /* PMNS operations */ #define DBG_TRACE_LIBPMDA (1<<15) /* libpcp_pmda */ #define DBG_TRACE_TIMECONTROL (1<<16) /* time control api */ #define DBG_TRACE_PMC (1<<17) /* metrics class */ #define DBG_TRACE_DERIVE (1<<18) /* derived metrics */ #define DBG_TRACE_LOCK (1<<19) /* lock tracing */ #define DBG_TRACE_INTERP (1<<20) /* interpolate mode for archives */ #define DBG_TRACE_CONFIG (1<<21) /* configuration parameters */ #define DBG_TRACE_LOOP (1<<22) /* pmLoop tracing */ #define DBG_TRACE_FAULT (1<<23) /* fault injection tracing */ #define DBG_TRACE_AUTH (1<<24) /* authentication tracing */ #define DBG_TRACE_DISCOVERY (1<<25) /* service discovery tracing */ /* not yet allocated, bits (1<<26) ... (1<<29) */ #define DBG_TRACE_DESPERATE (1<<30) /* verbose/desperate level */ extern int __pmParseDebug(const char *); extern void __pmDumpResult(FILE *, const pmResult *); extern void __pmPrintStamp(FILE *, const struct timeval *); extern void __pmPrintTimeval(FILE *, const __pmTimeval *); extern void __pmPrintDesc(FILE *, const pmDesc *); extern void __pmFreeResultValues(pmResult *); extern char *__pmPDUTypeStr_r(int, char *, int); extern const char *__pmPDUTypeStr(int); /* NOT thread-safe */ extern void __pmDumpNameSpace(FILE *, int); EXTERN int __pmLogReads; #ifdef PCP_DEBUG extern void __pmDumpIDList(FILE *, int, const pmID *); extern void __pmDumpNameList(FILE *, int, char **); extern void __pmDumpStatusList(FILE *, int, const int *); extern void __pmDumpNameAndStatusList(FILE *, int, char **, int *); #endif /* * Logs and archives of performance metrics (not to be confused * with diagnostic logs for error messages, etc.) * * __pmLogCtl log control * __pmLogTI temporal index record */ /* * Hashed Data Structures for the Processing of Logs and Archives */ typedef struct __pmHashNode { struct __pmHashNode *next; unsigned int key; void *data; } __pmHashNode; typedef struct __pmHashCtl { int nodes; int hsize; __pmHashNode **hash; __pmHashNode *next; unsigned int index; } __pmHashCtl; typedef enum { PM_HASH_WALK_START = 0, PM_HASH_WALK_NEXT, PM_HASH_WALK_STOP, PM_HASH_WALK_DELETE_NEXT, PM_HASH_WALK_DELETE_STOP, } __pmHashWalkState; extern void __pmHashInit(__pmHashCtl *); typedef __pmHashWalkState (*__pmHashWalkCallback)(const __pmHashNode *, void *); extern void __pmHashWalkCB(__pmHashWalkCallback, void *, const __pmHashCtl *); extern __pmHashNode *__pmHashWalk(__pmHashCtl *, __pmHashWalkState); extern __pmHashNode *__pmHashSearch(unsigned int, __pmHashCtl *); extern int __pmHashAdd(unsigned int, void *, __pmHashCtl *); extern int __pmHashDel(unsigned int, void *, __pmHashCtl *); extern void __pmHashClear(__pmHashCtl *); /* * External file and internal (below PMAPI) format for an archive label * Note: int is OK here, because configure ensures int is a 32-bit integer */ typedef struct { int ill_magic; /* PM_LOG_MAGIC | log format version no. */ int ill_pid; /* PID of logger */ __pmTimeval ill_start; /* start of this log */ int ill_vol; /* current log volume no. */ char ill_hostname[PM_LOG_MAXHOSTLEN];/* name of collection host */ char ill_tz[PM_TZ_MAXLEN]; /* $TZ at collection host */ } __pmLogLabel; /* * unfortunately, in this version, PCP archives are limited to no * more than 2 Gbytes ... */ typedef __uint32_t __pm_off_t; /* * Temporal Index Record * Note: int is OK here, because configure ensures int is a 32-bit integer */ typedef struct { __pmTimeval ti_stamp; /* now */ int ti_vol; /* current log volume no. */ __pm_off_t ti_meta; /* end of meta data file */ __pm_off_t ti_log; /* end of metrics log file */ } __pmLogTI; /* * Log/Archive Control */ typedef struct { int l_refcnt; /* number of contexts using this log */ char *l_name; /* external log base name */ FILE *l_tifp; /* temporal index */ FILE *l_mdfp; /* meta data */ FILE *l_mfp; /* current metrics log */ int l_curvol; /* current metrics log volume no. */ int l_state; /* (when writing) log state */ __pmHashCtl l_hashpmid; /* PMID hashed access */ __pmHashCtl l_hashindom; /* instance domain hashed access */ __pmHashCtl l_hashrange; /* ptr to first and last value in log for */ /* each metric */ int l_minvol; /* (when reading) lowest known volume no. */ int l_maxvol; /* (when reading) highest known volume no. */ int l_numseen; /* (when reading) size of l_seen */ int *l_seen; /* (when reading) volumes opened OK */ __pmLogLabel l_label; /* (when reading) log label */ __pm_off_t l_physend; /* (when reading) offset to physical EOF */ /* for last volume */ __pmTimeval l_endtime; /* (when reading) timestamp at logical EOF */ int l_numti; /* (when reading) no. temporal index entries */ __pmLogTI *l_ti; /* (when reading) temporal index */ __pmnsTree *l_pmns; /* namespace from meta data */ } __pmLogCtl; /* l_state values */ #define PM_LOG_STATE_NEW 0 #define PM_LOG_STATE_INIT 1 /* * Return the argument if it's a valid filename else return NULL * (note: this function could be replaced with a call to access(), * but is retained for historical reasons). */ extern const char *__pmFindPMDA(const char *); /* * Internal instance profile states */ #define PM_PROFILE_INCLUDE 0 /* include all, exclude some */ #define PM_PROFILE_EXCLUDE 1 /* exclude all, include some */ /* Profile entry (per instance domain) */ typedef struct __pmInDomProfile { pmInDom indom; /* instance domain */ int state; /* include all or exclude all */ int instances_len; /* length of instances array */ int *instances; /* array of instances */ } __pmInDomProfile; /* Instance profile for all domains */ typedef struct __pmProfile { int state; /* default global state */ int profile_len; /* length of profile array */ __pmInDomProfile *profile; /* array of instance profiles */ } __pmProfile; /* * Dump the instance profile, for a particular instance domain * If indom == PM_INDOM_NULL, then print all instance domains */ extern void __pmDumpProfile(FILE *, int, const __pmProfile *); /* * Result structure for instance domain queries * Only the PMDAs and pmcd need to know about this. */ typedef struct __pmInResult { pmInDom indom; /* instance domain */ int numinst; /* may be 0 */ int *instlist; /* instance ids, may be NULL */ char **namelist; /* instance names, may be NULL */ } __pmInResult; extern void __pmDumpInResult(FILE *, const __pmInResult *); /* instance profile methods */ extern int __pmProfileSetSent(void); extern void __pmFreeProfile(__pmProfile *); extern __pmInDomProfile *__pmFindProfile(pmInDom, const __pmProfile *); extern int __pmInProfile(pmInDom, const __pmProfile *, int); extern void __pmFreeInResult(__pmInResult *); /* * Version and capabilities information for PDU exchanges */ #define UNKNOWN_VERSION 0 #define PDU_VERSION2 2 #define PDU_VERSION PDU_VERSION2 #define PDU_OVERRIDE2 -1002 typedef struct { #ifdef HAVE_BITFIELDS_LTOR unsigned int zero : 1; /* ensure this is zero for 1.x compatibility */ unsigned int version : 7; /* PDU_VERSION collector protocol preference */ unsigned int licensed : 8; /* ensure this is one for 2.x compatibility */ unsigned int features : 16; /* advertised (enabled) collector features */ #else unsigned int features : 16; unsigned int licensed : 8; unsigned int version : 7; unsigned int zero : 1; #endif } __pmPDUInfo; /* * Host specification allowing one or more pmproxy host, and port numbers * within the one string, i.e. pmcd host specifications of the form: * host:port,port@proxy:port,port */ typedef struct { char *name; /* hostname (always valid) */ int *ports; /* array of host port numbers */ int nports; /* number of ports in host port array */ } pmHostSpec; extern int __pmParseHostSpec(const char *, pmHostSpec **, int *, char **); extern int __pmUnparseHostSpec(pmHostSpec *, int, char *, size_t); extern void __pmFreeHostSpec(pmHostSpec *, int); typedef enum { PCP_ATTR_NONE = 0, PCP_ATTR_PROTOCOL = 1, /* either pcp:/pcps: protocol (libssl) */ PCP_ATTR_SECURE = 2, /* relaxed/enforced pcps mode (libssl) */ PCP_ATTR_COMPRESS = 3, /* compression flag, no value (libnss) */ PCP_ATTR_USERAUTH = 4, /* user auth flag, no value (libsasl) */ PCP_ATTR_USERNAME = 5, /* user login identity (libsasl) */ PCP_ATTR_AUTHNAME = 6, /* authentication name (libsasl) */ PCP_ATTR_PASSWORD = 7, /* passphrase-based secret (libsasl) */ PCP_ATTR_METHOD = 8, /* use authentication method (libsasl) */ PCP_ATTR_REALM = 9, /* realm to authenticate in (libsasl) */ PCP_ATTR_UNIXSOCK = 10, /* AF_UNIX socket + SO_PEERCRED (unix) */ PCP_ATTR_USERID = 11, /* uid - user identifier (posix) */ PCP_ATTR_GROUPID = 12, /* gid - group identifier (posix) */ PCP_ATTR_LOCAL = 13, /* AF_UNIX socket with localhost fallback */ PCP_ATTR_PROCESSID = 14, /* pid - process identifier (posix) */ } __pmAttrKey; extern __pmAttrKey __pmLookupAttrKey(const char *, size_t); extern int __pmAttrKeyStr_r(__pmAttrKey, char *, size_t); extern int __pmAttrStr_r(__pmAttrKey, const char *, char *, size_t); extern int __pmParseHostAttrsSpec( const char *, pmHostSpec **, int *, __pmHashCtl *, char **); extern int __pmUnparseHostAttrsSpec( pmHostSpec *, int, __pmHashCtl *, char *, size_t); extern void __pmFreeHostAttrsSpec(pmHostSpec *, int, __pmHashCtl *); extern void __pmFreeAttrsSpec(__pmHashCtl *); /* * Control for connection to a PMCD */ typedef struct { __pmMutex pc_lock; /* mutex pmcd ipc */ int pc_refcnt; /* number of contexts using this socket */ int pc_fd; /* socket for comm with pmcd */ /* ... -1 means no connection */ pmHostSpec *pc_hosts; /* pmcd and proxy host specifications */ int pc_nhosts; /* number of pmHostSpec entries */ int pc_timeout; /* set if connect times out */ int pc_tout_sec; /* timeout for __pmGetPDU */ time_t pc_again; /* time to try again */ } __pmPMCDCtl; extern int __pmConnectPMCD(pmHostSpec *, int, int, __pmHashCtl *); extern int __pmConnectLocal(__pmHashCtl *); extern int __pmAuxConnectPMCD(const char *); extern int __pmAuxConnectPMCDPort(const char *, int); extern int __pmAuxConnectPMCDUnixSocket(const char *); extern int __pmAddHostPorts(pmHostSpec *, int *, int); extern void __pmDropHostPort(pmHostSpec *); extern void __pmConnectGetPorts(pmHostSpec *); /* * SSL/TLS/IPv6 support via NSS/NSPR. */ extern int __pmSecureServerSetup(const char *, const char *); extern void __pmSecureServerShutdown(void); extern int __pmSecureServerHandshake(int, int, __pmHashCtl *); extern int __pmSecureClientHandshake(int, int, const char *, __pmHashCtl *); #ifdef HAVE_SECURE_SOCKETS typedef struct { fd_set native_set; fd_set nspr_set; int num_native_fds; int num_nspr_fds; } __pmFdSet; #else typedef fd_set __pmFdSet; #endif typedef struct __pmSockAddr __pmSockAddr; typedef struct __pmHostEnt __pmHostEnt; extern int __pmCreateSocket(void); extern int __pmCreateIPv6Socket(void); extern int __pmCreateUnixSocket(void); extern void __pmCloseSocket(int); extern int __pmSetSockOpt(int, int, int, const void *, __pmSockLen); extern int __pmGetSockOpt(int, int, int, void *, __pmSockLen *); extern int __pmConnect(int, void *, __pmSockLen); extern int __pmBind(int, void *, __pmSockLen); extern int __pmListen(int, int); extern int __pmAccept(int, void *, __pmSockLen *); extern ssize_t __pmWrite(int, const void *, size_t); extern ssize_t __pmRead(int, void *, size_t); extern ssize_t __pmSend(int, const void *, size_t, int); extern ssize_t __pmRecv(int, void *, size_t, int); extern int __pmConnectTo(int, const __pmSockAddr *, int); extern int __pmFD(int); extern void __pmFD_CLR(int, __pmFdSet *); extern int __pmFD_ISSET(int, __pmFdSet *); extern void __pmFD_SET(int, __pmFdSet *); extern void __pmFD_ZERO(__pmFdSet *); extern void __pmFD_COPY(__pmFdSet *, const __pmFdSet *); extern int __pmSelectRead(int, __pmFdSet *, struct timeval *); extern int __pmSelectWrite(int, __pmFdSet *, struct timeval *); extern __pmSockAddr *__pmSockAddrAlloc(void); extern void __pmSockAddrFree(__pmSockAddr *); extern size_t __pmSockAddrSize(void); extern void __pmSockAddrInit(__pmSockAddr *, int, int, int); extern int __pmSockAddrCompare (const __pmSockAddr *, const __pmSockAddr *); extern __pmSockAddr *__pmSockAddrDup(const __pmSockAddr *); extern __pmSockAddr *__pmSockAddrMask(__pmSockAddr *, const __pmSockAddr *); extern void __pmSockAddrSetFamily(__pmSockAddr *, int); extern int __pmSockAddrGetFamily(const __pmSockAddr *); extern void __pmSockAddrSetPort(__pmSockAddr *, int); extern int __pmSockAddrGetPort(const __pmSockAddr *); extern void __pmSockAddrSetScope(__pmSockAddr *, int); extern void __pmSockAddrSetPath(__pmSockAddr *, const char *); extern int __pmSockAddrIsLoopBack(const __pmSockAddr *); extern int __pmSockAddrIsInet(const __pmSockAddr *); extern int __pmSockAddrIsIPv6(const __pmSockAddr *); extern int __pmSockAddrIsUnix(const __pmSockAddr *); extern char * __pmSockAddrToString(__pmSockAddr *); extern __pmSockAddr *__pmStringToSockAddr(const char *); extern __pmSockAddr *__pmLoopBackAddress(int); extern __pmHostEnt * __pmHostEntAlloc(void); extern void __pmHostEntFree(__pmHostEnt *); extern __pmSockAddr *__pmHostEntGetSockAddr(const __pmHostEnt *, void **); extern char * __pmHostEntGetName(__pmHostEnt *); extern __pmHostEnt * __pmGetAddrInfo(const char *); extern char * __pmGetNameInfo(__pmSockAddr *); /* * Query server features - used for expressing protocol capabilities */ typedef enum { PM_SERVER_FEATURE_SECURE = 0, PM_SERVER_FEATURE_COMPRESS, PM_SERVER_FEATURE_IPV6, PM_SERVER_FEATURE_AUTH, PM_SERVER_FEATURE_CREDS_REQD, PM_SERVER_FEATURE_UNIX_DOMAIN, PM_SERVER_FEATURE_DISCOVERY, PM_SERVER_FEATURES } __pmServerFeature; extern int __pmServerHasFeature(__pmServerFeature); extern int __pmServerSetFeature(__pmServerFeature); extern int __pmServerClearFeature(__pmServerFeature); extern int __pmServerAddPorts(const char *); extern int __pmServerAddInterface(const char *); extern void __pmServerSetLocalSocket(const char *); extern int __pmServerSetLocalCreds(int, __pmHashCtl *); extern void __pmServerSetServiceSpec(const char *); typedef void (*__pmServerCallback)(__pmFdSet *, int, int); extern void __pmServerAddNewClients(__pmFdSet *, __pmServerCallback); extern int __pmServerAddToClientFdSet(__pmFdSet *, int); extern int __pmServerOpenRequestPorts(__pmFdSet *, int); extern void __pmServerCloseRequestPorts(void); extern void __pmServerDumpRequestPorts(FILE *); extern char *__pmServerRequestPortString(int, char *, size_t); /* Service broadcasting, for servers. */ typedef struct __pmServerPresence __pmServerPresence; extern __pmServerPresence *__pmServerAdvertisePresence(const char *, int); extern void __pmServerUnadvertisePresence(__pmServerPresence *); /* * Per-context controls for archives and logs */ typedef struct { __pmLogCtl *ac_log; /* global logging and archive control */ long ac_offset; /* fseek ptr for archives */ int ac_vol; /* volume for ac_offset */ int ac_serial; /* serial access pattern for archives */ __pmHashCtl ac_pmid_hc; /* per PMID controls for INTERP */ double ac_end; /* time at end of archive */ void *ac_want; /* used in interp.c */ void *ac_unbound; /* used in interp.c */ } __pmArchCtl; /* * PMAPI context. We keep an array of these, * one for each context created by the application. */ typedef struct { __pmMutex c_lock; /* mutex for multi-thread access */ int c_type; /* HOST, ARCHIVE, LOCAL or FREE */ int c_mode; /* current mode PM_MODE_* */ __pmPMCDCtl *c_pmcd; /* pmcd control for HOST contexts */ __pmArchCtl *c_archctl; /* log control for ARCHIVE contexts */ __pmTimeval c_origin; /* pmFetch time origin / current time */ int c_delta; /* for updating origin */ int c_sent; /* profile has been sent to pmcd */ __pmProfile *c_instprof; /* instance profile */ void *c_dm; /* derived metrics, if any */ int c_flags; /* ctx flags (set via type/env/attrs) */ __pmHashCtl c_attrs; /* various optional context attributes */ } __pmContext; #define __PM_MODE_MASK 0xffff #define PM_CONTEXT_FREE -1 /* special type */ /* * Convert opaque context handle to __pmContext pointer */ extern __pmContext *__pmHandleToPtr(int); /* * Dump the current context (source details + instance profile), * for a particular instance domain. * If indom == PM_INDOM_NULL, then print all all instance domains */ extern void __pmDumpContext(FILE *, int, pmInDom); /* * pmFetch helper routines, providing hooks for derivations. */ extern int __pmPrepareFetch(__pmContext *, int, const pmID *, pmID **); extern int __pmFinishResult(__pmContext *, int, pmResult **); /* * Protocol data unit support * Note: int is OK here, because configure ensures int is a 32-bit integer */ typedef struct { int len; /* length of pdu_header + PDU */ int type; /* PDU type */ int from; /* pid of PDU originator */ } __pmPDUHdr; typedef __uint32_t __pmPDU; /* * round a size up to the next multiple of a __pmPDU size * * PM_PDU_SIZE is in units of __pmPDU size * PM_PDU_SIZE_BYTES is in units of bytes */ #define PM_PDU_SIZE(x) (((x)+sizeof(__pmPDU)-1)/sizeof(__pmPDU)) #define PM_PDU_SIZE_BYTES(x) (sizeof(__pmPDU)*PM_PDU_SIZE(x)) /* Types of credential PDUs (c_type) */ #define CVERSION 0x1 typedef struct { #ifdef HAVE_BITFIELDS_LTOR unsigned int c_type: 8; /* Credentials PDU type */ unsigned int c_vala: 8; unsigned int c_valb: 8; unsigned int c_valc: 8; #else unsigned int c_valc: 8; unsigned int c_valb: 8; unsigned int c_vala: 8; unsigned int c_type: 8; #endif } __pmCred; /* Flags for CVERSION credential PDUs, and __pmPDUInfo features */ #define PDU_FLAG_SECURE (1U<<0) #define PDU_FLAG_COMPRESS (1U<<1) #define PDU_FLAG_AUTH (1U<<2) #define PDU_FLAG_CREDS_REQD (1U<<3) /* Credential CVERSION PDU elements look like this */ typedef struct { #ifdef HAVE_BITFIELDS_LTOR unsigned int c_type: 8; /* Credentials PDU type */ unsigned int c_version: 8; /* PCP protocol version */ unsigned int c_flags: 16; /* All feature requests */ #else unsigned int c_flags: 16; unsigned int c_version: 8; unsigned int c_type: 8; #endif } __pmVersionCred; extern int __pmXmitPDU(int, __pmPDU *); extern int __pmGetPDU(int, int, int, __pmPDU **); extern int __pmGetPDUCeiling(void); extern int __pmSetPDUCeiling(int); EXTERN unsigned int *__pmPDUCntIn; EXTERN unsigned int *__pmPDUCntOut; extern void __pmSetPDUCntBuf(unsigned *, unsigned *); /* timeout options for PDU handling */ #define TIMEOUT_NEVER 0 #define TIMEOUT_DEFAULT -1 #define TIMEOUT_ASYNC -2 #define TIMEOUT_CONNECT -3 /* mode options for __pmGetPDU */ #define ANY_SIZE 0 /* replacement for old PDU_BINARY */ #define LIMIT_SIZE 2 /* replacement for old PDU_CLIENT */ extern __pmPDU *__pmFindPDUBuf(int); extern void __pmPinPDUBuf(void *); extern int __pmUnpinPDUBuf(void *); extern void __pmCountPDUBuf(int, int *, int *); #define PDU_START 0x7000 #define PDU_ERROR 0x7000 #define PDU_RESULT 0x7001 #define PDU_PROFILE 0x7002 #define PDU_FETCH 0x7003 #define PDU_DESC_REQ 0x7004 #define PDU_DESC 0x7005 #define PDU_INSTANCE_REQ 0x7006 #define PDU_INSTANCE 0x7007 #define PDU_TEXT_REQ 0x7008 #define PDU_TEXT 0x7009 #define PDU_CONTROL_REQ 0x700a #define PDU_CREDS 0x700c #define PDU_PMNS_IDS 0x700d #define PDU_PMNS_NAMES 0x700e #define PDU_PMNS_CHILD 0x700f #define PDU_PMNS_TRAVERSE 0x7010 #define PDU_AUTH 0x7011 #define PDU_FINISH 0x7011 #define PDU_MAX (PDU_FINISH - PDU_START) /* * Unit of space allocation for PDU buffer. */ #define PDU_CHUNK 1024 /* * PDU encoding formats * These have been retired ... * #define PDU_BINARY 0 * #define PDU_ASCII 1 * And this has been replaced by LIMIT_SIZE for __pmGetPDU * #define PDU_CLIENT 2 */ /* * Anonymous PDU sender, when context does not matter, e.g. PDUs from * a PMDA sent to PMCD */ #define FROM_ANON 0 extern int __pmSendError(int, int, int); extern int __pmDecodeError(__pmPDU *, int *); extern int __pmSendXtendError(int, int, int, int); extern int __pmDecodeXtendError(__pmPDU *, int *, int *); extern int __pmSendResult(int, int, const pmResult *); extern int __pmEncodeResult(int, const pmResult *, __pmPDU **); extern int __pmDecodeResult(__pmPDU *, pmResult **); extern int __pmSendProfile(int, int, int, __pmProfile *); extern int __pmDecodeProfile(__pmPDU *, int *, __pmProfile **); extern int __pmSendFetch(int, int, int, __pmTimeval *, int, pmID *); extern int __pmDecodeFetch(__pmPDU *, int *, __pmTimeval *, int *, pmID **); extern int __pmSendDescReq(int, int, pmID); extern int __pmDecodeDescReq(__pmPDU *, pmID *); extern int __pmSendDesc(int, int, pmDesc *); extern int __pmDecodeDesc(__pmPDU *, pmDesc *); extern int __pmSendInstanceReq(int, int, const __pmTimeval *, pmInDom, int, const char *); extern int __pmDecodeInstanceReq(__pmPDU *, __pmTimeval *, pmInDom *, int *, char **); extern int __pmSendInstance(int, int, __pmInResult *); extern int __pmDecodeInstance(__pmPDU *, __pmInResult **); extern int __pmSendTextReq(int, int, int, int); extern int __pmDecodeTextReq(__pmPDU *, int *, int *); extern int __pmSendText(int, int, int, const char *); extern int __pmDecodeText(__pmPDU *, int *, char **); extern int __pmSendCreds(int, int, int, const __pmCred *); extern int __pmDecodeCreds(__pmPDU *, int *, int *, __pmCred **); extern int __pmSendIDList(int, int, int, const pmID *, int); extern int __pmDecodeIDList(__pmPDU *, int, pmID *, int *); extern int __pmSendNameList(int, int, int, char **, const int *); extern int __pmDecodeNameList(__pmPDU *, int *, char ***, int **); extern int __pmSendChildReq(int, int, const char *, int); extern int __pmDecodeChildReq(__pmPDU *, char **, int *); extern int __pmSendTraversePMNSReq(int, int, const char *); extern int __pmDecodeTraversePMNSReq(__pmPDU *, char **); extern int __pmSendAuth(int, int, int, const char *, int); extern int __pmDecodeAuth(__pmPDU *, int *, char **, int *); #if defined(HAVE_64BIT_LONG) /* * A pmValue contains the union of a 32-bit int and a pointer. In the world * of 64-bit pointers, a pmValue is therefore larger than in the 32-bit world. * The structures below are used in all PDUs containing pmResults to ensure * 32-bit and 64-bit programs exchanging PDUs can communicate. * Note that a pmValue can only hold a 32-bit value in situ regardless of * whether the pointer size is 32 or 64 bits. */ typedef struct { int inst; /* instance identifier */ union { unsigned int pval; /* offset into PDU buffer for value */ int lval; /* 32-bit value in situ */ } value; } __pmValue_PDU; typedef struct { pmID pmid; /* metric identifier */ int numval; /* number of values */ int valfmt; /* value style */ __pmValue_PDU vlist[1]; /* set of instances/values */ } __pmValueSet_PDU; #elif defined(HAVE_32BIT_LONG) /* In the 32-bit world, structures may be used in PDUs as defined */ typedef pmValue __pmValue_PDU; typedef pmValueSet __pmValueSet_PDU; #else bozo - unknown size of long !!! #endif /* * For the help text PDUs, the type (PM_TEXT_ONELINE or PM_TEXT_HELP) * is 'or'd with the following to encode the request for a PMID or * a pmInDom ... * Note the values must therefore be (a) bit fields and (b) different * to the public macros PM_TEXT_* in pmapi.h */ #define PM_TEXT_PMID 4 #define PM_TEXT_INDOM 8 /* * no mem today, my love has gone away .... */ extern void __pmNoMem(const char *, size_t, int); #define PM_FATAL_ERR 1 #define PM_RECOV_ERR 0 /* * Startup handling: * set program name, as used in __pmNotifyErr() ... default is "pcp" * set default user for __pmSetProcessIdentity() ... default is "pcp" */ EXTERN char *pmProgname; extern int __pmSetProgname(const char *); extern int __pmGetUsername(char **); /* * Cleanup handling: * shutdown various components in libpcp, releasing all resources * (local context PMDAs, any global NSS socket state, etc). */ extern int __pmShutdown(void); /* * Map platform error values to PMAPI error codes. */ extern int __pmMapErrno(int); /* * __pmLogInDom is used to hold the instance identifiers for an instance * domain internally ... if multiple sets are observed over time, these * are linked together in reverse chronological order * -- externally we write these as * timestamp * indom <- note, added wrt indom_t * numinst * inst[0], .... inst[numinst-1] * nameindex[0] .... nameindex[numinst-1] * string (name) table, all null-byte terminated * * NOTE: 3 types of allocation * (1) * buf is NULL, * namelist and instlist have been allocated * separately and so must each be freed. * (2) * buf is NOT NULL, allinbuf == 1, * all allocations were in the buffer and so only * the buffer should be freed, * (3) * buf is NOT NULL, allinbuf == 0, * as well as buffer allocation, * the namelist has been allocated separately and so * both the buf and namelist should be freed. */ typedef struct _indom_t { struct _indom_t *next; __pmTimeval stamp; int numinst; int *instlist; char **namelist; int *buf; int allinbuf; } __pmLogInDom; /* * record header in the metadata log file ... len (by itself) also is * used as a trailer */ typedef struct { int len; /* record length, includes header and trailer */ int type; /* see TYPE_* #defines below */ } __pmLogHdr; #define TYPE_DESC 1 /* header, pmDesc, trailer */ #define TYPE_INDOM 2 /* header, __pmLogInDom, trailer */ extern void __pmLogPutIndex(const __pmLogCtl *, const __pmTimeval *); extern const char *__pmLogName_r(const char *, int, char *, int); extern const char *__pmLogName(const char *, int); /* NOT thread-safe */ extern FILE *__pmLogNewFile(const char *, int); extern int __pmLogCreate(const char *, const char *, int, __pmLogCtl *); #define PMLOGREAD_NEXT 0 #define PMLOGREAD_TO_EOF 1 extern int __pmLogRead(__pmLogCtl *, int, FILE *, pmResult **, int); extern int __pmLogWriteLabel(FILE *, const __pmLogLabel *); extern int __pmLogOpen(const char *, __pmContext *); extern int __pmLogLoadLabel(__pmLogCtl *, const char *); extern int __pmLogLoadIndex(__pmLogCtl *); extern int __pmLogLoadMeta(__pmLogCtl *); extern void __pmLogClose(__pmLogCtl *); extern void __pmLogCacheClear(FILE *); extern int __pmLogPutDesc(__pmLogCtl *, const pmDesc *, int, char **); extern int __pmLogLookupDesc(__pmLogCtl *, pmID, pmDesc *); extern int __pmLogPutInDom(__pmLogCtl *, pmInDom, const __pmTimeval *, int, int *, char **); extern int __pmLogGetInDom(__pmLogCtl *, pmInDom, __pmTimeval *, int **, char ***); extern int __pmLogLookupInDom(__pmLogCtl *, pmInDom, __pmTimeval *, const char *); extern int __pmLogNameInDom(__pmLogCtl *, pmInDom, __pmTimeval *, int, char **); extern int __pmLogPutResult(__pmLogCtl *, __pmPDU *); extern int __pmLogFetch(__pmContext *, int, pmID *, pmResult **); extern int __pmLogFetchInterp(__pmContext *, int, pmID *, pmResult **); extern void __pmLogSetTime(__pmContext *); extern void __pmLogResetInterp(__pmContext *); extern int __pmLogChangeVol(__pmLogCtl *, int); extern int __pmLogChkLabel(__pmLogCtl *, FILE *, __pmLogLabel *, int); extern int __pmGetArchiveEnd(__pmLogCtl *, struct timeval *); /* struct for maintaining information about pmlogger ports */ typedef struct { int pid; /* process id of logger */ int port; /* internet port for logger control */ char *pmcd_host; /* host pmlogger is collecting from */ char *archive; /* archive base pathname */ char *name; /* file name (minus dirname) */ } __pmLogPort; /* Returns control port info for a pmlogger given its pid. * If pid == PM_LOG_ALL_PIDS, get all pmloggers' control ports. * If pid == PM_LOG_PRIMARY_PID, get primar logger's control port. * Note: do NOT free any part of result returned via the parameter. * * __pmLogFindPort(const char *hostname, int pid, __pmLogPort **result); */ extern int __pmLogFindPort(const char *, int, __pmLogPort **); #define PM_LOG_PRIMARY_PID 0 /* symbolic pid for primary logger */ #define PM_LOG_PRIMARY_PORT 0 /* symbolic port for primary pmlogger */ #define PM_LOG_ALL_PIDS -1 /* symbolic pid for all pmloggers */ #define PM_LOG_NO_PID -2 /* not a valid pid for pmlogger */ #define PM_LOG_NO_PORT -2 /* not a valid port for pmlogger */ /* time utils */ extern time_t __pmMktime(struct tm *); /* reverse ctime and time interval parsing */ extern int __pmParseCtime(const char *, struct tm *, char **); extern int __pmConvertTime(struct tm *, struct timeval *, struct timeval *); extern int __pmParseTime(const char *, struct timeval *, struct timeval *, struct timeval *, char **); /* manipulate internal timestamps */ extern double __pmTimevalSub(const __pmTimeval *, const __pmTimeval *); /* 32-bit file checksum */ extern __int32_t __pmCheckSum(FILE *); /* check for localhost */ extern int __pmIsLocalhost(const char *); /* * struct timeval manipulations */ extern double __pmtimevalAdd(const struct timeval *, const struct timeval *); extern double __pmtimevalSub(const struct timeval *, const struct timeval *); extern double __pmtimevalToReal(const struct timeval *); extern void __pmtimevalFromReal(double, struct timeval *); extern void __pmtimevalSleep(struct timeval); extern void __pmtimevalPause(struct timeval); extern void __pmtimevalNow(struct timeval *); typedef struct { char *label; /* label to name tz */ char *tz; /* env $TZ */ int handle; /* handle from pmNewZone() */ } pmTimeZone; /* * event tracing for monitoring time between events */ extern void __pmEventTrace(const char *); /* NOT thread-safe */ extern void __pmEventTrace_r(const char *, int *, double *, double *); /* * More IPC protocol stuff */ typedef int (*__pmConnectHostType)(int, int); extern int __pmSetSocketIPC(int); extern int __pmSetVersionIPC(int, int); extern int __pmSetDataIPC(int, void *); extern int __pmDataIPCSize(void); extern int __pmLastVersionIPC(void); extern int __pmVersionIPC(int); extern int __pmSocketIPC(int); extern int __pmDataIPC(int, void *); extern void __pmOverrideLastFd(int); extern void __pmPrintIPC(void); extern void __pmResetIPC(int); /* safely insert an atom value into a pmValue */ extern int __pmStuffValue(const pmAtomValue *, pmValue *, int); /* * Optimized fetch bundling ("optfetch") services */ typedef struct __optreq { struct __optreq *r_next; /* next request */ struct __fetchctl *r_fetch; /* back ptr */ pmDesc *r_desc; /* pmDesc for request pmID */ int r_numinst; /* request instances */ int *r_instlist; /* request instances */ void *r_aux; /* generic pointer to aux data */ } optreq_t; typedef struct __pmidctl { struct __pmidctl *p_next; /* next pmid control */ optreq_t *p_rqp; /* first request for this metric */ pmID p_pmid; /* my pmID */ int p_numinst; /* union over requests */ int *p_instlist; /* union over requests */ void *p_aux; /* generic pointer to aux data */ } pmidctl_t; typedef struct __indomctl { struct __indomctl *i_next; /* next indom control */ pmidctl_t *i_pmp; /* first metric, in this group */ pmInDom i_indom; /* my pmInDom */ int i_numinst; /* arg for pmAddProfile */ int *i_instlist; /* arg for pmAddProfile */ void *i_aux; /* generic pointer to aux data */ } indomctl_t; typedef struct __fetchctl { struct __fetchctl *f_next; /* next fetch control */ indomctl_t *f_idp; /* first indom, in this group */ int f_state; /* state changes during updates */ int f_cost; /* used internally for optimization */ int f_newcost; /* used internally for optimization */ int f_numpmid; /* arg for pmFetch() */ pmID *f_pmidlist; /* arg for pmFetch() */ void *f_aux; /* generic pointer to aux data */ } fetchctl_t; /* states relevant to user */ #define OPT_STATE_NEW 1 /* newly created group */ #define OPT_STATE_PMID 2 /* list of pmids changed */ #define OPT_STATE_PROFILE 4 /* instance profile changed */ /* states used during optimization */ #define OPT_STATE_UMASK 7 /* preserve user state bits */ #define OPT_STATE_XREQ 8 /* things that may have changed */ #define OPT_STATE_XPMID 16 #define OPT_STATE_XINDOM 32 #define OPT_STATE_XFETCH 64 #define OPT_STATE_XPROFILE 128 /* * Objective function parameters */ typedef struct { int c_pmid; /* cost per PMD for PMIDs in a fetch */ int c_indom; /* cost per PMD for indoms in a fetch */ int c_fetch; /* cost of a new fetch group */ int c_indomsize; /* expected numer of instances for an indom */ int c_xtrainst; /* cost of retrieving an unwanted metric inst */ int c_scope; /* cost opt., 0 for incremental, 1 for global */ } optcost_t; #define OPT_COST_INFINITY 0x7fffffff extern void __pmOptFetchAdd(fetchctl_t **, optreq_t *); extern int __pmOptFetchDel(fetchctl_t **, optreq_t *); extern void __pmOptFetchRedo(fetchctl_t **); extern void __pmOptFetchDump(FILE *, const fetchctl_t *); extern void __pmOptFetchGetParams(optcost_t *); extern void __pmOptFetchPutParams(optcost_t *); /* work out local timezone */ extern char *__pmTimezone(void); /* NOT thread-safe */ extern char *__pmTimezone_r(char *, int); /* */ /* * Generic access control routines */ extern int __pmAccAddOp(unsigned int); extern int __pmAccAddHost(const char *, unsigned int, unsigned int, int); extern int __pmAccAddUser(const char *, unsigned int, unsigned int, int); extern int __pmAccAddGroup(const char *, unsigned int, unsigned int, int); extern int __pmAccAddClient(__pmSockAddr *, unsigned int *); extern int __pmAccAddAccount(const char *, const char *, unsigned int *); extern void __pmAccDelClient(__pmSockAddr *); extern void __pmAccDelAccount(const char *, const char *); extern void __pmAccDumpHosts(FILE *); extern void __pmAccDumpUsers(FILE *); extern void __pmAccDumpGroups(FILE *); extern void __pmAccDumpLists(FILE *); extern int __pmAccSaveHosts(void); extern int __pmAccSaveUsers(void); extern int __pmAccSaveGroups(void); extern int __pmAccSaveLists(void); extern int __pmAccRestoreHosts(void); extern int __pmAccRestoreUsers(void); extern int __pmAccRestoreGroups(void); extern int __pmAccRestoreLists(void); extern void __pmAccFreeSavedHosts(void); extern void __pmAccFreeSavedUsers(void); extern void __pmAccFreeSavedGroups(void); extern void __pmAccFreeSavedLists(void); /* * platform independent process routines */ extern int __pmProcessExists(pid_t); extern int __pmProcessTerminate(pid_t, int); extern pid_t __pmProcessCreate(char **, int *, int *); extern int __pmProcessDataSize(unsigned long *); extern int __pmProcessRunTimes(double *, double *); extern int __pmSetProcessIdentity(const char *); /* * platform independent memory mapped file handling */ extern void *__pmMemoryMap(int, size_t, int); extern void __pmMemoryUnmap(void *, size_t); /* * platform independent signal handling */ typedef void (*__pmSignalHandler)(int); extern int __pmSetSignalHandler(int, __pmSignalHandler); /* * platform independent environment and filesystem path access */ typedef void (*__pmConfigCallback)(char *, char *, char *); EXTERN const __pmConfigCallback __pmNativeConfig; extern void __pmConfig(__pmConfigCallback); extern char *__pmNativePath(char *); extern int __pmAbsolutePath(char *); extern int __pmPathSeparator(void); /* * discover configurable features of the shared libraries */ typedef void (*__pmAPIConfigCallback)(const char *, const char *); extern void __pmAPIConfig(__pmAPIConfigCallback); extern const char *__pmGetAPIConfig(const char *); /* * AF - general purpose asynchronous event management routines */ extern int __pmAFregister(const struct timeval *, void *, void (*)(int, void *)); extern int __pmAFunregister(int); extern void __pmAFblock(void); extern void __pmAFunblock(void); extern int __pmAFisempty(void); /* * private PDU protocol between pmlc and pmlogger */ #define LOG_PDU_VERSION2 2 /* private pdus & PCP 2.0 error codes */ #define LOG_PDU_VERSION LOG_PDU_VERSION2 #define LOG_REQUEST_NEWVOLUME 1 #define LOG_REQUEST_STATUS 2 #define LOG_REQUEST_SYNC 3 typedef struct { __pmTimeval ls_start; /* start time for log */ __pmTimeval ls_last; /* last time log written */ __pmTimeval ls_timenow; /* current time */ int ls_state; /* state of log (from __pmLogCtl) */ int ls_vol; /* current volume number of log */ __int64_t ls_size; /* size of current volume */ char ls_hostname[PM_LOG_MAXHOSTLEN]; /* name of pmcd host */ char ls_fqdn[PM_LOG_MAXHOSTLEN]; /* fully qualified domain name of pmcd host */ char ls_tz[PM_TZ_MAXLEN]; /* $TZ at collection host */ char ls_tzlogger[PM_TZ_MAXLEN]; /* $TZ at pmlogger */ } __pmLoggerStatus; #define PDU_LOG_CONTROL 0x8000 #define PDU_LOG_STATUS 0x8001 #define PDU_LOG_REQUEST 0x8002 extern int __pmConnectLogger(const char *, int *, int *); extern int __pmSendLogControl(int, const pmResult *, int, int, int); extern int __pmDecodeLogControl(const __pmPDU *, pmResult **, int *, int *, int *); extern int __pmSendLogRequest(int, int); extern int __pmDecodeLogRequest(const __pmPDU *, int *); extern int __pmSendLogStatus(int, __pmLoggerStatus *); extern int __pmDecodeLogStatus(__pmPDU *, __pmLoggerStatus **); /* logger timeout helper function */ extern int __pmLoggerTimeout(void); /* * other interfaces shared by pmlc and pmlogger */ extern int __pmControlLog(int, const pmResult *, int, int, int, pmResult **); #define PM_LOG_OFF 0 /* state */ #define PM_LOG_MAYBE 1 #define PM_LOG_ON 2 #define PM_LOG_MANDATORY 11 /* control */ #define PM_LOG_ADVISORY 12 #define PM_LOG_ENQUIRE 13 /* macros for logging control values from __pmControlLog() */ #define PMLC_SET_ON(val, flag) \ (val) = ((val) & ~0x1) | ((flag) & 0x1) #define PMLC_GET_ON(val) \ ((val) & 0x1) #define PMLC_SET_MAND(val, flag) \ (val) = ((val) & ~0x2) | (((flag) & 0x1) << 1) #define PMLC_GET_MAND(val) \ (((val) & 0x2) >> 1) #define PMLC_SET_AVAIL(val, flag) \ (val) = ((val) & ~0x4) | (((flag) & 0x1) << 2) #define PMLC_GET_AVAIL(val) \ (((val) & 0x4) >> 2) #define PMLC_SET_INLOG(val, flag) \ (val) = ((val) & ~0x8) | (((flag) & 0x1) << 3) #define PMLC_GET_INLOG(val) \ (((val) & 0x8) >> 3) #define PMLC_SET_STATE(val, state) \ (val) = ((val) & ~0xf) | ((state) & 0xf) #define PMLC_GET_STATE(val) \ ((val) & 0xf) /* 28 bits of delta, 32 bits of state */ #define PMLC_MAX_DELTA 0x0fffffff #define PMLC_SET_DELTA(val, delta) \ (val) = ((val) & 0xf) | ((delta) << 4) #define PMLC_GET_DELTA(val) \ ((((val) & ~0xf) >> 4) & PMLC_MAX_DELTA) /* * helper functions to register client identity with pmcd for export * via pmcd.client.whoami */ extern char *__pmGetClientId(int, char **); extern int __pmSetClientIdArgv(int, char **); extern int __pmSetClientId(const char *); /* * Adding/deleting/clearing the list of DSO PMDAs supported for * PM_CONTEXT_LOCAL contexts */ #define PM_LOCAL_ADD 1 #define PM_LOCAL_DEL 2 #define PM_LOCAL_CLEAR 3 extern int __pmLocalPMDA(int, int, const char *, const char *); extern char *__pmSpecLocalPMDA(const char *); /* * helper methods for packed arrays of event records (PM_TYPE_EVENT) */ extern int __pmCheckEventRecords(pmValueSet *, int); extern void __pmDumpEventRecords(FILE *, pmValueSet *, int); /* anonymous metric registration (uses derived metrics support) */ extern int __pmRegisterAnon(const char *, int); /* * Multi-thread support * Use PM_MULTI_THREAD_DEBUG for lock debugging with -Dlock[,appl?...] */ extern void __pmInitLocks(void); extern int __pmLock(void *, const char *, int); extern int __pmUnlock(void *, const char *, int); /* * Each of these scopes defines one or more PMAPI routines that will * not allow calls from more than one thread. */ #define PM_SCOPE_DSO_PMDA 0 #define PM_SCOPE_ACL 1 #define PM_SCOPE_AF 2 #define PM_SCOPE_LOGPORT 3 #define PM_SCOPE_MAX 3 extern int __pmMultiThreaded(int); #define PM_INIT_LOCKS() __pmInitLocks() #define PM_MULTIPLE_THREADS(x) __pmMultiThreaded(x) #define PM_LOCK(lock) __pmLock(&(lock), __FILE__, __LINE__) #define PM_UNLOCK(lock) __pmUnlock(&(lock), __FILE__, __LINE__) #ifdef HAVE_PTHREAD_MUTEX_T extern pthread_mutex_t __pmLock_libpcp; /* big libpcp lock */ #else extern void *__pmLock_libpcp; /* symbol exposure */ #endif #ifdef __cplusplus } #endif #endif /* _IMPL_H */ pcp-3.8.12ubuntu1/src/include/pcp/pmafm.h0000664000000000000000000000254412272262501015054 0ustar /* * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. */ #ifndef _PMAFM_H #define _PMAFM_H #ifdef __cplusplus extern "C" { #endif /* * Recording session support */ #define PM_REC_ON 40 #define PM_REC_OFF 41 #define PM_REC_DETACH 43 #define PM_REC_STATUS 44 #define PM_REC_SETARG 45 typedef struct { FILE *f_config; /* caller writes pmlogger configuration here */ int fd_ipc; /* IPC channel to pmlogger */ char *logfile; /* full pathname for pmlogger error logfile */ pid_t pid; /* process id for pmlogger */ int status; /* exit status, -1 if unknown */ } pmRecordHost; extern FILE *pmRecordSetup(const char *, const char *, int); extern int pmRecordAddHost(const char *, int, pmRecordHost **); extern int pmRecordControl(pmRecordHost *, int, const char *); #ifdef __cplusplus } #endif #endif /* _PMAFM_H */ pcp-3.8.12ubuntu1/src/pmimport/0000775000000000000000000000000012272262620013242 5ustar pcp-3.8.12ubuntu1/src/pmimport/sar2pcp/0000775000000000000000000000000012272262620014614 5ustar pcp-3.8.12ubuntu1/src/pmimport/sar2pcp/sar2pcp0000775000000000000000000006246712272262501016131 0ustar #!/usr/bin/perl # # Copyright (c) 2012-2013 Red Hat. # Copyright (c) 2010 Ken McDonell. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use XML::TokeParser; use Date::Parse; use Date::Format; use PCP::LogImport; my $sample = 0; my $stamp; my $zone = 'UTC'; # timestamps from sadf are in UTC by default my $parser; my %handlemap; # pmi* handles, one per metric-instance pair my %instmap; # ensures we don't add duplicate indom/instance pairs my $putsts = 0; # pmiPutValue() errors are only checked @ end of loop my $in_cpu_load = 0; my $snarf_text = 0; my $snarf_name; my $save_text; my $interface; my $disk_all_total; my $disk_all_total_bytes; sub dodate($) { # convert datetime format YYYY-MM-DD from sadf into the format # DD-Mmm-YYYY that Date::Parse seems to be able to parse correctly # my ($datetime) = @_; my @fields = split(/-/, $datetime); my $mm; my %mm_map = ( '01' => 'Jan', '02' => 'Feb', '03' => 'Mar', '04' => 'Apr', '05' => 'May', '06' => 'Jun', '07' => 'Jul', '08' => 'Aug', '09' => 'Sep', '10' => 'Oct', '11' => 'Nov', '12' => 'Dec', ); $#fields == 2 or die "dodate: bad datetime format: \"$datetime\"\n"; $mm = $fields[1]; if ($mm < 10 && $mm !~ /^0/) { $mm = "0" . $mm }; # add leading zero defined($mm_map{$mm}) or die "dodate: bad month in datetime: \"$datetime\"\n"; return $fields[2] . '-' . $mm_map{$mm} . '-' . $fields[0]; } sub dotime($) { # convert time format HH-MM-SS from a few 10.x sysstat versions # into the format HH:MM:SS that Date::Parse (reasonably) expects # my ($daytime) = @_; $daytime =~ s/-/:/g; return $daytime; } sub dovalue($) { # convert string to floating point value: "0,00" / "0.00" / undef # (unusual LC_NUMERIC settings put comma instead of decimal point) # fail to convert (or attempt arithmetic on unconverted values) => # e.g. 'Argument "\x{31}\x{2c}..." isn't numeric in addition (+)' # my ($value) = @_; return $value unless defined($value); $value =~ s/,/./g; return $value; } my %warning_tags; # XML tags we do not know and will issue warnings about my %skipped_tags = ( # XML tags we know about, but have no metric to map yet 'sysstat' => 1, 'sysdata-version' => 1, 'sysname' => 1, 'release' => 1, 'machine' => 1, 'comments' => 1, 'restarts' => 1, 'boot' => 1, 'file-date' => 1, 'statistics' => 1, 'interrupts' => 1, 'int-global' => 1, 'int-proc' => 1, 'irqcpu' => 1, 'serial' => 1, 'pty-nr' => 1, 'tty' => 1, 'super-sz' => 1, 'super-sz-percent' => 1, 'dquot-sz' => 1, 'dquot-sz-percent' => 1, 'rtsig-sz' => 1, 'rtsig-sz-percent' => 1, 'memory' => 1, 'memused-percent' => 1, 'commit' => 1, 'commit-percent' => 1, 'swpused' => 1, 'swpused-percent' => 1, 'swpcad-percent' => 1, 'frmpg' => 1, 'bufpg' => 1, 'campg' => 1, 'usb-devices' => 1, 'disk' => 1, 'network' => 1, 'power-management' => 1, 'cpu-frequency' => 1, 'cpu-weighted-frequency' => 1, 'cpufreq' => 1, 'cpuwfreq' => 1, 'cpu' => 1, 'hugepages' => 1, 'hugfree' => 1, 'hugused' => 1, 'hugused-percent' => 1, 'active' => 1, 'inactive' => 1, 'temperature' => 1, 'temp' => 1, 'usb' => 1, ); # Register metrics with a singular value. # sub register_single($) { my ($name) = @_; my $units = pmiUnits(0,0,0,0,0,0); my $type = PM_TYPE_FLOAT; my $sts; if ($name eq 'kernel.all.pswitch' || $name eq 'kernel.all.intr' || $name eq 'swap.pagesin' || $name eq 'swap.pagesout' || $name eq 'mem.vmstat.pgpgin' || $name eq 'mem.vmstat.pgpgout' || $name eq 'mem.vmstat.pgfault' || $name eq 'mem.vmstat.pgmajfault' || $name eq 'mem.vmstat.pgfree' || $name eq 'disk.all.total' || $name eq 'disk.all.read' || $name eq 'disk.all.write') { $units = pmiUnits(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE); } elsif ($name =~ /^mem\.util\./) { $units = pmiUnits(1,0,0,PM_SPACE_KBYTE,0,0); $type = PM_TYPE_U64; } elsif ($name =~ /disk\.all\..*bytes/) { $units = pmiUnits(1,-1,0,PM_SPACE_KBYTE,PM_TIME_SEC,0); } elsif ($name =~ /^vfs\./) { $type = PM_TYPE_U32; } $sts = pmiAddMetric($name, PM_ID_NULL, $type, PM_INDOM_NULL, PM_SEM_INSTANT, $units); die "pmiAddMetric($name, ...): " . pmiErrStr($sts) . "\n" unless ($sts == 0); } # Register metrics with multiple values. # sub register_multi($$) { my ($name,$indom) = @_; my $units = pmiUnits(0,0,0,0,0,0); my $type = PM_TYPE_FLOAT; my $sts; if ($name eq 'proc.runq.runnable' || $name eq 'proc.nprocs') { $units = pmiUnits(0,0,1,0,0,PM_COUNT_ONE); $type = PM_TYPE_U32; } elsif ($name =~ /disk\.dev\..*bytes/ || $name =~ /network\.interface\..*\.bytes/) { $units = pmiUnits(1,-1,0,PM_SPACE_KBYTE,PM_TIME_SEC,0); } elsif ($name eq 'disk.dev.total' || $name eq 'disk.dev.read' || $name eq 'disk.dev.write' || $name =~ /network\.interface\./) { $units = pmiUnits(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE); } $sts = pmiAddMetric($name, PM_ID_NULL, $type, $indom, PM_SEM_INSTANT, $units); die "pmiAddMetric($name, ...): " . pmiErrStr(-1) . "\n" unless ($sts == 0); } # Wrapper for pmiPutValueHandle() - used for non-indom-null metrics. # If first time this instance has been seen for this indom, add it to # the instance domain, and get a handle and add it to the handlemap. # Finally add the given value into the current result for the archive. # sub putinst($$$$) { my ($name,$indom,$instance,$value) = @_; my $handlekey = $name . '/' . $instance; my $instkey = $indom . '-' . $instance; my ($handle,$sts); return unless defined($value); # instmap{} holds the last allocated inst number with $indom as the # key, and marks the instance as known with $indom . $instance as the # key if (!defined($instmap{$instkey})) { my $inst; if (defined($instmap{$indom})) { $instmap{$indom}++; $inst = $instmap{$indom}; } else { $instmap{$indom} = 0; $inst = 0; } $sts = pmiAddInstance($indom, $instance, $inst); die "pmiAddInstance([$name], $instance, $inst): " . pmiErrStr($sts) . "\n" unless ($sts >= 0); $instmap{$instkey} = $inst; } $handle = $handlemap{$handlekey}; if (!defined($handle)) { if (!defined($handlemap{$name})) { register_multi($name, $indom); $handlemap{$name} = -1; # invalid handle for no-instance lookup } $sts = pmiGetHandle($name, $instance); die "pmiGetHandle($name, $instance): " . pmiErrStr($sts) . "\n" unless ($sts >= 0); $handlemap{$handlekey} = $handle = $sts; } $sts = pmiPutValueHandle($handle, dovalue($value)); if ($sts < 0 && $putsts == 0) { $putsts = $sts }; } # Wrapper for pmiPutValueHandle() - used for indom-null metrics only. # sub put($$) { my ($name,$value) = @_; my ($handle,$sts); return unless defined($value); $handle = $handlemap{$name}; if (!defined($handle)) { register_single($name); $sts = pmiGetHandle($name, ''); $sts >= 0 or die "pmiGetHandle($name, ...): " . pmiErrStr($sts) . "\n"; $handlemap{$name} = $handle = $sts; } $sts = pmiPutValueHandle($handle, dovalue($value)); if ($sts < 0 && $putsts == 0) { $putsts = $sts }; } if ($#ARGV != 1) { print STDERR "Usage: sar2pcp infile outfile\n"; exit(1); } if ($ARGV[0] =~ /\.xml$/i) { my $sts = open(XMLDATA, '<', $ARGV[0]); if (!defined($sts)) { print STDERR "sar2pcp: " . "Failed to open sadf XML file \"$ARGV[0]\": $!\n"; exit(1); } } else { my $sadf = 'sadf'; $sadf = $ENV{SADF} if defined($ENV{SADF}); my $pid = open(XMLDATA, '-|', "$sadf -x $ARGV[0] -- -A"); if (!defined($pid)) { print STDERR "sar2pcp: " . "Failed to launch $sadf to convert \"$ARGV[0]\" to XML\n"; exit(1); } } if (eof(XMLDATA)) { print STDERR "sar2pcp: XML document from $ARGV[0] contains no data\n"; exit(1); } $parser = XML::TokeParser->new(\*XMLDATA, Noempty => 1); if (!defined($parser)) { print STDERR "sar2pcp: Failed to open input stream for \"$ARGV[0]\"\n"; exit(1); } pmiStart($ARGV[1], 0); while (defined(my $token = $parser->get_token())) { if ($token->is_start_tag) { if ($token->tag eq 'timestamp') { $stamp = dodate($token->attr->{'date'}) . ' ' . dotime($token->attr->{'time'}); $sample++; $putsts = 0; } elsif ($token->tag eq 'cpu-load' || $token->tag eq 'cpu-load-all') { $in_cpu_load = 1; } elsif ($token->tag eq 'cpu' && $in_cpu_load) { # # # Take care: some are missing, some attribute names change! # my ($usr, $sys, $nice, $wait, $irq, $soft, $intr, $guest, $steal, $idle); $usr = $token->attr->{'usr'}; $usr = $token->attr->{'user'} unless defined($usr); # name change $usr = dovalue($usr) / 100 if defined($usr); $sys = $token->attr->{'sys'}; $sys = $token->attr->{'system'} unless defined($sys); # name change $sys = dovalue($sys) / 100 if defined($sys); $idle = $token->attr->{'idle'}; $idle = dovalue($idle) / 100 if defined($idle); $nice = $token->attr->{'nice'}; $nice = dovalue($nice) / 100 if defined($nice); $wait = $token->attr->{'iowait'}; $wait = dovalue($wait) / 100 if defined($wait); $irq = dovalue($token->attr->{'irq'}); $soft = dovalue($token->attr->{'soft'}); $intr = ($irq + $soft) / 100 unless (!defined($irq) || !defined($soft)); $guest = $token->attr->{'guest'}; $guest = dovalue($guest) / 100 if defined($guest); $steal = $token->attr->{'steal'}; $steal = dovalue($steal) / 100 if defined($steal); if ($token->attr->{'number'} eq 'all') { put('kernel.all.cpu.user', $usr); put('kernel.all.cpu.nice', $nice); put('kernel.all.cpu.sys', $sys); put('kernel.all.cpu.wait.total', $wait); put('kernel.all.cpu.steal', $steal); put('kernel.all.cpu.intr', $intr); put('kernel.all.cpu.guest', $guest); put('kernel.all.cpu.idle', $idle); } else { my $instance = 'cpu' . $token->attr->{'number'}; my $indom = pmInDom_build(PMI_DOMAIN, 0); putinst('kernel.percpu.cpu.user', $indom, $instance, $usr); putinst('kernel.percpu.cpu.nice', $indom, $instance, $nice); putinst('kernel.percpu.cpu.sys', $indom, $instance, $sys); putinst('kernel.percpu.cpu.wait.total', $indom, $instance, $wait); putinst('kernel.percpu.cpu.steal', $indom, $instance, $steal); putinst('kernel.percpu.cpu.intr', $indom, $instance, $intr); putinst('kernel.percpu.cpu.guest', $indom, $instance, $guest); putinst('kernel.percpu.cpu.idle', $indom, $instance, $idle); } } elsif ($token->tag eq 'process-and-context-switch' || $token->tag eq 'processes' || $token->tag eq 'context-switch') { # put('kernel.all.pswitch', $token->attr->{'cswch'}); # pro tem skip proc } elsif ($token->tag eq 'irq') { # if ($token->attr->{'intr'} eq 'sum') { put('kernel.all.intr', $token->attr->{'value'}); } # skip all other intr counts for now } elsif ($token->tag eq 'swap-pages') { # put('swap.pagesin', $token->attr->{'pswpin'}); put('swap.pagesout', $token->attr->{'pswpout'}); } elsif ($token->tag eq 'paging') { # put('mem.vmstat.pgpgin', $token->attr->{'pgpgin'}); put('mem.vmstat.pgpgout', $token->attr->{'pgpgout'}); put('mem.vmstat.pgfault', $token->attr->{'fault'}); put('mem.vmstat.pgmajfault', $token->attr->{'majflt'}); put('mem.vmstat.pgfree', $token->attr->{'pgfree'}); # pro tem skip pgscank, pgscand, pgsteal and vmeff-percent } elsif ($token->tag eq 'io') { # # no metric values from attribute data, all tags } elsif ($token->tag eq 'tps') { # 0.80 # no metric values from attribute data, all tags } elsif ($token->tag eq 'io-reads') { # # assume blocks are 512 bytes my $iops = dovalue($token->attr->{'rtps'}); if (defined($iops)) { put('disk.all.read', $iops); $disk_all_total = $iops; } my $bytes = dovalue($token->attr->{'bread'}); if (defined($bytes)) { put('disk.all.read_bytes', $bytes / 2); $disk_all_total_bytes = $bytes; } } elsif ($token->tag eq 'io-writes') { # # assume blocks are 512 bytes my $iops = dovalue($token->attr->{'wtps'}); if (defined($iops)) { $disk_all_total += $iops; put('disk.all.write', $iops); put('disk.all.total', $disk_all_total); } my $bytes = dovalue($token->attr->{'bwrtn'}); if (defined($bytes)) { put('disk.all.write_bytes', $bytes / 2); $disk_all_total_bytes += $bytes; put('disk.all.total_bytes', $disk_all_total_bytes / 2); } } elsif ($token->tag eq 'memfree') { # 78896 $snarf_name = 'mem.util.free'; $snarf_text = 1; } elsif ($token->tag eq 'memused') { # 947232 $snarf_name = 'mem.util.used'; $snarf_text = 1; } elsif ($token->tag eq 'buffers') { # 165296 $snarf_name = 'mem.util.bufmem'; $snarf_text = 1; } elsif ($token->tag eq 'cached') { # 368644 $snarf_name = 'mem.util.cached'; $snarf_text = 1; } # pro tem skip elsif ($token->tag eq 'swpfree') { # 1920808 $snarf_name = 'mem.util.swapFree'; $snarf_text = 1; } # pro tem skip elsif ($token->tag eq 'swpcad') { # 19208 $snarf_name = 'mem.util.swapCached'; $snarf_text = 1; } # pro tem skip , and elsif ($token->tag eq 'kernel') { # # depending on sadc version, these may be attributes # or separate tags (below). put('vfs.dentry.count', $token->attr->{'dentunusd'}); put('vfs.files.count', $token->attr->{'file-nr'}); put('vfs.inodes.count', $token->attr->{'inode-nr'}); # pro tem skip pty-nr } elsif ($token->tag eq 'dentunusd') { # 75415 $snarf_name = 'vfs.dentry.count'; $snarf_text = 1; } elsif ($token->tag eq 'file-nr' || $token->tag eq 'file-sz') { # 4608 # metric defined already (above - different XML output versions!) $snarf_name = 'vfs.files.count'; $snarf_text = 1; } elsif ($token->tag eq 'inode-nr' || $token->tag eq 'inode-sz') { # 72802 # metric defined already (above - different XML output versions!) $snarf_name = 'vfs.inodes.count'; $snarf_text = 1; } # pro tem skip pty-nr elsif ($token->tag eq 'queue') { my $indom = pmInDom_build(PMI_DOMAIN, 1); put('proc.runq.runnable', $token->attr->{'runq-sz'}); put('proc.nprocs', $token->attr->{'plist-sz'}); putinst('kernel.all.load', $indom, '1 minute', $token->attr->{'ldavg-1'}); putinst('kernel.all.load', $indom, '5 minute', $token->attr->{'ldavg-5'}); putinst('kernel.all.load', $indom, '15 minute', $token->attr->{'ldavg-15'}); } elsif ($token->tag eq 'disk-device') { # my $instance = 'disk' . $token->attr->{'dev'}; my $indom = pmInDom_build(PMI_DOMAIN, 2); my ($read_bytes, $write_bytes, $percent); putinst('disk.dev.total', $indom, $instance, $token->attr->{'tps'}); # 512-byte sectors/sec $percent = dovalue($token->attr->{'util-percent'}); $read_bytes = dovalue($token->attr->{'rd_sec'}); $write_bytes = dovalue($token->attr->{'wr_sec'}); if (defined($read_bytes)) { putinst('disk.dev.read_bytes', $indom, $instance, $read_bytes / 2); } if (defined($write_bytes)) { putinst('disk.dev.write_bytes', $indom, $instance, $write_bytes / 2); } if (defined($read_bytes) && defined($write_bytes)) { putinst('disk.dev.total_bytes', $indom, $instance, ($read_bytes + $write_bytes) / 2); } if (defined($percent)) { putinst('disk.dev.avactive', $indom, $instance, $percent / 100); } putinst('disk.dev.avrqsz', $indom, $instance, dovalue($token->attr->{'avgrq-sz'})); putinst('disk.dev.avqsz', $indom, $instance, dovalue($token->attr->{'avgqu-sz'})); putinst('disk.dev.await', $indom, $instance, dovalue($token->attr->{'await'})); putinst('disk.dev.svctm', $indom, $instance, dovalue($token->attr->{'svctm'})); # TODO disk.all aggregation? } elsif ($token->tag eq 'net-device') { # $interface = $token->attr->{'iface'}; } elsif ($token->tag eq 'net-dev') { # my $indom = pmInDom_build(PMI_DOMAIN, 4); my $iface = $token->attr->{'iface'}; $interface = $iface if (defined($iface)); # else it comes from net-device putinst('network.interface.in.packets', $indom, $interface, $token->attr->{'rxpck'}); putinst('network.interface.out.packets', $indom, $interface, $token->attr->{'txpck'}); putinst('network.interface.in.bytes', $indom, $interface, $token->attr->{'rxkB'}); putinst('network.interface.out.bytes', $indom, $interface, $token->attr->{'txkB'}); # pro tem skip rxcmp, txcmp, rxmcst } elsif ($token->tag eq 'net-edev') { # my $indom = pmInDom_build(PMI_DOMAIN, 4); my $iface = $token->attr->{'iface'}; $interface = $iface if (defined($iface)); # else it comes from net-device putinst('network.interface.in.errors', $indom, $interface, $token->attr->{'rxerr'}); putinst('network.interface.out.errors', $indom, $interface, $token->attr->{'txerr'}); putinst('network.interface.collisions', $indom, $interface, $token->attr->{'coll'}); putinst('network.interface.in.drops', $indom, $interface, $token->attr->{'rxdrop'}); putinst('network.interface.out.drops', $indom, $interface, $token->attr->{'txdrop'}); putinst('network.interface.out.carrier', $indom, $interface, $token->attr->{'txcarr'}); putinst('network.interface.in.frame', $indom, $interface, $token->attr->{'rxfram'}); putinst('network.interface.in.fifo', $indom, $interface, $token->attr->{'rxfifo'}); putinst('network.interface.out.fifo', $indom, $interface, $token->attr->{'txfifo'}); } elsif ($token->tag eq 'net-nfs' || $token->tag eq 'net-nfsd' || $token->tag eq 'net-sock' || $token->tag eq 'net-sock6' || $token->tag eq 'net-ip' || $token->tag eq 'net-eip' || $token->tag eq 'net-ip6' || $token->tag eq 'net-eip6' || $token->tag eq 'net-icmp' || $token->tag eq 'net-eicmp' || $token->tag eq 'net-icmp6' || $token->tag eq 'net-eicmp6' || $token->tag eq 'net-tcp' || $token->tag eq 'net-etcp' || $token->tag eq 'net-udp' || $token->tag eq 'net-udp6') { # skip all the network protocol stats for now next; } elsif ($token->tag eq 'host') { # pmiSetHostname($token->attr->{'nodename'}) >= 0 or die "pmiSetHostname($token->attr->{'nodename'}): " . pmiErrStr(-1) . "\n"; pmiSetTimezone($zone) >= 0 or die "pmiSetTimezone($zone): " . pmiErrStr(-1) . "\n"; } elsif ($token->tag eq 'number-of-cpus') { # 1 $snarf_name = 'hinv.ncpu'; $snarf_text = 2; } elsif (!defined($skipped_tags{$token->tag})) { $warning_tags{$token->tag} = 1; } if ($putsts != 0) { my $tag = $token->tag; die "pmiPutValue: Failed @ $stamp on $tag: " . pmiErrStr($putsts) . "\n"; } next; } elsif ($token->is_end_tag) { #debug# print "end: " . $token->tag . "\n"; if ($token->tag eq 'timestamp') { #debug# my ($ss,$mm,$hh,$day,$month,$year,$zone) = strptime($stamp, "+1000"); #debug# print "stamp: $stamp time: " . str2time($stamp) . " pieces: ss=$ss mm=$mm hh=$hh dd=$day month=$month year=$year"; #debug# if (defined($zone)) { print " zone=$zone"; } #debug# print "\n"; pmiWrite(str2time($stamp, $zone), 0) >= 0 or die "pmiWrite: @ $stamp: " . pmiErrStr(-1) . "\n"; } elsif ($token->tag eq 'cpu-load' || $token->tag eq 'cpu-load-all') { $in_cpu_load = 0; } elsif ($token->tag eq 'number-of-cpus') { # log metric once ... don't create or use handle # value snarfed in $save_text pmiAddMetric($snarf_name, PM_ID_NULL, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, pmiUnits(0,0,0,0,0,0)) == 0 or die "pmiAddMetric(hinv.ncpu, ...): " . pmiErrStr(-1) . "\n"; pmiPutValue($snarf_name, '', $save_text) >= 0 or die "pmiPutValue(hinv.ncpu,,$save_text): " . pmiErrStr(-1) . "\n"; } } elsif ($token->is_text) { if ($snarf_text == 1) { put($snarf_name, $token->text); $snarf_text = 0; } elsif ($snarf_text == 2) { $save_text = $token->text; $snarf_text = 0; } else { #debug# print "text: " . $token->text . "\n"; ; } next; } elsif ($token->is_comment) { #debug# print "comment: " . $token->text . "\n"; next; } elsif ($token->is_pi) { #debug# print "process instruction: " . $token->target . "\n"; next; } } if (%warning_tags) { my @warned = keys %warning_tags; my $nwarns = $#warned + 1; print STDERR "PCP archive produced, but $nwarns unrecognised tag(s) detected in ". "$sample samples:\n\t"; print STDERR '"', pop(@warned), '"'; while (@warned) { print STDERR ', "', pop(@warned), '"'; } print STDERR "\n"; } pmiEnd(); =pod =head1 NAME sar2pcp - Import sar data and create a PCP archive =head1 SYNOPSIS B I I =head1 DESCRIPTION B is intended to read a binary System Activity Reporting (sar) data file as created by B(1) (I) and translate this into a Performance Co-Pilot (PCP) archive with the basename I. However, if I has the suffix ".xml", then it will be considered already in XML format and B will operate directly on it. The resultant PCP achive may be used with all the PCP client tools to graph subsets of the data using B(1), perform data reduction and reporting, filter with the PCP inference engine B(1), etc. A series of physical files will be created with the prefix I. These are IB<.0> (the performance data), IB<.meta> (the metadata that describes the performance data) and IB<.index> (a temporal index to improve efficiency of replay operations for the archive). If any of these files exists already, then B will B overwrite them and will exit with an error message of the form __pmLogNewFile: "blah.0" already exists, not over-written B is a Perl script that uses the PCP::LogImport Perl wrapper around the PCP I library, and as such could be used as an example to develop new tools to import other types of performance data and create PCP archives. A Python wrapper module is also available. =head1 CAVEATS When not using the XML input option, B requires I to have been created by a version of B(1) from L which includes the B(1) utility to translate I into an XML stream (any since version 6); B will automatically run B(1) and translate the resultant XML into a PCP archive. When using binary B files it is important to ensure the installed B is compatible with the version of B that originally generated the binary files. Simply assuming a newer installed version will work is unfortunately far too optimistic, and nor should one assume that binary data from different platforms (e.g. different endianness) will work - these issues are due to limitations in B and B, and not in B itself. Fortunately, the B message indicating that an incompatibility has been detected is consistent across versions, and is always prefixed Invalid system activity file Using an XML I has the advantage that the installed version of B is completely bypassed. B undertakes to transform any valid XML produced by any of the different variations of B into a valid PCP archive. Any version of PCP will be able to interpret the archive files produced by any version of B, and you are also free to move the binary PCP archive between different platforms, different hardware, even different operating systems - it Just Works (TM). =head1 SEE ALSO B(1), B(1), B(1), B(1), B(1), B(1), B(1), B(1), B(3pm), B(3pm), B(3pm), B(3pm) and B(3). pcp-3.8.12ubuntu1/src/pmimport/sar2pcp/README0000664000000000000000000000413312272262501015473 0ustar Converting a sadc data file to a PCP archive This example uses the PCP::LogImport Perl wrapper around the libpcp_import library to convert a sadc datafile into a PCP archive. The version of sar that is supported here is the one from http://freshmeat.net/projects/sysstat/ which includes the sadf utility to translate the sadc datafile into an XML file. The Perl script sar2pcp runs sadf and translates the XML into a PCP archive. Usage: sar2pcp sadcfile archive The translation currently supports the following PCP metrics: disk.all.read disk.all.read_bytes disk.all.total disk.all.total_bytes disk.all.write disk.all.write_bytes disk.dev.avactive disk.dev.read_bytes disk.dev.total disk.dev.total_bytes disk.dev.write_bytes kernel.all.cpu.idle kernel.all.cpu.intr kernel.all.cpu.nice kernel.all.cpu.sys kernel.all.cpu.user kernel.all.cpu.wait.total kernel.all.intr kernel.all.load kernel.all.pswitch kernel.percpu.cpu.idle kernel.percpu.cpu.intr kernel.percpu.cpu.nice kernel.percpu.cpu.sys kernel.percpu.cpu.user kernel.percpu.cpu.wait.total mem.util.bufmem mem.util.cached mem.util.free mem.util.swapCached mem.util.swapFree mem.util.used mem.vmstat.pgfault mem.vmstat.pgfree mem.vmstat.pgmajfault mem.vmstat.pgpgin mem.vmstat.pgpgout network.interface.collisions network.interface.in.bytes network.interface.in.drops network.interface.in.errors network.interface.in.fifo network.interface.in.frame network.interface.in.packets network.interface.out.bytes network.interface.out.carrier network.interface.out.drops network.interface.out.errors network.interface.out.fifo network.interface.out.packets proc.runq.runnable swap.pagesin swap.pagesout vfs.dentry.count vfs.files.count vfs.inodes.count This is sufficient to support the following standard pmchart views: CPU Disk Diskbytes Loadavg Memory Netbytes Netpackets Overview (except for a lesser memory stats) Paging pcp-3.8.12ubuntu1/src/pmimport/sar2pcp/GNUmakefile0000664000000000000000000000215212272262501016664 0ustar #!gmake # # Copyright (c) 2010 Ken McDonell. All Rights Reserved. # Copyright (c) 2009 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs SCRIPT = sar2pcp LDIRT = $(MAN_PAGES) $(MAN_PAGES).tmp LSRCFILES = $(SCRIPT) README ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = $(SCRIPT).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: $(MAN_PAGES) $(SCRIPT).$(MAN_SECTION): $(SCRIPT) $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 $(SCRIPT) $(PCP_BIN_DIR)/$(SCRIPT) @$(INSTALL_MAN) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmimport/mrtg2pcp/0000775000000000000000000000000012272262620015000 5ustar pcp-3.8.12ubuntu1/src/pmimport/mrtg2pcp/README0000664000000000000000000000067612272262501015667 0ustar Converting a mrtg log file to a PCP archive This example uses the PCP::LogImport Perl wrapper around the libpcp_import library to convert a sadc datafile into a PCP archive. Usage: mrtg2pcp hostname devname timezone mrtglogfile archive The translation currently supports the following PCP metrics: network.interface.in.bytes network.interface.out.bytes This is sufficient to support the following standard pmchart views: Netbytes pcp-3.8.12ubuntu1/src/pmimport/mrtg2pcp/mrtg2pcp0000775000000000000000000001030212272262501016456 0ustar #!/usr/bin/perl # # Copyright (c) 2010 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::LogImport; if ($#ARGV != 4) { print "Usage: mrtg2pcp hostname devname timezone infile outfile\n"; exit(1); } # Note: these match the linux pmda, change to your heart's content my $domain = 60; my $cluster = 3; my $in_item = 0; my $out_item = 8; my $indomid = 3; # the internal instance id my $intinstid= 1; my $hostname=$ARGV[0]; my $devname=$ARGV[1]; my $zone=$ARGV[2]; my $infile=$ARGV[3]; my $outfile=$ARGV[4]; # first, read the input file open(INFILE, "<$infile") or die "open($infile): $!"; ; # skip the first line my @lines = ; # read the remainder into memory @lines = reverse(@lines); close(INFILE) or die "close($infile): $!"; # now the PCP part pmiStart($outfile, 0) >= 0 or die "pmiStart($outfile, 0): " . pmiErrStr(-1) . "\n"; pmiSetHostname($hostname) == 0 or die "pmiSetHostname($hostname): ". pmiErrStr(-1) . "\n"; pmiSetTimezone($zone) == 0 or die "pmiSetTimezone($zone): ". pmiErrStr(-1) . "\n"; my $indom = pmInDom_build($domain, $indomid); pmiAddMetric("network.interface.in.bytes", pmid_build($domain,$cluster,$in_item), PM_TYPE_U64, $indom, PM_SEM_COUNTER, pmiUnits(1,0,0,PM_SPACE_BYTE,0,0)) == 0 or die "pmiAddMetric(network.interface.in.bytes, ...): " . pmiErrStr(-1) . "\n"; pmiAddMetric("network.interface.out.bytes", pmid_build($domain,$cluster,$out_item), PM_TYPE_U64, $indom, PM_SEM_COUNTER, pmiUnits(1,0,0,PM_SPACE_BYTE,0,0)) == 0 or die "pmiAddMetric(network.interface.out.bytes, ...): " . pmiErrStr(-1) . "\n"; pmiAddInstance($indom, $devname, $intinstid) >= 0 or die "pmiAddInstance(..., ".$devname.", $intinstid): " . pmiErrStr(-1) . "\n"; my $ihndl = pmiGetHandle("network.interface.in.bytes", $devname); my $ohndl = pmiGetHandle("network.interface.out.bytes", $devname); my @prev = (); my $ictr = 0; my $octr = 0; foreach (@lines) { my @info = split(/ /); if (scalar(@prev) > 0) { $ictr += $info[1] * ($info[0] - $prev[0]); $octr += $info[2] * ($info[0] - $prev[0]); } pmiPutValueHandle($ihndl, $ictr); pmiPutValueHandle($ohndl, $octr); pmiWrite($info[0], 0) >= 0 or die "pmiWrite: @ ".$info[0].": " . pmiErrStr(-1) . "\n"; @prev = @info; } pmiEnd(); =pod =head1 NAME mrtg2pcp - Import mrtg data and create a PCP archive =head1 SYNOPSIS B I I I I I =head1 DESCRIPTION B is intended to read an MRTG log file as created by B(1) and translate this into a Performance Co-Pilot (PCP) archive with the basename I. The I, I, and I arguments specify information about the system for which the statistics were gathered. The resultant PCP achive may be used with all the PCP client tools to graph subsets of the data using B(1), perform data reduction and reporting, filter with the PCP inference engine B(1), etc. A series of physical files will be created with the prefix I. These are IB<.0> (the performance data), IB<.meta> (the metadata that describes the performance data) and IB<.index> (a temporal index to improve efficiency of replay operations for the archive). If any of these files exists already, then B will B overwrite them and will exit with an error message of the form __pmLogNewFile: "blah.0" already exists, not over-written B is a Perl script that uses the PCP::LogImport Perl wrapper around the PCP I library, and as such could be used as an example to develop new tools to import other types of performance data and create PCP archives. =head1 SEE ALSO B(3), B(3pm), B(1), B(1) B(1). pcp-3.8.12ubuntu1/src/pmimport/mrtg2pcp/GNUmakefile0000664000000000000000000000215312272262501017051 0ustar #!gmake # # Copyright (c) 2010 Ken McDonell. All Rights Reserved. # Copyright (c) 2009 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs SCRIPT = mrtg2pcp LDIRT = $(MAN_PAGES) $(MAN_PAGES).tmp LSRCFILES = $(SCRIPT) README ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = $(SCRIPT).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: $(MAN_PAGES) $(SCRIPT).$(MAN_SECTION): $(SCRIPT) $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 $(SCRIPT) $(PCP_BIN_DIR)/$(SCRIPT) @$(INSTALL_MAN) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmimport/iostat2pcp/0000775000000000000000000000000012272262620015332 5ustar pcp-3.8.12ubuntu1/src/pmimport/iostat2pcp/README0000664000000000000000000000771012272262501016215 0ustar Converting a iostat output to a PCP archive This example uses the PCP::LogImport Perl wrapper around the libpcp_import library to convert a sadc datafile into a PCP archive. The version of iostat that is supported here is the one from http://freshmeat.net/projects/sysstat and provides the following reporting options: -t Add timestamps like 27/07/10 12:47:34 ahead of each sample. If $S_TIME_FORMAT=ISO in the environment, then the format changes to 2010-07-27T12:46:07+1000 The default is to not include any timestamps. Start date is on first line Linux 2.6.32-23-generic (bozo) 27/07/10 _i686_ (1 CPU) -z supress activity for idle devices -k Disk activity in Kilobytes not blocks Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn -m Disk activity in megabytes not blocks Device: tps MB_read/s MB_wrtn/s MB_read MB_wrtn -c CPU utilization avg-cpu: %user %nice %system %iowait %steal %idle 75.00 0.00 25.00 0.00 0.00 0.00 -d Disk activity Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda 9.27 42.38 135.10 128 408 sdb 83.44 182.78 1634.44 552 4936 scd0 0.00 0.00 0.00 0 0 -n NFS report Filesystem: rBlk_nor/s wBlk_nor/s rBlk_dir/s wBlk_dir/s rBlk_svr/s wBlk_svr/s rops/s wops/s -x Extended disk activity Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util sda 0.00 10.30 0.00 4.32 0.00 116.94 27.08 0.00 0.31 0.31 0.13 sdb 0.00 83.39 0.33 10.63 2.66 754.82 69.09 0.05 4.36 0.85 0.93 scd0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 -p like -d but for partitions (example below is with -z) Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda 2.99 0.00 77.08 0 232 sda1 2.99 0.00 77.08 0 232 sdb 20.60 2.66 890.37 8 2680 sdb6 20.60 2.66 890.37 8 2680 Usage: iostat2pcp infile archive The translation currently supports the following PCP metrics: disk.all.read disk.all.read_bytes disk.all.total disk.all.total_bytes disk.all.write disk.all.write_bytes disk.dev.avactive disk.dev.read_bytes disk.dev.total disk.dev.total_bytes disk.dev.write_bytes kernel.all.cpu.idle kernel.all.cpu.intr kernel.all.cpu.nice kernel.all.cpu.sys kernel.all.cpu.user kernel.all.cpu.wait.total kernel.all.intr kernel.all.load kernel.all.pswitch kernel.percpu.cpu.idle kernel.percpu.cpu.intr kernel.percpu.cpu.nice kernel.percpu.cpu.sys kernel.percpu.cpu.user kernel.percpu.cpu.wait.total mem.util.bufmem mem.util.cached mem.util.free mem.util.swapCached mem.util.swapFree mem.util.used mem.vmstat.pgfault mem.vmstat.pgfree mem.vmstat.pgmajfault mem.vmstat.pgpgin mem.vmstat.pgpgout network.interface.collisions network.interface.in.bytes network.interface.in.drops network.interface.in.errors network.interface.in.fifo network.interface.in.frame network.interface.in.packets network.interface.out.bytes network.interface.out.carrier network.interface.out.drops network.interface.out.errors network.interface.out.fifo network.interface.out.packets proc.runq.runnable swap.pagesin swap.pagesout vfs.dentry.count vfs.files.count vfs.inodes.count This is sufficient to support the following standard pmchart views: CPU Disk Diskbytes Loadavg Memory Netbytes Netpackets Overview (except for a lesser memory stats) Paging pcp-3.8.12ubuntu1/src/pmimport/iostat2pcp/iostat2pcp0000775000000000000000000006522412272262501017357 0ustar #!/usr/bin/perl # # Copyright (c) 2010 Ken McDonell. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Assumptions: # Except for line suppresion for idle devices with -z, output from # iostat is completely deterministic, with the number and order of # values identical for each sample interval. # # Since we don't know what sort of system the data came from # there is no point trying to match the PMIDs with those from # any particular OS PMDA. For the names we'll use the common # names where possible, else the Linux names (as the most likely # case). # use strict; use warnings; use Getopt::Std; use Date::Parse; use Date::Format; use PCP::LogImport; my $line = 0; # input line number my $basedate = undef; my $basetime = "00:00:00"; my $stamp_style = 0; my $host = undef; my $zone = "UTC"; # default timezone # unless -t & $S_TIME_FORMAT=ISO or -Z on command line my $first_tag = undef; my $sts; my %options; # for command line arguments my $sample = -1; my $interval = undef; my $in_dev = 0; # in Device: group my $dev_style; # "d" for standard -d Device: data, "x" for -x Device: data # Note -x and -d are mutually exclusive to iostat my $in_cpu = 0; # in avg-cpu: group my $stamp; # timestamp from -t output lines my $now; # faked tv_sec of gettimeofday() for current sample my $next_stamp; # ready for next sample interval my $next_now; my $vflag; # -v for verbosity my @handle = (); # pmi* handles, one per metric-instance pair my $h = 0; # index into handle[] my $putsts = 0; # pmiPutValue() errors are only checked @ end of loop my $dev_thru_scale; # scale factor for disk thruput - 0.5 for blocks, 1 for # kB and 1024 for MB my $dev_indom = pmInDom_build(PMI_DOMAIN, 0); my %dev_first_handle; # for each disk instance, index into handle[] for first # handle, other handles for related metrics for the same # instance follow consecutively in handle[] my %dev_prev; # previous values for each instance for disk.dev.* metrics my %dev_seen; # tracking disk instances seen in this sample for # handling -z and missing lines for inactive devices my %inst_map = (); # key=indom value=last_inst_assigned, and # key=indom.instance value=inst sub dodate($) { # convert datetime formats 27/07/10 12:47:34 or # 2013-07-05 09:17:28 or 2010-07-27T12:46:07+1000 # into ISO-8601 dates that Date::Parse # seems to be able to parse correctly ... this would appear to # have to be YYYY-MM-DDTHH:MM:SS.000000 and then pass the timezone # as the second parameter to str2time() # my ($datetime) = @_; my @fields; my $mm; my $yy; my $dd; my $time; @fields = split(/T/, $datetime); if ($#fields == 1) { # ISO format - YYYY-MM-DDTHH:MM:SS[timezone] $time = $fields[1]; $time =~ s/[+-].*//; @fields = split(/-/, $fields[0]); $#fields == 2 or die "dodate: bad datetime format: \"$datetime\"\n"; $yy = $fields[0]; $mm = $fields[1]; $dd = $fields[2]; } else { @fields = split(/\//, $datetime); if ($#fields == 2) { # DD/MM/YY HH:MM:SS format @fields = split(/ /, $datetime); $#fields == 1 or die "dodate: bad datetime format 1: \"$datetime\"\n"; $time = $fields[1]; @fields = split(/\//, $fields[0]); $#fields == 2 or die "dodate: bad date format 1: \"$datetime\"\n"; $dd = $fields[0]; $mm = $fields[1]; $yy = $fields[2]; } else { @fields = split(/-/, $datetime); if ($#fields == 2) { # YYYY-MM-DD HH:MM:SS format @fields = split(/ /, $datetime); $#fields == 1 or die "dodate: bad datetime format 3: \"$datetime\"\n"; $time = $fields[1]; @fields = split(/-/, $fields[0]); $#fields == 2 or die "dodate: bad date format 3: \"$datetime\"\n"; $yy = $fields[0]; $mm = $fields[1]; $dd = $fields[2]; } } } if ($time !~ /\./) { $time .= ".000000" } # get into canonical DD, MM and YYYY format if ($dd < 10 && $dd !~ /^0/) { $dd .= "0" }; # add leading zero if ($mm < 10 && $mm !~ /^0/) { $mm .= "0" }; # add leading zero if ($yy < 100) { # terrible Y2K hack ... will stop working in 2080 if ($yy <= 80) { $yy += 2000; } else { $yy += 1900; } } return $yy . "-" . $mm . "-" . $dd . "T" . $time; } # for stamp_style 1 or 2 or 3, -S and -t options ignored # for stamp_style 2, -Z option ignored # sub check_opts() { return if $stamp_style == 0; if (exists($options{S})) { print "iostat2pcp: Warning: timestamps found, -S $basetime option ignored\n"; } if (exists($options{t})) { print "iostat2pcp: Warning: timestamps found, -t $interval option ignored\n"; } if ($stamp_style == 2 && exists($options{Z})) { print "iostat2pcp: Warning: ISO timestamps found, -Z $zone option ignored\n"; } } # Handle metrics with the a singular value, calling pmiAddMetric() and # pmiGetHandle() # sub def_single($) { my ($name) = @_; my $sts; my $units = pmiUnits(0,0,0,0,0,0); my $type = PM_TYPE_FLOAT; if (pmiAddMetric($name, PM_ID_NULL, $type, PM_INDOM_NULL, PM_SEM_INSTANT, $units) < 0) { pmiDump(); die "pmiAddMetric($name, ...): " . pmiErrStr(-1) . "\n"; } $sts = pmiGetHandle($name, ""); if ($sts < 0) { pmiDump(); die "pmiGetHandle($name, ...): " . pmiErrStr($sts) . "\n"; } push(@handle, $sts); } # Handle metrics with multiple values, calling pmiAddMetric(). # Defer to pmiGetHandle() to def_metric_inst(). # sub def_multi($$) { my ($name,$indom) = @_; my $units = pmiUnits(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE); my $type = PM_TYPE_FLOAT; my $sem = PM_SEM_INSTANT; if ($name eq "disk.dev.avactive") { $units = pmiUnits(0,0,0,0,0,0); } elsif ($name =~ /disk\.dev\..*bytes/) { $units = pmiUnits(1,-1,0,PM_SPACE_KBYTE,PM_TIME_SEC,0); } if (pmiAddMetric($name, PM_ID_NULL, $type, $indom, $sem, $units) < 0) { pmiDump(); die "pmiAddMetric($name, ...): " . pmiErrStr(-1) . "\n"; } } # Deal with metric-instance pairs. # If first time this instance has been seen for this indom, add it to # the instance domain. # Get a handle and add it to handle[]. # sub def_metric_inst($$$) { my ($name,$indom,$instance) = @_; my $sts; # inst_map{} holds the last allocated inst number with $indom as the # key, and marks the instance as known with $indom . $instance as the # key if (!exists($inst_map{$indom . $instance})) { my $inst; if (exists($inst_map{$indom})) { $inst_map{$indom}++; $inst = $inst_map{$indom}; } else { $inst_map{$indom} = 0; $inst = 0; } if (pmiAddInstance($indom, $instance, $inst) < 0) { pmiDump(); die "pmiAddInstance([$name], $instance, $inst): " . pmiErrStr(-1) . "\n"; } $inst_map{$indom . $instance} = $inst; } $sts = pmiGetHandle($name, $instance); if ($sts < 0) { pmiDump(); die "pmiGetHandle($name, $instance): " . pmiErrStr($sts) . "\n"; } push(@handle, $sts); } # wrapper for pmiPutValueHandle(), using @handle # sub put($) { my ($value) = @_; my $sts; if (!exists($handle[$h])) { pmiDump(); die <) { my $end_sample = 0; my $header = 0; chomp; $line++; #debug# print "[" . $line . "] {" . $sample . "} $_\n"; if ($line == 1) { # first line ... extract baseline date in format YYYY-MM-DD # from something like ... # Linux 2.6.32-23-generic (bozo) 27/07/10 _i686_ (1 CPU) # if (/.*\s+([^\s]+)\s+[0-3][0-9]\/[0-1][0-9]\/[0-9][0-9]\s+/) { my @part; $basedate = $_; $basedate =~ s#.*([0-3][0-9]/[0-1][0-9]/[0-9][0-9]).*#$1#; @part = split(/\//, $basedate); # terrible Y2K hack ... will stop working in 2080 if ($part[2] <= 80) { $part[2] += 2000; } else { $part[2] += 1900; } $basedate = $part[2] . "-" . $part[1] . "-" . $part[0]; } # or possibly like this when $S_TIME_FORMAT=ISO is set in the # environment (ISO 8601) ... # Linux 2.6.32-23-generic (bozo) 2010-07-27 _i686_ (1 CPU) elsif (/.*\s+([^\s]+)\s+[12][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]\s+/) { $basedate = $_; $basedate =~ s#.*([12][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]).*#$1#; } # or possibly like this ... # Linux 2.6.18-194.3.1.el5 (somehost.somewhere.com) 07/27/2010 elsif (/.*\s+([^\s]+)\s+[0-1][0-9]\/[0-3][0-9]\/[12][0-9][0-9][0-9]/) { my @part; $basedate = $_; $basedate =~ s#.*([0-1][0-9]\/[0-3][0-9]\/[12][0-9][0-9][0-9]).*#$1#; @part = split(/\//, $basedate); $basedate = $part[2] . "-" . $part[0] . "-" . $part[1]; } else { print "[" . $line . "] $_\n"; print "iostat2pcp: First line does not look like iostat ... I give up\n"; exit(0); } $host = $_; $host =~ s/[^(]*\(//; $host =~ s/\).*//; next; } elsif ($line == 3 && /[0-3][0-9]\/[0-1][0-9]\/[0-9][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]/) { # simple -t option timestamp # 27/07/10 12:47:34 # $stamp_style = 1; check_opts(); next; } elsif ($line == 3 && /[1-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9][-+][0-9]+/) { # -t option timestamp and $S_TIME_FORMAT=ISO set in the environment # 2010-07-27T12:46:07+1000 # $zone = $_; $zone =~ s/.*([-+][0-9]+).*/$1/; $stamp_style = 2; check_opts(); next; } elsif ($line == 3 && /[1-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]/) { # -t option timestamp and ??? not sure ... but visible in # https://bugzilla.redhat.com/show_bug.cgi?id=981545 # 2013-07-05 09:17:28 # $stamp_style = 3; check_opts(); next; } elsif ($line == 3) { # first group tag $first_tag = $_; $first_tag =~ s/([^:]+):.*/$1/; } next if /^\s*$/; if ($stamp_style == 0 && $line > 3) { my $tag = $_; $tag =~ s/([^:]+):.*/$1/; if ($tag eq $first_tag) { if ($sample > 0) { # for sample #0, time is set below in the end_sample code $next_now = $now + $interval; $next_stamp = ctime($next_now, $zone); chomp $next_stamp; } $end_sample = 1; } } elsif ($stamp_style == 1) { if (/[0-3][0-9]\/[0-1][0-9]\/[0-9][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]/) { $next_stamp = dodate($_); $next_now = str2time($next_stamp, $zone); $end_sample = 1; } } elsif ($stamp_style == 2) { if (/[1-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9][-+][0-9]+/) { $next_stamp = dodate($_); $next_now = str2time($next_stamp, $zone); $end_sample = 1; } } elsif ($stamp_style == 3) { if (/[1-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9] [0-2][0-9]:[0-5][0-9]:[0-5][0-9]/) { $next_stamp = dodate($_); $next_now = str2time($next_stamp, $zone); $end_sample = 1; } } if ($end_sample) { if ($stamp_style == 0 && $sample == 0) { print "iostat2pcp: Warning: no timestamps, assuming data starts at $basedate $basetime $zone\n"; $stamp = dodate($basedate . "T" . $basetime); $now = str2time($stamp, $zone); if (!defined($interval)) { print "iostat2pcp: Warning: cannot determine sample interval, assuming 15 seconds\n"; $interval = 15; } $now += $interval; $stamp = ctime($now, $zone); chomp $stamp; $next_now = $now + $interval; $next_stamp = ctime($next_now, $zone); chomp $next_stamp; } if ($vflag) { if ($sample == 0) { print "stamp_style=$stamp_style zone=$zone basedate=$basedate now=$now stamp=$stamp"; print " interval=$interval" if defined($interval); print " first_tag=$first_tag" if defined($first_tag); print "\n"; } } if ($sample > -1) { if ($sample == 0) { # Serious strangeness here ... # the Perl Date::Parse and Date::Format routines appear to # only work with timezones of the format +NNNN or -NNNN # ("UTC" is an exception) # # PCP expects a $TZ style timezone in the archive label, so # we have to make up a PCP-xx:xx timezone ... note this # involves a sign reversal! # my $label_zone = $zone; if ($zone =~ /^[-+][0-9][0-9][0-9][0-9]/) { $label_zone =~ s/^\+/PCP-/; $label_zone =~ s/^-/PCP+/; $label_zone =~ s/(..)$/:$1/; } elsif ($zone ne "UTC") { print "iostat2pcp: Warning: unexpected timezone ($zone), reverting to UTC\n"; $zone = "UTC"; $label_zone = "UTC"; } pmiSetTimezone($label_zone) >= 0 or die "pmiSetTimezone($label_zone): " . pmiErrStr(-1) . "\n"; if (defined($host)) { pmiSetHostname($host) >= 0 or die "pmiSetHostname($host): " . pmiErrStr(-1) . "\n"; } } sample_done(); } $sample++; $stamp = $next_stamp; $now = $next_now; # if timestamp, get onto real data in following lines # ($stamp_style == 1 || $stamp_style == 2 || $stamp_style == 3) and next; } if (/^Device:/) { $in_cpu = 0; $in_dev = 1; $header = 1; } elsif (/^avg-cpu:/) { $in_dev = 0; $in_cpu = 1; $header = 1; } if ($sample == -1) { # first time we have the stats since boot, we need to figure # out the meta data, and for $stamp_style == 0, try to compute # the sample interval # if ($in_cpu && $header) { # avg-cpu: %user %nice %system %iowait %steal %idle # if present, always comes first # def_single("kernel.all.cpu.user"); def_single("kernel.all.cpu.nice"); def_single("kernel.all.cpu.sys"); def_single("kernel.all.cpu.wait.total"); def_single("kernel.all.cpu.steal"); def_single("kernel.all.cpu.idle"); } elsif ($in_dev) { if ($header) { # one of ... # Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn # Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn # Device: tps MB_read/s MB_wrtn/s MB_read MB_wrtn # Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util if (/tps/) { $dev_style = "d"; # -d option if (/Blk_read/) { $dev_thru_scale = 0.5; } elsif (/kB_read/) { $dev_thru_scale = 1; } elsif (/MB_read/) { $dev_thru_scale = 1024; } else { print "[$line] $_\n"; die "Device: cannot determine thruput scale"; } def_multi("disk.dev.total", $dev_indom); def_multi("disk.dev.read_bytes", $dev_indom); def_multi("disk.dev.write_bytes", $dev_indom); } else { $dev_style = "x"; # assume -x option $dev_thru_scale = 0.5; # assume 512-byte sectors def_multi("disk.dev.read_merge", $dev_indom); def_multi("disk.dev.write_merge", $dev_indom); def_multi("disk.dev.read", $dev_indom); def_multi("disk.dev.write", $dev_indom); def_multi("disk.dev.read_bytes", $dev_indom); def_multi("disk.dev.write_bytes", $dev_indom); def_multi("disk.dev.avactive", $dev_indom); } } # Note: instances are populated as they are found _after_ the # first (from boot time) stats are processed } next; } elsif ($sample >= 0 && $in_dev && $dev_style eq "d" && $header == 0 && $stamp_style == 0 && !defined($interval)) { # if basic Device: stats, can compute sample interval from ratio of # totals to rate for reads or writes ... need to avoid divide zero # counts ... must do on the second sample interval and may fail if # no -d or -z and no activity my @part = split(/\s+/, $_); if ($#part != 5) { print "[$line] $_\n"; die "Device: number of values? expected 6, found " . ($#part+1) . "\n"; } if ($part[4] != 0) { $interval = int(0.5 + $part[4]/$part[2]); } elsif ($part[5] != 0) { $interval = int(0.5 + $part[5]/$part[3]); } if (defined($interval) && $interval <= 0) { # in case we've really screwed up, better to be clueless $interval = undef; } } if ($header == 0 && $sample >= 0) { if ($in_cpu) { my @part = split(/\s+/, $_); # $part[0] is empty white space before first value if ($#part != 6) { print "[$line] $_\n"; die "avg-cpu: number of values? expected 7, found " . ($#part+1) . "\n"; } put($part[1]/100); # user put($part[2]/100); # nice put($part[3]/100); # system put($part[4]/100); # iowait put($part[5]/100); # steal put($part[6]/100); # idle } elsif ($in_dev) { # Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn # sda 3.34 10.70 77.59 32 232 # or # Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s avgrq-sz avgqu-sz await svctm %util # sda 0.03 0.76 0.32 0.21 8.90 7.79 31.61 0.01 13.37 2.11 0.11 my @part = split(/\s+/, $_); my @thisval; my $instance; if ($#part == 0) { # workaround for https://bugzilla.redhat.com/show_bug.cgi?id=604637 # long device name followed by embedded newline ... append the next # input line # $instance = $part[0]; $_ = $instance . " " . ; chomp; $line++; @part = split(/\s+/, $_); } if ($dev_style eq "d") { if ($#part != 5) { print "[$line] $_\n"; die "Device: number of values? expected 6, found " . ($#part+1) . "\n"; } $instance = $part[0]; } else { if ($#part != 11) { print "[$line] $_\n"; die "Device: number of values? expected 12, found " . ($#part+1) . "\n"; } $instance = $part[0]; } if (exists($dev_first_handle{$instance})) { $h = $dev_first_handle{$instance}; } else { # first time we've seen this instance, set up indom and handles # if ($dev_style eq "d") { def_metric_inst("disk.dev.total", $dev_indom, $instance); $dev_first_handle{$instance} = $#handle; def_metric_inst("disk.dev.read_bytes", $dev_indom, $instance); def_metric_inst("disk.dev.write_bytes", $dev_indom, $instance); } else { def_metric_inst("disk.dev.read_merge", $dev_indom, $instance); $dev_first_handle{$instance} = $#handle; def_metric_inst("disk.dev.write_merge", $dev_indom, $instance); def_metric_inst("disk.dev.read", $dev_indom, $instance); def_metric_inst("disk.dev.write", $dev_indom, $instance); def_metric_inst("disk.dev.read_bytes", $dev_indom, $instance); def_metric_inst("disk.dev.write_bytes", $dev_indom, $instance); def_metric_inst("disk.dev.avactive", $dev_indom, $instance); } # populate dev_seen for each instance $dev_seen{$instance} = 0; } if ($dev_style eq "d") { # disk.dev.total # disk.dev.read_bytes # disk.dev.write_bytes @thisval = ($part[1], $part[2] * $dev_thru_scale, $part[3] * $dev_thru_scale); if (!exists($dev_prev{$instance})) { # first time seen for this instance $dev_prev{$instance} = [0,0,0]; } for (my $i = 0; $i <= $#thisval; $i++) { # all these are instantaneous $dev_prev{$instance}->[$i] = $thisval[$i]; put($dev_prev{$instance}->[$i]); } $dev_seen{$instance} = 1; } else { if (exists($dev_first_handle{$instance})) { $h = $dev_first_handle{$instance}; } else { pmiDump(); print "[$line] $_\n"; die "Device: no first handle for instance \"" . $instance . "\", check Handles in dump above"; } # disk.dev.read_merge # disk.dev.write_merge # disk.dev.read # disk.dev.write # disk.dev.read_bytes # disk.dev.write_bytes # disk.dev.avactive @thisval = ($part[1], $part[2], $part[3], $part[4], $part[5] * $dev_thru_scale, $part[6] * $dev_thru_scale, $part[11]); if (!exists($dev_prev{$instance})) { # first time seen for this instance $dev_prev{$instance} = [0,0,0,0,0,0,0]; } for (my $i = 0; $i <= $#thisval; $i++) { # all these are instantaneous $dev_prev{$instance}->[$i] = $thisval[$i]; put($dev_prev{$instance}->[$i]); } $dev_seen{$instance} = 1; } } } } # flush last sample out ... end of file is the end of the sample # sample_done(); pmiEnd(); exit(0); =pod =head1 NAME iostat2pcp - Import iostat data and create a PCP archive =head1 SYNOPSIS B [B<-v>] [B<-S> I] [B<-t> I] [B<-Z> I] I I =head1 DESCRIPTION B reads a text file created with B(1) (I) and translates this into a Performance Co-Pilot (PCP) archive with the basename I. If I is E-E then I reads for standard input, allowing easy preprocessing of the I(1) output with I(1) or similar. The resultant PCP archive may be used with all the PCP client tools to graph subsets of the data using B(1), perform data reduction and reporting, filter with the PCP inference engine B(1), etc. A series of physical files will be created with the prefix I. These are IB<.0> (the performance data), IB<.meta> (the metadata that describes the performance data) and IB<.index> (a temporal index to improve efficiency of replay operations for the archive). If any of these files exists already, then B will B overwrite them and will exit with an error message. The first output sample from I(1) contains a statistical summary since boot time and is ignored by I, so the first real data set is the second one in the I(1) output. The best results are obtained when I(1) was run with its own B<-t> flag, so each output sample is prefixed with a timestamp. Even better is B<-t> with $B set in environment when I(1) is run, in which case the timestamp includes the timezone. Note that if $B is B used with the B<-t> option then I(1) may produce a timestamp controlled by B from the locale that is in a format I cannot parse. The formats for the timestamp that I accepts are illustrated by these examples: =over 4 =item B<2013-07-06T21:34:39+1000> (for the $B). =item B<2013-07-06 21:34:39> (for some of the European formats, e.g. de_AT, de_BE, de_LU and en_DK.utf8). =item B<06/07/13 21:34:39> (for all of the $B settings for English locales outside North America, e.g. en_AU, en_GB, en_IE, en_NZ, en_SG and en_ZA, and all the Spanish locales, e.g. es_ES, es_MX and es_AR). =back In particular, note that some common North American $B settings will B work with I (namely, en_US, POSIX and C) because they use the MM/DD format which may be incorrectly converted with the assumed DD/MM format. This is another reason to recommend setting $B. If there are no timestamps in the input stream, I will try and deduce the sample interval if basic Disk data (B<-d> option for I(1)) is found. If this fails, then the B<-t> option may be used to specify the sample I in seconds. This option is ignored if timestamps are found in the input stream. The B<-S> option may be used to specify as start time for the first real sample in I, where I must have the format HH:MM:SS. This option is ignored if timestamps are found in the input stream. The B<-Z> option may be used to specify a timezone. It must have the format +HHMM (for hours and minutes East of UTC) or -HHMM (for hours and minutes West of UTC). Note in particular that B the B (aka Olson) format, e.g. Europe/Paris, nor the Posix B format, e.g. EST+5 is allowed for the B<-Z> option. This option is ignored if ISO timestamps are found in the input stream. If the timezone is not specified and cannot be deduced, it defaults to EUTCE. Some additional diagnostic output is generated with the B<-v> option. B is a Perl script that uses the PCP::LogImport Perl wrapper around the PCP I library, and as such could be used as an example to develop new tools to import other types of performance data and create PCP archives. =head1 CAVEAT B requires I to have been created by the version of B(1) from L. B handles the B<-c> (CPU), B<-d> (Disk), B<-x> (eXtended Disk) and B<-p> (Partition) report formats (including their B<-k>, B<-m>, B<-z> and B variants), but does not accommodate the B<-n> (Network Filesystem) report format from B(1); this is a demand-driven limitation rather than a technical limitation. =head1 SEE ALSO B(3pm), B(3pm), B(1), B(3), B(3pm), B(1), B(1), B(1) and B(1). pcp-3.8.12ubuntu1/src/pmimport/iostat2pcp/GNUmakefile0000664000000000000000000000215512272262501017405 0ustar #!gmake # # Copyright (c) 2010 Ken McDonell. All Rights Reserved. # Copyright (c) 2009 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs SCRIPT = iostat2pcp LDIRT = $(MAN_PAGES) $(MAN_PAGES).tmp LSRCFILES = $(SCRIPT) README ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = $(SCRIPT).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: $(MAN_PAGES) $(SCRIPT).$(MAN_SECTION): $(SCRIPT) $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 $(SCRIPT) $(PCP_BIN_DIR)/$(SCRIPT) @$(INSTALL_MAN) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmimport/GNUmakefile0000664000000000000000000000160212272262501015311 0ustar # # Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs SUBDIRS = sar2pcp sheet2pcp iostat2pcp mrtg2pcp collectl2pcp default: $(SUBDIRS) $(SUBDIRS_MAKERULE) include $(BUILDRULES) install: default $(SUBDIRS) $(SUBDIRS_MAKERULE) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/0000775000000000000000000000000012272262620015630 5ustar pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/load.c0000664000000000000000000000177712272262501016725 0ustar /* * Copyright (c) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Handler for load average * "load 1.07 1.18 1.30 3/658 4944" * */ #include "metrics.h" int loadavg_handler(handler_t *h, fields_t *f) { pmInDom indom = pmInDom_build(LINUX_DOMAIN, LOADAVG_INDOM); if (f->nfields < 4) return -1; put_str_value("kernel.all.load", indom, "1 minute", f->fields[1]); put_str_value("kernel.all.load", indom, "5 minute", f->fields[2]); put_str_value("kernel.all.load", indom, "15 minute", f->fields[3]); return 0; } pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/util.c0000664000000000000000000001153212272262501016751 0ustar /* * Copyright (c) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * */ #include "metrics.h" metric_t * find_metric(char *name) { metric_t *m; for (m = metrics; m->name; m++) { if (strcmp(name, m->name) == 0) break; } return m->name ? m : NULL; } handler_t * find_handler(char *tag) { handler_t *h; for (h = handlers; h->pattern; h++) { if (strchr(h->pattern, '*') != NULL) { /* match tag as a prefix, e.g. cpu* matches cpu123 */ if (strncmp(h->pattern, tag, strlen(h->pattern)-1) == 0) break; } else { /* exact match */ if (strcmp(h->pattern, tag) == 0) break; } } return h->pattern ? h : NULL; } int put_str_instance(pmInDom indom, char *instance) { int sts; __pmInDom_int *idp = __pmindom_int(&indom); int id = indom_cnt[idp->serial]++; sts = pmiAddInstance(indom, instance, id); return sts ? sts : id; } int put_str_value(char *name, pmInDom indom, char *instance, char *val) { int sts = 0; if (!val) fprintf(stderr, "Warning: put_str_value: ignored NULL value for \"%s\"\n", name); else if (indom != PM_INDOM_NULL && !instance) fprintf(stderr, "Warning: put_str_value: ignored NULL instance for non-singular indom for \"%s\"\n", name); else { sts = pmiPutValue(name, instance, val); if (sts == PM_ERR_NAME) { #if 0 if (vflag) fprintf(stderr, "Warning: unknown metric name \"%s\". Check metrics.c\n", name); #endif return sts; } if (indom != PM_INDOM_NULL && instance && (sts == PM_ERR_INST || sts == PM_ERR_INDOM)) { /* New instance has appeared */ sts = put_str_instance(indom, instance); if (sts < 0) fprintf(stderr, "Warning: put_str_value failed to add new instance \"%s\" for indom:%d err:%d : %s\n", instance, indom, sts, pmiErrStr(sts)); else if (vflag) printf("New instance %s[%d] \"%s\"\n", name, sts, instance); sts = pmiPutValue(name, instance, val); } if (sts < 0) fprintf(stderr, "Warning: put_str_value \"%s\" inst:\"%s\" value:\"%s\" failed: err=%d %s\n", name, instance ? instance : "NULL", val ? val : "NULL", sts, pmiErrStr(sts)); } return sts; } int put_int_value(char *name, pmInDom indom, char *instance, int val) { char valbuf[64]; sprintf(valbuf, "%d", val); return put_str_value(name, indom, instance, valbuf); } int put_ull_value(char *name, pmInDom indom, char *instance, unsigned long long val) { char valbuf[64]; sprintf(valbuf, "%llu", val); return put_str_value(name, indom, instance, valbuf); } /* split a string into fields and their lengths. Free fields[0] when done. */ int strfields(const char *s, int len, char **fields, int *fieldlen, int maxfields) { int i; char *p; char *p_end; if (!s || *s == '\0') return 0; if ((p = strdup(s)) == NULL) return 0; for (i=0, p_end = p+len; i < maxfields;) { fields[i] = p; fieldlen[i] = 0; while(*p && !isspace(*p) && p < p_end) { p++; fieldlen[i]++; } i++; if (!*p) break; *p++ ='\0'; while (isspace(*p)) p++; } return i; } fields_t * fields_new(const char *s, int len) { int n = 1; const char *p; fields_t *f = (fields_t *)malloc(sizeof(fields_t)); memset(f, 0, sizeof(fields_t)); f->len = len; for (p=s; *p && p < s+len; p++) { if (isspace(*p)) n++; } /* * n is an upper bound, at least 1 (separator may repeat). * fields[0] is the actual buffer, allocated by strfields */ f->fields = (char **)malloc(n * sizeof(char *)); f->fieldlen = (int *)malloc(n * sizeof(int)); f->nfields = strfields(s, len, f->fields, f->fieldlen, n); f->buf = f->fields[0]; return f; } fields_t * fields_dup(fields_t *f) { int i; fields_t *copy; copy = malloc(sizeof(fields_t)); memset(copy, 0, sizeof(fields_t)); copy->len = f->len; copy->buf = (char *)malloc(f->len + 1); memcpy(copy->buf, f->buf, f->len); copy->nfields = f->nfields; copy->fields = (char **)malloc(f->nfields * sizeof(char *)); copy->fieldlen = (int *)malloc(f->nfields * sizeof(int)); copy->fields[0] = copy->buf; for (i=1; i < f->nfields; i++) { copy->fieldlen[i] = f->fieldlen[i]; copy->fields[i] = copy->fields[0] + (f->fields[i] - f->fields[0]); } return copy; } void fields_free(fields_t *f) { free(f->buf); free(f->fields); free(f->fieldlen); free(f); } pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/metrics.c0000664000000000000000000052643412272262501017456 0ustar /* This file is automatically generated .. do not edit! */ #include "metrics.h" metric_t metrics[] = { /* 60.1.9 */ { "hinv.physmem", { 0xf000409, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=2, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.11 */ { "hinv.pagesize", { 0xf00040b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.32 */ { "hinv.ncpu", { 0xf000020, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.33 */ { "hinv.ndisk", { 0xf000021, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.5.0 */ { "hinv.nfilesys", { 0xf001400, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.27 */ { "hinv.ninterface", { 0xf000c1b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.18.7 */ { "hinv.machine", { 0xf004807, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.15.0 */ { "hinv.map.scsi", { 0xf003c00, PM_TYPE_STRING, 0xf00000b, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.18.6 */ { "hinv.map.cpu_num", { 0xf004806, PM_TYPE_U32, 0xf000000, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.18.8 */ { "hinv.map.cpu_node", { 0xf004808, PM_TYPE_U32, 0xf000000, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.52.0 */ { "hinv.map.lvname", { 0xf00d000, PM_TYPE_STRING, 0xf000016, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.18.0 */ { "hinv.cpu.clock", { 0xf004800, PM_TYPE_FLOAT, 0xf000000, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=10, .scaleCount=0 } } }, /* 60.18.1 */ { "hinv.cpu.vendor", { 0xf004801, PM_TYPE_STRING, 0xf000000, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.18.2 */ { "hinv.cpu.model", { 0xf004802, PM_TYPE_STRING, 0xf000000, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.18.3 */ { "hinv.cpu.stepping", { 0xf004803, PM_TYPE_STRING, 0xf000000, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.18.4 */ { "hinv.cpu.cache", { 0xf004804, PM_TYPE_U32, 0xf000000, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.18.5 */ { "hinv.cpu.bogomips", { 0xf004805, PM_TYPE_FLOAT, 0xf000000, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.2.0 */ { "kernel.all.load", { 0xf000800, PM_TYPE_FLOAT, 0xf000002, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.12 */ { "kernel.all.intr", { 0xf00000c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.13 */ { "kernel.all.pswitch", { 0xf00000d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.14 */ { "kernel.all.sysfork", { 0xf00000e, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.48 */ { "kernel.all.hz", { 0xf000030, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=-1, .dimCount=1, .scaleSpace=0, .scaleTime=3, .scaleCount=0 } } }, /* 60.26.0 */ { "kernel.all.uptime", { 0xf006800, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=3, .scaleCount=0 } } }, /* 60.26.1 */ { "kernel.all.idletime", { 0xf006801, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=3, .scaleCount=0 } } }, /* 60.25.0 */ { "kernel.all.nusers", { 0xf006400, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.2.1 */ { "kernel.all.lastpid", { 0xf000801, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.2.2 */ { "kernel.all.runnable", { 0xf000802, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.2.3 */ { "kernel.all.nprocs", { 0xf000803, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.20 */ { "kernel.all.cpu.user", { 0xf000014, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.21 */ { "kernel.all.cpu.nice", { 0xf000015, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.22 */ { "kernel.all.cpu.sys", { 0xf000016, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.23 */ { "kernel.all.cpu.idle", { 0xf000017, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.34 */ { "kernel.all.cpu.intr", { 0xf000022, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.55 */ { "kernel.all.cpu.steal", { 0xf000037, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.60 */ { "kernel.all.cpu.guest", { 0xf00003c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.35 */ { "kernel.all.cpu.wait.total", { 0xf000023, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.53 */ { "kernel.all.cpu.irq.soft", { 0xf000035, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.54 */ { "kernel.all.cpu.irq.hard", { 0xf000036, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.4.3 */ { "kernel.all.interrupts.errors", { 0xf001003, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.50.11 */ { "kernel.percpu.interrupts.MCP", { 0xf00c80b, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.50.10 */ { "kernel.percpu.interrupts.MCE", { 0xf00c80a, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.50.9 */ { "kernel.percpu.interrupts.THR", { 0xf00c809, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.50.8 */ { "kernel.percpu.interrupts.TRM", { 0xf00c808, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.50.7 */ { "kernel.percpu.interrupts.TLB", { 0xf00c807, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.50.6 */ { "kernel.percpu.interrupts.CAL", { 0xf00c806, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.50.5 */ { "kernel.percpu.interrupts.RES", { 0xf00c805, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.50.4 */ { "kernel.percpu.interrupts.RTR", { 0xf00c804, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.50.3 */ { "kernel.percpu.interrupts.IWI", { 0xf00c803, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.50.2 */ { "kernel.percpu.interrupts.PMI", { 0xf00c802, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.50.1 */ { "kernel.percpu.interrupts.SPU", { 0xf00c801, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.50.0 */ { "kernel.percpu.interrupts.LOC", { 0xf00c800, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.14 */ { "kernel.percpu.interrupts.line46", { 0xf00c40e, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.13 */ { "kernel.percpu.interrupts.line45", { 0xf00c40d, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.12 */ { "kernel.percpu.interrupts.line44", { 0xf00c40c, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.11 */ { "kernel.percpu.interrupts.line43", { 0xf00c40b, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.10 */ { "kernel.percpu.interrupts.line42", { 0xf00c40a, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.9 */ { "kernel.percpu.interrupts.line41", { 0xf00c409, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.8 */ { "kernel.percpu.interrupts.line40", { 0xf00c408, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.7 */ { "kernel.percpu.interrupts.line23", { 0xf00c407, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.6 */ { "kernel.percpu.interrupts.line19", { 0xf00c406, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.5 */ { "kernel.percpu.interrupts.line16", { 0xf00c405, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.4 */ { "kernel.percpu.interrupts.line12", { 0xf00c404, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.3 */ { "kernel.percpu.interrupts.line9", { 0xf00c403, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.2 */ { "kernel.percpu.interrupts.line8", { 0xf00c402, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.1 */ { "kernel.percpu.interrupts.line1", { 0xf00c401, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.49.0 */ { "kernel.percpu.interrupts.line0", { 0xf00c400, PM_TYPE_U32, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.0 */ { "kernel.percpu.cpu.user", { 0xf000000, PM_TYPE_U64, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.1 */ { "kernel.percpu.cpu.nice", { 0xf000001, PM_TYPE_U64, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.2 */ { "kernel.percpu.cpu.sys", { 0xf000002, PM_TYPE_U64, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.3 */ { "kernel.percpu.cpu.idle", { 0xf000003, PM_TYPE_U64, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.31 */ { "kernel.percpu.cpu.intr", { 0xf00001f, PM_TYPE_U64, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.58 */ { "kernel.percpu.cpu.steal", { 0xf00003a, PM_TYPE_U64, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.61 */ { "kernel.percpu.cpu.guest", { 0xf00003d, PM_TYPE_U64, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.30 */ { "kernel.percpu.cpu.wait.total", { 0xf00001e, PM_TYPE_U64, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.56 */ { "kernel.percpu.cpu.irq.soft", { 0xf000038, PM_TYPE_U64, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.57 */ { "kernel.percpu.cpu.irq.hard", { 0xf000039, PM_TYPE_U64, 0xf000000, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.62 */ { "kernel.pernode.cpu.user", { 0xf00003e, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.63 */ { "kernel.pernode.cpu.nice", { 0xf00003f, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.64 */ { "kernel.pernode.cpu.sys", { 0xf000040, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.65 */ { "kernel.pernode.cpu.idle", { 0xf000041, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.66 */ { "kernel.pernode.cpu.intr", { 0xf000042, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.67 */ { "kernel.pernode.cpu.steal", { 0xf000043, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.68 */ { "kernel.pernode.cpu.guest", { 0xf000044, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.69 */ { "kernel.pernode.cpu.wait.total", { 0xf000045, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.70 */ { "kernel.pernode.cpu.irq.soft", { 0xf000046, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.71 */ { "kernel.pernode.cpu.irq.hard", { 0xf000047, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.12.0 */ { "kernel.uname.release", { 0xf003000, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.12.1 */ { "kernel.uname.version", { 0xf003001, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.12.2 */ { "kernel.uname.sysname", { 0xf003002, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.12.3 */ { "kernel.uname.machine", { 0xf003003, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.12.4 */ { "kernel.uname.nodename", { 0xf003004, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.12.7 */ { "kernel.uname.distro", { 0xf003007, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.0 */ { "mem.physmem", { 0xf000400, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.10 */ { "mem.freemem", { 0xf00040a, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.1 */ { "mem.util.used", { 0xf000401, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.2 */ { "mem.util.free", { 0xf000402, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.3 */ { "mem.util.shared", { 0xf000403, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.4 */ { "mem.util.bufmem", { 0xf000404, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.5 */ { "mem.util.cached", { 0xf000405, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.12 */ { "mem.util.other", { 0xf00040c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.13 */ { "mem.util.swapCached", { 0xf00040d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.14 */ { "mem.util.active", { 0xf00040e, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.15 */ { "mem.util.inactive", { 0xf00040f, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.16 */ { "mem.util.highTotal", { 0xf000410, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.17 */ { "mem.util.highFree", { 0xf000411, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.18 */ { "mem.util.lowTotal", { 0xf000412, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.19 */ { "mem.util.lowFree", { 0xf000413, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.20 */ { "mem.util.swapTotal", { 0xf000414, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.21 */ { "mem.util.swapFree", { 0xf000415, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.22 */ { "mem.util.dirty", { 0xf000416, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.23 */ { "mem.util.writeback", { 0xf000417, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.24 */ { "mem.util.mapped", { 0xf000418, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.25 */ { "mem.util.slab", { 0xf000419, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.26 */ { "mem.util.committed_AS", { 0xf00041a, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.27 */ { "mem.util.pageTables", { 0xf00041b, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.28 */ { "mem.util.reverseMaps", { 0xf00041c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.29 */ { "mem.util.cache_clean", { 0xf00041d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.30 */ { "mem.util.anonpages", { 0xf00041e, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.31 */ { "mem.util.commitLimit", { 0xf00041f, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.32 */ { "mem.util.bounce", { 0xf000420, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.33 */ { "mem.util.NFS_Unstable", { 0xf000421, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.34 */ { "mem.util.slabReclaimable", { 0xf000422, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.35 */ { "mem.util.slabUnreclaimable", { 0xf000423, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.36 */ { "mem.util.active_anon", { 0xf000424, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.37 */ { "mem.util.inactive_anon", { 0xf000425, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.38 */ { "mem.util.active_file", { 0xf000426, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.39 */ { "mem.util.inactive_file", { 0xf000427, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.40 */ { "mem.util.unevictable", { 0xf000428, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.41 */ { "mem.util.mlocked", { 0xf000429, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.42 */ { "mem.util.shmem", { 0xf00042a, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.43 */ { "mem.util.kernelStack", { 0xf00042b, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.44 */ { "mem.util.hugepagesTotal", { 0xf00042c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.45 */ { "mem.util.hugepagesFree", { 0xf00042d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.46 */ { "mem.util.hugepagesRsvd", { 0xf00042e, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.47 */ { "mem.util.hugepagesSurp", { 0xf00042f, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.48 */ { "mem.util.directMap4k", { 0xf000430, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.49 */ { "mem.util.directMap2M", { 0xf000431, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.50 */ { "mem.util.vmallocTotal", { 0xf000432, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.51 */ { "mem.util.vmallocUsed", { 0xf000433, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.52 */ { "mem.util.vmallocChunk", { 0xf000434, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.53 */ { "mem.util.mmap_copy", { 0xf000435, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.54 */ { "mem.util.quicklists", { 0xf000436, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.55 */ { "mem.util.corrupthardware", { 0xf000437, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.56 */ { "mem.util.anonhugepages", { 0xf000438, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.0 */ { "mem.numa.util.total", { 0xf009000, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.1 */ { "mem.numa.util.free", { 0xf009001, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.2 */ { "mem.numa.util.used", { 0xf009002, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.3 */ { "mem.numa.util.active", { 0xf009003, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.4 */ { "mem.numa.util.inactive", { 0xf009004, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.5 */ { "mem.numa.util.active_anon", { 0xf009005, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.6 */ { "mem.numa.util.inactive_anon", { 0xf009006, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.7 */ { "mem.numa.util.active_file", { 0xf009007, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.8 */ { "mem.numa.util.inactive_file", { 0xf009008, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.9 */ { "mem.numa.util.highTotal", { 0xf009009, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.10 */ { "mem.numa.util.highFree", { 0xf00900a, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.11 */ { "mem.numa.util.lowTotal", { 0xf00900b, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.12 */ { "mem.numa.util.lowFree", { 0xf00900c, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.13 */ { "mem.numa.util.unevictable", { 0xf00900d, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.14 */ { "mem.numa.util.mlocked", { 0xf00900e, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.15 */ { "mem.numa.util.dirty", { 0xf00900f, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.16 */ { "mem.numa.util.writeback", { 0xf009010, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.17 */ { "mem.numa.util.filePages", { 0xf009011, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.18 */ { "mem.numa.util.mapped", { 0xf009012, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.19 */ { "mem.numa.util.anonpages", { 0xf009013, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.20 */ { "mem.numa.util.shmem", { 0xf009014, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.21 */ { "mem.numa.util.kernelStack", { 0xf009015, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.22 */ { "mem.numa.util.pageTables", { 0xf009016, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.23 */ { "mem.numa.util.NFS_Unstable", { 0xf009017, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.24 */ { "mem.numa.util.bounce", { 0xf009018, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.25 */ { "mem.numa.util.writebackTmp", { 0xf009019, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.26 */ { "mem.numa.util.slab", { 0xf00901a, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.27 */ { "mem.numa.util.slabReclaimable", { 0xf00901b, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.28 */ { "mem.numa.util.slabUnreclaimable", { 0xf00901c, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.29 */ { "mem.numa.util.hugepagesTotal", { 0xf00901d, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.30 */ { "mem.numa.util.hugepagesFree", { 0xf00901e, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.31 */ { "mem.numa.util.hugepagesSurp", { 0xf00901f, PM_TYPE_U64, 0xf000013, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.32 */ { "mem.numa.alloc.hit", { 0xf009020, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.33 */ { "mem.numa.alloc.miss", { 0xf009021, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.34 */ { "mem.numa.alloc.foreign", { 0xf009022, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.35 */ { "mem.numa.alloc.interleave_hit", { 0xf009023, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.36 */ { "mem.numa.alloc.local_node", { 0xf009024, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.36.37 */ { "mem.numa.alloc.other_node", { 0xf009025, PM_TYPE_U64, 0xf000013, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.20.0 */ { "mem.slabinfo.objects.active", { 0xf005000, PM_TYPE_U64, 0xf00000c, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.20.1 */ { "mem.slabinfo.objects.total", { 0xf005001, PM_TYPE_U64, 0xf00000c, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.20.2 */ { "mem.slabinfo.objects.size", { 0xf005002, PM_TYPE_U32, 0xf00000c, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.20.3 */ { "mem.slabinfo.slabs.active", { 0xf005003, PM_TYPE_U32, 0xf00000c, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.20.4 */ { "mem.slabinfo.slabs.total", { 0xf005004, PM_TYPE_U32, 0xf00000c, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.20.5 */ { "mem.slabinfo.slabs.pages_per_slab", { 0xf005005, PM_TYPE_U32, 0xf00000c, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.20.6 */ { "mem.slabinfo.slabs.objects_per_slab", { 0xf005006, PM_TYPE_U32, 0xf00000c, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.20.7 */ { "mem.slabinfo.slabs.total_size", { 0xf005007, PM_TYPE_U64, 0xf00000c, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.35 */ { "mem.vmstat.allocstall", { 0xf007023, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.57 */ { "mem.vmstat.compact_blocks_moved", { 0xf007039, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.58 */ { "mem.vmstat.compact_fail", { 0xf00703a, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.59 */ { "mem.vmstat.compact_pagemigrate_failed", { 0xf00703b, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.60 */ { "mem.vmstat.compact_pages_moved", { 0xf00703c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.61 */ { "mem.vmstat.compact_stall", { 0xf00703d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.62 */ { "mem.vmstat.compact_success", { 0xf00703e, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.43 */ { "mem.vmstat.htlb_buddy_alloc_fail", { 0xf00702b, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.44 */ { "mem.vmstat.htlb_buddy_alloc_success", { 0xf00702c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.33 */ { "mem.vmstat.kswapd_inodesteal", { 0xf007021, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.87 */ { "mem.vmstat.kswapd_low_wmark_hit_quickly", { 0xf007057, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.88 */ { "mem.vmstat.kswapd_high_wmark_hit_quickly", { 0xf007058, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.89 */ { "mem.vmstat.kswapd_skip_congestion_wait", { 0xf007059, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.32 */ { "mem.vmstat.kswapd_steal", { 0xf007020, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.45 */ { "mem.vmstat.nr_active_anon", { 0xf00702d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.46 */ { "mem.vmstat.nr_active_file", { 0xf00702e, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.39 */ { "mem.vmstat.nr_anon_pages", { 0xf007027, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.90 */ { "mem.vmstat.nr_anon_transparent_hugepages", { 0xf00705a, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.40 */ { "mem.vmstat.nr_bounce", { 0xf007028, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.91 */ { "mem.vmstat.nr_dirtied", { 0xf00705b, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.0 */ { "mem.vmstat.nr_dirty", { 0xf007000, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.92 */ { "mem.vmstat.nr_dirty_background_threshold", { 0xf00705c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.93 */ { "mem.vmstat.nr_dirty_threshold", { 0xf00705d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.47 */ { "mem.vmstat.nr_free_pages", { 0xf00702f, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.48 */ { "mem.vmstat.nr_inactive_anon", { 0xf007030, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.49 */ { "mem.vmstat.nr_inactive_file", { 0xf007031, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.50 */ { "mem.vmstat.nr_isolated_anon", { 0xf007032, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.51 */ { "mem.vmstat.nr_isolated_file", { 0xf007033, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.52 */ { "mem.vmstat.nr_kernel_stack", { 0xf007034, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.4 */ { "mem.vmstat.nr_mapped", { 0xf007004, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.53 */ { "mem.vmstat.nr_mlock", { 0xf007035, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.3 */ { "mem.vmstat.nr_page_table_pages", { 0xf007003, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.54 */ { "mem.vmstat.nr_shmem", { 0xf007036, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.5 */ { "mem.vmstat.nr_slab", { 0xf007005, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.37 */ { "mem.vmstat.nr_slab_reclaimable", { 0xf007025, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.38 */ { "mem.vmstat.nr_slab_unreclaimable", { 0xf007026, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.55 */ { "mem.vmstat.nr_unevictable", { 0xf007037, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.2 */ { "mem.vmstat.nr_unstable", { 0xf007002, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.42 */ { "mem.vmstat.nr_vmscan_write", { 0xf00702a, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.1 */ { "mem.vmstat.nr_writeback", { 0xf007001, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.56 */ { "mem.vmstat.nr_writeback_temp", { 0xf007038, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.94 */ { "mem.vmstat.nr_written", { 0xf00705e, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.95 */ { "mem.vmstat.numa_foreign", { 0xf00705f, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.96 */ { "mem.vmstat.numa_hit", { 0xf007060, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.97 */ { "mem.vmstat.numa_interleave", { 0xf007061, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.98 */ { "mem.vmstat.numa_local", { 0xf007062, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.99 */ { "mem.vmstat.numa_miss", { 0xf007063, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.100 */ { "mem.vmstat.numa_other", { 0xf007064, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.34 */ { "mem.vmstat.pageoutrun", { 0xf007022, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.14 */ { "mem.vmstat.pgactivate", { 0xf00700e, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.12 */ { "mem.vmstat.pgalloc_dma", { 0xf00700c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.63 */ { "mem.vmstat.pgalloc_dma32", { 0xf00703f, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.10 */ { "mem.vmstat.pgalloc_high", { 0xf00700a, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.64 */ { "mem.vmstat.pgalloc_movable", { 0xf007040, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.11 */ { "mem.vmstat.pgalloc_normal", { 0xf00700b, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.65 */ { "mem.vmstat.pgrefill_dma32", { 0xf007041, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.66 */ { "mem.vmstat.pgrefill_movable", { 0xf007042, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.15 */ { "mem.vmstat.pgdeactivate", { 0xf00700f, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.16 */ { "mem.vmstat.pgfault", { 0xf007010, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.13 */ { "mem.vmstat.pgfree", { 0xf00700d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.30 */ { "mem.vmstat.pginodesteal", { 0xf00701e, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.17 */ { "mem.vmstat.pgmajfault", { 0xf007011, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.6 */ { "mem.vmstat.pgpgin", { 0xf007006, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.7 */ { "mem.vmstat.pgpgout", { 0xf007007, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.20 */ { "mem.vmstat.pgrefill_dma", { 0xf007014, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.18 */ { "mem.vmstat.pgrefill_high", { 0xf007012, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.19 */ { "mem.vmstat.pgrefill_normal", { 0xf007013, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.36 */ { "mem.vmstat.pgrotated", { 0xf007024, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.29 */ { "mem.vmstat.pgscan_direct_dma", { 0xf00701d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.67 */ { "mem.vmstat.pgscan_direct_dma32", { 0xf007043, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.27 */ { "mem.vmstat.pgscan_direct_high", { 0xf00701b, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.68 */ { "mem.vmstat.pgscan_direct_movable", { 0xf007044, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.28 */ { "mem.vmstat.pgscan_direct_normal", { 0xf00701c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.26 */ { "mem.vmstat.pgscan_kswapd_dma", { 0xf00701a, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.69 */ { "mem.vmstat.pgscan_kswapd_dma32", { 0xf007045, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.24 */ { "mem.vmstat.pgscan_kswapd_high", { 0xf007018, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.70 */ { "mem.vmstat.pgscan_kswapd_movable", { 0xf007046, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.25 */ { "mem.vmstat.pgscan_kswapd_normal", { 0xf007019, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.23 */ { "mem.vmstat.pgsteal_dma", { 0xf007017, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.71 */ { "mem.vmstat.pgsteal_dma32", { 0xf007047, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.21 */ { "mem.vmstat.pgsteal_high", { 0xf007015, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.72 */ { "mem.vmstat.pgsteal_movable", { 0xf007048, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.22 */ { "mem.vmstat.pgsteal_normal", { 0xf007016, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.8 */ { "mem.vmstat.pswpin", { 0xf007008, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.9 */ { "mem.vmstat.pswpout", { 0xf007009, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.31 */ { "mem.vmstat.slabs_scanned", { 0xf00701f, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.73 */ { "mem.vmstat.thp_fault_alloc", { 0xf007049, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.74 */ { "mem.vmstat.thp_fault_fallback", { 0xf00704a, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.75 */ { "mem.vmstat.thp_collapse_alloc", { 0xf00704b, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.76 */ { "mem.vmstat.thp_collapse_alloc_failed", { 0xf00704c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.77 */ { "mem.vmstat.thp_split", { 0xf00704d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.78 */ { "mem.vmstat.unevictable_pgs_cleared", { 0xf00704e, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.79 */ { "mem.vmstat.unevictable_pgs_culled", { 0xf00704f, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.80 */ { "mem.vmstat.unevictable_pgs_mlocked", { 0xf007050, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.81 */ { "mem.vmstat.unevictable_pgs_mlockfreed", { 0xf007051, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.82 */ { "mem.vmstat.unevictable_pgs_munlocked", { 0xf007052, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.83 */ { "mem.vmstat.unevictable_pgs_rescued", { 0xf007053, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.84 */ { "mem.vmstat.unevictable_pgs_scanned", { 0xf007054, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.85 */ { "mem.vmstat.unevictable_pgs_stranded", { 0xf007055, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.28.86 */ { "mem.vmstat.zone_reclaim_failed", { 0xf007056, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.8 */ { "swap.pagesin", { 0xf000008, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.9 */ { "swap.pagesout", { 0xf000009, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.10 */ { "swap.in", { 0xf00000a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.11 */ { "swap.out", { 0xf00000b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.8 */ { "swap.free", { 0xf000408, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.6 */ { "swap.length", { 0xf000406, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.1.7 */ { "swap.used", { 0xf000407, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.13 */ { "network.interface.collisions", { 0xf000c0d, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.21 */ { "network.interface.mtu", { 0xf000c15, PM_TYPE_U32, 0xf000003, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.22 */ { "network.interface.speed", { 0xf000c16, PM_TYPE_FLOAT, 0xf000003, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=-1, .dimCount=0, .scaleSpace=2, .scaleTime=3, .scaleCount=0 } } }, /* 60.3.23 */ { "network.interface.baudrate", { 0xf000c17, PM_TYPE_U32, 0xf000003, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=-1, .dimCount=0, .scaleSpace=0, .scaleTime=3, .scaleCount=0 } } }, /* 60.3.24 */ { "network.interface.duplex", { 0xf000c18, PM_TYPE_U32, 0xf000003, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.25 */ { "network.interface.up", { 0xf000c19, PM_TYPE_U32, 0xf000003, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.26 */ { "network.interface.running", { 0xf000c1a, PM_TYPE_U32, 0xf000003, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.33.0 */ { "network.interface.inet_addr", { 0xf008400, PM_TYPE_STRING, 0xf000011, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.0 */ { "network.interface.in.bytes", { 0xf000c00, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.1 */ { "network.interface.in.packets", { 0xf000c01, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.2 */ { "network.interface.in.errors", { 0xf000c02, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.3 */ { "network.interface.in.drops", { 0xf000c03, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.4 */ { "network.interface.in.fifo", { 0xf000c04, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.5 */ { "network.interface.in.frame", { 0xf000c05, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.6 */ { "network.interface.in.compressed", { 0xf000c06, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.7 */ { "network.interface.in.mcasts", { 0xf000c07, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.8 */ { "network.interface.out.bytes", { 0xf000c08, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.9 */ { "network.interface.out.packets", { 0xf000c09, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.10 */ { "network.interface.out.errors", { 0xf000c0a, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.11 */ { "network.interface.out.drops", { 0xf000c0b, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.12 */ { "network.interface.out.fifo", { 0xf000c0c, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.14 */ { "network.interface.out.carrier", { 0xf000c0e, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.15 */ { "network.interface.out.compressed", { 0xf000c0f, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.16 */ { "network.interface.total.bytes", { 0xf000c10, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.17 */ { "network.interface.total.packets", { 0xf000c11, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.18 */ { "network.interface.total.errors", { 0xf000c12, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.19 */ { "network.interface.total.drops", { 0xf000c13, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.3.20 */ { "network.interface.total.mcasts", { 0xf000c14, PM_TYPE_U64, 0xf000003, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.11.0 */ { "network.sockstat.tcp.inuse", { 0xf002c00, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.11.1 */ { "network.sockstat.tcp.highest", { 0xf002c01, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.11.2 */ { "network.sockstat.tcp.util", { 0xf002c02, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.11.3 */ { "network.sockstat.udp.inuse", { 0xf002c03, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.11.4 */ { "network.sockstat.udp.highest", { 0xf002c04, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.11.5 */ { "network.sockstat.udp.util", { 0xf002c05, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.11.6 */ { "network.sockstat.raw.inuse", { 0xf002c06, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.11.7 */ { "network.sockstat.raw.highest", { 0xf002c07, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.11.8 */ { "network.sockstat.raw.util", { 0xf002c08, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.0 */ { "network.ip.forwarding", { 0xf003800, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.1 */ { "network.ip.defaultttl", { 0xf003801, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.2 */ { "network.ip.inreceives", { 0xf003802, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.3 */ { "network.ip.inhdrerrors", { 0xf003803, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.4 */ { "network.ip.inaddrerrors", { 0xf003804, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.5 */ { "network.ip.forwdatagrams", { 0xf003805, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.6 */ { "network.ip.inunknownprotos", { 0xf003806, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.7 */ { "network.ip.indiscards", { 0xf003807, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.8 */ { "network.ip.indelivers", { 0xf003808, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.9 */ { "network.ip.outrequests", { 0xf003809, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.10 */ { "network.ip.outdiscards", { 0xf00380a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.11 */ { "network.ip.outnoroutes", { 0xf00380b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.12 */ { "network.ip.reasmtimeout", { 0xf00380c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.13 */ { "network.ip.reasmreqds", { 0xf00380d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.14 */ { "network.ip.reasmoks", { 0xf00380e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.15 */ { "network.ip.reasmfails", { 0xf00380f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.16 */ { "network.ip.fragoks", { 0xf003810, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.17 */ { "network.ip.fragfails", { 0xf003811, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.18 */ { "network.ip.fragcreates", { 0xf003812, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.20 */ { "network.icmp.inmsgs", { 0xf003814, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.21 */ { "network.icmp.inerrors", { 0xf003815, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.22 */ { "network.icmp.indestunreachs", { 0xf003816, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.23 */ { "network.icmp.intimeexcds", { 0xf003817, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.24 */ { "network.icmp.inparmprobs", { 0xf003818, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.25 */ { "network.icmp.insrcquenchs", { 0xf003819, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.26 */ { "network.icmp.inredirects", { 0xf00381a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.27 */ { "network.icmp.inechos", { 0xf00381b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.28 */ { "network.icmp.inechoreps", { 0xf00381c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.29 */ { "network.icmp.intimestamps", { 0xf00381d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.30 */ { "network.icmp.intimestampreps", { 0xf00381e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.31 */ { "network.icmp.inaddrmasks", { 0xf00381f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.32 */ { "network.icmp.inaddrmaskreps", { 0xf003820, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.33 */ { "network.icmp.outmsgs", { 0xf003821, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.34 */ { "network.icmp.outerrors", { 0xf003822, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.35 */ { "network.icmp.outdestunreachs", { 0xf003823, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.36 */ { "network.icmp.outtimeexcds", { 0xf003824, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.37 */ { "network.icmp.outparmprobs", { 0xf003825, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.38 */ { "network.icmp.outsrcquenchs", { 0xf003826, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.39 */ { "network.icmp.outredirects", { 0xf003827, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.40 */ { "network.icmp.outechos", { 0xf003828, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.41 */ { "network.icmp.outechoreps", { 0xf003829, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.42 */ { "network.icmp.outtimestamps", { 0xf00382a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.43 */ { "network.icmp.outtimestampreps", { 0xf00382b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.44 */ { "network.icmp.outaddrmasks", { 0xf00382c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.45 */ { "network.icmp.outaddrmaskreps", { 0xf00382d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.50 */ { "network.tcp.rtoalgorithm", { 0xf003832, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.51 */ { "network.tcp.rtomin", { 0xf003833, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.52 */ { "network.tcp.rtomax", { 0xf003834, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.53 */ { "network.tcp.maxconn", { 0xf003835, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.54 */ { "network.tcp.activeopens", { 0xf003836, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.55 */ { "network.tcp.passiveopens", { 0xf003837, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.56 */ { "network.tcp.attemptfails", { 0xf003838, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.57 */ { "network.tcp.estabresets", { 0xf003839, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.58 */ { "network.tcp.currestab", { 0xf00383a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.59 */ { "network.tcp.insegs", { 0xf00383b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.60 */ { "network.tcp.outsegs", { 0xf00383c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.61 */ { "network.tcp.retranssegs", { 0xf00383d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.62 */ { "network.tcp.inerrs", { 0xf00383e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.63 */ { "network.tcp.outrsts", { 0xf00383f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.70 */ { "network.udp.indatagrams", { 0xf003846, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.71 */ { "network.udp.noports", { 0xf003847, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.72 */ { "network.udp.inerrors", { 0xf003848, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.74 */ { "network.udp.outdatagrams", { 0xf00384a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.75 */ { "network.udp.recvbuferrors", { 0xf00384b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.76 */ { "network.udp.sndbuferrors", { 0xf00384c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.77 */ { "network.udplite.indatagrams", { 0xf00384d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.78 */ { "network.udplite.noports", { 0xf00384e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.79 */ { "network.udplite.inerrors", { 0xf00384f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.80 */ { "network.udplite.outdatagrams", { 0xf003850, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.81 */ { "network.udplite.recvbuferrors", { 0xf003851, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.14.82 */ { "network.udplite.sndbuferrors", { 0xf003852, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.19.1 */ { "network.tcpconn.established", { 0xf004c01, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.19.2 */ { "network.tcpconn.syn_sent", { 0xf004c02, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.19.3 */ { "network.tcpconn.syn_recv", { 0xf004c03, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.19.4 */ { "network.tcpconn.fin_wait1", { 0xf004c04, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.19.5 */ { "network.tcpconn.fin_wait2", { 0xf004c05, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.19.6 */ { "network.tcpconn.time_wait", { 0xf004c06, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.19.7 */ { "network.tcpconn.close", { 0xf004c07, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.19.8 */ { "network.tcpconn.close_wait", { 0xf004c08, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.19.9 */ { "network.tcpconn.last_ack", { 0xf004c09, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.19.10 */ { "network.tcpconn.listen", { 0xf004c0a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.19.11 */ { "network.tcpconn.closing", { 0xf004c0b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.20 */ { "network.ib.status", { 0xf007414, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.21 */ { "network.ib.control", { 0xf007415, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.0 */ { "network.ib.in.bytes", { 0xf007400, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.1 */ { "network.ib.in.packets", { 0xf007401, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.2 */ { "network.ib.in.errors.drop", { 0xf007402, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.3 */ { "network.ib.in.errors.filter", { 0xf007403, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.4 */ { "network.ib.in.errors.local", { 0xf007404, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.5 */ { "network.ib.in.errors.remote", { 0xf007405, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.6 */ { "network.ib.out.bytes", { 0xf007406, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.7 */ { "network.ib.out.packets", { 0xf007407, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.8 */ { "network.ib.out.errors.drop", { 0xf007408, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.9 */ { "network.ib.out.errors.filter", { 0xf007409, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.16 */ { "network.ib.total.bytes", { 0xf007410, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.17 */ { "network.ib.total.packets", { 0xf007411, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.18 */ { "network.ib.total.errors.drop", { 0xf007412, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.19 */ { "network.ib.total.errors.filter", { 0xf007413, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.10 */ { "network.ib.total.errors.link", { 0xf00740a, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.11 */ { "network.ib.total.errors.recover", { 0xf00740b, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.12 */ { "network.ib.total.errors.integrity", { 0xf00740c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.13 */ { "network.ib.total.errors.vl15", { 0xf00740d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.14 */ { "network.ib.total.errors.overrun", { 0xf00740e, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.29.15 */ { "network.ib.total.errors.symbol", { 0xf00740f, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.4 */ { "disk.dev.read", { 0xf000004, PM_TYPE_U64, 0xf000001, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.5 */ { "disk.dev.write", { 0xf000005, PM_TYPE_U64, 0xf000001, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.28 */ { "disk.dev.total", { 0xf00001c, PM_TYPE_U64, 0xf000001, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.6 */ { "disk.dev.blkread", { 0xf000006, PM_TYPE_U64, 0xf000001, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.7 */ { "disk.dev.blkwrite", { 0xf000007, PM_TYPE_U64, 0xf000001, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.36 */ { "disk.dev.blktotal", { 0xf000024, PM_TYPE_U64, 0xf000001, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.38 */ { "disk.dev.read_bytes", { 0xf000026, PM_TYPE_U32, 0xf000001, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.39 */ { "disk.dev.write_bytes", { 0xf000027, PM_TYPE_U32, 0xf000001, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.40 */ { "disk.dev.total_bytes", { 0xf000028, PM_TYPE_U32, 0xf000001, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.49 */ { "disk.dev.read_merge", { 0xf000031, PM_TYPE_U64, 0xf000001, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.50 */ { "disk.dev.write_merge", { 0xf000032, PM_TYPE_U64, 0xf000001, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.46 */ { "disk.dev.avactive", { 0xf00002e, PM_TYPE_U32, 0xf000001, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.72 */ { "disk.dev.read_rawactive", { 0xf000048, PM_TYPE_U32, 0xf000001, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.73 */ { "disk.dev.write_rawactive", { 0xf000049, PM_TYPE_U32, 0xf000001, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.47 */ { "disk.dev.aveq", { 0xf00002f, PM_TYPE_U32, 0xf000001, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.59 */ { "disk.dev.scheduler", { 0xf00003b, PM_TYPE_STRING, 0xf000001, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.24 */ { "disk.all.read", { 0xf000018, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.25 */ { "disk.all.write", { 0xf000019, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.29 */ { "disk.all.total", { 0xf00001d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.26 */ { "disk.all.blkread", { 0xf00001a, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.27 */ { "disk.all.blkwrite", { 0xf00001b, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.37 */ { "disk.all.blktotal", { 0xf000025, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.41 */ { "disk.all.read_bytes", { 0xf000029, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.42 */ { "disk.all.write_bytes", { 0xf00002a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.43 */ { "disk.all.total_bytes", { 0xf00002b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.51 */ { "disk.all.read_merge", { 0xf000033, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.52 */ { "disk.all.write_merge", { 0xf000034, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.0.44 */ { "disk.all.avactive", { 0xf00002c, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.74 */ { "disk.all.read_rawactive", { 0xf00004a, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.75 */ { "disk.all.write_rawactive", { 0xf00004b, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.0.45 */ { "disk.all.aveq", { 0xf00002d, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 60.10.0 */ { "disk.partitions.read", { 0xf002800, PM_TYPE_U32, 0xf00000a, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.10.1 */ { "disk.partitions.write", { 0xf002801, PM_TYPE_U32, 0xf00000a, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.10.2 */ { "disk.partitions.total", { 0xf002802, PM_TYPE_U32, 0xf00000a, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.10.3 */ { "disk.partitions.blkread", { 0xf002803, PM_TYPE_U32, 0xf00000a, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.10.4 */ { "disk.partitions.blkwrite", { 0xf002804, PM_TYPE_U32, 0xf00000a, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.10.5 */ { "disk.partitions.blktotal", { 0xf002805, PM_TYPE_U32, 0xf00000a, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.10.6 */ { "disk.partitions.read_bytes", { 0xf002806, PM_TYPE_U32, 0xf00000a, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.10.7 */ { "disk.partitions.write_bytes", { 0xf002807, PM_TYPE_U32, 0xf00000a, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.10.8 */ { "disk.partitions.total_bytes", { 0xf002808, PM_TYPE_U32, 0xf00000a, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.5.1 */ { "filesys.capacity", { 0xf001401, PM_TYPE_U64, 0xf000005, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.5.2 */ { "filesys.used", { 0xf001402, PM_TYPE_U64, 0xf000005, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.5.3 */ { "filesys.free", { 0xf001403, PM_TYPE_U64, 0xf000005, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.5.4 */ { "filesys.maxfiles", { 0xf001404, PM_TYPE_U32, 0xf000005, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.5.5 */ { "filesys.usedfiles", { 0xf001405, PM_TYPE_U32, 0xf000005, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.5.6 */ { "filesys.freefiles", { 0xf001406, PM_TYPE_U32, 0xf000005, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.5.7 */ { "filesys.mountdir", { 0xf001407, PM_TYPE_STRING, 0xf000005, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.5.8 */ { "filesys.full", { 0xf001408, PM_TYPE_DOUBLE, 0xf000005, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.5.9 */ { "filesys.blocksize", { 0xf001409, PM_TYPE_U32, 0xf000005, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.5.10 */ { "filesys.avail", { 0xf00140a, PM_TYPE_U64, 0xf000005, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.5.11 */ { "filesys.readonly", { 0xf00140b, PM_TYPE_U32, 0xf000005, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.6.0 */ { "swapdev.free", { 0xf001800, PM_TYPE_U32, 0xf000006, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.6.1 */ { "swapdev.length", { 0xf001801, PM_TYPE_U32, 0xf000006, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.6.2 */ { "swapdev.maxswap", { 0xf001802, PM_TYPE_U32, 0xf000006, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.6.3 */ { "swapdev.vlength", { 0xf001803, PM_TYPE_U32, 0xf000006, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.6.4 */ { "swapdev.priority", { 0xf001804, PM_TYPE_32, 0xf000006, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.20 */ { "rpc.client.rpccnt", { 0xf001c14, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.21 */ { "rpc.client.rpcretrans", { 0xf001c15, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.22 */ { "rpc.client.rpcauthrefresh", { 0xf001c16, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.24 */ { "rpc.client.netcnt", { 0xf001c18, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.25 */ { "rpc.client.netudpcnt", { 0xf001c19, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.26 */ { "rpc.client.nettcpcnt", { 0xf001c1a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.27 */ { "rpc.client.nettcpconn", { 0xf001c1b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.30 */ { "rpc.server.rpccnt", { 0xf001c1e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.31 */ { "rpc.server.rpcerr", { 0xf001c1f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.32 */ { "rpc.server.rpcbadfmt", { 0xf001c20, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.33 */ { "rpc.server.rpcbadauth", { 0xf001c21, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.34 */ { "rpc.server.rpcbadclnt", { 0xf001c22, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.35 */ { "rpc.server.rchits", { 0xf001c23, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.36 */ { "rpc.server.rcmisses", { 0xf001c24, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.37 */ { "rpc.server.rcnocache", { 0xf001c25, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.38 */ { "rpc.server.fh_cached", { 0xf001c26, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.39 */ { "rpc.server.fh_valid", { 0xf001c27, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.40 */ { "rpc.server.fh_fixup", { 0xf001c28, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.41 */ { "rpc.server.fh_lookup", { 0xf001c29, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.42 */ { "rpc.server.fh_stale", { 0xf001c2a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.43 */ { "rpc.server.fh_concurrent", { 0xf001c2b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.44 */ { "rpc.server.netcnt", { 0xf001c2c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.45 */ { "rpc.server.netudpcnt", { 0xf001c2d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.46 */ { "rpc.server.nettcpcnt", { 0xf001c2e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.47 */ { "rpc.server.nettcpconn", { 0xf001c2f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.51 */ { "rpc.server.fh_anon", { 0xf001c33, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.52 */ { "rpc.server.fh_nocache_dir", { 0xf001c34, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.53 */ { "rpc.server.fh_nocache_nondir", { 0xf001c35, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.54 */ { "rpc.server.io_read", { 0xf001c36, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.55 */ { "rpc.server.io_write", { 0xf001c37, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.56 */ { "rpc.server.th_cnt", { 0xf001c38, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.57 */ { "rpc.server.th_fullcnt", { 0xf001c39, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.1 */ { "nfs.client.calls", { 0xf001c01, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.4 */ { "nfs.client.reqs", { 0xf001c04, PM_TYPE_U32, 0xf000007, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.50 */ { "nfs.server.calls", { 0xf001c32, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.12 */ { "nfs.server.reqs", { 0xf001c0c, PM_TYPE_U32, 0xf000007, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.60 */ { "nfs3.client.calls", { 0xf001c3c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.61 */ { "nfs3.client.reqs", { 0xf001c3d, PM_TYPE_U32, 0xf000008, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.62 */ { "nfs3.server.calls", { 0xf001c3e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.63 */ { "nfs3.server.reqs", { 0xf001c3f, PM_TYPE_U32, 0xf000008, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.64 */ { "nfs4.client.calls", { 0xf001c40, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.65 */ { "nfs4.client.reqs", { 0xf001c41, PM_TYPE_U32, 0xf00000e, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.66 */ { "nfs4.server.calls", { 0xf001c42, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.7.67 */ { "nfs4.server.reqs", { 0xf001c43, PM_TYPE_U32, 0xf00000f, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.51 */ { "xfs.write", { 0xf004033, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.52 */ { "xfs.write_bytes", { 0xf004034, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.53 */ { "xfs.read", { 0xf004035, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.54 */ { "xfs.read_bytes", { 0xf004036, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.67 */ { "xfs.iflush_count", { 0xf004043, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.68 */ { "xfs.icluster_flushcnt", { 0xf004044, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.69 */ { "xfs.icluster_flushinode", { 0xf004045, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.0 */ { "xfs.allocs.alloc_extent", { 0xf004000, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.1 */ { "xfs.allocs.alloc_block", { 0xf004001, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.2 */ { "xfs.allocs.free_extent", { 0xf004002, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.3 */ { "xfs.allocs.free_block", { 0xf004003, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.4 */ { "xfs.alloc_btree.lookup", { 0xf004004, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.5 */ { "xfs.alloc_btree.compare", { 0xf004005, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.6 */ { "xfs.alloc_btree.insrec", { 0xf004006, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.7 */ { "xfs.alloc_btree.delrec", { 0xf004007, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.8 */ { "xfs.block_map.read_ops", { 0xf004008, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.9 */ { "xfs.block_map.write_ops", { 0xf004009, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.10 */ { "xfs.block_map.unmap", { 0xf00400a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.11 */ { "xfs.block_map.add_exlist", { 0xf00400b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.12 */ { "xfs.block_map.del_exlist", { 0xf00400c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.13 */ { "xfs.block_map.look_exlist", { 0xf00400d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.14 */ { "xfs.block_map.cmp_exlist", { 0xf00400e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.15 */ { "xfs.bmap_btree.lookup", { 0xf00400f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.16 */ { "xfs.bmap_btree.compare", { 0xf004010, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.17 */ { "xfs.bmap_btree.insrec", { 0xf004011, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.18 */ { "xfs.bmap_btree.delrec", { 0xf004012, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.19 */ { "xfs.dir_ops.lookup", { 0xf004013, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.20 */ { "xfs.dir_ops.create", { 0xf004014, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.21 */ { "xfs.dir_ops.remove", { 0xf004015, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.22 */ { "xfs.dir_ops.getdents", { 0xf004016, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.23 */ { "xfs.transactions.sync", { 0xf004017, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.24 */ { "xfs.transactions.async", { 0xf004018, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.25 */ { "xfs.transactions.empty", { 0xf004019, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.26 */ { "xfs.inode_ops.ig_attempts", { 0xf00401a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.27 */ { "xfs.inode_ops.ig_found", { 0xf00401b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.28 */ { "xfs.inode_ops.ig_frecycle", { 0xf00401c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.29 */ { "xfs.inode_ops.ig_missed", { 0xf00401d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.30 */ { "xfs.inode_ops.ig_dup", { 0xf00401e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.31 */ { "xfs.inode_ops.ig_reclaims", { 0xf00401f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.32 */ { "xfs.inode_ops.ig_attrchg", { 0xf004020, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.33 */ { "xfs.log.writes", { 0xf004021, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.34 */ { "xfs.log.blocks", { 0xf004022, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.78 */ { "xfs.log.write_ratio", { 0xf00404e, PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.35 */ { "xfs.log.noiclogs", { 0xf004023, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.36 */ { "xfs.log.force", { 0xf004024, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.37 */ { "xfs.log.force_sleep", { 0xf004025, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.38 */ { "xfs.log_tail.try_logspace", { 0xf004026, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.39 */ { "xfs.log_tail.sleep_logspace", { 0xf004027, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.40 */ { "xfs.log_tail.push_ail.pushes", { 0xf004028, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.41 */ { "xfs.log_tail.push_ail.success", { 0xf004029, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.42 */ { "xfs.log_tail.push_ail.pushbuf", { 0xf00402a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.43 */ { "xfs.log_tail.push_ail.pinned", { 0xf00402b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.44 */ { "xfs.log_tail.push_ail.locked", { 0xf00402c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.45 */ { "xfs.log_tail.push_ail.flushing", { 0xf00402d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.46 */ { "xfs.log_tail.push_ail.restarts", { 0xf00402e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.47 */ { "xfs.log_tail.push_ail.flush", { 0xf00402f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.48 */ { "xfs.xstrat.bytes", { 0xf004030, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.49 */ { "xfs.xstrat.quick", { 0xf004031, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.50 */ { "xfs.xstrat.split", { 0xf004032, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.55 */ { "xfs.attr.get", { 0xf004037, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.56 */ { "xfs.attr.set", { 0xf004038, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.57 */ { "xfs.attr.remove", { 0xf004039, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.58 */ { "xfs.attr.list", { 0xf00403a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.59 */ { "xfs.quota.reclaims", { 0xf00403b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.60 */ { "xfs.quota.reclaim_misses", { 0xf00403c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.61 */ { "xfs.quota.dquot_dups", { 0xf00403d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.62 */ { "xfs.quota.cachemisses", { 0xf00403e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.63 */ { "xfs.quota.cachehits", { 0xf00403f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.64 */ { "xfs.quota.wants", { 0xf004040, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.65 */ { "xfs.quota.shake_reclaims", { 0xf004041, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.66 */ { "xfs.quota.inact_reclaims", { 0xf004042, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.17.0 */ { "xfs.buffer.get", { 0xf004400, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.17.1 */ { "xfs.buffer.create", { 0xf004401, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.17.2 */ { "xfs.buffer.get_locked", { 0xf004402, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.17.3 */ { "xfs.buffer.get_locked_waited", { 0xf004403, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.17.4 */ { "xfs.buffer.busy_locked", { 0xf004404, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.17.5 */ { "xfs.buffer.miss_locked", { 0xf004405, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.17.6 */ { "xfs.buffer.page_retries", { 0xf004406, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.17.7 */ { "xfs.buffer.page_found", { 0xf004407, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.17.8 */ { "xfs.buffer.get_read", { 0xf004408, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.70 */ { "xfs.vnodes.active", { 0xf004046, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.71 */ { "xfs.vnodes.alloc", { 0xf004047, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.72 */ { "xfs.vnodes.get", { 0xf004048, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.73 */ { "xfs.vnodes.hold", { 0xf004049, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.74 */ { "xfs.vnodes.rele", { 0xf00404a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.75 */ { "xfs.vnodes.reclaim", { 0xf00404b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.76 */ { "xfs.vnodes.remove", { 0xf00404c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.77 */ { "xfs.vnodes.free", { 0xf00404d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.79 */ { "xfs.control.reset", { 0xf00404f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.80 */ { "xfs.btree.alloc_blocks.lookup", { 0xf004050, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.81 */ { "xfs.btree.alloc_blocks.compare", { 0xf004051, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.82 */ { "xfs.btree.alloc_blocks.insrec", { 0xf004052, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.83 */ { "xfs.btree.alloc_blocks.delrec", { 0xf004053, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.84 */ { "xfs.btree.alloc_blocks.newroot", { 0xf004054, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.85 */ { "xfs.btree.alloc_blocks.killroot", { 0xf004055, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.86 */ { "xfs.btree.alloc_blocks.increment", { 0xf004056, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.87 */ { "xfs.btree.alloc_blocks.decrement", { 0xf004057, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.88 */ { "xfs.btree.alloc_blocks.lshift", { 0xf004058, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.89 */ { "xfs.btree.alloc_blocks.rshift", { 0xf004059, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.90 */ { "xfs.btree.alloc_blocks.split", { 0xf00405a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.91 */ { "xfs.btree.alloc_blocks.join", { 0xf00405b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.92 */ { "xfs.btree.alloc_blocks.alloc", { 0xf00405c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.93 */ { "xfs.btree.alloc_blocks.free", { 0xf00405d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.94 */ { "xfs.btree.alloc_blocks.moves", { 0xf00405e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.95 */ { "xfs.btree.alloc_contig.lookup", { 0xf00405f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.96 */ { "xfs.btree.alloc_contig.compare", { 0xf004060, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.97 */ { "xfs.btree.alloc_contig.insrec", { 0xf004061, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.98 */ { "xfs.btree.alloc_contig.delrec", { 0xf004062, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.99 */ { "xfs.btree.alloc_contig.newroot", { 0xf004063, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.100 */ { "xfs.btree.alloc_contig.killroot", { 0xf004064, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.101 */ { "xfs.btree.alloc_contig.increment", { 0xf004065, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.102 */ { "xfs.btree.alloc_contig.decrement", { 0xf004066, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.103 */ { "xfs.btree.alloc_contig.lshift", { 0xf004067, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.104 */ { "xfs.btree.alloc_contig.rshift", { 0xf004068, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.105 */ { "xfs.btree.alloc_contig.split", { 0xf004069, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.106 */ { "xfs.btree.alloc_contig.join", { 0xf00406a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.107 */ { "xfs.btree.alloc_contig.alloc", { 0xf00406b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.108 */ { "xfs.btree.alloc_contig.free", { 0xf00406c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.109 */ { "xfs.btree.alloc_contig.moves", { 0xf00406d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.110 */ { "xfs.btree.block_map.lookup", { 0xf00406e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.111 */ { "xfs.btree.block_map.compare", { 0xf00406f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.112 */ { "xfs.btree.block_map.insrec", { 0xf004070, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.113 */ { "xfs.btree.block_map.delrec", { 0xf004071, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.114 */ { "xfs.btree.block_map.newroot", { 0xf004072, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.115 */ { "xfs.btree.block_map.killroot", { 0xf004073, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.116 */ { "xfs.btree.block_map.increment", { 0xf004074, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.117 */ { "xfs.btree.block_map.decrement", { 0xf004075, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.118 */ { "xfs.btree.block_map.lshift", { 0xf004076, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.119 */ { "xfs.btree.block_map.rshift", { 0xf004077, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.120 */ { "xfs.btree.block_map.split", { 0xf004078, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.121 */ { "xfs.btree.block_map.join", { 0xf004079, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.122 */ { "xfs.btree.block_map.alloc", { 0xf00407a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.123 */ { "xfs.btree.block_map.free", { 0xf00407b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.124 */ { "xfs.btree.block_map.moves", { 0xf00407c, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.125 */ { "xfs.btree.inode.lookup", { 0xf00407d, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.126 */ { "xfs.btree.inode.compare", { 0xf00407e, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.127 */ { "xfs.btree.inode.insrec", { 0xf00407f, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.128 */ { "xfs.btree.inode.delrec", { 0xf004080, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.129 */ { "xfs.btree.inode.newroot", { 0xf004081, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.130 */ { "xfs.btree.inode.killroot", { 0xf004082, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.131 */ { "xfs.btree.inode.increment", { 0xf004083, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.132 */ { "xfs.btree.inode.decrement", { 0xf004084, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.133 */ { "xfs.btree.inode.lshift", { 0xf004085, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.134 */ { "xfs.btree.inode.rshift", { 0xf004086, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.135 */ { "xfs.btree.inode.split", { 0xf004087, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.136 */ { "xfs.btree.inode.join", { 0xf004088, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.137 */ { "xfs.btree.inode.alloc", { 0xf004089, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.138 */ { "xfs.btree.inode.free", { 0xf00408a, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.16.139 */ { "xfs.btree.inode.moves", { 0xf00408b, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.12.5 */ { "pmda.uname", { 0xf003005, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.12.6 */ { "pmda.version", { 0xf003006, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.21.0 */ { "ipc.sem.max_semmap", { 0xf005400, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.21.1 */ { "ipc.sem.max_semid", { 0xf005401, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.21.2 */ { "ipc.sem.max_sem", { 0xf005402, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.21.3 */ { "ipc.sem.num_undo", { 0xf005403, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.21.4 */ { "ipc.sem.max_perid", { 0xf005404, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.21.5 */ { "ipc.sem.max_ops", { 0xf005405, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.21.6 */ { "ipc.sem.max_undoent", { 0xf005406, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.21.7 */ { "ipc.sem.sz_semundo", { 0xf005407, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.21.8 */ { "ipc.sem.max_semval", { 0xf005408, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.21.9 */ { "ipc.sem.max_exit", { 0xf005409, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.22.0 */ { "ipc.msg.sz_pool", { 0xf005800, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.22.1 */ { "ipc.msg.mapent", { 0xf005801, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.22.2 */ { "ipc.msg.max_msgsz", { 0xf005802, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.22.3 */ { "ipc.msg.max_defmsgq", { 0xf005803, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.22.4 */ { "ipc.msg.max_msgqid", { 0xf005804, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.22.5 */ { "ipc.msg.max_msgseg", { 0xf005805, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.22.6 */ { "ipc.msg.num_smsghdr", { 0xf005806, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.22.7 */ { "ipc.msg.max_seg", { 0xf005807, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.23.0 */ { "ipc.shm.max_segsz", { 0xf005c00, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.23.1 */ { "ipc.shm.min_segsz", { 0xf005c01, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.23.2 */ { "ipc.shm.max_seg", { 0xf005c02, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.23.3 */ { "ipc.shm.max_segproc", { 0xf005c03, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.23.4 */ { "ipc.shm.max_shmsys", { 0xf005c04, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.27.0 */ { "vfs.files.count", { 0xf006c00, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.27.1 */ { "vfs.files.free", { 0xf006c01, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.27.2 */ { "vfs.files.max", { 0xf006c02, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.27.3 */ { "vfs.inodes.count", { 0xf006c03, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.27.4 */ { "vfs.inodes.free", { 0xf006c04, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.27.5 */ { "vfs.dentry.count", { 0xf006c05, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.27.6 */ { "vfs.dentry.free", { 0xf006c06, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.30.0 */ { "quota.state.project.accounting", { 0xf007800, PM_TYPE_U32, 0xf000005, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.30.1 */ { "quota.state.project.enforcement", { 0xf007801, PM_TYPE_U32, 0xf000005, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.30.6 */ { "quota.project.space.hard", { 0xf007806, PM_TYPE_U64, 0xf000010, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.30.7 */ { "quota.project.space.soft", { 0xf007807, PM_TYPE_U64, 0xf000010, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.30.8 */ { "quota.project.space.used", { 0xf007808, PM_TYPE_U64, 0xf000010, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.30.9 */ { "quota.project.space.time_left", { 0xf007809, PM_TYPE_32, 0xf000010, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=3, .scaleCount=0 } } }, /* 60.30.10 */ { "quota.project.files.hard", { 0xf00780a, PM_TYPE_U64, 0xf000010, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.30.11 */ { "quota.project.files.soft", { 0xf00780b, PM_TYPE_U64, 0xf000010, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.30.12 */ { "quota.project.files.used", { 0xf00780c, PM_TYPE_U64, 0xf000010, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.30.13 */ { "quota.project.files.time_left", { 0xf00780d, PM_TYPE_32, 0xf000010, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=3, .scaleCount=0 } } }, /* 60.34.1 */ { "tmpfs.capacity", { 0xf008801, PM_TYPE_U64, 0xf000012, PM_SEM_DISCRETE, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.34.2 */ { "tmpfs.used", { 0xf008802, PM_TYPE_U64, 0xf000012, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.34.3 */ { "tmpfs.free", { 0xf008803, PM_TYPE_U64, 0xf000012, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 60.34.4 */ { "tmpfs.maxfiles", { 0xf008804, PM_TYPE_U32, 0xf000012, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.34.5 */ { "tmpfs.usedfiles", { 0xf008805, PM_TYPE_U32, 0xf000012, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.34.6 */ { "tmpfs.freefiles", { 0xf008806, PM_TYPE_U32, 0xf000012, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.34.7 */ { "tmpfs.full", { 0xf008807, PM_TYPE_DOUBLE, 0xf000012, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 60.35.0 */ { "sysfs.kernel.uevent_seqnum", { 0xf008c00, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.99 */ { "proc.nprocs", { 0xc02063, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.0 */ { "proc.psinfo.pid", { 0xc02000, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.1 */ { "proc.psinfo.cmd", { 0xc02001, PM_TYPE_STRING, 0xc00009, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.2 */ { "proc.psinfo.sname", { 0xc02002, PM_TYPE_STRING, 0xc00009, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.3 */ { "proc.psinfo.ppid", { 0xc02003, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.4 */ { "proc.psinfo.pgrp", { 0xc02004, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.5 */ { "proc.psinfo.session", { 0xc02005, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.6 */ { "proc.psinfo.tty", { 0xc02006, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.7 */ { "proc.psinfo.tty_pgrp", { 0xc02007, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.8 */ { "proc.psinfo.flags", { 0xc02008, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.9 */ { "proc.psinfo.minflt", { 0xc02009, PM_TYPE_U32, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.10 */ { "proc.psinfo.cmin_flt", { 0xc0200a, PM_TYPE_U32, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.11 */ { "proc.psinfo.maj_flt", { 0xc0200b, PM_TYPE_U32, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.12 */ { "proc.psinfo.cmaj_flt", { 0xc0200c, PM_TYPE_U32, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.13 */ { "proc.psinfo.utime", { 0xc0200d, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 3.8.14 */ { "proc.psinfo.stime", { 0xc0200e, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 3.8.15 */ { "proc.psinfo.cutime", { 0xc0200f, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 3.8.16 */ { "proc.psinfo.cstime", { 0xc02010, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=2, .scaleCount=0 } } }, /* 3.8.17 */ { "proc.psinfo.priority", { 0xc02011, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.18 */ { "proc.psinfo.nice", { 0xc02012, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.20 */ { "proc.psinfo.it_real_value", { 0xc02014, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.21 */ { "proc.psinfo.start_time", { 0xc02015, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=3, .scaleCount=0 } } }, /* 3.8.22 */ { "proc.psinfo.vsize", { 0xc02016, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.23 */ { "proc.psinfo.rss", { 0xc02017, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.24 */ { "proc.psinfo.rss_rlim", { 0xc02018, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.25 */ { "proc.psinfo.start_code", { 0xc02019, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.26 */ { "proc.psinfo.end_code", { 0xc0201a, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.27 */ { "proc.psinfo.start_stack", { 0xc0201b, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.28 */ { "proc.psinfo.esp", { 0xc0201c, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.29 */ { "proc.psinfo.eip", { 0xc0201d, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.30 */ { "proc.psinfo.signal", { 0xc0201e, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.31 */ { "proc.psinfo.blocked", { 0xc0201f, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.32 */ { "proc.psinfo.sigignore", { 0xc02020, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.33 */ { "proc.psinfo.sigcatch", { 0xc02021, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.34 */ { "proc.psinfo.wchan", { 0xc02022, PM_TYPE_U64, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.35 */ { "proc.psinfo.nswap", { 0xc02023, PM_TYPE_U32, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.36 */ { "proc.psinfo.cnswap", { 0xc02024, PM_TYPE_U32, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.37 */ { "proc.psinfo.exit_signal", { 0xc02025, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.38 */ { "proc.psinfo.processor", { 0xc02026, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.39 */ { "proc.psinfo.ttyname", { 0xc02027, PM_TYPE_STRING, 0xc00009, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.40 */ { "proc.psinfo.wchan_s", { 0xc02028, PM_TYPE_STRING, 0xc00009, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.8.41 */ { "proc.psinfo.psargs", { 0xc02029, PM_TYPE_STRING, 0xc00009, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.16 */ { "proc.psinfo.signal_s", { 0xc06010, PM_TYPE_STRING, 0xc00009, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.17 */ { "proc.psinfo.blocked_s", { 0xc06011, PM_TYPE_STRING, 0xc00009, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.18 */ { "proc.psinfo.sigignore_s", { 0xc06012, PM_TYPE_STRING, 0xc00009, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.19 */ { "proc.psinfo.sigcatch_s", { 0xc06013, PM_TYPE_STRING, 0xc00009, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.9.0 */ { "proc.memory.size", { 0xc02400, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.9.1 */ { "proc.memory.rss", { 0xc02401, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.9.2 */ { "proc.memory.share", { 0xc02402, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.9.3 */ { "proc.memory.textrss", { 0xc02403, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.9.4 */ { "proc.memory.librss", { 0xc02404, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.9.5 */ { "proc.memory.datrss", { 0xc02405, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.9.6 */ { "proc.memory.dirty", { 0xc02406, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.9.7 */ { "proc.memory.maps", { 0xc02407, PM_TYPE_STRING, 0xc00009, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.20 */ { "proc.memory.vmsize", { 0xc06014, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.21 */ { "proc.memory.vmlock", { 0xc06015, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.22 */ { "proc.memory.vmrss", { 0xc06016, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.23 */ { "proc.memory.vmdata", { 0xc06017, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.24 */ { "proc.memory.vmstack", { 0xc06018, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.25 */ { "proc.memory.vmexe", { 0xc06019, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.26 */ { "proc.memory.vmlib", { 0xc0601a, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=1, .scaleTime=0, .scaleCount=0 } } }, /* 3.13.0 */ { "proc.runq.runnable", { 0xc03400, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.13.1 */ { "proc.runq.blocked", { 0xc03401, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.13.2 */ { "proc.runq.sleeping", { 0xc03402, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.13.3 */ { "proc.runq.stopped", { 0xc03403, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.13.4 */ { "proc.runq.swapped", { 0xc03404, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.13.5 */ { "proc.runq.defunct", { 0xc03405, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.13.6 */ { "proc.runq.unknown", { 0xc03406, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.13.7 */ { "proc.runq.kernel", { 0xc03407, PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.0 */ { "proc.id.uid", { 0xc06000, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.1 */ { "proc.id.euid", { 0xc06001, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.2 */ { "proc.id.suid", { 0xc06002, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.3 */ { "proc.id.fsuid", { 0xc06003, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.4 */ { "proc.id.gid", { 0xc06004, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.5 */ { "proc.id.egid", { 0xc06005, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.6 */ { "proc.id.sgid", { 0xc06006, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.7 */ { "proc.id.fsgid", { 0xc06007, PM_TYPE_U32, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.8 */ { "proc.id.uid_nm", { 0xc06008, PM_TYPE_STRING, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.9 */ { "proc.id.euid_nm", { 0xc06009, PM_TYPE_STRING, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.10 */ { "proc.id.suid_nm", { 0xc0600a, PM_TYPE_STRING, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.11 */ { "proc.id.fsuid_nm", { 0xc0600b, PM_TYPE_STRING, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.12 */ { "proc.id.gid_nm", { 0xc0600c, PM_TYPE_STRING, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.13 */ { "proc.id.egid_nm", { 0xc0600d, PM_TYPE_STRING, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.14 */ { "proc.id.sgid_nm", { 0xc0600e, PM_TYPE_STRING, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.24.15 */ { "proc.id.fsgid_nm", { 0xc0600f, PM_TYPE_STRING, 0xc00009, PM_SEM_DISCRETE, { .dimSpace=0, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.32.0 */ { "proc.io.rchar", { 0xc08000, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.32.1 */ { "proc.io.wchar", { 0xc08001, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.32.2 */ { "proc.io.syscr", { 0xc08002, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.32.3 */ { "proc.io.syscw", { 0xc08003, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.32.4 */ { "proc.io.read_bytes", { 0xc08004, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.32.5 */ { "proc.io.write_bytes", { 0xc08005, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.32.6 */ { "proc.io.cancelled_write_bytes", { 0xc08006, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=1, .dimTime=0, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.31.0 */ { "proc.schedstat.cpu_time", { 0xc07c00, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.31.1 */ { "proc.schedstat.run_delay", { 0xc07c01, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=1, .dimCount=0, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.31.2 */ { "proc.schedstat.pcount", { 0xc07c02, PM_TYPE_U64, 0xc00009, PM_SEM_COUNTER, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, /* 3.51.0 */ { "proc.fd.count", { 0xc0cc00, PM_TYPE_U32, 0xc00009, PM_SEM_INSTANT, { .dimSpace=0, .dimTime=0, .dimCount=1, .scaleSpace=0, .scaleTime=0, .scaleCount=0 } } }, { NULL } }; pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/pmdesc.c0000664000000000000000000000454112272262501017251 0ustar /* * Copyright (c) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * * Lookup up the metrics named on stdin and generate pmDesc descriptors. * Mark Goodwin May 2013. */ #include #include #include static char *semStr[] = { "0", "PM_SEM_COUNTER", "2", "PM_SEM_INSTANT", "PM_SEM_DISCRETE" }; static char * indomStr(int indom) { static char buf[16]; if (indom == PM_INDOM_NULL) strcpy(buf, "PM_INDOM_NULL"); else sprintf(buf, "0x%04x", indom); return buf; } int main(int argc, char *argv[]) { int ctx; int sts; char buf[1024]; char *name = buf; char *p; pmID pmid; pmDesc desc; ctx = pmNewContext(PM_CONTEXT_HOST, "local:"); if (ctx < 0) { fprintf(stderr, "Error: pmNewContext %s\n", pmErrStr(ctx)); exit(1); } printf("/* This file is automatically generated .. do not edit! */\n"); printf("#include \"metrics.h\"\n\n"); printf("metric_t metrics[] = {\n"); while (fgets(buf, sizeof(buf), stdin)) { if ((p = strrchr(buf, '\n')) != NULL) *p = '\0'; if ((sts = pmLookupName(1, &name, &pmid)) < 0) { fprintf(stderr, "Error: pmLookupName \"%s\": %s\n", name, pmErrStr(sts)); exit(1); } if ((sts = pmLookupDesc(pmid, &desc)) < 0) { fprintf(stderr, "Error: pmLookupDesc \"%s\": %s\n", name, pmErrStr(sts)); exit(1); } printf(" /* %-8s */ { \"%s\", { 0x%04x, PM_TYPE_%s, %s, %s,\n" " { .dimSpace=%d, .dimTime=%d, .dimCount=%d, " ".scaleSpace=%d, .scaleTime=%d, .scaleCount=%d } } },\n", pmIDStr(desc.pmid), name, desc.pmid, pmTypeStr(desc.type), indomStr(desc.indom), semStr[desc.sem], desc.units.dimSpace, desc.units.dimTime, desc.units.dimCount, desc.units.scaleSpace, desc.units.scaleTime, desc.units.scaleCount); } printf(" { NULL }\n};\n"); exit(0); } pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/header.c0000664000000000000000000001111112272262501017215 0ustar /* * Copyright (c) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Parse collectl header up to (and including) the first timestamp. */ #include "metrics.h" static char *hostname = NULL; int header_time = 0; int header_handler(FILE *fp, char *fname, char *buf, int maxbuf) { int i; char *s; fields_t *f; int sts = 0; while(fgets(buf, maxbuf, fp)) { if ((s = strrchr(buf, '\n')) != NULL) *s = '\0'; if (!buf[0]) continue; f = fields_new(buf, strlen(buf)+1); if (f->nfields == 0) { fields_free(f); continue; } if (strncmp(f->fields[0], ">>>", 3) == 0) { /* first timestamp: we're finished parsing the header */ sts = timestamp_handler(find_handler(">>>"), f); fields_free(f); break; } if (f->nfields > 3 && strncmp(f->fields[1], "Host:", 5) == 0) { /* # Host: somehostname ... */ if (hostname && strcmp(hostname, f->fields[2]) != 0) { fprintf(stderr, "FATAL Error: host mismatch: \"%s\" contains data for host \"%s\", not \"%s\"\n", fname, f->fields[2], hostname); exit(1); } if (!hostname) { hostname = strdup(f->fields[2]); pmiSetHostname(hostname); put_str_value("kernel.uname.nodename", PM_INDOM_NULL, NULL, hostname); put_str_value("kernel.uname.sysname", PM_INDOM_NULL, NULL, "Linux"); } } if (f->nfields > 2 && strncmp(f->fields[1], "Distro:", 7) == 0) { strcpy(buf, f->fields[2]); for (i=3; i < f->nfields; i++) { if (strcmp(f->fields[i], "Platform:") == 0) break; strcat(buf, " "); strcat(buf, f->fields[i]); } put_str_value("kernel.uname.distro", PM_INDOM_NULL, NULL, buf); #if 0 /* TODO -- add hinv.platform */ if (i < f->nfields) { /* found embedded platform */ strcpy(buf, f->fields[++i]); for (; i < f->nfields; i++) { strcat(buf, " "); strcat(buf, f->fields[i]); } put_str_value("hinv.platform", PM_INDOM_NULL, NULL, buf); } #endif } if (f->nfields == 7 && strncmp(f->fields[1], "Date:", 5) == 0) { /* # Date: 20130505-170328 Secs: 1367791408 TZ: -0500 */ int d = strtol(f->fields[4], NULL, 0); if (d < header_time) { fprintf(stderr, "FATAL Error: input file order mismatch: \"%s\" contains data at %d, prior to %d\n", fname, d, header_time); exit(1); } header_time = d; sts = pmiSetTimezone(f->fields[6]); utc_offset = strtol(f->fields[6], NULL, 0); sscanf(f->fields[6], "%d", &utc_offset); /* e.g. -0500 */ utc_offset /= 100; if (vflag) printf("Timezone set to \"%s\" utc_offset=%d hours, sts=%d\n", f->fields[6], utc_offset, sts); } if (f->nfields > 8 && strncmp(f->fields[1], "SubSys:", 7) == 0) { /* # SubSys: bcdfijmnstYZ Options: Interval: 10:60 NumCPUs: 24 NumBud: 3 Flags: i */ put_str_value("hinv.ncpu", PM_INDOM_NULL, NULL, f->fields[7]); } if (f->nfields == 7 && strncmp(f->fields[1], "HZ:", 3) == 0) { /* # HZ: 100 Arch: x86_64-linux-thread-multi PageSize: 4096 */ kernel_all_hz = strtol(f->fields[2], NULL, 0); put_str_value("kernel.all.hz", PM_INDOM_NULL, NULL, f->fields[2]); put_str_value("kernel.uname.machine", PM_INDOM_NULL, NULL, f->fields[4]); put_str_value("hinv.pagesize", PM_INDOM_NULL, NULL, f->fields[6]); } if (f->nfields == 9 && strncmp(f->fields[1], "Kernel:", 7) == 0) { /* # Kernel: 2.6.18-274.17.1.el5 Memory: 131965176 kB Swap: 134215000 kB */ put_str_value("kernel.uname.release", PM_INDOM_NULL, NULL, f->fields[2]); put_int_value("hinv.physmem", PM_INDOM_NULL, NULL, atoi(f->fields[4])/1024); put_str_value("hinv.machine", PM_INDOM_NULL, NULL, "linux"); } if (f->nfields > 4 && strncmp(f->fields[1], "NumDisks:", 9) == 0) { /* # NumDisks: 846 DiskNames: sda sdb .... */ put_str_value("hinv.ndisk", PM_INDOM_NULL, NULL, f->fields[2]); } if (f->nfields > 4 && strncmp(f->fields[1], "NumNets:", 8) == 0) { /* # NumNets: 5 NetNames: em1: lo: ... */ put_str_value("hinv.ninterface", PM_INDOM_NULL, NULL, f->fields[2]); } fields_free(f); } if (vflag) printf("Parsed header in file:\"%s\" host:\"%s\" sts=%d\n", fname, hostname, sts); return sts; } pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/timestamp.c0000664000000000000000000000276312272262501020005 0ustar /* * Copyright (c) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Handler for timestamps * >>> 1368076410.001 <<< */ #include "metrics.h" static int seconds = 0, mseconds = 0; int timestamp_flush(void) { int sts; int err = 0; /* * timstamps in collectl logs are seconds.mseconds since the epoch in utc * Since we've set pmiSetTimezone to what was found in the header, we need * to offset it here so the PCP archive matches the host timezone. */ if (seconds && (sts = pmiWrite(seconds + utc_offset * 60 * 60, mseconds*1000)) < 0) { if (sts != PMI_ERR_NODATA) { fprintf(stderr, "Error: pmiWrite failed: error %d: %s\n", sts, pmiErrStr(sts)); err = sts; /* probably fatal */ } } return err; } int timestamp_handler(handler_t *h, fields_t *f) { int sts; int err = 0; /* >>> 1368076390.001 <<< */ if (f->nfields != 3) return -1; if ((sts = timestamp_flush()) < 0) err = sts; sscanf(f->fields[1], "%d.%d", &seconds, &mseconds); return err; } pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/net.c0000664000000000000000000000533712272262501016570 0ustar /* * Copyright (c) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Handler for network.interface.* * Net lo: 216173634 2124262 0 0 0 0 0 0 216173634 2124262 0 0 0 0 0 0 */ #include "metrics.h" int net_handler(handler_t *h, fields_t *f) { int n; char *s; char *inst; pmInDom indom = pmInDom_build(LINUX_DOMAIN, NET_DEV_INDOM); /* Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed lo: 4060748 39057 0 0 0 0 0 0 4060748 39057 0 0 0 0 0 0 eth0: 0 337614 0 0 0 0 0 0 0 267537 0 0 0 27346 62 0 */ if (f->nfields != 18) return -1; inst = f->fields[1]; if ((s = strchr(inst, ':')) != NULL) *s = '\0'; n = 2; put_str_value("network.interface.in.bytes", indom, inst, f->fields[n++]); put_str_value("network.interface.in.packets", indom, inst, f->fields[n++]); put_str_value("network.interface.in.errors", indom, inst, f->fields[n++]); put_str_value("network.interface.in.drops", indom, inst, f->fields[n++]); put_str_value("network.interface.in.fifo", indom, inst, f->fields[n++]); put_str_value("network.interface.in.frame", indom, inst, f->fields[n++]); put_str_value("network.interface.in.compressed", indom, inst, f->fields[n++]); put_str_value("network.interface.in.mcasts", indom, inst, f->fields[n++]); put_str_value("network.interface.out.bytes", indom, inst, f->fields[n++]); put_str_value("network.interface.out.packets", indom, inst, f->fields[n++]); put_str_value("network.interface.out.errors", indom, inst, f->fields[n++]); put_str_value("network.interface.out.drops", indom, inst, f->fields[n++]); put_str_value("network.interface.out.fifo", indom, inst, f->fields[n++]); put_str_value("network.interface.collisions", indom, inst, f->fields[n++]); put_str_value("network.interface.out.carrier", indom, inst, f->fields[n++]); put_str_value("network.interface.out.compressed", indom, inst, f->fields[n++]); return 0; } pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/GNUmakefile0000664000000000000000000000253512272262501017705 0ustar # Copyright (c) 2013 Red Hat Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs HFILES = metrics.h CFILES = collectl2pcp.c cpu.c disk.c net.c load.c timestamp.c util.c \ metrics.c header.c generic.c proc.c LSRCFILES = pmdesc.c CMDTARGET = collectl2pcp LLDLIBS = -L$(TOPDIR)/src/libpcp_import/src -lpcp_import $(PCPLIB) # LCFLAGS += -pg # # metrics.c is generated (but committed for now) # LDIRT = metrics.c LDIRT = pmdesc pmdesc.o default: pmdesc $(CMDTARGET) include $(BUILDRULES) install: $(CMDTARGET) $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) # metrics.c: pmdesc # $(RUN_IN_BUILD_ENV) pminfo hinv kernel mem swap network disk filesys \ # swapdev rpc nfs nfs3 nfs4 xfs pmda ipc vfs quota tmpfs sysfs proc \ # | ./pmdesc > metrics.c pmdesc: pmdesc.o default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/collectl2pcp.c0000664000000000000000000002011512272262501020357 0ustar /* * Copyright (c) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Import collectl raw data file and create a PCP archive. * Mark Goodwin May 2013. */ #include #include #include #include #include "metrics.h" #define BUFSIZE 1048576 handler_t handlers[] = { { ">>>", timestamp_handler }, /* /proc/PID/... */ { "proc:*", proc_handler }, /* /proc/stat */ { "cpu*", cpu_handler }, { "processes", generic1_handler, "kernel.all.nprocs" }, { "intr", generic1_handler, "kernel.all.intr" }, { "ctxt", generic1_handler, "kernel.all.pswitch" }, /* /proc/diskstats */ { "disk", disk_handler }, /* /proc/net/dev */ { "Net", net_handler }, /* /proc/loadavg */ { "load", loadavg_handler }, /* /proc/meminfo */ { "MemTotal:", generic1_handler, "mem.physmem" }, { "MemFree:", generic1_handler, "mem.util.free" }, { "Buffers:", generic1_handler, "mem.util.bufmem" }, { "Cached:", generic1_handler, "mem.util.cached" }, { "SwapCached:", generic1_handler, "mem.util.swapCached" }, { "Active:", generic1_handler, "mem.util.active" }, { "Inactive:", generic1_handler, "mem.util.inactive" }, { "Active(anon):", generic1_handler, "mem.util.active_anon" }, { "Inactive(anon):", generic1_handler, "mem.util.inactive_anon" }, { "Active(file):", generic1_handler, "mem.util.active_file" }, { "Inactive(file):", generic1_handler, "mem.util.inactive_file" }, { "Unevictable:", generic1_handler, "mem.util.unevictable" }, { "Mlocked:", generic1_handler, "mem.util.mlocked" }, { "SwapTotal:", generic1_handler, "mem.util.swapTotal" }, { "SwapFree:", generic1_handler, "mem.util.swapFree" }, { "Dirty:", generic1_handler, "mem.util.dirty" }, { "Writeback:", generic1_handler, "mem.util.writeback" }, { "AnonPages:", generic1_handler, "mem.util.anonpages" }, { "Mapped:", generic1_handler, "mem.util.mapped" }, { "Shmem:", generic1_handler, "mem.util.shmem" }, { "Slab:", generic1_handler, "mem.util.slab" }, { "SReclaimable:", generic1_handler, "mem.util.slabReclaimable" }, { "SUnreclaim:", generic1_handler, "mem.util.slabUnreclaimable" }, { "KernelStack:", generic1_handler, "mem.util.kernelStack" }, { "PageTables:", generic1_handler, "mem.util.pageTables" }, { "NFS_Unstable:", generic1_handler, "mem.util.NFS_Unstable" }, { "Bounce:", generic1_handler, "mem.util.bounce" }, { "WritebackTmp:", generic1_handler, "unknown" }, { "CommitLimit:", generic1_handler, "mem.util.commitLimit" }, { "Committed_AS:", generic1_handler, "mem.util.committed_AS" }, { "VmallocTotal:", generic1_handler, "mem.util.vmallocTotal" }, { "VmallocUsed:", generic1_handler, "mem.util.vmallocUsed" }, { "VmallocChunk:", generic1_handler, "mem.util.vmallocChunk" }, { "HardwareCorrupted:", generic1_handler, "mem.util.corrupthardware" }, { "AnonHugePages:", generic1_handler, "mem.util.anonhugepages" }, { "HugePages_Total:", generic1_handler, "mem.util.hugepagesTotal" }, { "HugePages_Free:", generic1_handler, "mem.util.hugepagesFree" }, { "HugePages_Rsvd:", generic1_handler, "mem.util.hugepagesRsvd" }, { "HugePages_Surp:", generic1_handler, "mem.util.hugepagesSurp" }, { "Hugepagesize:", generic1_handler, "unknown" }, { "DirectMap4k:", generic1_handler, "mem.util.directMap4k" }, { "DirectMap2M:", generic1_handler, "mem.util.directMap2M" }, { NULL } }; int indom_cnt[NUM_INDOMS]; /* global options */ int vflag; int Fflag; int kernel_all_hz; int utc_offset; static void usage(void) { fprintf(stderr, "Usage: %s [-F] [-v] [-D N] inputfile [inputfile ...] archive\n" "Each 'inputfile' is a collectl archive, must be for the same host (may be gzipped).\n" "'archive' is the base name for the PCP archive to be created.\n" "\n" "Options:\n" " -F forces overwrite of 'archive' if it already exists.\n" " -v enables verbose messages. Use more -v for extra verbosity.\n" " -D N switch on debugging bits 'N', see pmdbg(1).\n", pmProgname); exit(1); } int main(int argc, char *argv[]) { int sts; int ctx; int errflag = 0; int c; char *infile; int nfilelist; int filenum; char *archive = NULL; int j; char *buf; fields_t *f; char *s; int gzipped; FILE *fp; metric_t *m; handler_t *h; int unhandled_metric_cnt = 0; __pmSetProgname(argv[0]); while ((c = getopt(argc, argv, "FD:v")) != EOF) { switch (c) { case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case 'F': Fflag = 1; break; case 'v': vflag++; break; case '?': default: errflag++; break; } } nfilelist = argc - optind - 1; if (nfilelist < 1) errflag++; else archive = argv[argc-1]; if (errflag) usage(); if ((buf = malloc(BUFSIZE)) == NULL) { perror("Error: out of memory:"); exit(1); } if (Fflag) { snprintf(buf, BUFSIZE, "%s.meta", archive); unlink(buf); snprintf(buf, BUFSIZE, "%s.index", archive); unlink(buf); for (j=0;; j++) { snprintf(buf, BUFSIZE, "%s.%d", archive, j); if (unlink(buf) < 0) break; } } ctx = pmiStart(archive, 0); if ((sts = pmiUseContext(ctx)) < 0) { fprintf(stderr, "Error: pmiUseContext failed: %s\n", pmiErrStr(sts)); exit(1); } /* * Define the metrics name space, see metrics.c (generated by pmdesc) */ for (m = metrics; m->name; m++) { pmDesc *d = &m->desc; sts = pmiAddMetric(m->name, d->pmid, d->type, d->indom, d->sem, d->units); if (sts < 0) { fprintf(stderr, "Error: failed to add metric %s: %s\n", m->name, pmiErrStr(sts)); exit(1); } } /* * Populate special case instance domains */ pmiAddInstance(pmInDom_build(LINUX_DOMAIN, LOADAVG_INDOM), "1 minute", 1); pmiAddInstance(pmInDom_build(LINUX_DOMAIN, LOADAVG_INDOM), "5 minute", 5); pmiAddInstance(pmInDom_build(LINUX_DOMAIN, LOADAVG_INDOM), "15 minute", 15); indom_cnt[LOADAVG_INDOM] = 3; for (filenum=0; filenum < nfilelist; filenum++) { infile = argv[optind + filenum]; gzipped = strstr(infile, ".gz") != NULL; if (gzipped) { snprintf(buf, BUFSIZE, "gzip -c -d %s", infile); if ((fp = popen(buf, "r")) == NULL) perror(buf); } else if ((fp = fopen(infile, "r")) == NULL) perror(infile); if (fp == NULL) usage(); /* * parse the header */ sts = header_handler(fp, infile, buf, BUFSIZE); /* * Parse remaining data stream for this input file */ while(fgets(buf, BUFSIZE, fp)) { if ((s = strrchr(buf, '\n')) != NULL) *s = '\0'; if (!buf[0]) continue; f = fields_new(buf, strlen(buf)+1); if (f->nfields > 0) { if ((h = find_handler(f->fields[0])) == NULL) { unhandled_metric_cnt++; if (vflag > 1) printf("Unhandled tag: \"%s\"\n", f->fields[0]); } else { sts = h->handler(h, f); if (sts < 0 && h->handler == timestamp_handler) { fprintf(stderr, "Error: %s\n", pmiErrStr(sts)); exit(1); } } } fields_free(f); } /* final flush for this file */ if ((sts = timestamp_flush()) < 0) { fprintf(stderr, "Error: failed to write final timestamp: %s\n", pmiErrStr(sts)); exit(1); } if (gzipped) pclose(fp); else fclose(fp); } sts = pmiEnd(); if (unhandled_metric_cnt && vflag) fprintf(stderr, "Warning: %d unhandled metric/values\n", unhandled_metric_cnt); exit(0); } pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/proc.c0000664000000000000000000001411312272262501016735 0ustar /* * Copyright (c) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Handler for per-process metrics * * proc:28896 stat 28896 (bash) S 3574 28896 28896 34844 28896 4202496 2286 23473 1 21 4 2 486 129 20 0 1 0 125421198 119214080 85 18446744073709551615 4194304 5080360 140737040162832 140737040157848 212270400064 0 0 3686404 1266761467 18446744071582594345 0 0 17 2 0 0 0 0 0 9310744 9344396 14004224 * */ #include "metrics.h" #define ticks_to_msec(ticks) (1000ULL * strtoull(ticks, NULL, 0) / kernel_all_hz) /* /proc/PID/stat fields (starting at fields[2]) */ #define PROC_PID_STAT_PID 0 #define PROC_PID_STAT_CMD 1 #define PROC_PID_STAT_STATE 2 #define PROC_PID_STAT_PPID 3 #define PROC_PID_STAT_PGRP 4 #define PROC_PID_STAT_SESSION 5 #define PROC_PID_STAT_TTY 6 #define PROC_PID_STAT_TTY_PGRP 7 #define PROC_PID_STAT_FLAGS 8 #define PROC_PID_STAT_MINFLT 9 #define PROC_PID_STAT_CMIN_FLT 10 #define PROC_PID_STAT_MAJ_FLT 11 #define PROC_PID_STAT_CMAJ_FLT 12 #define PROC_PID_STAT_UTIME 13 #define PROC_PID_STAT_STIME 14 #define PROC_PID_STAT_CUTIME 15 #define PROC_PID_STAT_CSTIME 16 #define PROC_PID_STAT_PRIORITY 17 #define PROC_PID_STAT_NICE 18 #define PROC_PID_STAT_REMOVED 19 #define PROC_PID_STAT_IT_REAL_VALUE 20 #define PROC_PID_STAT_START_TIME 21 #define PROC_PID_STAT_VSIZE 22 #define PROC_PID_STAT_RSS 23 #define PROC_PID_STAT_RSS_RLIM 24 #define PROC_PID_STAT_START_CODE 25 #define PROC_PID_STAT_END_CODE 26 #define PROC_PID_STAT_START_STACK 27 #define PROC_PID_STAT_ESP 28 #define PROC_PID_STAT_EIP 29 #define PROC_PID_STAT_SIGNAL 30 #define PROC_PID_STAT_BLOCKED 31 #define PROC_PID_STAT_SIGIGNORE 32 #define PROC_PID_STAT_SIGCATCH 33 #define PROC_PID_STAT_WCHAN 34 #define PROC_PID_STAT_NSWAP 35 #define PROC_PID_STAT_CNSWAP 36 #define PROC_PID_STAT_EXIT_SIGNAL 37 #define PROC_PID_STAT_PROCESSOR 38 #define PROC_PID_STAT_TTYNAME 39 #define PROC_PID_STAT_WCHAN_SYMBOL 40 #define PROC_PID_STAT_PSARGS 41 static char *inst; static fields_t *proc_stat; static int find_command_start(const char *buf, size_t len) { int i; /* skip over (minimal) leading "proc:N cmd " */ for (i = 7; i < len - 4; i++) if (strncmp(&buf[i], "cmd", 4) == 0) return i + 4; return -1; /* wha? cannot find the "cmd" component */ } static void inst_command_clean(char *command, size_t size) { int i; /* command contains nulls - replace 'em */ for (i = 0; i < size; i++) { if (!isprint(command[i])) command[i] = ' '; } /* and trailing whitespace - clean that */ while (--size) { if (isspace(command[size])) command[size] = '\0'; else break; } } void base_command_name(const char *command, char *base, size_t size) { char *p, *start, *end; int kernel = (command[0] == '('); /* kernel daemons heuristic */ /* moral equivalent of basename, dealing with args stripping too */ for (p = end = start = (char *)command; *p; end = ++p) { if (kernel) continue; else if (*p == '/') start = end = p+1; else if (isspace(*p)) break; } size--; /* allow for a null */ if (size > (end - start)) size = (end - start); memcpy(base, start, size); base[size] = '\0'; } int proc_handler(handler_t *h, fields_t *f) { int pid, off, bytes; char *command; size_t size; if (f->nfields < 2 || f->fieldlen[0] < 6) return 0; if (strcmp(f->fields[1], "cmd") == 0) { /* * e.g. : * proc:27041 cmd /bin/sh /usr/prod/mts/common/bin/dblogin_gateway_reader */ if ((off = find_command_start(f->buf, f->len)) < 0) return 0; size = f->len - off + 16; /* +16 for the "%06d " pid */ if ((inst = (char *)malloc(size)) == NULL) return 0; sscanf(f->buf, "proc:%d", &pid); bytes = snprintf(inst, size, "%06d ", pid); /* f->buf contains nulls - so memcpy it then replace 'em */ size = f->len - off - 1; command = inst + bytes; memcpy(command, f->buf + off, size); command[size] = '\0'; inst_command_clean(command, size); } if (inst == NULL && strcmp(f->fields[1], "stat") == 0) { /* no instance yet, so stash it for later */ proc_stat = fields_dup(f); return 0; } if (inst) { pmInDom indom = pmInDom_build(PROC_DOMAIN, PROC_PROC_INDOM); if ((command = strchr(inst, ' ')) != NULL) { char cmdname[MAXPATHLEN]; command++; base_command_name(command, &cmdname[0], sizeof(cmdname)); put_str_value("proc.psinfo.cmd", indom, inst, cmdname); put_str_value("proc.psinfo.psargs", indom, inst, command); } /* emit the stashed proc_stat fields */ put_ull_value("proc.psinfo.utime", indom, inst, ticks_to_msec(proc_stat->fields[PROC_PID_STAT_UTIME+2])); put_ull_value("proc.psinfo.stime", indom, inst, ticks_to_msec(proc_stat->fields[PROC_PID_STAT_STIME+2])); put_str_value("proc.psinfo.processor", indom, inst, proc_stat->fields[PROC_PID_STAT_PROCESSOR+2]); put_str_value("proc.psinfo.rss", indom, inst, proc_stat->fields[PROC_PID_STAT_RSS+2]); put_str_value("proc.psinfo.vsize", indom, inst, proc_stat->fields[PROC_PID_STAT_VSIZE+2]); put_str_value("proc.psinfo.sname", indom, inst, proc_stat->fields[PROC_PID_STAT_STATE+2]); /* and the rest .. */ fields_free(proc_stat); proc_stat = NULL; /* TODO emit other stashed stuff .. */ free(inst); inst = NULL; } return 0; } pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/generic.c0000664000000000000000000000201512272262501017404 0ustar /* * Copyright (c) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Generic handler for singular metrics with value in fields[1] e.g. : * "processes 516779" * */ #include "metrics.h" /* generic handler for */ int generic1_handler(handler_t *h, fields_t *f) { put_str_value(h->metric_name, PM_INDOM_NULL, NULL, f->fields[1]); return 0; } /* generic handler for */ int generic2_handler(handler_t *h, fields_t *f) { put_str_value(h->metric_name, PM_INDOM_NULL, NULL, f->fields[2]); return 0; } pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/cpu.c0000664000000000000000000000623712272262501016571 0ustar /* * Copyright (c) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Handler for kernel.{percpu,all}.cpu.* * * cpu 66057896 4079 13437134 575696782 4513632 1463907 1701801 0 28602 0 * cpu0 24489004 2578 3862841 132669978 2807446 852698 928386 0 28602 0 * */ #include "metrics.h" #define ticks_to_msec(ticks) (1000ULL * strtoull(ticks, NULL, 0) / kernel_all_hz) int cpu_handler(handler_t *h, fields_t *f) { char *inst = NULL; if (f->fieldlen[0] < 3 || f->nfields < 9) return -1; if (f->fieldlen[0] > 3 && isdigit(f->fields[0][3])) { /* kernel.percpu.cpu.* */ pmInDom indom = pmInDom_build(LINUX_DOMAIN, CPU_INDOM); inst = f->fields[0]; /* cpuN */ put_ull_value("kernel.percpu.cpu.user", indom, inst, ticks_to_msec(f->fields[1])); put_ull_value("kernel.percpu.cpu.nice", indom, inst, ticks_to_msec(f->fields[2])); put_ull_value("kernel.percpu.cpu.sys", indom, inst, ticks_to_msec(f->fields[3])); put_ull_value("kernel.percpu.cpu.idle", indom, inst, ticks_to_msec(f->fields[4])); put_ull_value("kernel.percpu.cpu.wait.total", indom, inst, ticks_to_msec(f->fields[5])); put_ull_value("kernel.percpu.cpu.irq.hard", indom, inst, ticks_to_msec(f->fields[6])); put_ull_value("kernel.percpu.cpu.irq.soft", indom, inst, ticks_to_msec(f->fields[7])); put_ull_value("kernel.percpu.cpu.steal", indom, inst, ticks_to_msec(f->fields[8])); if (f->nfields > 9) /* guest cpu usage is only in more recent kernels */ put_ull_value("kernel.percpu.cpu.guest", indom, inst, ticks_to_msec(f->fields[9])); put_ull_value("kernel.percpu.cpu.intr", indom, inst, 1000 * ((double)strtoull(f->fields[6], NULL, 0) + (double)strtoull(f->fields[7], NULL, 0)) / kernel_all_hz); } else { put_ull_value("kernel.all.cpu.user", PM_INDOM_NULL, NULL, ticks_to_msec(f->fields[1])); put_ull_value("kernel.all.cpu.nice", PM_INDOM_NULL, NULL, ticks_to_msec(f->fields[2])); put_ull_value("kernel.all.cpu.sys", PM_INDOM_NULL, NULL, ticks_to_msec(f->fields[3])); put_ull_value("kernel.all.cpu.idle", PM_INDOM_NULL, NULL, ticks_to_msec(f->fields[4])); put_ull_value("kernel.all.cpu.wait.total", PM_INDOM_NULL, NULL, ticks_to_msec(f->fields[5])); put_ull_value("kernel.all.cpu.irq.hard", PM_INDOM_NULL, NULL, ticks_to_msec(f->fields[6])); put_ull_value("kernel.all.cpu.irq.soft", PM_INDOM_NULL, NULL, ticks_to_msec(f->fields[7])); put_ull_value("kernel.all.cpu.steal", PM_INDOM_NULL, NULL, ticks_to_msec(f->fields[8])); if (f->nfields > 9) put_ull_value("kernel.all.cpu.guest", PM_INDOM_NULL, NULL, ticks_to_msec(f->fields[9])); put_ull_value("kernel.all.cpu.intr", PM_INDOM_NULL, NULL, 1000 * ((double)strtoull(f->fields[6], NULL, 0) + (double)strtoull(f->fields[7], NULL, 0)) / kernel_all_hz); } return 0; } pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/metrics.h0000664000000000000000000000554012272262501017451 0ustar /* * Copyright (c) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Mark Goodwin May 2013. */ #include #include #include #include #include /* domains from stdpmid */ #define LINUX_DOMAIN 60 #define PROC_DOMAIN 3 /* Linux PMDA instance domain identifiers */ #include "../../pmdas/linux/indom.h" /* PCP metric, see metrics.c */ typedef struct { char *name; pmDesc desc; } metric_t; /* parsed input buffer, split into fields. See fields_new() et al */ typedef struct { int len; char *buf; int nfields; char **fields; int *fieldlen; } fields_t; /* handler to convert parsed fields into pcp metrics and emit them */ typedef struct handler { char *pattern; int (*handler)(struct handler *h, fields_t *f); char *metric_name; } handler_t; /* global options */ extern int vflag; extern int kernel_all_hz; extern int utc_offset; /* metric table, see metrics.c (generated from pmdesc) */ extern metric_t metrics[]; /* instance domain count table - needed for dynamic instances */ extern int indom_cnt[NUM_INDOMS]; /* metric value handler table */ extern handler_t handlers[]; /* handlers */ extern int header_handler(FILE *fp, char *fname, char *buf, int buflen); extern int timestamp_flush(void); extern int timestamp_handler(handler_t *h, fields_t *f); extern int cpu_handler(handler_t *h, fields_t *f); extern int proc_handler(handler_t *h, fields_t *f); extern int disk_handler(handler_t *h, fields_t *f); extern int net_handler(handler_t *h, fields_t *f); extern int loadavg_handler(handler_t *h, fields_t *f); extern int generic1_handler(handler_t *h, fields_t *f); extern int generic2_handler(handler_t *h, fields_t *f); /* various helpers, see util.c */ extern metric_t *find_metric(char *name); extern handler_t *find_handler(char *buf); extern int put_str_instance(pmInDom indom, char *instance); extern int put_str_value(char *name, pmInDom indom, char *instance, char *val); extern int put_int_value(char *name, pmInDom indom, char *instance, int val); extern int put_ull_value(char *name, pmInDom indom, char *instance, unsigned long long val); /* helpers to parse and manage input buffers */ extern int strfields(const char *s, int len, char **fields, int *fieldlen, int maxfields); extern fields_t *fields_new(const char *s, int len); extern fields_t *fields_dup(fields_t *f); extern void fields_free(fields_t *f); pcp-3.8.12ubuntu1/src/pmimport/collectl2pcp/disk.c0000664000000000000000000000365512272262501016735 0ustar /* * Copyright (c) 2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Handler for disk.dev * * disk 8 0 sda 13911739 267073 1248592592 58081804 4912190 5603474 382020376 181762699 0 53315955 240138732 */ #include "metrics.h" int disk_handler(handler_t *h, fields_t *f) { char *inst; pmInDom indom = pmInDom_build(LINUX_DOMAIN, DISK_INDOM); if (f->nfields != 15) return -1; /* disk.dev.* */ inst = f->fields[3]; /* diskname */ put_str_value("disk.dev.read", indom, inst, f->fields[4]); put_str_value("disk.dev.read_merge", indom, inst, f->fields[5]); put_str_value("disk.dev.blkread", indom, inst, f->fields[6]); /* skip read_ticks at f->fields[7] */ put_str_value("disk.dev.write", indom, inst, f->fields[8]); put_str_value("disk.dev.write_merge", indom, inst, f->fields[9]); put_str_value("disk.dev.blkwrite", indom, inst, f->fields[10]); /* skip write_ticks at f->fields[11] */ /* skip in_flight at f->fields[12] */ put_str_value("disk.dev.avactive", indom, inst, f->fields[13]); put_str_value("disk.dev.aveq", indom, inst, f->fields[14]); /* derived values */ put_ull_value("disk.dev.write_bytes", indom, inst, strtoull(f->fields[10], NULL, 0) / 2); put_ull_value("disk.dev.read_bytes", indom, inst, strtoull(f->fields[6], NULL, 0) / 2); put_ull_value("disk.dev.total_bytes", indom, inst, strtoull(f->fields[6], NULL, 0) + strtoull(f->fields[10], NULL, 0)); return 0; } pcp-3.8.12ubuntu1/src/pmimport/sheet2pcp/0000775000000000000000000000000012272262620015137 5ustar pcp-3.8.12ubuntu1/src/pmimport/sheet2pcp/GNUmakefile0000664000000000000000000000214512272262501017211 0ustar #!gmake # # Copyright (c) 2010 Ken McDonell. All Rights Reserved. # Copyright (c) 2009 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs SCRIPT = sheet2pcp LDIRT = $(MAN_PAGES) $(MAN_PAGES).tmp LSRCFILES = $(SCRIPT) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = $(SCRIPT).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: $(MAN_PAGES) $(SCRIPT).$(MAN_SECTION): $(SCRIPT) $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 $(SCRIPT) $(PCP_BIN_DIR)/$(SCRIPT) @$(INSTALL_MAN) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmimport/sheet2pcp/sheet2pcp0000775000000000000000000006233012272262501016764 0ustar #!/usr/bin/perl # # Copyright (c) 2010 Ken McDonell. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use XML::TokeParser; use Getopt::Std; use Date::Parse; use Date::Format; use PCP::LogImport; # Spreadsheet::Read is not include in some distros, so we give some # hints here, rather than dying with # Can't locate Spreadsheet/Read in @INC ... # eval { require Spreadsheet::Read; Spreadsheet::Read->import(); }; if ($@) { # failed die "Error: Perl module Spreadsheet::Read needs to be installed either from\nyour distro or downloaded and installed from CPAN\n"; } my $skip_rows = 0; # N from my $in_metric = 0; # XML parser context state ... in element my $in_data = 0; # XML parser context state ... in element my $idx = -1; # index into columns of spreadsheet my $stamp_idx = -1; # column containing the datetime info my %indom_map = (); # key=metricname value=indom my %inst_map = (); # key=indom value=last_inst_assigned, and # key=indom.instance value=inst my @handle = (); # pmi* handles, one per metric-instance pair my $sheet; my $zone = "UTC"; # default timezone my $label_zone; my $datefmt = "DMY"; # default order of date fields my %options; # for command line arguments sub dodate($) { # convert datetime format DD[/-]MM[/-]YY[YY] HH:MM[:SS] from spreadsheet # parsers into the ISO-8601 dates that Date::Parse # seems to be able to parse correctly ... this would appear to # have to be YYYY-MM-DDTHH:MM:SS.000000 and then pass the timezone # as the second parameter to str2time() # my ($datetime) = @_; # date separators may be - or /, space separates date from time, time # separators are : my @field = split(/[ :\/-]/, $datetime); my $mm; my $yy; my $dd; if ($#field == 4) { # assume :SS is missing, set seconds to 00 push(@field, "00"); } if ($#field != 5) { print "dodate: bad datetime format: \"$datetime\" => "; foreach (@field) { print " $_"; } print "\n"; exit(1); } if ($datefmt eq "DMY") { $dd = $field[0]; $mm = $field[1]; $yy = $field[2]; } elsif ($datefmt eq "MDY") { $mm = $field[0]; $dd = $field[1]; $yy = $field[2]; } elsif ($datefmt eq "YMD") { $yy = $field[0]; $mm = $field[1]; $dd = $field[2]; } # get into cannonical DD, MM and YYYY format if ($dd < 10 && $dd !~ /^0/) { $dd .= "0" }; # add leading zero if ($mm < 10 && $mm !~ /^0/) { $mm .= "0" }; # add leading zero if ($yy < 100) { # terrible Y2K hack ... will stop working in 2080 if ($yy <= 80) { $yy += 2000; } else { $yy += 1900; } } return $yy . "-" . $mm . "-" . $dd . "T" . $field[3] . ":" . $field[4] . ":" . $field[5]; } # process the mapfile and set up the metadata and handles needed # by the main loop # sub domap($) { my ($mapfile) = @_; my $sts = 0; my $pmid; my $indom; my $units; my $type; my $sem; my $name; my $instance; my $lsts; my $parser = XML::TokeParser->new($mapfile, Noempty => 1); if (!defined($parser)) { print "sheet2pcp: Failed to open mapfile \"$mapfile\"\n"; exit(1); } while (defined(my $token = $parser->get_token())) { if ($token->is_start_tag) { if ($token->tag eq "sheet") { foreach my $a (keys %{$token->attr}) { if ($a eq "heading") { $skip_rows = $token->attr->{heading}; } elsif ($a eq "hostname") { if (pmiSetHostname($token->attr->{hostname}) < 0) { print "Mapfile Warning: failed to set hostname " . $token->attr->{hostname} . ": " . pmiErrStr(-1) . "\n"; } } elsif ($a eq "timezone") { $zone = $token->attr->{timezone}; } elsif ($a eq "datefmt") { if ($token->attr->{datefmt} eq "DMY" || $token->attr->{datefmt} eq "MDY" || $token->attr->{datefmt} eq "YMD") { $datefmt = $token->attr->{datefmt}; } else { print "Mapfile Error: bad format for attribute datefmt=\"" . $token->attr->{datefmt} . "\"\n"; $sts++; } } else { print "Mapfile Error: attribute $a=\"" . $token->attr->{$a} . "\" not expected for tag\n"; $sts++; } } } elsif ($token->tag eq "metric") { $in_metric = 1; # defaults ... $pmid = PM_ID_NULL; $indom = PM_INDOM_NULL; $units = pmiUnits(0,0,0,0,0,0); $type = PM_TYPE_FLOAT; $sem = PM_SEM_INSTANT; $name = undef; $lsts = $sts; foreach my $a (keys %{$token->attr}) { if ($a eq "pmid") { my $value = $token->attr->{pmid}; if ($value =~ /^[0-9]+\.[0-9]+\.[0-9]+$/ || $value =~ /^PMI_DOMAIN\.[0-9]+\.[0-9]+$/) { # expected N.N.N or PMI_DOMAIN.N.N format my @args = split(/\./, $value); $args[0] = PMI_DOMAIN if $args[0] eq "PMI_DOMAIN"; $pmid = pmid_build($args[0],$args[1],$args[2]); } elsif ($value eq "PM_ID_NULL") { # accept literal default value $pmid = PM_ID_NULL; } else { print "Mapfile Error: bad format for attribute pmid=\"$value\"\n"; $sts++; } } elsif ($a eq "indom") { my $value = $token->attr->{indom}; if ($value =~ /^[0-9]+\.[0-9]+$/ || $value =~ /^PMI_DOMAIN\.[0-9]+$/) { # expected N.N or PMI_DOMAIN.N format my @args = split(/\./, $value); $args[0] = PMI_DOMAIN if $args[0] eq "PMI_DOMAIN"; $indom = pmInDom_build($args[0],$args[1]); } elsif ($value eq "PM_INDOM_NULL") { # accept literal default value $indom = PM_INDOM_NULL; } else { print "Mapfile Error: bad format for attribute indom=\"$value\"\n"; $sts++; } } elsif ($a eq "units") { my $value = $token->attr->{units}; my @args = split(/,/, $value); if ($#args != 5) { print "Mapfile Error: bad format for attribute units=\"$value\"\n"; $sts++; } else { for (my $i = 0; $i < 6; $i++) { $_ = eval($args[$i]); if (!defined($_)) { print "Mapfile Error: bad component ($args[$i]) for attribute units=\"$value\"\n"; $sts++; } else { $args[$i] = $_; } } if ($sts == 0) { $units = pmiUnits($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]); } } } elsif ($a eq "type") { my $value = $token->attr->{type}; $_ = eval($value); if (!defined($_)) { print "Mapfile Error: bad value for attribute type=\"$value\"\n"; $sts++; } else { $type = $_; } } elsif ($a eq "sem") { my $value = $token->attr->{sem}; $_ = eval($value); if (!defined($_)) { print "Mapfile Error: bad value for attribute sem=\"$value\"\n"; $sts++; } else { $sem = $_; } } else { print "Mapfile Error: attribute $a=\"" . $token->attr->{$a} . "\" not expected for tag\n"; $sts++; } } } elsif ($token->tag eq "data") { $in_data = 1; $idx++; $name = undef; $instance = undef; $lsts = $sts; foreach my $a (keys %{$token->attr}) { print "Mapfile Error: attribute $a=\"" . $token->attr->{$a} . "\" not expected for tag\n"; $sts++; } } elsif ($token->tag eq "datetime") { $idx++; $stamp_idx = $idx; foreach my $a (keys %{$token->attr}) { print "Mapfile Error: attribute $a=\"" . $token->attr->{$a} . "\" not expected for tag\n"; $sts++; } } elsif ($token->tag eq "skip") { $idx++; foreach my $a (keys %{$token->attr}) { print "Mapfile Error: attribute $a=\"" . $token->attr->{$a} . "\" not expected for tag\n"; $sts++; } } else { print "Mapfile Error: unexpected start tag " . $token->raw . "\n"; $sts++; } } elsif ($token->is_end_tag) { if ($token->tag eq "sheet") { if ($stamp_idx == -1) { print "Mapfile Error: missing element\n"; $sts++; } elsif ($idx < 1) { print "Mapfile Error: no element\n"; $sts++; } # all finished, nothing more to be done } elsif ($token->tag eq "metric") { if (defined($name)) { if ($lsts == $sts) { # no errors in this name element if (pmiAddMetric($name, $pmid, $type, $indom, $sem, $units) < 0) { print "Mapfile Error: failed to define metric $name: " . pmiErrStr(-1) . "\n"; $sts++; } else { # need metric name => indom for later # $indom_map{$name} = $indom; } } } else { print "Mapfile Error: missing metric name in element\n"; $sts++; } $in_metric = 0; } elsif ($token->tag eq "data") { if (defined($name)) { if ($lsts == $sts) { # no errors in this metricspec element $indom = $indom_map{$name}; if (defined($indom)) { if (defined($instance)) { if (!defined($inst_map{$indom . $instance})) { # first time for this instance and indom my $inst; if (defined($inst_map{$indom})) { $inst_map{$indom}++; $inst = $inst_map{$indom}; } else { # first time for this indom $inst_map{$indom} = 0; $inst = 0; } if (pmiAddInstance($indom, $instance, $inst) < 0) { print "Mapfile Error: failed to define instance \"$instance\" ($inst) for metric $name: " . pmiErrStr(-1) . "\n"; $sts++; } else { # add new instance for indom $inst_map{$indom . $instance} = $inst; } } my $h = pmiGetHandle($name, $instance); if ($h < 0) { die "pmiGetHandle: failed to create handle for metricspec $name" . "[" . $instance . "]: " . pmiErrStr($sts) . "\n"; $sts++; } else { push(@handle, $h); } } else { my $h = pmiGetHandle($name, ""); if ($h < 0) { die "pmiGetHandle: failed to create handle for metricspec $name: " . pmiErrStr($sts) . "\n"; } else { push(@handle, $h); } } } else { print "Mapfile Error: metric name ($name) in element not defined in earlier element\n"; $sts++; } } } else { print "Mapfile Error: missing metricspec in element\n"; $sts++; } $in_data = 0; } elsif ($token->tag eq "datetime" || $token->tag eq "skip") { # -1 flags this a column to be skipped push(@handle, -1); } else { print "Mapfile Error: unexpected end tag " . $token->raw . "\n"; $sts++; } } elsif ($token->is_text) { if ($in_metric || $in_data) { $name = $token->text; $name =~ s/^\s+//; $name =~ s/\s+$//; if ($in_data) { my @field = split(/\[/, $name); if ($#field > 1) { print "Mapfile Error: extra [ in metricspec \"" . $token->text . "\" in element\n"; $sts++; } else { if (defined($field[1])) { $name = $field[0]; $instance = $field[1]; if ($instance =~ /]$/) { $instance =~ s/]$//; } else { print "Mapfile Error: missing ] in metricspec \"" . $token->text . "\" in element\n"; $sts++; } } } } } else { print "Mapfile Error: unexpected text \"" . $token->text . "\"\n"; $sts++; } } elsif ($token->is_comment) { # is special, silently ignore other comments pmiDump() if $token->text eq "pmiDump"; } elsif ($token->is_pi) { print "Mapfile Warning: unexpected process instruction (ignored) " . $token->raw . "\n"; } } if ($sts != 0) { print "Abandoned after $sts mapfile error"; print "s" if $sts > 1; print "\n"; exit(0); } } my $sts = getopts('h:Z:', \%options); if (!defined($sts) || $#ARGV != 2) { print "Usage: sheet2pcp [-h host] [-Z timezone] infile mapfile outfile\n"; exit(1); } if (exists($options{Z})) { $zone = $options{Z}; if ($zone !~ /^[-+][0-9][0-9][0-9][0-9]$/) { print "sheet2pcp: Illegal -Z value, must be +NNNN or -NNNN\n"; exit(1); } } # initialize the output archive so we can add the metadata from the mapfile # pmiStart($ARGV[2], 0); if (exists($options{h})) { if (pmiSetHostname($options{h}) < 0) { print "sheet2pcp: Warning: failed to set hostname from -h " . $options{h} . ": " . pmiErrStr(-1) . "\n"; } } # all the hard work is done here ... # domap($ARGV[1]); # Serious strangeness here ... # the Perl Date::Parse and Date::Format routines appear to # only work with timezones of the format +NNNN or -NNNN # ("UTC" is an exception) # # PCP expects a $TZ style timezone in the archive label, so # we have to make up a PCP-xx:xx timezone ... note this # invloves a sign reversal! # $label_zone = $zone; if ($zone =~ /^[-+][0-9][0-9][0-9][0-9]/) { $label_zone =~ s/^\+/PCP-/; $label_zone =~ s/^-/PCP+/; $label_zone =~ s/(..)$/:$1/; } elsif ($zone ne "UTC") { print "sheet2pcp: Warning: unexpected timezone ($zone), reverting to UTC\n"; $zone = "UTC"; $label_zone = "UTC"; } if (pmiSetTimezone($label_zone) < 0) { print "Mapfile Warning: failed to set timezone \"" . $label_zone . "\": " . pmiErrStr(-1) . "\n"; } if ($ARGV[0] =~ /\.csv$/) { system("perl -MText::CSV_XS -e 1 >/dev/null 2>&1") == 0 or die "Perl Text::CSV_XS module not installed"; $sheet = ReadData($ARGV[0]); } elsif ($ARGV[0] =~ /\.ods$/ || $ARGV[0] =~ /\.sxc$/) { system("perl -MArchive::Zip -e 1 >/dev/null 2>&1") == 0 or die "Perl Archive::Zip module not installed"; system("perl -MSpreadsheet::ReadSXC -e 1 >/dev/null 2>&1") == 0 or die "Perl Spreadsheet::ReadSXC module not installed"; $sheet = ReadData($ARGV[0], dtfmt => "yyyy-mm-dd"); } elsif ($ARGV[0] =~ /\.xls$/) { system("perl -MOLE::Storage_Lite -e 1 >/dev/null 2>&1") == 0 or die "Perl OLE::Storage_Lite module not installed"; system("perl -MSpreadsheet::ParseExcel -e 1 >/dev/null 2>&1") == 0 or die "Perl Spreadsheet::ParseExcel module not installed"; $sheet = ReadData($ARGV[0], dtfmt => "yyyy-mm-dd"); } elsif ($ARGV[0] =~ /\.xlsx$/) { system("perl -MOLE::Storage_Lite -e 1 >/dev/null 2>&1") == 0 or die "Perl OLE::Storage_Lite module not installed"; system("perl -MSpreadsheet::ParseExcel -e 1 >/dev/null 2>&1") == 0 or die "Perl Spreadsheet::ParseExcel module not installed"; system("perl -MSpreadsheet::XLSX -e 1 >/dev/null 2>&1") == 0 or die "Perl Spreadsheet::XLSX module not installed"; $sheet = ReadData($ARGV[0], dtfmt => "yyyy-mm-dd"); } else { print "sheet2pcp: Error: No clue how to deduce format of spreadsheet $ARGV[0]\n"; exit(1); } if (!defined($sheet)) { print "sheet2pcp: Failed to open spreadsheet \"$ARGV[0]\"\n"; exit(1); } #debug# print "maxrow=$sheet->[1]{maxrow} maxcol=$sheet->[1]{maxcol}\n"; #debug# print "mapfile " . ($idx+1) . " columns, timestamp @ column " . $stamp_idx . "\n"; if ($sheet->[1]{maxcol} != $idx+1) { print "sheet2pcp: Warning: columns from mapfile (" . ($idx+1) . ") not equal to columns from spreadsheet (" . $sheet->[1]{maxcol} . "), some data will not be exported\n"; } for (my $row = 1; $row <= $sheet->[1]{maxrow}; $row++) { my $stamp = undef; if ($skip_rows) { $skip_rows--; next; } for (my $col = 1; $col <= $sheet->[1]{maxcol}; $col++) { my $cell = cr2cell($col, $row); # ignore columns after last one in mapfile next if ($col > $idx+1); #debug# print "$cell = $sheet->[1]{$cell}\n" if (!defined($handle[$col-1])) { pmiDump(); die "No handle[] entry for cell[" . $cell . "]. Check Handles in dump above.\n"; } if (!defined($sheet->[1]{$cell})) { print "Warning: cell[" . $cell . "] empty, but data expected\n"; } else { if ($col == $stamp_idx+1) { $stamp = dodate($sheet->[1]{$cell}); #debug# print $sheet->[1]{$cell} . " -> " . $stamp . "\n"; } elsif ($handle[$col-1] != -1) { pmiPutValueHandle($handle[$col-1], $sheet->[1]{$cell}) >= 0 or die "pmiPutValueHandle: failed at cell[" . $cell . "]: " . pmiErrStr(-1) . "\n"; } } } if (!defined($stamp)) { die "Error: no datetime at row[ " . $row . "]"; } pmiWrite(str2time($stamp, $zone), 0) >= 0 or die "pmiWrite: at row[ ". $row . "] ($stamp): " . pmiErrStr(-1) . "\n"; } pmiEnd(); exit(0); =pod =head1 NAME sheet2pcp - Import spreadsheet data and create a PCP archive =head1 SYNOPSIS B [B<-h> I] [B<-Z> I] I I I =head1 DESCRIPTION B is intended to read a data spreadsheet (I) translate this into a Performance Co-Pilot (PCP) archive with the basename I. The input spreadsheet can be in any of the common formats, provided the appropriate Perl modules have been installed (see the B section below). The spreadsheet must be EnormalizedE so that each row contains data for the same time interval, and one of the columns contains the date and time for the data in each row. The resultant PCP archive may be used with all the PCP client tools to graph subsets of the data using B(1), perform data reduction and reporting, filter with the PCP inference engine B(1), etc. The I controls the import process and defines the data mapping from the spreadsheet columns onto the PCP data model. The file is written in XML and conforms to the syntax defined in the B section below. A series of physical files will be created with the prefix I. These are IB<.0> (the performance data), IB<.meta> (the metadata that describes the performance data) and IB<.index> (a temporal index to improve efficiency of replay operations for the archive). If any of these files exists already, then B will B overwrite them and will exit with an error message. The B<-h> option is an alternate to the B attribute of the BsheetE> element in I described below. If both are specified, the value from I is used. The B<-Z> option is an alternate to the B attribute of the BsheetE> element in I described below. If both are specified, the value from I is used. B is a Perl script that uses the PCP::LogImport Perl wrapper around the PCP I library, and as such could be used as an example to develop new tools to import other types of performance data and create PCP archives. =head1 MAPPING CONFIGURATION The I contains specifications in standard XML format. The whole specification is wrapped in a BsheetE> ... B/sheetE> element. The B tag supports the following optional attributes: =over 10 =item B Specifies the number of heading rows to skip at the start of the spreadsheet before processing data. Example: heading="1". =item B Set the source hostname in the PCP archive (the default is to use the hostname of the local host). Example: hostname="some.where.com". =item B Set the source timezone in the PCP archive (the default is to use UTC). The timezone must have the format +HHMM (for hours and minutes East of UTC) or -HHMM (for hours and minutes West of UTC). Note in particular that B the B (aka Olson) format, e.g. Europe/Paris, nor the Posix B format, e.g. EST+5 is allowed. Example: timezone="+1100". =item B The format of the date imported from the spreadsheet may be specified as a concatenation of values that specify the order of the year (B), month (B) and day (B) fields in a date. The supported variants are B (the default), B and B. Example: datefmt="YMD". =back A BsheetE> element contains one or more metric specifications of the form BmetricE>IB/metricE>. The B tag supports the following optional attributes: =over 10 =item B The Performance Metrics Identifier (PMID), specified as 3 numbers separated by a periods (.) to set the B, B and B fields of the PMID, see B(4) for more details of PMIDs. If omitted, the PMID will be automatically assigned by B(3). The value B may be used to explicitly nominate the default behaviour. Examples: pmid="60.0.2", pmid="PM_ID_NULL". =item B Each metric may have one or more values. If a metric B has one value, it is singular and the Instance Domain should be set to B. Otherwise B should be specified as 2 numbers separated by a period (.) to set the B and B fields of the Instance Domain, see the B<__pmInDom_int> typedef in Ipcp/impl.hE>. Examples: indom="PM_INDOM_NULL", indom="60.3", indom="PMI_DOMAIN.4". More than one metric can share the same Instance Domain when the metrics have defined values over similar sets of instances, e.g. all the metrics for each network interface. It is standard practice for the B field to be the same for the B and the B; if the B attribute is missing, then the B field for the B should be the reserved domain B. If the B attribute is omitted then the default Instance Domain for the metric is B. =item B The scale and dimension of the metric values along the axes of space, time and count (events, messages, packets, etc.) is specified with a 6-tuple. These values are passed to the B(3) function to generate a I structure. Refer to B(3) for a full description of all the fields of this structure. The default is to assign no scale or dimension to the metric, i.e. units="0,0,0,0,0,0". Examples: units="0,1,0,0,PM_TIME_MSEC,0" (milliseconds), units="1,-1,0,PM_SPACE_MBYTE,PM_TIME_SEC,0" (Mbytes/sec), units="0,1,-1,0,PM_TIME_USEC,PM_COUNT_ONE" (microseconds/event). =item B Defines the data type for the metric. Refer to B(3) for a full description of the possible type values; the default is B. Examples: type="PM_TYPE_32", type="PM_TYPE_U64", type="PM_TYPE_STRING". =item B Defines the semantics of the metric. Refer to B(3) for a full description of the possible values; the default is B. Examples: sem="PM_SEM_COUNTER", type="PM_SEM_DISCRETE". =back The remaining specifications define the data columns B using B one BdatetimeE>B/datetimeE> element, one or more BdataE>IB/dataE> elements and one or more BskipE>B/skipE> elements. The BdatetimeE> element defines the column in which a date and time will be found to form the timestamp in the PCP archive for all the data in each row of the PCP archive. For the BdataE> element, a I consists of a metric name (as defined in an earlier BmetricE> element), optionally followed by an instance name that is enclosed by square brackets, e.g. hinv.ncpu, kernel.all.load[1 minute]. The B tag defines the column that should be skipped when preparing data for the PCP archive. The order of the BdatetimeE>, BdataE> and BskipE> elements matches the order of columns in the spreadsheet. If the number of elements is not the same as the number of columns a warning is issued, and the extra elements or columns generate no metric values in the output archive. =head2 EXAMPLE The I ... kernel.percpu.cpu.sys kernel.percpu.cpu.sys[cpu0] kernel.percpu.cpu.sys[cpu1] could be used for a spreadsheet in which the first few rows are ... Date;"Status";"SysTime - 0";"SysTime - 1"; 26/01/2001 14:05:22;"Some Busy";0.750;0.133 26/01/2001 14:05:37;"OK";0.150;0.273 26/01/2001 14:05:52;"All Busy";0.733;0.653 =head1 CAVEATS Only the first sheet from I will be processed. Additional Perl modules must be installed for the various spreadsheet formats, although these are checked for ar run-time so only the modules required for the specific types of spreadsheets you wish to process need be installed: =over 6 =item B<*.csv> Spreadsheets in the Comma Separated Values (CSV) format require B(3pm). =item B<*.sxc> or B<*.ods> OpenOffice documents require B(3pm), which in turn requires B(3pm). =item B<*.xls> Classical Microsoft Office documents require B(3pm), which in turn requires B(3pm). =item B<*.xlsx> Microsoft OpenXML documents require B(3pm). B does not appear to work with OpenXML documents saved from OpenOffice. =back =head1 SEE ALSO B(3pm), B(3pm), B(3pm), B(3), B(3pm), B(3pm), B(1), B(3), B(1), B(3), B(1), B(3), B(4), B(3pm), B(3pm), B(3pm), B(3pm) and B(3pm). pcp-3.8.12ubuntu1/src/pmfind/0000775000000000000000000000000012272262620012650 5ustar pcp-3.8.12ubuntu1/src/pmfind/GNUmakefile0000664000000000000000000000147512272262501014727 0ustar # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmfind.c CMDTARGET = pmfind$(EXECSUFFIX) LLDLIBS = $(PCPLIB) default : $(CMDTARGET) include $(BUILDRULES) install : default $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmfind/pmfind.c0000664000000000000000000000457212272262501014277 0ustar /* * Copyright (c) 2013-2014 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" static int quiet; static char *service; static char *mechanism; static int discovery(void) { int i, sts; char **urls; if (!service) service = PM_SERVER_SERVICE_SPEC; /* pmcd */ sts = pmDiscoverServices(service, mechanism, &urls); if (sts < 0) { fprintf(stderr, "%s: service %s discovery failure: %s\n", pmProgname, service, pmErrStr(sts)); return 2; } if (sts == 0) { if (!quiet) printf("No %s servers discovered\n", service); return 1; } if (!quiet) { printf("Discovered %s servers:\n", service); for (i = 0; i < sts; ++i) printf(" %s\n", urls[i]); } free(urls); return 0; } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\ \n\ Options:\n\ -m mechanism set the discovery method to use [avahi|...|all]\n\ -q quiet mode, do not write to stdout\n\ -s service discover local services [pmcd|...]\n", pmProgname); } int main(int argc, char **argv) { int c; int sts; int errflag = 0; __pmSetProgname(argv[0]); while ((c = getopt(argc, argv, "D:m:s:q?")) != EOF) { switch (c) { case 'D': /* debug flag */ if ((sts = __pmParseDebug(optarg)) < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else { pmDebug |= sts; } break; case 'm': /* discovery mechanism */ if (strcmp(optarg, "all") == 0) mechanism = NULL; else mechanism = optarg; break; case 'q': /* no stdout messages */ quiet = 1; break; case 's': /* discover named service */ service = optarg; break; case '?': if (errflag == 0) { usage(); exit(0); } break; } } if (optind != argc) errflag++; if (errflag) { usage(); exit(1); } return discovery(); } pcp-3.8.12ubuntu1/src/pmsignal/0000775000000000000000000000000012272262620013205 5ustar pcp-3.8.12ubuntu1/src/pmsignal/pmsignal.sh0000775000000000000000000000400512272262501015353 0ustar #!/bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Cross-platform signal/event sender for Performance Co-Pilot utilities. # Supports a minimal set of signals, used by PCP tools on all platforms. # . $PCP_DIR/etc/pcp.env prog=`basename $0` sigs="HUP USR1 TERM KILL" usage() { [ ! -z "$@" ] && echo $@ 1>&2 echo 1>&2 "Usage: $prog [options] PID ... | name ... Options: -a send signal to all named processes (killall mode) -l list available signals -n dry-run, list processes that would be affected -s signal signal to send ($sigs)" exit 0 } check() { for sig in $sigs do [ $sig = "$1" ] && echo $sig && return done usage "$prog: invalid signal - $1" } signal=TERM aflag=false lflag=false nflag=false while getopts "?alns:" c do case $c in a) aflag=true ;; l) lflag=true ;; n) nflag=true ;; s) signal=`check "$OPTARG"` ;; ?) usage "" ;; esac done [ $lflag = true ] && echo "$sigs" && exit 0 shift `expr $OPTIND - 1` [ $# -lt 1 ] && usage "$prog: too few arguments" if [ $aflag = true ] then pids="" for name in "$@"; do program=`basename "$name"` pidlist=`_get_pids_by_name "$program"` pids="$pids $pidlist" done else pids="$@" fi [ $nflag = true ] && echo "$pids" && exit 0 sts=0 if [ "$PCP_PLATFORM" = mingw ] then for pid in $pids ; do pcp-setevent $signal $pid [ $? -eq 0 ] || sts=$? done else for pid in $pids ; do kill -$signal $pid [ $? -eq 0 ] || sts=$? done fi exit $sts pcp-3.8.12ubuntu1/src/pmsignal/GNUmakefile0000664000000000000000000000145112272262501015256 0ustar #!gmake # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs LSRCFILES = pmsignal.sh default: include $(BUILDRULES) install: default $(INSTALL) -m 755 pmsignal.sh $(PCP_BINADM_DIR)/pmsignal$(SHELLSUFFIX) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmcollectl/0000775000000000000000000000000012272262620013531 5ustar pcp-3.8.12ubuntu1/src/pmcollectl/GNUmakefile0000664000000000000000000000144112272262501015601 0ustar # # Copyright (c) 2012 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs TARGET = pmcollectl PYFILES = $(TARGET).py default default_pcp: $(PYFILES) include $(BUILDRULES) install install_pcp: $(PYFILES) ifneq "$(PYTHON)" "" $(INSTALL) -m 755 $(PYFILES) $(PCP_BIN_DIR)/$(TARGET) endif pcp-3.8.12ubuntu1/src/pmcollectl/pmcollectl.py0000775000000000000000000007350712272262501016256 0ustar #!/usr/bin/python # # pmcollectl.py # # Copyright (C) 2012-2013 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # """System status collector using the libpcp Wrapper module Additional Information: Performance Co-Pilot Web Site http://oss.sgi.com/projects/pcp """ # ignore line too long, missing docstring, method could be a function, # too many public methods # pylint: disable=C0301 # pylint: disable=C0111 # pylint: disable=R0201 # pylint: disable=R0904 ############################################################################## # # imports # import os import sys import time import cpmapi as c_api import cpmgui as c_gui from pcp import pmapi, pmgui from pcp.pmsubsys import Subsystem ME = "pmcollectl" def usage (): print "\nUsage:", sys.argv[0], "\n\t[-h HOST] [-sSUBSYS] [-f|--filename FILE] [-p|--playback FILE]" print '''\t[-R|--runtime N] [-c|--count N] [-i|--interval N] [--verbose] ''' # scale ----------------------------------------------------------------- def scale (value, magnitude): return (value + (magnitude / 2)) / magnitude # record --------------------------------------------------------------- def record (context, config, interval, path, host): if os.path.exists(path): print ME + "archive %s already exists\n" % path sys.exit(1) status = context.pmRecordSetup (path, ME, 0) # pylint: disable=W0621 (status, rhp) = context.pmRecordAddHost (host, 1, config) # just a filename status = context.pmRecordControl (0, c_gui.PM_REC_SETARG, "-T" + str(interval) + "sec") status = context.pmRecordControl (0, c_gui.PM_REC_ON, "") # sleep +1 to make sure pmlogger gets to the -T limit time.sleep(interval+1) # don't need to do anything else ... pmlogger will stop of it's own # once -T limit is reached, or pmcollectl exits, and in particular # calling # status = context.pmRecordControl (rhp, c_gui.PM_REC_OFF, "") # produces a popup dialog we don't want # # record_add_creator ------------------------------------------------------ def record_add_creator (path): fdesc = open (path, "a+") args = "" for i in sys.argv: args = args + i + " " fdesc.write("# Created by " + args) fdesc.write("\n#\n") fdesc.close() # _CollectPrint ------------------------------------------------------- class _CollectPrint(object): def __init__(self, ss): self.ss = ss def print_header1(self): if self.verbosity == "brief": self.print_header1_brief() elif self.verbosity == "detail": self.print_header1_detail() elif self.verbosity == "verbose": self.print_header1_verbose() def print_header2(self): if self.verbosity == "brief": self.print_header2_brief() elif self.verbosity == "detail": self.print_header2_detail() elif self.verbosity == "verbose": self.print_header2_verbose() def print_header1_brief(self): True # pylint: disable-msg=W0104 def print_header2_brief(self): True # pylint: disable-msg=W0104 def print_header1_detail(self): True # pylint: disable-msg=W0104 def print_header2_detail(self): True # pylint: disable-msg=W0104 def print_header1_verbose(self): True # pylint: disable-msg=W0104 def print_header2_verbose(self): True # pylint: disable-msg=W0104 def print_line(self): if self.verbosity == "brief": self.print_brief() elif self.verbosity == "detail": self.print_detail() elif self.verbosity == "verbose": self.print_verbose() def print_brief(self): True # pylint: disable-msg=W0104 def print_verbose(self): True # pylint: disable-msg=W0104 def print_detail(self): True # pylint: disable-msg=W0104 def divide_check(self, dividend, divisor): if divisor == 0: return 0 else: return dividend / divisor def set_verbosity(self, cpverbosity): self.verbosity = cpverbosity # pylint: disable-msg=W0201 # _cpuCollectPrint -------------------------------------------------- class _cpuCollectPrint(_CollectPrint): def print_header1_brief(self): print '#<--------CPU-------->', def print_header1_detail(self): print '# SINGLE CPU STATISTICS' def print_header1_verbose(self): print '# CPU SUMMARY (INTR, CTXSW & PROC /sec)' def print_header2_brief(self): print '#cpu sys inter ctxsw', def print_header2_detail(self): print '# Cpu User Nice Sys Wait IRQ Soft Steal Idle' def print_header2_verbose(self): print '#User Nice Sys Wait IRQ Soft Steal Idle CPUs Intr Ctxsw Proc RunQ Run Avg1 Avg5 Avg15 RunT BlkT' def print_brief(self): print "%4d" % (100 * (self.ss.get_metric_value('kernel.all.cpu.nice') + self.ss.get_metric_value('kernel.all.cpu.user') + self.ss.get_metric_value('kernel.all.cpu.intr') + self.ss.get_metric_value('kernel.all.cpu.sys') + self.ss.get_metric_value('kernel.all.cpu.steal') + self.ss.get_metric_value('kernel.all.cpu.irq.hard') + self.ss.get_metric_value('kernel.all.cpu.irq.soft')) / ss.cpu_total), print "%3d" % (100 * (self.ss.get_metric_value('kernel.all.cpu.intr') + self.ss.get_metric_value('kernel.all.cpu.sys') + self.ss.get_metric_value('kernel.all.cpu.steal') + self.ss.get_metric_value('kernel.all.cpu.irq.hard') + self.ss.get_metric_value('kernel.all.cpu.irq.soft')) / ss.cpu_total), print "%5d %6d" % (self.ss.get_metric_value('kernel.all.intr'), self.ss.get_metric_value('kernel.all.pswitch')), def print_detail(self): for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.cpu.user'))): print " %3d %4d %4d %3d %4d %3d %4d %5d %4d" % ( k, (100 * (self.ss.get_scalar_value('kernel.percpu.cpu.nice',k) + self.ss.get_scalar_value('kernel.percpu.cpu.user',k) + self.ss.get_scalar_value('kernel.percpu.cpu.intr',k) + self.ss.get_scalar_value('kernel.percpu.cpu.sys',k) + self.ss.get_scalar_value('kernel.percpu.cpu.steal',k) + self.ss.get_scalar_value('kernel.percpu.cpu.irq.hard',k) + self.ss.get_scalar_value('kernel.percpu.cpu.irq.soft',k)) / ss.cpu_total), self.ss.get_scalar_value('kernel.percpu.cpu.nice',k), (100 * (self.ss.get_scalar_value('kernel.percpu.cpu.intr',k) + self.ss.get_scalar_value('kernel.percpu.cpu.sys',k) + self.ss.get_scalar_value('kernel.percpu.cpu.steal',k) + self.ss.get_scalar_value('kernel.percpu.cpu.irq.hard',k) + self.ss.get_scalar_value('kernel.percpu.cpu.irq.soft',k)) / ss.cpu_total), self.ss.get_scalar_value('kernel.percpu.cpu.wait.total',k), self.ss.get_scalar_value('kernel.percpu.cpu.irq.hard',k), self.ss.get_scalar_value('kernel.percpu.cpu.irq.soft',k), self.ss.get_scalar_value('kernel.percpu.cpu.steal',k), self.ss.get_scalar_value('kernel.percpu.cpu.idle',k) / 10) def print_verbose(self): ncpu = self.ss.get_metric_value('hinv.ncpu') print "%4d %6d %5d %4d %4d %5d " % ( (100 * (self.ss.get_metric_value('kernel.all.cpu.nice') + self.ss.get_metric_value('kernel.all.cpu.user') + self.ss.get_metric_value('kernel.all.cpu.intr') + self.ss.get_metric_value('kernel.all.cpu.sys') + self.ss.get_metric_value('kernel.all.cpu.steal') + self.ss.get_metric_value('kernel.all.cpu.irq.hard') + self.ss.get_metric_value('kernel.all.cpu.irq.soft')) / ss.cpu_total), self.ss.get_metric_value('kernel.all.cpu.nice'), (100 * (self.ss.get_metric_value('kernel.all.cpu.intr') + self.ss.get_metric_value('kernel.all.cpu.sys') + self.ss.get_metric_value('kernel.all.cpu.steal') + self.ss.get_metric_value('kernel.all.cpu.irq.hard') + self.ss.get_metric_value('kernel.all.cpu.irq.soft')) / ss.cpu_total), self.ss.get_metric_value('kernel.all.cpu.wait.total'), self.ss.get_metric_value('kernel.all.cpu.irq.hard'), self.ss.get_metric_value('kernel.all.cpu.irq.soft') ), print "%6d %6d %5d %5d %6d" % ( self.ss.get_metric_value('kernel.all.cpu.steal'), self.ss.get_metric_value('kernel.all.cpu.idle') / (10 * ncpu), ncpu, self.ss.get_metric_value('kernel.all.intr'), self.ss.get_metric_value('kernel.all.pswitch') ), print "%5d %5d %5d %5.2f %5.2f %5.2f %4d %4d" % ( self.ss.get_metric_value('kernel.all.nprocs'), self.ss.get_metric_value('kernel.all.runnable'), self.ss.get_metric_value('proc.runq.runnable'), self.ss.get_metric_value('kernel.all.load')[0], self.ss.get_metric_value('kernel.all.load')[1], self.ss.get_metric_value('kernel.all.load')[2], self.ss.get_metric_value('kernel.all.runnable'), self.ss.get_metric_value('proc.runq.blocked')) # _interruptCollectPrint --------------------------------------------- class _interruptCollectPrint(_CollectPrint): def print_header1_brief(self): ndashes = (((self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))) * 6) - 6) / 2 hdr = "#<" for k in range(ndashes): hdr += "-" hdr += "Int" for k in range(ndashes): hdr += "-" hdr += ">" print hdr, def print_header1_detail(self): print '# INTERRUPT DETAILS' print '# Int ', for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))): print 'Cpu%d ' % k, print 'Type Device(s)' def print_header1_verbose(self): print '# INTERRUPT SUMMARY' def print_header2_brief(self): for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))): if k == 0: print '#Cpu%d ' % k, else: print 'Cpu%d ' % k, def print_header2_verbose(self): print '# ', for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))): print 'Cpu%d ' % k, print def print_brief(self): int_count = [] for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))): int_count.append(0) for j in ss.metrics: if j[0:24] == 'kernel.percpu.interrupts': int_count[k] += self.ss.get_scalar_value(self.ss.metrics_dict[j], k) for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))): print "%4d " % (int_count[k]), def print_detail(self): for j in ss.metrics: if j[0:24] != 'kernel.percpu.interrupts': continue j_i = self.ss.metrics_dict[j] have_nonzero_value = False for k in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))): if self.ss.get_scalar_value(j_i, k) != 0: have_nonzero_value = True if not have_nonzero_value: continue if have_nonzero_value: # pcp does not give the interrupt # so print spaces print "%-8s" % self.ss.metrics[j_i].split(".")[3], for i in range(self.ss.get_len(self.ss.get_metric_value('kernel.percpu.interrupts.THR'))): print "%4d " % (self.ss.get_scalar_value(j_i, i)), text = (pm.pmLookupText(self.ss.metric_pmids[j_i], c_api.PM_TEXT_ONELINE)) print "%-18s %s" % (text[:(str.index(text," "))], text[(str.index(text," ")):]) def print_verbose(self): print " ", self.print_brief() print # _diskCollectPrint -------------------------------------------------- class _diskCollectPrint(_CollectPrint): def print_header1_brief(self): print '<----------Disks----------->', def print_header1_detail(self): print '# DISK STATISTICS (/sec)' def print_header1_verbose(self): print '\n\n# DISK SUMMARY (/sec)' def print_header2_brief(self): print ' KBRead Reads KBWrit Writes', def print_header2_detail(self): print '# <---------reads---------><---------writes---------><--------averages--------> Pct' print '#Name KBytes Merged IOs Size KBytes Merged IOs Size RWSize QLen Wait SvcTim Util' def print_header2_verbose(self): print '#KBRead RMerged Reads SizeKB KBWrite WMerged Writes SizeKB\n', def print_brief(self): print "%6d %6d %6d %6d" % ( self.ss.get_metric_value('disk.all.read_bytes'), self.ss.get_metric_value('disk.all.read'), self.ss.get_metric_value('disk.all.write_bytes'), self.ss.get_metric_value('disk.all.write')), def print_detail(self): for j in xrange(len(self.ss.metric_pmids)): try: (inst, iname) = pm.pmGetInDom(self.ss.metric_descs[j]) break except pmapi.pmErr, e: iname = "X" # metric values may be scalars or arrays depending on # of disks for j in xrange(self.ss.get_len(self.ss.get_metric_value('disk.dev.read_bytes'))): print "%-10s %6d %6d %4d %4d %6d %6d %4d %4d %6d %6d %4d %6d %4d" % ( iname[j], self.ss.get_scalar_value ('disk.dev.read_bytes', j), self.ss.get_scalar_value ('disk.dev.read_merge', j), self.ss.get_scalar_value ('disk.dev.read', j), self.ss.get_scalar_value ('disk.dev.blkread', j), self.ss.get_scalar_value ('disk.dev.write_bytes', j), self.ss.get_scalar_value ('disk.dev.write_merge', j), self.ss.get_scalar_value ('disk.dev.write', j), self.ss.get_scalar_value ('disk.dev.blkwrite', j), 0, 0, 0, 0, 0) # ??? replace 0 with required fields def print_verbose(self): avgrdsz = avgwrsz = 0 if self.ss.get_metric_value('disk.all.read') > 0: avgrdsz = self.ss.get_metric_value('disk.all.read_bytes') avgrdsz /= self.ss.get_metric_value('disk.all.read') if self.ss.get_metric_value('disk.all.write') > 0: avgwrsz = self.ss.get_metric_value('disk.all.write_bytes') avgwrsz /= self.ss.get_metric_value('disk.all.write') print '%6d %6d %6d %6d %7d %8d %6d %6d' % ( avgrdsz, self.ss.get_metric_value('disk.all.read_merge'), self.ss.get_metric_value('disk.all.read'), 0, avgwrsz, self.ss.get_metric_value('disk.all.write_merge'), self.ss.get_metric_value('disk.all.write'), 0) # _memoryCollectPrint ------------------------------------------------ class _memoryCollectPrint(_CollectPrint): def print_header1_brief(self): print '#<-----------Memory----------->' def print_header1_verbose(self): print '# MEMORY SUMMARY' def print_header2_brief(self): print '#Free Buff Cach Inac Slab Map' def print_header2_verbose(self): print '#<-------------------------------Physical Memory--------------------------------------><-----------Swap------------><-------Paging------>' print '# Total Used Free Buff Cached Slab Mapped Anon Commit Locked Inact Total Used Free In Out Fault MajFt In Out' def print_brief(self): print "%4dM %3dM %3dM %3dM %3dM %3dM " % ( scale(self.ss.get_metric_value('mem.freemem'), 1000), scale(self.ss.get_metric_value('mem.util.bufmem'), 1000), scale(self.ss.get_metric_value('mem.util.cached'), 1000), scale(self.ss.get_metric_value('mem.util.inactive'), 1000), scale(self.ss.get_metric_value('mem.util.slab'), 1000), scale(self.ss.get_metric_value('mem.util.mapped'), 1000)), def print_verbose(self): print "%8dM %6dM %6dM %6dM %6dM %6dM %6dM %6dM %6dM %6dM %5dM %5dM %5dM %5dM %6d %6d %6d %6d %6d %6d " % ( scale(self.ss.get_metric_value('mem.physmem'), 1000), scale(self.ss.get_metric_value('mem.util.used'), 1000), scale(self.ss.get_metric_value('mem.freemem'), 1000), scale(self.ss.get_metric_value('mem.util.bufmem'), 1000), scale(self.ss.get_metric_value('mem.util.cached'), 1000), scale(self.ss.get_metric_value('mem.util.slab'), 1000), scale(self.ss.get_metric_value('mem.util.mapped'), 1000), scale(self.ss.get_metric_value('mem.util.anonpages'), 1000), scale(self.ss.get_metric_value('mem.util.committed_AS'), 1000), scale(self.ss.get_metric_value('mem.util.mlocked'), 1000), scale(self.ss.get_metric_value('mem.util.inactive'), 1000), scale(self.ss.get_metric_value('mem.util.swapTotal'), 1000), scale(self.ss.get_metric_value('swap.used'), 1000), scale(self.ss.get_metric_value('swap.free'), 1000), scale(self.ss.get_metric_value('swap.pagesin'), 1000), scale(self.ss.get_metric_value('swap.pagesout'), 1000), scale(self.ss.get_metric_value('mem.vmstat.pgfault') - self.ss.get_metric_value('mem.vmstat.pgmajfault'), 1000), scale(self.ss.get_metric_value('mem.vmstat.pgmajfault'), 1000), scale(self.ss.get_metric_value('mem.vmstat.pgpgin'), 1000), scale(self.ss.get_metric_value('mem.vmstat.pgpgout'), 1000)) # _netCollectPrint -------------------------------------------------- class _netCollectPrint(_CollectPrint): def print_header1_brief(self): print '<----------Network--------->', def print_header1_detail(self): print '# NETWORK STATISTICS (/sec)' def print_header1_verbose(self): print '\n\n# NETWORK SUMMARY (/sec)' def print_header2_brief(self): print ' KBIn PktIn KBOut PktOut', def print_header2_detail(self): print '#Num Name KBIn PktIn SizeIn MultI CmpI ErrsI KBOut PktOut SizeO CmpO ErrsO' def print_header2_verbose(self): print '# KBIn PktIn SizeIn MultI CmpI ErrsI KBOut PktOut SizeO CmpO ErrsO' def print_brief(self): print "%5d %6d %6d %6d" % ( sum(self.ss.get_metric_value('network.interface.in.bytes')) / 1024, sum(self.ss.get_metric_value('network.interface.in.packets')), sum(self.ss.get_metric_value('network.interface.out.bytes')) / 1024, sum(self.ss.get_metric_value('network.interface.out.packets'))), def average_packet_size(self, bytes, packets): # calculate mean packet size safely (note that divisor may be zero) result = 0 bin = sum(self.ss.get_metric_value('network.interface.' + bytes)) pin = sum(self.ss.get_metric_value('network.interface.' + packets)) if pin > 0: result = bin / pin return result def print_verbose(self): # don't include loopback; TODO: pmDelProfile would be more appropriate self.ss.get_metric_value('network.interface.in.bytes')[0] = 0 self.ss.get_metric_value('network.interface.out.bytes')[0] = 0 print '%6d %5d %6d %6d %6d %6d %6d %6d %6d %6d %7d' % ( sum(self.ss.get_metric_value('network.interface.in.bytes')) / 1024, sum(self.ss.get_metric_value('network.interface.in.packets')), self.average_packet_size('in.bytes', 'in.packets'), sum(self.ss.get_metric_value('network.interface.in.mcasts')), sum(self.ss.get_metric_value('network.interface.in.compressed')), sum(self.ss.get_metric_value('network.interface.in.errors')), sum(self.ss.get_metric_value('network.interface.out.bytes')) / 1024, sum(self.ss.get_metric_value('network.interface.out.packets')), self.average_packet_size('out.bytes', 'out.packets'), sum(self.ss.get_metric_value('network.interface.total.mcasts')), sum(self.ss.get_metric_value('network.interface.out.errors'))) def print_detail(self): for j in xrange(len(self.ss.metric_pmids)): try: (inst, iname) = pm.pmGetInDom(self.ss.metric_descs[j]) break except pmapi.pmErr, e: # pylint: disable-msg=C0103 iname = "X" for j in xrange(len(self.ss.get_metric_value('network.interface.in.bytes'))): print '%4d %-7s %6d %5d %6d %6d %6d %6d %6d %6d %6d %6d %7d' % ( j, iname[j], self.ss.get_metric_value('network.interface.in.bytes')[j] / 1024, self.ss.get_metric_value('network.interface.in.packets')[j], self.divide_check (self.ss.get_metric_value('network.interface.in.bytes')[j], self.ss.get_metric_value('network.interface.in.packets')[j]), self.ss.get_metric_value('network.interface.in.mcasts')[j], self.ss.get_metric_value('network.interface.in.compressed')[j], self.ss.get_metric_value('network.interface.in.errors')[j], self.ss.get_metric_value('network.interface.in.packets')[j], self.ss.get_metric_value('network.interface.out.packets')[j], self.divide_check (self.ss.get_metric_value('network.interface.in.packets')[j], self.ss.get_metric_value('network.interface.out.packets')[j]) / 1024, self.ss.get_metric_value('network.interface.total.mcasts')[j], self.ss.get_metric_value( 'network.interface.out.compressed')[j]) # main ----------------------------------------------------------------- # ignore These are actually global names; ignore invalid name warning for now # TODO move main into a def and enable # pylint: disable-msg=C0103 if __name__ == '__main__': n_samples = 0 subsys = list() verbosity = "brief" output_file = "" input_file = "" duration = 0 interval_arg = 1 duration_arg = 0 create_archive = False replay_archive = False host = "" ss = Subsystem() ss.init_processor_metrics() ss.init_interrupt_metrics() ss.init_disk_metrics() ss.init_memory_metrics() ss.init_network_metrics() cpu = _cpuCollectPrint(ss) interrupt = _interruptCollectPrint(ss) disk = _diskCollectPrint(ss) memory = _memoryCollectPrint(ss) net = _netCollectPrint(ss) s_options = {"d":[disk, "brief"], "D":[disk, "detail"], "c":[cpu, "brief"], "C":[cpu, "detail"], "n":[net, "brief"], "N":[net, "detail"], "j":[interrupt, "brief"], "J":[interrupt, "detail"], # "b":[ss, "brief"], # "B":[ss, "detail"], "m":[memory, "brief"], # "M":[ss, "detail"], # "f":[ss, "brief"], "F":[ss, "detail"], # "y":[ss, "brief"], "Y":[ss, "detail"], # "z":[ss, "detail"], "Z":[ss, "detail"] } argx = 1 while argx < len(sys.argv): if (sys.argv[argx] == "-c" or sys.argv[argx] == "--count"): argx += 1 n_samples = int(sys.argv[argx]) elif (sys.argv[argx][:2] == "-c"): n_samples = int(sys.argv[argx][2:]) elif (sys.argv[argx] == "-f" or sys.argv[argx] == "--filename"): argx += 1 output_file = sys.argv[argx] create_archive = True elif (sys.argv[argx] == "-p" or sys.argv[argx] == "--playback"): argx += 1 input_file = sys.argv[argx] replay_archive = True elif (sys.argv[argx] == "-R" or sys.argv[argx] == "--runtime"): argx += 1 duration_arg = sys.argv[argx] elif (sys.argv[argx] == "-i" or sys.argv[argx] == "--interval"): argx += 1 interval_arg = sys.argv[argx] # TODO: --subsys XYZ elif (sys.argv[argx][:2] == "-s"): for ssx in xrange(len(sys.argv[argx][2:])): subsys_arg = sys.argv[argx][ssx+2:ssx+3] try: subsys.append(s_options[subsys_arg][0]) except KeyError: print sys.argv[0] + \ ": Unimplemented subsystem -s" + subsys_arg sys.exit(1) if subsys_arg.isupper(): verbosity = s_options[subsys_arg][1] elif (sys.argv[argx] == "--verbose"): if verbosity != "detail": verbosity = "verbose" elif (sys.argv[argx] == "--help"): usage() sys.exit(1) elif (sys.argv[argx] == "-h"): argx += 1 host = sys.argv[argx] elif (sys.argv[argx][:1] == "-"): print sys.argv[0] + ": Unknown option ", sys.argv[argx] print "Try `" + sys.argv[0] + " --help' for more information." sys.exit(1) argx += 1 if len(subsys) == 0: if create_archive: map( subsys.append, (cpu, disk, net, interrupt, memory)) else: map( subsys.append, (cpu, disk, net) ) if replay_archive: archive = input_file if not os.path.exists(input_file): print input_file, "does not exist" sys.exit(1) for line in open(input_file): if (line[:8] == "Archive:"): tokens = line[:-1].split() archive = os.path.join(os.path.dirname(input_file), tokens[2]) try: pm = pmapi.pmContext(c_api.PM_CONTEXT_ARCHIVE, archive) except pmapi.pmErr, e: print "Cannot open PCP archive: %s" % archive sys.exit(1) else: if host == "": host = "local:" try: pm = pmapi.pmContext(target=host) except pmapi.pmErr, e: print "Cannot connect to pmcd on " + host sys.exit(1) # Find server-side pmcd host-name host = pm.pmGetContextHostName() if duration_arg != 0: (code, timeval, errmsg) = pm.pmParseInterval(duration_arg) if code < 0: print errmsg sys.exit(1) duration = timeval.tv_sec (delta, errmsg) = pm.pmParseInterval(str(interval_arg) + " seconds") if create_archive: configuration = "log mandatory on every " + \ str(interval_arg) + " seconds { " configuration += ss.dump_metrics() configuration += "}" if duration == 0: if n_samples != 0: duration = n_samples * interval_arg else: duration = 10 * interval_arg record (pmgui.GuiClient(), configuration, duration, output_file, host) record_add_creator (output_file) sys.exit(0) try: ss.setup_metrics(pm) ss.get_stats(pm) except pmapi.pmErr, e: if replay_archive: import textwrap print str(cpu.metrics) print "One of the following metrics is required " + \ "but absent in " + input_file + "\n" + \ textwrap.fill(str(metrics)) else: print "unable to setup metrics" sys.exit(1) for ssx in subsys: ssx.set_verbosity(verbosity) # brief headings for different subsystems are concatenated together if verbosity == "brief": for ssx in subsys: if ssx == 0: continue ssx.print_header1() print for ssx in subsys: if ssx == 0: continue ssx.print_header2() print try: i_samples = 0 while (i_samples < n_samples) or (n_samples == 0): pm.pmtimevalSleep(delta) if verbosity != "brief" and len(subsys) > 1: print "\n### RECORD %d >>> %s <<< %s ###" % \ (i_samples+1, host, time.strftime("%a %b %d %H:%M:%S %Y")) try: ss.get_stats(pm) ss.get_total() except pmapi.pmErr, e: if str(e).find("PM_ERR_EOL") != -1: print str(e) sys.exit(1) for ssx in subsys: if ssx == 0: continue if verbosity != "brief" and (len(subsys) > 1 or i_samples == 0): print ssx.print_header1() ssx.print_header2() ssx.print_line() if verbosity == "brief": print i_samples += 1 except KeyboardInterrupt: True # pylint: disable-msg=W0104 pcp-3.8.12ubuntu1/src/pmdate/0000775000000000000000000000000012272262620012645 5ustar pcp-3.8.12ubuntu1/src/pmdate/pmdate.c0000664000000000000000000000654412272262501014272 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Display offset date */ #include "pmapi.h" #include "impl.h" #define usage "Usage: pmdate { +valueS | -valueS } ... format\n\ \n\ where the scale \"S\" is one of: S (seconds), M (minutes), H (hours), \n\ d (days), m (months) or y (years)\n" int main(int argc, char *argv[]) { time_t now; int need; char *buf; char *p; char *pend; struct tm *tmp; int sgn; int val; int mo_delta = 0; int yr_delta = 0; __pmSetProgname(argv[0]); if (argc < 2) { fprintf(stderr, usage); exit(1); } if (strcmp(argv[1], "-?") == 0) { fprintf(stderr, usage); exit(1); } time(&now); while (argc > 2) { p = argv[1]; if (*p == '+') sgn = 1; else if (*p == '-') sgn = -1; else { fprintf(stderr, "%s: incorrect leading sign for offset (%s), must be \"+\" or \"-\"\n", pmProgname, argv[1]); exit(1); } p++; val = (int)strtol(p, &pend, 10); switch (*pend) { case 'S': now += sgn * val; break; case 'M': now += sgn * val * 60; break; case 'H': now += sgn * val * 60 * 60; break; case 'd': now += sgn * val * 24 * 60 * 60; break; case 'm': mo_delta += sgn*val; break; case 'y': yr_delta += sgn*val; break; case '\0': fprintf(stderr, "%s: missing scale after offset (%s)\n", pmProgname, argv[1]); exit(1); case '?': fprintf(stderr, usage); exit (1); default: fprintf(stderr, "%s: unknown scale after offset (%s)\n", pmProgname, argv[1]); exit(1); } argv++; argc--; } tmp = localtime(&now); if (yr_delta) { /* * tm_year is years since 1900 and yr_delta is relative (not * absolute), so this is Y2K safe */ tmp->tm_year += yr_delta; } if (mo_delta) { /* * tm_year is years since 1900 and the tm_year-- and * tm_year++ is adjusting for underflow and overflow in * tm_mon as a result of relative month delta, so this * is Y2K safe */ tmp->tm_mon += mo_delta; while (tmp->tm_mon < 0) { tmp->tm_mon += 12; tmp->tm_year--; } while (tmp->tm_mon > 12) { tmp->tm_mon -= 12; tmp->tm_year++; } } /* * Note: 256 is _more_ than enough to accommodate the longest * value for _every_ %? lexicon that strftime() understands */ need = strlen(argv[1]) + 256; if ((buf = (char *)malloc(need)) == NULL) { fprintf(stderr, "%s: malloc failed\n", pmProgname); exit(1); } if (strftime(buf, need, argv[1], tmp) == 0) { fprintf(stderr, "%s: format too long\n", pmProgname); exit(1); } else { buf[need-1] = '\0'; printf("%s\n", buf); exit(0); } } pcp-3.8.12ubuntu1/src/pmdate/GNUmakefile0000664000000000000000000000154212272262501014717 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmdate.c LLDLIBS = $(PCPLIB) CMDTARGET = pmdate$(EXECSUFFIX) default: $(CMDTARGET) include $(BUILDRULES) install: default $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/bashrc/0000775000000000000000000000000012272262617012643 5ustar pcp-3.8.12ubuntu1/src/bashrc/pcp_completion.sh0000664000000000000000000000326512272262501016210 0ustar # Programmable completion for Performance Co-Pilot commands under bash. # Author: Roman Revyakin (Roman), rrevyakin@aconex.com _pminfo_complete () { local cur=${COMP_WORDS[$COMP_CWORD]} local opt_regex= curpos_expand= COMPREPLY=() # Options that need no completion and the cursor position to start # expansion from for different programs case ${COMP_WORDS[0]} in pminfo) opt_regex="-[abhnOZ]" curpos_expand=1 ;; pmprobe) opt_regex="-[ahnOZ]" curpos_expand=1 ;; pmdumptext) opt_regex="-[AacdfhnOPRsStTUwZ]" curpos_expand=1 ;; pmdumplog) opt_regex="-[nSTZ]" curpos_expand=1 ;; pmlogsummary) opt_regex="-[BnpSTZ]" curpos_expand=2 ;; pmstore) opt_regex="-[hin]" curpos_expand=1 ;; pmval) opt_regex="-[AafhinOpSsTtwZ]" curpos_expand=1 ;; pmevent) opt_regex="-[ahKOpSsTtZ]" curpos_expand=1 ;; esac # --- end of case --- # We expand either straight from the cursor if it is at the position to # expand or check for the preceding options whether to expand or not if (( $COMP_CWORD == $curpos_expand )) || \ ( (( $COMP_CWORD > $curpos_expand )) \ && ! [[ "${COMP_WORDS[$((COMP_CWORD-1))]}" =~ $opt_regex ]] ) then COMPREPLY=(`compgen -W '$(command pminfo)' 2>/dev/null $cur`) fi } # ---------- end of function _pminfo_complete ---------- complete -F _pminfo_complete -o default pminfo pmprobe pmdumptext pmdumplog pmlogsummary pmstore pmval pmevent pcp-3.8.12ubuntu1/src/bashrc/GNUmakefile0000664000000000000000000000155312272262501014711 0ustar # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs BASHRC = pcp_completion.sh BASHDIR = $(PCP_ETC_DIR)/bash_completion.d LSRCFILES = $(BASHRC) default: $(BASHRC) include $(BUILDRULES) install: default $(INSTALL) -d $(BASHDIR) $(INSTALL) -m 644 $(BASHRC) $(BASHDIR)/pcp default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmproxy/0000775000000000000000000000000012272262620013111 5ustar pcp-3.8.12ubuntu1/src/pmproxy/rc_pmproxy0000664000000000000000000001576612272262521015255 0ustar #! /bin/sh # # Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Start or Stop the Performance Co-Pilot (PCP) proxy daemon for pmcd # # The following is for chkconfig on RedHat based systems # chkconfig: 2345 95 05 # description: pmproxy is the pmcd proxy daemon for the Performance Co-Pilot (PCP) # # The following is for insserv(1) based systems, # e.g. SuSE, where chkconfig is a perl script. ### BEGIN INIT INFO # Provides: pmproxy # Required-Start: $remote_fs # Should-Start: $local_fs $network $syslog $time $pmcd # Required-Stop: $remote_fs # Should-Stop: $local_fs $network $syslog $pmcd # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Control pmproxy (the pmcd proxy daemon for PCP) # Description: Configure and control pmproxy (the pmcd proxy daemon for the Performance Co-Pilot) ### END INIT INFO . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/rc-proc.sh PMPROXY=$PCP_BINADM_DIR/pmproxy PMPROXYOPTS=$PCP_PMPROXYOPTIONS_PATH RUNDIR=$PCP_LOG_DIR/pmproxy pmprog=$PCP_RC_DIR/pmproxy prog=$PCP_RC_DIR/`basename $0` tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1 status=1 trap "rm -rf $tmp; exit \$status" 0 1 2 3 15 if [ $pmprog = $prog ] then VERBOSE_CTL=on else VERBOSE_CTL=off fi case "$PCP_PLATFORM" in mingw) # nothing we can usefully do here, skip the test # ;; *) # standard Unix/Linux style test # ID=id test -f /usr/xpg4/bin/id && ID=/usr/xpg4/bin/id IAM=`$ID -u 2>/dev/null` if [ -z "$IAM" ] then # do it the hardway # IAM=`$ID | sed -e 's/.*uid=//' -e 's/(.*//'` fi ;; esac _shutdown() { # Is pmproxy running? # _get_pids_by_name pmproxy >$tmp/tmp if [ ! -s $tmp/tmp ] then [ "$1" = verbose ] && echo "$pmprog: pmproxy not running" return 0 fi # Send pmproxy a SIGTERM, which is noted as a pending shutdown. # When finished the currently active request, pmproxy will close any # connections and then exit. # Wait for pmproxy to terminate. # pmsignal -a -s TERM pmproxy > /dev/null 2>&1 $ECHO $PCP_ECHO_N "Waiting for pmproxy to terminate ...""$PCP_ECHO_C" gone=0 for i in 1 2 3 4 5 6 do sleep 3 _get_pids_by_name pmproxy >$tmp/tmp if [ ! -s $tmp/tmp ] then gone=1 break fi # If pmproxy doesn't go in 15 seconds, SIGKILL and sleep 1 more time # to allow any clients reading from pmproxy sockets to fail so that # socket doesn't end up in TIME_WAIT or somesuch. # if [ $i = 5 ] then $ECHO echo "Process ..." $PCP_PS_PROG $PCP_PS_ALL_FLAGS >$tmp/ps sed 1q $tmp/ps for pid in `cat $tmp/tmp` do $PCP_AWK_PROG <$tmp/ps "\$2 == $pid { print }" done echo "$prog: Warning: Forcing pmproxy to terminate!" pmsignal -a -s KILL pmproxy > /dev/null 2>&1 else $ECHO $PCP_ECHO_N ".""$PCP_ECHO_C" fi done if [ $gone != 1 ] # It just WON'T DIE, give up. then echo "Process ..." cat $tmp/tmp echo "$prog: Warning: pmproxy won't die!" exit fi $RC_STATUS -v $PCP_BINADM_DIR/pmpost "stop pmproxy from $pmprog" } _usage() { echo "Usage: $pmprog [-v] {start|restart|condrestart|stop|status|reload|force-reload}" } while getopts v c do case $c in v) # force verbose VERBOSE_CTL=on ;; *) _usage exit 1 ;; esac done shift `expr $OPTIND - 1` if [ $VERBOSE_CTL = on ] then # For a verbose startup and shutdown ECHO=$PCP_ECHO_PROG else # For a quiet startup and shutdown ECHO=: fi if [ "$IAM" != 0 -a "$1" != "status" ] then if [ -n "$PCP_DIR" ] then : running in a non-default installation, do not need to be root else echo "$prog:"' Error: You must be root (uid 0) to start or stop the PCP pmproxy daemon.' exit fi fi # First reset status of this service $RC_RESET # Return values acc. to LSB for all commands but status: # 0 - success # 1 - misc error # 2 - invalid or excess args # 3 - unimplemented feature (e.g. reload) # 4 - insufficient privilege # 5 - program not installed # 6 - program not configured # # Note that starting an already running service, stopping # or restarting a not-running service as well as the restart # with force-reload (in case signalling is not supported) are # considered a success. case "$1" in 'start'|'restart'|'condrestart'|'reload'|'force-reload') if [ "$1" = "condrestart" ] && ! is_chkconfig_on pmproxy then status=0 exit fi _shutdown quietly # pmproxy messages should go to stderr, not the GUI notifiers # unset PCP_STDERR if [ -x $PMPROXY ] then if [ ! -f $PCP_PMPROXYCONF_PATH ] then echo "$prog:"' Error: pmproxy control file "$PCP_PMPROXYCONF_PATH" is missing, cannot start pmproxy.' exit fi if [ ! -d "$RUNDIR" ] then mkdir -p -m 775 "$RUNDIR" chown $PCP_USER:$PCP_GROUP "$RUNDIR" fi cd $RUNDIR # salvage the previous versions of any pmproxy # if [ -f pmproxy.log ] then rm -f pmproxylog.log.prev mv pmproxy.log pmproxy.log.prev fi $ECHO $PCP_ECHO_N "Starting pmproxy ..." "$PCP_ECHO_C" # options file processing ... # only consider lines which start with a hyphen # get rid of the -f option # ensure multiple lines concat onto 1 line OPTS=`sed <$PMPROXYOPTS 2>/dev/null \ -e '/^[^-]/d' \ -e 's/^/ /' \ -e 's/$/ /' \ -e 's/ -f / /g' \ -e 's/^ //' \ -e 's/ $//' \ | tr '\012' ' ' ` # environment stuff # eval `sed -e 's/"/\\"/g' $PMPROXYOPTS \ | awk -F= ' BEGIN { exports="" } /^[A-Z]/ && NF == 2 { exports=exports" "$1 printf "%s=${%s:-\"%s\"}\n", $1, $1, $2 } END { if (exports != "") print "export", exports }'` $PMPROXY $OPTS $RC_STATUS -v $PCP_BINADM_DIR/pmpost "start pmproxy from $pmprog" fi status=0 ;; 'stop') _shutdown status=0 ;; 'status') # NOTE: $RC_CHECKPROC returns LSB compliant status values. $ECHO $PCP_ECHO_N "Checking for pmproxy:" "$PCP_ECHO_C" if [ -r /etc/rc.status ] then # SuSE $RC_CHECKPROC $PMPROXY $RC_STATUS -v status=$? else # not SuSE $RC_CHECKPROC $PMPROXY status=$? if [ $status -eq 0 ] then $ECHO running else $ECHO stopped fi fi ;; *) _usage ;; esac pcp-3.8.12ubuntu1/src/pmproxy/util.c0000664000000000000000000000514612272262501014236 0ustar /* * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2009 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmproxy.h" #ifdef IS_MINGW void StartDaemon(int argc, char **argv) { PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; LPTSTR cmdline = NULL; int i, sz = 3; /* -f\0 */ for (i = 0; i < argc; i++) sz += strlen(argv[i]) + 1; if ((cmdline = malloc(sz)) == NULL) { __pmNotifyErr(LOG_ERR, "StartDaemon: no memory"); exit(1); } for (sz = i = 0; i < argc; i++) sz += sprintf(cmdline, "%s ", argv[i]); sprintf(cmdline + sz, "-f"); ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); if (0 == CreateProcess( NULL, cmdline, NULL, NULL, /* process and thread attributes */ FALSE, /* inherit handles */ CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, /* environment (from parent) */ NULL, /* current directory */ &siStartInfo, /* STARTUPINFO pointer */ &piProcInfo)) { /* receives PROCESS_INFORMATION */ __pmNotifyErr(LOG_ERR, "StartDaemon: CreateProcess"); /* but keep going */ } else { /* parent, let her exit, but avoid ugly "Log finished" messages */ fclose(stderr); exit(0); } } #else /* Based on Stevens (Unix Network Programming, p.83) */ void StartDaemon(int argc, char **argv) { int childpid; (void)argc; (void)argv; #if defined(HAVE_TERMIO_SIGNALS) signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTSTP, SIG_IGN); #endif if ((childpid = fork()) < 0) __pmNotifyErr(LOG_ERR, "StartDaemon: fork"); /* but keep going */ else if (childpid > 0) { /* parent, let her exit, but avoid ugly "Log finished" messages */ fclose(stderr); exit(0); } /* not a process group leader, lose controlling tty */ if (setsid() == -1) __pmNotifyErr(LOG_WARNING, "StartDaemon: setsid"); /* but keep going */ close(0); /* don't close other fd's -- we know that only good ones are open! */ /* don't chdir("/") -- we still need to open pmcd.log */ } #endif pcp-3.8.12ubuntu1/src/pmproxy/client.c0000664000000000000000000001511512272262501014534 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmproxy.h" #define MIN_CLIENTS_ALLOC 8 ClientInfo *client; int nClients; /* Number in array, (not all in use) */ int maxReqPortFd; /* highest request port fd */ int maxSockFd; /* largest fd for a client */ __pmFdSet sockFds; /* for client select() */ static int NewClient(void) { int i; static int clientSize; for (i = 0; i < nClients; i++) if (!client[i].status.connected) break; if (i == clientSize) { int j, sz; clientSize = clientSize ? clientSize * 2 : MIN_CLIENTS_ALLOC; sz = sizeof(ClientInfo) * clientSize; client = (ClientInfo *) realloc(client, sz); if (client == NULL) { __pmNoMem("NewClient", sz, PM_RECOV_ERR); Shutdown(); exit(1); } for (j = i; j < clientSize; j++) { client[j].addr = NULL; } } client[i].addr = __pmSockAddrAlloc(); if (client[i].addr == NULL) { __pmNoMem("NewClient", __pmSockAddrSize(), PM_RECOV_ERR); Shutdown(); exit(1); } if (i >= nClients) nClients = i + 1; return i; } /* MY_BUFLEN needs to big enough to hold "hostname port" */ #define MY_BUFLEN (MAXHOSTNAMELEN+10) #define MY_VERSION "pmproxy-server 1\n" /* Establish a new socket connection to a client */ ClientInfo * AcceptNewClient(int reqfd) { int i; int fd; __pmSockLen addrlen; int ok = 0; char buf[MY_BUFLEN]; char *bp; char *endp; char *abufp; i = NewClient(); addrlen = __pmSockAddrSize(); fd = __pmAccept(reqfd, client[i].addr, &addrlen); if (fd == -1) { __pmNotifyErr(LOG_ERR, "AcceptNewClient(%d) __pmAccept failed: %s", reqfd, netstrerror()); Shutdown(); exit(1); } __pmSetSocketIPC(fd); if (fd > maxSockFd) maxSockFd = fd; __pmFD_SET(fd, &sockFds); client[i].fd = fd; client[i].pmcd_fd = -1; client[i].status.connected = 1; client[i].pmcd_hostname = NULL; /* * version negotiation (converse to negotiate_proxy() logic in * libpcp * * __pmRecv client version message * __pmSend my server version message * __pmRecv pmcd hostname and pmcd port */ for (bp = buf; bp < &buf[MY_BUFLEN]; bp++) { if (__pmRecv(fd, bp, 1, 0) != 1) { *bp = '\0'; /* null terminate what we have */ bp = &buf[MY_BUFLEN]; /* flag error */ break; } /* end of line means no more ... */ if (*bp == '\n' || *bp == '\r') { *bp = '\0'; break; } } if (bp < &buf[MY_BUFLEN]) { /* looks OK so far ... is this a version we can support? */ if (strcmp(buf, "pmproxy-client 1") == 0) { client[i].version = 1; ok = 1; } } if (!ok) { abufp = __pmSockAddrToString(client[i].addr); __pmNotifyErr(LOG_WARNING, "Bad version string from client at %s", abufp); free(abufp); fprintf(stderr, "AcceptNewClient: bad version string was \""); for (bp = buf; *bp && bp < &buf[MY_BUFLEN]; bp++) fputc(*bp & 0xff, stderr); fprintf(stderr, "\"\n"); DeleteClient(&client[i]); return NULL; } if (__pmSend(fd, MY_VERSION, strlen(MY_VERSION), 0) != strlen(MY_VERSION)) { abufp = __pmSockAddrToString(client[i].addr); __pmNotifyErr(LOG_WARNING, "AcceptNewClient: failed to send version " "string (%s) to client at %s\n", MY_VERSION, abufp); free(abufp); DeleteClient(&client[i]); return NULL; } for (bp = buf; bp < &buf[MY_BUFLEN]; bp++) { if (__pmRecv(fd, bp, 1, 0) != 1) { *bp = '\0'; /* null terminate what we have */ bp = &buf[MY_BUFLEN]; /* flag error */ break; } /* end of line means no more ... */ if (*bp == '\n' || *bp == '\r') { *bp = '\0'; break; } } if (bp < &buf[MY_BUFLEN]) { /* looks OK so far ... get hostname and port */ for (bp = buf; *bp && *bp != ' '; bp++) ; if (bp != buf) { *bp = '\0'; client[i].pmcd_hostname = strdup(buf); if (client[i].pmcd_hostname == NULL) __pmNoMem("PMCD.hostname", strlen(buf), PM_FATAL_ERR); bp++; client[i].pmcd_port = (int)strtoul(bp, &endp, 10); if (*endp != '\0') { abufp = __pmSockAddrToString(client[i].addr); __pmNotifyErr(LOG_WARNING, "AcceptNewClient: bad pmcd port " "\"%s\" from client at %s", bp, abufp); free(abufp); DeleteClient(&client[i]); return NULL; } } /* error, fall through */ } if (client[i].pmcd_hostname == NULL) { abufp = __pmSockAddrToString(client[i].addr); __pmNotifyErr(LOG_WARNING, "AcceptNewClient: failed to get PMCD " "hostname (%s) from client at %s", buf, abufp); free(abufp); DeleteClient(&client[i]); return NULL; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) { /* * note error message gets appended to once pmcd connection is * made in ClientLoop() */ abufp = __pmSockAddrToString(client[i].addr); fprintf(stderr, "AcceptNewClient [%d] fd=%d from %s to %s (port %s)", i, fd, abufp, client[i].pmcd_hostname, bp); free(abufp); } #endif return &client[i]; } void DeleteClient(ClientInfo *cp) { int i; for (i = 0; i < nClients; i++) if (cp == &client[i]) break; if (i == nClients) { fprintf(stderr, "DeleteClient: Botch: tried to delete non-existent client @" PRINTF_P_PFX "%p\n", cp); return; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) fprintf(stderr, "DeleteClient [%d]\n", i); #endif if (cp->fd >= 0) { __pmFD_CLR(cp->fd, &sockFds); __pmCloseSocket(cp->fd); } if (cp->pmcd_fd >= 0) { __pmFD_CLR(cp->pmcd_fd, &sockFds); __pmCloseSocket(cp->pmcd_fd); } if (i == nClients-1) { i--; while (i >= 0 && !client[i].status.connected) i--; nClients = (i >= 0) ? i + 1 : 0; } if (cp->fd == maxSockFd || cp->pmcd_fd == maxSockFd) { maxSockFd = maxReqPortFd; for (i = 0; i < nClients; i++) { if (cp->status.connected == 0) continue; if (client[i].fd > maxSockFd) maxSockFd = client[i].fd; if (client[i].pmcd_fd > maxSockFd) maxSockFd = client[i].pmcd_fd; } } __pmSockAddrFree(cp->addr); cp->addr = NULL; cp->status.connected = 0; cp->fd = -1; cp->pmcd_fd = -1; if (cp->pmcd_hostname != NULL) { free(cp->pmcd_hostname); cp->pmcd_hostname = NULL; } } pcp-3.8.12ubuntu1/src/pmproxy/GNUmakefile0000664000000000000000000000242312272262501015162 0ustar # # Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CMDTARGET = pmproxy$(EXECSUFFIX) HFILES = pmproxy.h CFILES = pmproxy.c client.c util.c LSRCFILES = rc_pmproxy pmproxy.options LLDLIBS = $(PCPLIB) LDIRT += pmproxy.log LCFLAGS += $(PIECFLAGS) LLDFLAGS += $(PIELDFLAGS) default: $(CMDTARGET) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d `dirname $(PCP_PMPROXYOPTIONS_PATH)` $(INSTALL) -m 644 pmproxy.options $(PCP_PMPROXYOPTIONS_PATH) $(INSTALL) -m 755 rc_pmproxy $(PCP_RC_DIR)/pmproxy $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BINADM_DIR)/$(CMDTARGET) $(INSTALL) -m 775 -o $(PCP_USER) -g $(PCP_USER) -d $(PCP_LOG_DIR)/pmproxy default_pcp : default install_pcp : install pmproxy.o client.o: pmproxy.h pcp-3.8.12ubuntu1/src/pmproxy/pmproxy.options0000664000000000000000000000141012272262501016236 0ustar # command-line options and environment variables for pmproxy # uncomment/edit lines as required # run in the foreground # -f # restrict PCP monitoring client connections to these interfaces # -i gateway-public-0.foo.bar.com # -i gateway-public-1.foo.bar.com # make log go someplace else # -l /some/place/else # maximum incoming PDU size (default 64KB) # -L 16384 # assume identity of some user other than "pcp" # -U nobody # emergency messages before logfile created # -x /tmp/desperate.log # setting of environment variables for pmproxy # port for incomining connections from PCP monitoring clients # PMPROXY_PORT=44322 # timeouts for interactions with pmcd on behalf of clients # PMCD_CONNECT_TIMEOUT=10 # PMCD_RECONNECT_TIMEOUT=10,20,30 # PMCD_REQUEST_TIMEOUT=10 pcp-3.8.12ubuntu1/src/pmproxy/pmproxy.h0000664000000000000000000000327612272262501015006 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _PROXY_H #define _PROXY_H #include "pmapi.h" #include "impl.h" /* The table of clients, used by pmproxy */ typedef struct { int fd; /* client socket descriptor */ int version; /* proxy-client protocol version */ struct { /* Status of connection to client */ unsigned int connected : 1; /* Client connected, socket level */ unsigned int allowed : 1; /* Creds seen, OK to talk to pmcd */ } status; char *pmcd_hostname; /* PMCD hostname */ int pmcd_port; /* PMCD port */ int pmcd_fd; /* PMCD socket file descriptor */ __pmSockAddr *addr; /* address of client */ } ClientInfo; extern ClientInfo *client; /* Array of clients */ extern int nClients; /* Number of entries in array */ extern int maxReqPortFd; /* highest request port fd */ extern int maxSockFd; /* largest fd for a clients * and pmcd connections */ extern __pmFdSet sockFds; /* for select() */ /* prototypes */ extern ClientInfo *AcceptNewClient(int); extern void DeleteClient(ClientInfo *); extern void StartDaemon(int, char **); extern void Shutdown(void); #endif /* _PROXY_H */ pcp-3.8.12ubuntu1/src/pmproxy/pmproxy.c0000664000000000000000000003117412272262501014777 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmproxy.h" #include #ifdef HAVE_PWD_H #include #endif #define MAXPENDING 5 /* maximum number of pending connections */ #define FDNAMELEN 40 /* maximum length of a fd description */ #define STRINGIFY(s) #s #define TO_STRING(s) STRINGIFY(s) #ifdef PCP_DEBUG static char *FdToString(int); #endif static int timeToDie; /* For SIGINT handling */ static char *logfile = "pmproxy.log"; /* log file name */ static int run_daemon = 1; /* run as a daemon, see -f */ static char *fatalfile = "/dev/tty";/* fatal messages at startup go here */ static char *username; static char *certdb; /* certificate DB path (NSS) */ static char *dbpassfile; /* certificate DB password file */ static char *hostname; static void DontStart(void) { FILE *tty; FILE *log; __pmNotifyErr(LOG_ERR, "pmproxy not started due to errors!\n"); if ((tty = fopen(fatalfile, "w")) != NULL) { fflush(stderr); fprintf(tty, "NOTE: pmproxy not started due to errors! "); if ((log = fopen(logfile, "r")) != NULL) { int c; fprintf(tty, "Log file \"%s\" contains ...\n", logfile); while ((c = fgetc(log)) != EOF) fputc(c, tty); fclose(log); } else fprintf(tty, "Log file \"%s\" has vanished!\n", logfile); fclose(tty); } exit(1); } static void ParseOptions(int argc, char *argv[], int *nports) { int c; int sts; int errflag = 0; int usage = 0; int val; while ((c = getopt(argc, argv, "C:D:fi:l:L:p:P:U:x:?")) != EOF) switch (c) { case 'C': /* path to NSS certificate database */ certdb = optarg; break; case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } pmDebug |= sts; break; case 'f': /* foreground, i.e. do _not_ run as a daemon */ run_daemon = 0; break; case 'i': /* one (of possibly several) interfaces for client requests */ __pmServerAddInterface(optarg); break; case 'l': /* log file name */ logfile = optarg; break; case 'L': /* Maximum size for PDUs from clients */ val = (int)strtol (optarg, NULL, 0); if ( val <= 0 ) { fputs ("pmproxy: -L requires a positive value\n", stderr); errflag++; } else { __pmSetPDUCeiling (val); } break; case 'p': if (__pmServerAddPorts(optarg) < 0) { fprintf(stderr, "pmproxy: -p requires a positive numeric argument (%s)\n", optarg); errflag++; } else { *nports += 1; } break; case 'P': /* password file for certificate database access */ dbpassfile = optarg; break; case 'U': /* run as user username */ username = optarg; break; case 'x': fatalfile = optarg; break; case '?': usage = 1; break; default: errflag++; break; } if (usage || errflag || optind < argc) { fprintf(stderr, "Usage: %s [options]\n\n" "Options:\n" " -C dirname path to NSS certificate database\n" " -f run in the foreground\n" " -i ipaddress accept connections on this IP address\n" " -l logfile redirect diagnostics and trace output\n" " -L bytes maximum size for PDUs from clients [default 65536]\n" " -p port accept connections on this port\n" " -P passfile password file for certificate database access\n" " -U username assume identity of username (only when run as root)\n" " -x file fatal messages at startup sent to file [default /dev/tty]\n", pmProgname); if (usage) exit(0); else DontStart(); } } static void CleanupClient(ClientInfo *cp, int sts) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { int i; for (i = 0; i < nClients; i++) { if (cp == &client[i]) break; } fprintf(stderr, "CleanupClient: client[%d] fd=%d %s (%d)\n", i, cp->fd, pmErrStr(sts), sts); } #endif DeleteClient(cp); } static int VerifyClient(ClientInfo *cp, __pmPDU *pb) { int i, sts, flags = 0, sender = 0, credcount = 0; __pmPDUHdr *header = (__pmPDUHdr *)pb; __pmHashCtl attrs = { 0 }; /* TODO */ __pmCred *credlist; /* first check that this is a credentials PDU */ if (header->type != PDU_CREDS) return PM_ERR_IPC; /* now decode it and if secure connection requested, set it up */ if ((sts = __pmDecodeCreds(pb, &sender, &credcount, &credlist)) < 0) return sts; for (i = 0; i < credcount; i++) { if (credlist[i].c_type == CVERSION) { __pmVersionCred *vcp = (__pmVersionCred *)&credlist[i]; flags = vcp->c_flags; break; } } if (credlist != NULL) free(credlist); /* need to ensure both the pmcd and client channel use flags */ if (sts >= 0 && flags) sts = __pmSecureServerHandshake(cp->fd, flags, &attrs); /* send credentials PDU through to pmcd now (order maintained) */ if (sts >= 0) sts = __pmXmitPDU(cp->pmcd_fd, pb); /* finally perform any additional handshaking needed with pmcd */ if (sts >= 0 && flags) sts = __pmSecureClientHandshake(cp->pmcd_fd, flags, hostname, &attrs); return sts; } /* Determine which clients (if any) have sent data to the server and handle it * as required. */ void HandleInput(__pmFdSet *fdsPtr) { int i, sts; __pmPDU *pb; ClientInfo *cp; /* input from clients */ for (i = 0; i < nClients; i++) { if (!client[i].status.connected || !__pmFD_ISSET(client[i].fd, fdsPtr)) continue; cp = &client[i]; sts = __pmGetPDU(cp->fd, LIMIT_SIZE, 0, &pb); if (sts <= 0) { CleanupClient(cp, sts); continue; } /* We *must* see a credentials PDU as the first PDU */ if (!cp->status.allowed) { sts = VerifyClient(cp, pb); __pmUnpinPDUBuf(pb); if (sts < 0) { CleanupClient(cp, sts); continue; } cp->status.allowed = 1; continue; } sts = __pmXmitPDU(cp->pmcd_fd, pb); __pmUnpinPDUBuf(pb); if (sts <= 0) { CleanupClient(cp, sts); continue; } } /* input from pmcds */ for (i = 0; i < nClients; i++) { if (!client[i].status.connected || !__pmFD_ISSET(client[i].pmcd_fd, fdsPtr)) continue; cp = &client[i]; sts = __pmGetPDU(cp->pmcd_fd, ANY_SIZE, 0, &pb); if (sts <= 0) { CleanupClient(cp, sts); continue; } sts = __pmXmitPDU(cp->fd, pb); __pmUnpinPDUBuf(pb); if (sts <= 0) { CleanupClient(cp, sts); continue; } } } /* Called to shutdown pmproxy in an orderly manner */ void Shutdown(void) { int i; for (i = 0; i < nClients; i++) if (client[i].status.connected) __pmCloseSocket(client[i].fd); __pmServerCloseRequestPorts(); __pmSecureServerShutdown(); __pmNotifyErr(LOG_INFO, "pmproxy Shutdown\n"); fflush(stderr); } void SignalShutdown(void) { __pmNotifyErr(LOG_INFO, "pmproxy caught SIGINT or SIGTERM\n"); Shutdown(); exit(0); } static void CheckNewClient(__pmFdSet * fdset, int rfd, int family) { ClientInfo *cp; if (__pmFD_ISSET(rfd, fdset)) { if ((cp = AcceptNewClient(rfd)) == NULL) /* failed to negotiate, already cleaned up */ return; /* establish a new connection to pmcd */ if ((cp->pmcd_fd = __pmAuxConnectPMCDPort(cp->pmcd_hostname, cp->pmcd_port)) < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) /* append to message started in AcceptNewClient() */ fprintf(stderr, " oops!\n" "__pmAuxConnectPMCDPort(%s,%d) failed: %s\n", cp->pmcd_hostname, cp->pmcd_port, pmErrStr(-oserror())); #endif CleanupClient(cp, -oserror()); } else { if (cp->pmcd_fd > maxSockFd) maxSockFd = cp->pmcd_fd; __pmFD_SET(cp->pmcd_fd, &sockFds); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) /* append to message started in AcceptNewClient() */ fprintf(stderr, " fd=%d\n", cp->pmcd_fd); #endif } } } /* Loop, synchronously processing requests from clients. */ static void ClientLoop(void) { int i, sts; int maxFd; __pmFdSet readableFds; for (;;) { /* Figure out which file descriptors to wait for input on. Keep * track of the highest numbered descriptor for the select call. */ readableFds = sockFds; maxFd = maxSockFd + 1; sts = __pmSelectRead(maxFd, &readableFds, NULL); if (sts > 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) for (i = 0; i <= maxSockFd; i++) if (__pmFD_ISSET(i, &readableFds)) fprintf(stderr, "__pmSelectRead(): from %s fd=%d\n", FdToString(i), i); #endif __pmServerAddNewClients(&readableFds, CheckNewClient); HandleInput(&readableFds); } else if (sts == -1 && neterror() != EINTR) { __pmNotifyErr(LOG_ERR, "ClientLoop select: %s\n", netstrerror()); break; } if (timeToDie) { SignalShutdown(); break; } } } static void SigIntProc(int s) { #ifdef IS_MINGW SignalShutdown(); #else signal(SIGINT, SigIntProc); signal(SIGTERM, SigIntProc); timeToDie = 1; #endif } static void SigBad(int sig) { __pmNotifyErr(LOG_ERR, "Unexpected signal %d ...\n", sig); fprintf(stderr, "\nDumping to core ...\n"); fflush(stderr); abort(); } /* * Hostname extracted and cached for later use during protocol negotiations */ static void GetProxyHostname(void) { __pmHostEnt *hep; char host[MAXHOSTNAMELEN]; if (gethostname(host, MAXHOSTNAMELEN) < 0) { __pmNotifyErr(LOG_ERR, "%s: gethostname failure\n", pmProgname); DontStart(); } host[MAXHOSTNAMELEN-1] = '\0'; hep = __pmGetAddrInfo(host); if (hep == NULL) { __pmNotifyErr(LOG_ERR, "%s: __pmGetAddrInfo failure\n", pmProgname); DontStart(); } else { hostname = __pmHostEntGetName(hep); if (!hostname) { /* no reverse DNS lookup for local hostname */ hostname = strdup(host); if (!hostname) /* out of memory, we're having a bad day!?! */ __pmNoMem("PMPROXY.hostname", strlen(host), PM_FATAL_ERR); } __pmHostEntFree(hep); } } int main(int argc, char *argv[]) { int sts; int nport = 0; char *envstr; umask(022); __pmSetProgname(argv[0]); __pmGetUsername(&username); __pmSetInternalState(PM_STATE_PMCS); if ((envstr = getenv("PMPROXY_PORT")) != NULL) nport = __pmServerAddPorts(envstr); ParseOptions(argc, argv, &nport); if (nport == 0) __pmServerAddPorts(TO_STRING(PROXY_PORT)); GetProxyHostname(); if (run_daemon) { fflush(stderr); StartDaemon(argc, argv); } __pmSetSignalHandler(SIGHUP, SIG_IGN); __pmSetSignalHandler(SIGINT, SigIntProc); __pmSetSignalHandler(SIGTERM, SigIntProc); __pmSetSignalHandler(SIGBUS, SigBad); __pmSetSignalHandler(SIGSEGV, SigBad); /* Open request ports for client connections */ if ((sts = __pmServerOpenRequestPorts(&sockFds, MAXPENDING)) < 0) DontStart(); maxReqPortFd = maxSockFd = sts; __pmOpenLog(pmProgname, logfile, stderr, &sts); /* close old stdout, and force stdout into same stream as stderr */ fflush(stdout); close(fileno(stdout)); if (dup(fileno(stderr)) == -1) { fprintf(stderr, "Warning: dup() failed: %s\n", pmErrStr(-oserror())); } fprintf(stderr, "pmproxy: PID = %" FMT_PID, getpid()); fprintf(stderr, ", PDU version = %u\n", PDU_VERSION); __pmServerDumpRequestPorts(stderr); fflush(stderr); /* lose root privileges if we have them */ __pmSetProcessIdentity(username); if (__pmSecureServerSetup(certdb, dbpassfile) < 0) DontStart(); /* all the work is done here */ ClientLoop(); Shutdown(); exit(0); } #ifdef PCP_DEBUG /* Convert a file descriptor to a string describing what it is for. */ static char * FdToString(int fd) { static char fdStr[FDNAMELEN]; static char *stdFds[4] = {"*UNKNOWN FD*", "stdin", "stdout", "stderr"}; int i; if (fd >= -1 && fd < 3) return stdFds[fd + 1]; if (__pmServerRequestPortString(fd, fdStr, FDNAMELEN) != NULL) return fdStr; for (i = 0; i < nClients; i++) { if (client[i].status.connected && fd == client[i].fd) { sprintf(fdStr, "client[%d] client socket", i); return fdStr; } if (client[i].status.connected && fd == client[i].pmcd_fd) { sprintf(fdStr, "client[%d] pmcd socket", i); return fdStr; } } return stdFds[0]; } #endif pcp-3.8.12ubuntu1/src/pmhostname/0000775000000000000000000000000012272262620013546 5ustar pcp-3.8.12ubuntu1/src/pmhostname/GNUmakefile0000664000000000000000000000156212272262501015622 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmhostname.c LLDLIBS = $(PCPLIB) CMDTARGET = pmhostname$(EXECSUFFIX) default: $(CMDTARGET) include $(BUILDRULES) install: $(CMDTARGET) $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BINADM_DIR)/$(CMDTARGET) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmhostname/pmhostname.c0000664000000000000000000000335612272262501016072 0ustar /* * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" static void usage() { fprintf(stderr, "Usage: pmhostname [hostname]\n"); } int main(int argc, char **argv) { char *name, *hename; char host[MAXHOSTNAMELEN]; __pmHostEnt *hep; int c; int sts; int errflag = 0; __pmSetProgname(argv[0]); while ((c = getopt(argc, argv, "D:?")) != EOF) { switch (c) { case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case '?': if (errflag == 0) { usage(); exit(0); } } } if (errflag || argc > optind+1) { usage(); exit(1); } if (argc == optind) { if (gethostname(host, MAXHOSTNAMELEN) < 0) { __pmNotifyErr(LOG_ERR, "%s: gethostname failure\n", pmProgname); exit(1); } name = host; } else name = argv[optind]; hep = __pmGetAddrInfo(name); if (hep == NULL) { printf("%s\n", name); } else { hename = __pmHostEntGetName(hep); printf("%s\n", hename ? hename : name); } exit(0); } pcp-3.8.12ubuntu1/src/procmemstat/0000775000000000000000000000000012272262620013731 5ustar pcp-3.8.12ubuntu1/src/procmemstat/README0000664000000000000000000000151112272262501014605 0ustar procmemstat - a sample client using the PMAPI ============================================= procmemstat is a sample client that uses the Performance Metrics Application Programming Interface (PMAPI) to report its own memory use. The source is shipped as part of pcp.sw.demo and is installed in /var/pcp/demos/procmemstat. If you have the C compiler installed, the source and Makefile in this directory may be used to create a functionally equivalent binary, simply by entering the command % make The source in procmemstat.c demonstrates most of the PMAPI services, and may be used as a template and style guide when creating your own PMAPI clients. Note in particular, the use of ./pmnsmap.spec and the shipped tool pmgenmap to assist in the creation of arguments to the PMAPI routines, and the manipulation of PMAPI data structures. pcp-3.8.12ubuntu1/src/procmemstat/procmemstat.c0000664000000000000000000000757612272262501016450 0ustar /* * procmemstat - sample, simple PMAPI client to report your own memory * usage * * Copyright (c) 2013 Red Hat. * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmnsmap.h" static void get_sample(void) { int first = 1; static pmResult *rp; static int numpmid; static pmID *pmidlist; static pmDesc *desclist; pmUnits kbyte_scale; int pid; pmAtomValue tmp; pmAtomValue atom; int sts; int i; if (first) { memset(&kbyte_scale, 0, sizeof(kbyte_scale)); kbyte_scale.dimSpace = 1; kbyte_scale.scaleSpace = PM_SPACE_KBYTE; numpmid = sizeof(metrics) / sizeof(char *); if ((pmidlist = (pmID *)malloc(numpmid * sizeof(pmidlist[0]))) == NULL) { fprintf(stderr, "%s: get_sample: malloc: %s\n", pmProgname, osstrerror()); exit(1); } if ((desclist = (pmDesc *)malloc(numpmid * sizeof(desclist[0]))) == NULL) { fprintf(stderr, "%s: get_sample: malloc: %s\n", pmProgname, osstrerror()); exit(1); } if ((sts = pmLookupName(numpmid, metrics, pmidlist)) < 0) { printf("%s: pmLookupName: %s\n", pmProgname, pmErrStr(sts)); for (i = 0; i < numpmid; i++) { if (pmidlist[i] == PM_ID_NULL) fprintf(stderr, "%s: metric \"%s\" not in name space\n", pmProgname, metrics[i]); } exit(1); } for (i = 0; i < numpmid; i++) { if ((sts = pmLookupDesc(pmidlist[i], &desclist[i])) < 0) { fprintf(stderr, "%s: cannot retrieve description for metric \"%s\" (PMID: %s)\nReason: %s\n", pmProgname, metrics[i], pmIDStr(pmidlist[i]), pmErrStr(sts)); exit(1); } } /* * All metrics we care about share the same instance domain, * and the instance of interest is _my_ PID */ pmDelProfile(desclist[0].indom, 0, NULL); /* all off */ pid = (int)getpid(); pmAddProfile(desclist[0].indom, 1, &pid); first = 0; } /* fetch the current metrics */ if ((sts = pmFetch(numpmid, pmidlist, &rp)) < 0) { fprintf(stderr, "%s: pmFetch: %s\n", pmProgname, pmErrStr(sts)); exit(1); } printf("memory metrics for pid %" FMT_PID " (sizes in Kbytes)\n", pid); for (i = 0; i < numpmid; i++) { /* process metrics in turn */ pmExtractValue(rp->vset[i]->valfmt, rp->vset[i]->vlist, desclist[i].type, &tmp, PM_TYPE_U32); pmConvScale(PM_TYPE_U32, &tmp, &desclist[i].units, &atom, &kbyte_scale); printf("%8d %s\n", atom.l, metrics[i]); } } int main(int argc, char **argv) { int c; int sts; char *p; char *q; int errflag = 0; __pmSetProgname(argv[0]); setlinebuf(stdout); while ((c = getopt(argc, argv, "D:?")) != EOF) { switch (c) { case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case '?': default: errflag++; break; } } if (errflag || optind < argc-1) { fprintf(stderr, "Usage: %s\n", pmProgname); exit(1); } if ((sts = pmNewContext(PM_CONTEXT_HOST, "local:")) < 0) { fprintf(stderr, "%s: Cannot connect to PMCD on host \"local:\": %s\n", pmProgname, pmErrStr(sts)); exit(1); } get_sample(); #define ARRAY 1*1024*1024 p = (char *)malloc(ARRAY); for (q = p; q < &p[ARRAY]; q += 1024) *q = '\0'; printf("\nAfter malloc ...\n"); get_sample(); exit(0); } pcp-3.8.12ubuntu1/src/procmemstat/GNUmakefile0000664000000000000000000000321212272262501015777 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = procmemstat.c TARGETS = LLDLIBS = $(PCPLIB) LDIRT = pmnsmap.h mylog.* runme.sh $(TARGETS) pmnsmap.i GNUmakefile.install.xxx LSRCFILES = README GNUmakefile.install pmnsmap.spec DEMODIR=$(PCP_DEMOS_DIR)/procmemstat default: $(TARGETS) GNUmakefile.install.xxx include $(BUILDRULES) install: $(TARGETS) $(INSTALL) -m 755 -d $(DEMODIR) $(INSTALL) -m 644 GNUmakefile.install.xxx $(DEMODIR)/Makefile $(INSTALL) -m 644 procmemstat.c README pmnsmap.spec $(DEMODIR) procmemstat.o : pmnsmap.h pmnsmap.h: pmnsmap.spec PCP_CONF=$(TOPDIR)/src/include/pcp.conf; export PCP_CONF; \ sed -e "s;^\. \$PCP_DIR/etc/pcp.env;. $(TOPDIR)/src/include/pcp.env;" \ ../pmgenmap/pmgenmap.sh >runme.sh; \ $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/pmcpp/pmcpp -D$(TARGET_OS) pmnsmap.spec \ | sed -e '/^#/d' -e '/^$$/d' >pmnsmap.i sh ./runme.sh pmnsmap.i >pmnsmap.h GNUmakefile.install.xxx: GNUmakefile.install sed -e "s;;$(PCP_BINADM_DIR)/pmcpp -D$(TARGET_OS);" GNUmakefile.install.xxx default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/procmemstat/GNUmakefile.install0000664000000000000000000000230612272262501017447 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # CFILES = procmemstat.c CFLAGS = -I/usr/include/pcp -DPCP_DEBUG=1 TARGETS = procmemstat LDOPTS = LDLIBS = -lpcp default: $(TARGETS) install: clobber: rm -f $(TARGETS) *.o core a.out pmnsmap.h mylog.* pmnsmap.i procmemstat: procmemstat.c pmnsmap.h rm -f $@ $(CC) $(CFLAGS) procmemstat.c -o $@ $(LDOPTS) $(LDLIBS) pmnsmap.h: pmnsmap.spec pmnsmap.i pmgenmap pmnsmap.i >pmnsmap.h pcp-3.8.12ubuntu1/src/procmemstat/pmnsmap.spec0000664000000000000000000000103412272262501016254 0ustar metrics { #ifdef linux proc.memory.rss RSS_TOTAL proc.memory.textrss RSS_TEXT proc.memory.librss RSS_LIB proc.memory.datrss RSS_DATA #endif #ifdef sgi /* IRIX */ proc.memory.virtual.txt V_TXT proc.memory.virtual.dat V_DAT proc.memory.virtual.bss V_BSS proc.memory.virtual.stack V_STK proc.memory.virtual.shm V_SHM proc.memory.physical.txt P_TXT proc.memory.physical.dat P_DAT proc.memory.physical.bss P_BSS proc.memory.physical.stack P_STK proc.memory.physical.shm P_SHM #endif } pcp-3.8.12ubuntu1/src/GNUmakefile0000664000000000000000000000274012272262501013446 0ustar # # Copyright (c) 2012-2013 Red Hat. # Copyright (c) 2000,2004,2012 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = .. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs SUBDIRS = include libpcp pmns \ libpcp_pmda libpcp_trace libpcp_http libpcp_pmcd libpcp_gui \ libpcp_mmv libpcp_import \ pmconfig newhelp pmfind pminfo pmcpp pmcd pmcd_wait pmerr pmdbg \ pmdate pmie pmieconf pmpost pmprobe pmlock pmval pmlogger \ pmdumplog pmlogextract pmstore pmhostname pmgenmap pmevent \ pmlogconf pmloglabel pmlogsummary pmclient pcp pmlc dbpmda \ pmtrace pmstat pmsocks pmdas pmafm procmemstat pmimport \ pmlogreduce genpmda pmproxy pmsignal pmsleep pmtop \ autofsd-probe telnet-probe bashrc pmiestatus \ pmevent pmlogrewrite pmcollectl pmatop pmwebapi \ perl python win32ctl pmmgr default :: default_pcp default_pcp : $(SUBDIRS) $(SUBDIRS_MAKERULE) install :: default_pcp install_pcp install_pcp : $(SUBDIRS) $(SUBDIRS_MAKERULE) include $(BUILDRULES) pcp-3.8.12ubuntu1/src/telnet-probe/0000775000000000000000000000000012272262620013773 5ustar pcp-3.8.12ubuntu1/src/telnet-probe/GNUmakefile0000664000000000000000000000206312272262501016044 0ustar #!gmake # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = telnet-probe.c CMDTARGET = telnet-probe default: $(CMDTARGET) include $(BUILDRULES) install: $(CMDTARGET) $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BINADM_DIR)/$(CMDTARGET) install_pcp : install default_pcp : default pcp-3.8.12ubuntu1/src/telnet-probe/telnet-probe.c0000664000000000000000000000550212272262501016537 0ustar /* * Lightweight telnet clone for shping and espping PMDAs. * * Usage: telnet-probe [-v] host port * * Once telnet connection is established: * read stdin until EOF, writing to telnet connection * read telnet until EOF, discarding data * -c (connect only) flag skips the send-receive processing * * Exit status is 1 in the case of any errors, else 0. */ #include "pmapi.h" #include "impl.h" int main(int argc, char *argv[]) { struct hostent *servInfo; char *endnum; int port = 0; int s; int nodelay = 1; struct linger nolinger = {1, 0}; struct sockaddr_in myAddr; FILE *fp; int errflag = 0; int cflag = 0; int vflag = 0; int sts = 1; int c; while ((c = getopt(argc, argv, "cv?")) != EOF) { switch (c) { case 'c': cflag = 1; break; case 'v': vflag = 1; break; case '?': default: errflag++; break; } } if (optind+2 != argc) { fprintf(stderr, "%s: requires two arguments\n", argv[0]); errflag++; } else { port = (int)strtol(argv[optind+1], &endnum, 10); if (*endnum != '\0' || port < 0) { fprintf(stderr, "%s: port must be a positive number\n", argv[0]); errflag++; } } if (errflag) { fprintf(stderr, "Usage: %s [-c] [-v] host port\n", argv[0]); goto done; } if ((servInfo = gethostbyname(argv[optind])) == NULL) { if (vflag) fprintf(stderr, "gethostbyname: %s\n", hoststrerror()); goto done; } if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { if (vflag) fprintf(stderr, "socket: %s\n", netstrerror()); goto done; } setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *) &nodelay, (__pmSockLen)sizeof(nodelay)); setsockopt(s, SOL_SOCKET, SO_LINGER, (char *) &nolinger, (__pmSockLen)sizeof(nolinger)); memset(&myAddr, 0, sizeof(myAddr)); myAddr.sin_family = AF_INET; memcpy(&myAddr.sin_addr, servInfo->h_addr, servInfo->h_length); myAddr.sin_port = htons(port); if (connect(s, (struct sockaddr*) &myAddr, sizeof(myAddr)) < 0) { if (vflag) fprintf(stderr, "connect: %s\n", netstrerror()); goto done; } if (cflag) { /* skip send-recv exercise */ sts = 0; goto done; } fp = fdopen(s, "r+"); if (vflag) fprintf(stderr, "send ...\n"); while ((c = getc(stdin)) != EOF) { if (vflag) { fputc(c, stderr); fflush(stderr); } fputc(c, fp); if (ferror(fp)) { if (vflag) fprintf(stderr, "telnet write: %s\n", osstrerror()); goto done; } fflush(fp); } if (vflag) fprintf(stderr, "recv ...\n"); while ((c = getc(fp)) != EOF) { if (vflag) { fputc(c, stderr); fflush(stderr); } } if (ferror(fp)) { if (vflag) fprintf(stderr, "telnet read: %s\n", osstrerror()); goto done; } sts = 0; done: if (vflag) fprintf(stderr, "exit: %d\n", sts); exit(sts); } pcp-3.8.12ubuntu1/src/pmcd_wait/0000775000000000000000000000000012272262620013342 5ustar pcp-3.8.12ubuntu1/src/pmcd_wait/pmcd_wait.c0000664000000000000000000000766512272262501015471 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1998 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include "pmapi.h" #include "impl.h" /* possible exit states */ #define EXIT_STS_SUCCESS 0 #define EXIT_STS_USAGE 1 #define EXIT_STS_TIMEOUT 2 #define EXIT_STS_UNIXERR 3 #define EXIT_STS_PCPERR 4 static char *hostname = NULL; static long delta = 60; static int verbose = 0; static void PrintUsage(void) { fprintf(stderr, "Usage: %s [options] \n\ \n\ Options:\n\ -h host wait for PMCD on host\n\ -t interval maximum interval to wait for PMCD [default 60 seconds]\n\ -v turn on output messages\n", pmProgname); } static void ParseOptions(int argc, char *argv[]) { int c; int sts; int errflag = 0; char *msg; struct timeval delta_time; while ((c = getopt(argc, argv, "D:h:t:v?")) != EOF) { switch (c) { case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: Unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case 'h': /* contact PMCD on this hostname */ hostname = optarg; break; case 't': /* delta to wait */ if (pmParseInterval(optarg, &delta_time, &msg) < 0) { fprintf(stderr, "%s: Illegal -t argument (%s)\n", pmProgname, optarg); fputs(msg, stderr); free(msg); errflag++; } delta = delta_time.tv_sec; if (delta <= 0) { fprintf(stderr, "%s: -t argument must be at least 1 second\n", pmProgname); errflag++; } break; case 'v': verbose = 1; break; default: case '?': PrintUsage(); exit(EXIT_STS_SUCCESS); } } if (optind < argc) { fprintf(stderr, "%s: Too many arguments\n", pmProgname); errflag++; } if (errflag) { PrintUsage(); exit(EXIT_STS_USAGE); } } void PrintTimeout(void) { if (verbose) { fprintf(stderr, "%s: Failed to connect to PMCD on host \"%s\"" " in %ld seconds\n", pmProgname, hostname, delta); } } int main(int argc, char **argv) { int sts; char env[256]; long delta_count; __pmSetProgname(argv[0]); ParseOptions(argc, argv); if (hostname == NULL) { hostname = "local:"; } sts = sprintf(env, "PMCD_CONNECT_TIMEOUT=%ld", delta); if (sts < 0) { if (verbose) { fprintf(stderr, "%s: Failed to create env string: %s\n", pmProgname, osstrerror()); } exit(EXIT_STS_UNIXERR); } sts = putenv(env); if (sts != 0) { if (verbose) { fprintf(stderr, "%s: Failed to set PMCD_CONNECT_TIMEOUT: %s\n", pmProgname, osstrerror()); } exit(EXIT_STS_UNIXERR); } delta_count = delta; for(;;) { sts = pmNewContext(PM_CONTEXT_HOST, hostname); if (sts >= 0) { (void)pmDestroyContext(sts); exit(EXIT_STS_SUCCESS); } if (sts == -ECONNREFUSED || sts == PM_ERR_IPC) { static const struct timeval onesec = { 1, 0}; delta_count--; if (delta_count < 0) { PrintTimeout(); exit(EXIT_STS_TIMEOUT); } __pmtimevalSleep(onesec); } else if (sts == PM_ERR_TIMEOUT) { PrintTimeout(); exit(EXIT_STS_TIMEOUT); } else { if (verbose) { fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", pmProgname, hostname, pmErrStr(sts)); } if (sts > PM_ERR_BASE) exit(EXIT_STS_UNIXERR); else exit(EXIT_STS_PCPERR); } } } pcp-3.8.12ubuntu1/src/pmcd_wait/GNUmakefile0000664000000000000000000000155412272262501015417 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmcd_wait.c LLDLIBS = $(PCPLIB) CMDTARGET = pmcd_wait$(EXECSUFFIX) default: $(CMDTARGET) include $(BUILDRULES) install: default $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BINADM_DIR)/$(CMDTARGET) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmdas/0000775000000000000000000000000012272262620012477 5ustar pcp-3.8.12ubuntu1/src/pmdas/mounts/0000775000000000000000000000000012272262620014024 5ustar pcp-3.8.12ubuntu1/src/pmdas/mounts/README0000664000000000000000000000425212272262501014705 0ustar # # Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) # for the portions of the code supporting the initial agent functionality. # All rights reserved. # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # Mounts PMDA ============ This PMDA exports information about the mount status of file systems specified in a config file. The default config file is $PCP_PMDAS_DIR/mounts/mounts.conf, which should contain one line for each file system you wish to monitor. This source code was contributed by Alan Bailey (abailey@ncsa.uiuc.edu) to the PCP open source project. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT mounts Installation ============ + # cd $PCP_PMDAS_DIR/mounts + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use ($PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options -- everything else is automated. + Alternatively, to install just the Performance Metrics Name Space for the mounts metrics on the local system, but not the mounts PMDA (presumably because the local system is running PCP 1.x and you wish to connect to a remote system where PCP 2.0 and the mounts PMDA is running), make sure the Performance Metrics Domain defined in ./domain.h matches the domain chosen for the mounts PMDA on the remote system (check the second field in the corresponding line of the $PCP_PMCDCONF_PATH file on the remote system), then # ./Install -N De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/mounts # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/mounts.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/mounts/Remove0000775000000000000000000000233712272262501015212 0ustar #! /bin/sh # # Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) # for the portions of the code supporting the initial agent functionality. # All rights reserved. # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the mounts PMDA # # source the PCP configuration environment variables . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=mounts # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/mounts/mounts.c0000664000000000000000000002544312272262501015523 0ustar /* * Mounts, info on current mounts * * Copyright (c) 2012 Red Hat. * Copyright (c) 2001,2003,2004 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) * for the portions of the code supporting the initial agent functionality. * All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include #include /* * Mounts PMDA * * Metrics * mounts.device * The device which the mount is mounted on * mounts.type * The type of filesystem * mounts.options * The mounting options * mounts.up * always equals 1 */ /* * all metrics supported in this PMDA - one table entry for each */ #ifdef IS_SOLARIS #define MOUNT_FILE "/etc/vfstab" #else #define MOUNT_FILE "/proc/mounts" #endif static pmdaInstid *mounts = NULL; static pmdaIndom indomtab[] = { #define MOUNTS_INDOM 0 { MOUNTS_INDOM, 0, NULL } }; static pmdaMetric metrictab[] = { /* mounts.device */ { NULL, { PMDA_PMID(0,0), PM_TYPE_STRING, MOUNTS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mounts.type */ { NULL, { PMDA_PMID(0,1), PM_TYPE_STRING, MOUNTS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mounts.options */ { NULL, { PMDA_PMID(0,2), PM_TYPE_STRING, MOUNTS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mounts.up */ { NULL, { PMDA_PMID(0,3), PM_TYPE_DOUBLE, MOUNTS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, }; /* Structures needed for this file */ typedef struct { int up; char device[100]; char type[100]; char options[100]; } mountinfo; /* Variables needed for this file */ static mountinfo *mount_list = NULL; static struct stat file_change; static int isDSO = 1; static char mypath[MAXPATHLEN]; static char *username; /* Routines in this file */ static void mounts_clear_config_info(void); static void mounts_grab_config_info(void); static void mounts_config_file_check(void); static void mounts_refresh_mounts(void); static void mounts_config_file_check(void) { /* * This code was taken from the simple PMDA, in simple.c, for checking * to see if a file has been changed. It has been changed slightly. * Note that this then calls mounts_clear_config_info and * mounts_grab_config_info if the file has been updated. */ struct stat statbuf; static int last_error; int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "mounts" "%c" "mounts.conf", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); if (stat(mypath, &statbuf) == -1) { if (oserror() != last_error) { last_error = oserror(); __pmNotifyErr(LOG_WARNING, "stat failed on %s: %s\n", mypath, pmErrStr(last_error)); } } else { last_error = 0; #if defined(HAVE_ST_MTIME_WITH_E) if (statbuf.st_mtime != file_change.st_mtime) { #elif defined(HAVE_ST_MTIME_WITH_SPEC) if (statbuf.st_mtimespec.tv_sec != file_change.st_mtimespec.tv_sec || statbuf.st_mtimespec.tv_nsec != file_change.st_mtimespec.tv_nsec) { #else if (statbuf.st_mtim.tv_sec != file_change.st_mtim.tv_sec || statbuf.st_mtim.tv_nsec != file_change.st_mtim.tv_nsec) { #endif mounts_clear_config_info(); mounts_grab_config_info(); file_change = statbuf; } } } static void mounts_clear_config_info(void) { int i; /* Free the memory holding the mount name */ for (i = 0; i < indomtab[MOUNTS_INDOM].it_numinst; i++) { free(mounts[i].i_name); mounts[i].i_name = NULL; } /* Free the mounts structure */ if (mounts != NULL) { free(mounts); } /* Free the mount_list structure */ if (mount_list != NULL) { free(mount_list); } mount_list = NULL; indomtab[MOUNTS_INDOM].it_set = mounts = NULL; indomtab[MOUNTS_INDOM].it_numinst = 0; } void mounts_grab_config_info() { /* * This routine opens the config file and stores the information in the * mounts structure. The mounts structure must be reallocated as * necessary, and also the num_procs structure needs to be reallocated * as we define new mounts. When all of that is done, we fill in the * values in the indomtab structure, those being the number of instances * and the pointer to the mounts structure. * * A lot of this code was taken from the simple.c code, but in this * case, I changed a lot of it to fit my purposes... */ FILE *fp; char mount_name[1024]; char *q; int mount_number = 0; int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "mounts" "%c" "mounts.conf", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); if ((fp = fopen(mypath, "r")) == NULL) { __pmNotifyErr(LOG_ERR, "fopen on %s failed: %s\n", mypath, pmErrStr(-oserror())); if (mounts) { free(mounts); mounts = NULL; mount_number = 0; } goto done; } while (fgets(mount_name, sizeof(mount_name), fp) != NULL) { if (mount_name[0] == '#') continue; /* Remove the newline */ if ((q = strchr(mount_name, '\n')) != NULL) { *q = '\0'; } else { /* This means the line was too long */ __pmNotifyErr(LOG_WARNING, "line number %d in the config file was too long\n" ,mount_number+1); } mounts = realloc(mounts, (mount_number+1)*sizeof(pmdaInstid)); if (mounts == NULL) { __pmNoMem("process", (mount_number+1)*sizeof(pmdaInstid), PM_FATAL_ERR); /* Not reached */ } mounts[mount_number].i_name = malloc(strlen(mount_name) + 1); strcpy(mounts[mount_number].i_name, mount_name); mounts[mount_number].i_inst = mount_number; mount_number++; } fclose(fp); done: if (mounts == NULL) { __pmNotifyErr(LOG_WARNING, "\"mounts\" instance domain is empty"); } indomtab[MOUNTS_INDOM].it_set = mounts; indomtab[MOUNTS_INDOM].it_numinst = mount_number; mount_list = realloc(mount_list, (mount_number)*sizeof(mountinfo)); } static void mounts_refresh_mounts(void) { FILE *fd; char device[100]; char mount[100]; char type[100]; char options[100]; char junk[10]; int item; int mount_name; /* Clear the variables */ for(item = 0; item < indomtab[MOUNTS_INDOM].it_numinst; item++) { strcpy(mount_list[item].device, "none"); strcpy(mount_list[item].type, "none"); strcpy(mount_list[item].options, "none"); mount_list[item].up = 0; } if ((fd = fopen(MOUNT_FILE, "r")) != NULL) { #ifdef IS_SOLARIS char device_to_fsck[100]; char fsck_pass[100]; char mount_at_boot[100]; while ((fscanf(fd, "%s %s %s %s %s %s %s", device, device_to_fsck, mount, type, fsck_pass, mount_at_boot, options)) == 7) { #else while ((fscanf(fd, "%s %s %s %s", device, mount, type, options)) == 4) { #endif if (fgets(junk, sizeof(junk), fd) == NULL) { /* early EOF? will be caught in next iteration */ ; } for(mount_name = 0; mount_name < indomtab[MOUNTS_INDOM].it_numinst; mount_name++) { if (strcmp(mount, (mounts[mount_name]).i_name) == 0) { strcpy(mount_list[mount_name].device, device); strcpy(mount_list[mount_name].type, type); strcpy(mount_list[mount_name].options, options); mount_list[mount_name].up = 1; } } memset(device, 0, sizeof(device)); memset(mount, 0, sizeof(mount)); memset(type, 0, sizeof(type)); memset(options, 0, sizeof(options)); } fclose(fd); } } static int mounts_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { /* * This is the wrapper over the pmdaFetch routine, to handle the problem * of varying instance domains. All this does is delete the previous * mount list, and then get the current one, by calling * mounts_refresh_mounts. */ mounts_config_file_check(); mounts_refresh_mounts(); return pmdaFetch(numpmid, pmidlist, resp, pmda); } /* * callback provided to pmdaFetch */ static int mounts_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); if (idp->cluster != 0) { return PM_ERR_PMID; } if (inst >= indomtab[MOUNTS_INDOM].it_numinst) { return PM_ERR_INST; } if (idp->item == 0) { atom->cp = (mount_list[inst]).device; } else if (idp->item == 1) { atom->cp = (mount_list[inst]).type; } else if (idp->item == 2) { atom->cp = (mount_list[inst]).options; } else if (idp->item == 3) { atom->d = (mount_list[inst]).up; } else { return PM_ERR_PMID; } return 0; } /* * Initialise the agent (both daemon and DSO). */ void mounts_init(pmdaInterface *dp) { if (isDSO) { int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "mounts" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_2, "mounts DSO", mypath); } else { __pmSetProcessIdentity(username); } if (dp->status != 0) return; dp->version.two.fetch = mounts_fetch; /* Let's grab the info right away just to make sure it's there. */ mounts_grab_config_info(); pmdaSetFetchCallBack(dp, mounts_fetchCallBack); pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), metrictab, sizeof(metrictab)/sizeof(metrictab[0])); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int c, sep = __pmPathSeparator(); int err = 0; pmdaInterface desc; isDSO = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(mypath, sizeof(mypath), "%s%c" "mounts" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&desc, PMDA_INTERFACE_2, pmProgname, MOUNTS, "mounts.log", mypath); while ((c = pmdaGetOpt(argc, argv, "D:d:l:U:?", &desc, &err)) != EOF) { switch(c) { case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&desc); mounts_init(&desc); pmdaConnect(&desc); pmdaMain(&desc); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/mounts/Install0000775000000000000000000000165712272262501015367 0ustar #! /bin/sh # # Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) # for the portions of the code supporting the initial agent functionality. # All rights reserved. # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the mounts PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=mounts pmda_interface=2 forced_restart=false pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/mounts/GNUmakefile0000664000000000000000000000337212272262501016101 0ustar # # Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) # for the portions of the code supporting the initial agent functionality. # # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = mounts DOMAIN = MOUNTS TARGETS = $(IAM)$(EXECSUFFIX) CFILES = mounts.c SCRIPTS = Install Remove DFILES = README LSRCFILES= $(SCRIPTS) pmns help root $(DFILES) mounts.conf PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) PMCHART = $(PCP_VAR_DIR)/config/pmchart LDIRT = domain.h *.o $(IAM).log pmda$(IAM) pmda_$(IAM).so $(TARGETS) \ help.pag help.dir LLDLIBS = $(PCP_PMDALIB) default: build-me include $(BUILDRULES) # This PMDA is only valid on platforms with a mount table (e.g. /proc/mounts) ifeq "$(findstring $(TARGET_OS),mingw darwin)" "" build-me: $(TARGETS) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) $(INSTALL) -m 755 $(SCRIPTS) $(PMDADIR) $(INSTALL) -m 644 $(DFILES) pmns help root domain.h $(PMDADIR) $(INSTALL) -m 644 mounts.conf $(PMDADIR)/mounts.conf else build-me: install: endif $(IAM)$(EXECSUFFIX): $(OBJECTS) default_pcp: default install_pcp: install mounts.o: domain.h domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/mounts/root0000664000000000000000000000056412272262501014735 0ustar /* * fake "root" for validating the local PMNS subtree * * Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) * for the portions of the code supporting the initial agent functionality. * All rights reserved. * Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. */ #include root { mounts } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/mounts/pmns0000664000000000000000000000216512272262501014726 0ustar /* * Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) * for the portions of the code supporting the initial agent functionality. * All rights reserved. * Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Metrics for mounts PMDA */ mounts { device MOUNTS:0:0 type MOUNTS:0:1 options MOUNTS:0:2 up MOUNTS:0:3 } pcp-3.8.12ubuntu1/src/pmdas/mounts/mounts.conf0000664000000000000000000000043112272262501016214 0ustar # # Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) # for the portions of the code supporting the initial agent functionality. # All rights reserved. # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # / /boot /afs /not-here pcp-3.8.12ubuntu1/src/pmdas/mounts/help0000664000000000000000000000341412272262501014677 0ustar # # Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) # for the portions of the code supporting the initial agent functionality. # All rights reserved. # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # mounts PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ mounts.device Tracks the current mounts Tracks the current mounts @ mounts.type Tracks the types of current mounts Tracks the types of current mounts @ mounts.options Tracks the mount options of current mounts Tracks the mount options of current mounts @ mounts.up Simply tells that the mount is up Simply tells that the mount is up pcp-3.8.12ubuntu1/src/pmdas/memcache/0000775000000000000000000000000012272262620014241 5ustar pcp-3.8.12ubuntu1/src/pmdas/memcache/client.pl0000775000000000000000000000074312272262501016061 0ustar #!/usr/bin/perl use strict; use warnings; use Cache::Memcached; use vars qw( $memd $val ); $memd = new Cache::Memcached { 'servers' => [ "127.0.0.1:11211" ], 'debug' => 0, 'compress_threshold' => 10_000, }; $memd->set("my_key", "Some value"); $memd->set("object_key", { 'complex' => [ "object", 2, 4 ]}); $val = $memd->get("my_key"); $val = $memd->get("object_key"); if ($val) { print $val->{'complex'}->[2]; } $memd->incr("key"); $memd->decr("key"); $memd->incr("key", 2); pcp-3.8.12ubuntu1/src/pmdas/memcache/Remove0000775000000000000000000000161012272262501015420 0ustar #! /bin/sh # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the memcached PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=memcache pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/memcache/Install0000775000000000000000000000135312272262501015575 0ustar #! /bin/sh # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the memcached PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=memcache perl_opt=true daemon_opt=false forced_restart=false pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/memcache/GNUmakefile0000664000000000000000000000273212272262501016315 0ustar #!gmake # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = memcache DOMAIN = MEMCACHE PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl client.pl ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif LDIRT = domain.h root pmns *.log $(MAN_PAGES) default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/memcache/pmdamemcache.pl0000664000000000000000000002670012272262501017205 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # The memcached PMDA # NOTE: Not all metrics are exported at the moment, in particular, # the per-slab and per-item statistics are not. It may be better to # manage instances differently as these values are dynamic - perhaps # have the monitored memcaches (the current indom) in the namespace, # like the old DBMS PMDAs. # use strict; use warnings; use PCP::PMDA; use vars qw( $pmda $id $n %caches ); my $memcache_delay = 5; # refresh rate in seconds my @memcache_instances = ( 0 => '127.0.0.1:11211', # 1 => '127.0.0.1:11212', # 2 => '192.168.5.76:11211', ); # Configuration files for overriding the above settings for my $file ( pmda_config('PCP_PMDAS_DIR') . '/memcache/memcache.conf', './memcache.conf' ) { eval `cat $file` unless ! -f $file; } my $memcache_indom = 0; # one for each memcached my $query = "stats\r\nstats slabs\r\nstats items\r\n"; # sent to memcached sub memcache_stats_callback { ( $id, $_ ) = @_; # $pmda->log("memcache_stats_callback: id $id"); if (/^STAT items:(\d+):(\w+) (\d+)/) { # stats items # $caches{$id}{"item$1"}{$2} = $3; } elsif (/^STAT (\d+):(\w+) (\d+)/) { # stats slabs # $caches{$id}{"slab$1"}{$2} = $3; } elsif (/^STAT (\w+) (\d+)/) { # stats $caches{$id}{$1} = $2; } elsif (!(/^END/)) { # unknown $pmda->log("Eh?: $_"); } } sub memcache_connect { # $pmda->log("memcache_connect: $#memcache_instances"); for ($id = 0; $id < $#memcache_instances; $id += 2) { my ($host, $port) = split(/:/, $memcache_instances[$id+1]); $pmda->add_sock($host, $port, \&memcache_stats_callback, $id); } } sub memcache_timer_callback { # $pmda->log("memcache_timer_callback"); for ($id = 0; $id < $#memcache_instances; $id += 2) { $pmda->put_sock($id, $query); } } sub memcache_fetch_callback { my ($cluster, $item, $inst) = @_; # $pmda->log("memcache_fetch_callback: $cluster:$item ($inst)"); return (PM_ERR_INST, 0) unless ($inst != PM_IN_NULL); return (PM_ERR_INST, 0) unless ($inst < $#memcache_instances); $id = $memcache_instances[$inst]; return (PM_ERR_AGAIN, 0) unless defined($caches{$id}); if ($cluster == 0) { if ($item == 0) { return ($caches{$id}{'pid'}, 1); } elsif ($item == 1) { return ($caches{$id}{'uptime'}, 1); } elsif ($item == 2) { return ($caches{$id}{'curr_items'}, 1); } elsif ($item == 3) { return ($caches{$id}{'total_items'}, 1); } elsif ($item == 4) { return ($caches{$id}{'bytes'}, 1); } elsif ($item == 5) { return ($caches{$id}{'curr_connections'}, 1); } elsif ($item == 6) { return ($caches{$id}{'total_connections'}, 1); } elsif ($item == 7) { return ($caches{$id}{'connection_structures'}, 1); } elsif ($item == 8) { return ($caches{$id}{'cmd_get'}, 1); } elsif ($item == 9) { return ($caches{$id}{'cmd_set'}, 1); } elsif ($item == 10) { return ($caches{$id}{'get_hits'}, 1); } elsif ($item == 11) { return ($caches{$id}{'get_misses'}, 1); } elsif ($item == 12) { return ($caches{$id}{'bytes_read'}, 1); } elsif ($item == 13) { return ($caches{$id}{'bytes_written'}, 1); } elsif ($item == 14) { return ($caches{$id}{'limit_maxbytes'}, 1); } } # elsif ($cluster == 1) { # # many different slabs (X..Y), and 7 metrics in this cluster # if ($item > 7 * 11) { return (PM_ERR_PMID, 0); } # $id = int($item / 7) + 6; # $item %= 7; # my $slab = "slab$id"; # # return (PM_ERR_AGAIN, 0) unless defined($caches{$id}{$slab}); # if ($item == 0) { return ($caches{$id}{$slab}{'chunk_size'}, 1); } # elsif ($item == 1) { return ($caches{$id}{$slab}{'chunks_per_page'}, 1); } # elsif ($item == 2) { return ($caches{$id}{$slab}{'total_pages'}, 1); } # elsif ($item == 3) { return ($caches{$id}{$slab}{'total_chunks'}, 1); } # elsif ($item == 4) { return ($caches{$id}{$slab}{'used_chunks'}, 1); } # elsif ($item == 5) { return ($caches{$id}{$slab}{'free_chunks'}, 1); } # elsif ($item == 6) { return ($caches{$id}{$slab}{'free_chunks_end'}, 1); } # } elsif ($cluster == 2) { if ($item == 0) { return ($caches{$id}{'active_slabs'}, 1); } elsif ($item == 1) { return ($caches{$id}{'total_malloced'}, 1); } } # elsif ($cluster == 3) { # # many different slabs (X..Y), and 2 metrics in this cluster # if ($item > 2 * [Y]) { return (PM_ERR_PMID, 0); } # $id = int($item / 2) + [X]; # $item %= 2; # my $itemid = "item$id"; # # return (PM_ERR_AGAIN, 0) unless defined($caches{$id}{$itemid}); # if ($item == 0) { return ($caches{$id}{$itemid}{'count'}, 1); } # elsif ($item == 1) { return ($caches{$id}{$itemid}{'age'}, 1); } # } return (PM_ERR_PMID, 0); } $pmda = PCP::PMDA->new('memcache', 89); $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U32, $memcache_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'memcache.pid', '', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_U32, $memcache_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'memcache.uptime', '', ''); $pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U32, $memcache_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'memcache.current_items', '', ''); $pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U32, $memcache_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'memcache.total_items', '', ''); $pmda->add_metric(pmda_pmid(0,4), PM_TYPE_U64, $memcache_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'memcache.bytes', '', ''); $pmda->add_metric(pmda_pmid(0,5), PM_TYPE_U32, $memcache_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'memcache.current_connections', '', ''); $pmda->add_metric(pmda_pmid(0,6), PM_TYPE_U32, $memcache_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'memcache.total_connections', '', ''); $pmda->add_metric(pmda_pmid(0,7), PM_TYPE_U32, $memcache_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'memcache.connection_structures', '', ''); $pmda->add_metric(pmda_pmid(0,8), PM_TYPE_U32, $memcache_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'memcache.gets', '', ''); $pmda->add_metric(pmda_pmid(0,9), PM_TYPE_U32, $memcache_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'memcache.sets', '', ''); $pmda->add_metric(pmda_pmid(0,10), PM_TYPE_U32, $memcache_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'memcache.hits', '', ''); $pmda->add_metric(pmda_pmid(0,11), PM_TYPE_U32, $memcache_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'memcache.misses', '', ''); $pmda->add_metric(pmda_pmid(0,12), PM_TYPE_U64, $memcache_indom, PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'memcache.bytes_read', '', ''); $pmda->add_metric(pmda_pmid(0,13), PM_TYPE_U64, $memcache_indom, PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'memcache.bytes_written', '', ''); $pmda->add_metric(pmda_pmid(0,14), PM_TYPE_U32, $memcache_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'memcache.limit_maxbytes', '', ''); # $id = 0; # foreach $n (6 .. 17) { # stats slabs (N=6-17) # $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, # PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), # "memcache.slabs.slab$n.chunk_size", '', ''); # $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, # PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), # "memcache.slabs.slab$n.chunks_per_page", '', ''); # $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, # PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), # "memcache.slabs.slab$n.total_pages", '', ''); # $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, # PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), # "memcache.slabs.slab$n.total_chunks", '', ''); # $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, # PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), # "memcache.slabs.slab$n.used_chunks", '', ''); # $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, # PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), # "memcache.slabs.slab$n.free_chunks", '', ''); # $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom, # PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), # "memcache.slabs.slab$n.free_chunks_end", '', ''); # } $pmda->add_metric(pmda_pmid(2,0), PM_TYPE_U32, $memcache_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'memcache.active_slabs', '', ''); $pmda->add_metric(pmda_pmid(2,1), PM_TYPE_U32, $memcache_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'memcache.total_malloced', '', ''); # $id = 0; # foreach $n (6 .. 17) { # stats items (N=6-17) # $pmda->add_metric(pmda_pmid(3,$id++), PM_TYPE_U32, $memcache_indom, # PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), # "memcache.items.item$n.count", '', ''); # $pmda->add_metric(pmda_pmid(3,$id++), PM_TYPE_U32, $memcache_indom, # PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), # "memcache.items.item$n.age", '', ''); # } $pmda->add_indom($memcache_indom, \@memcache_instances, 'Instance domain exporting each memcache daemon', ''); $pmda->add_timer($memcache_delay, \&memcache_timer_callback, 0); $pmda->set_fetch_callback(\&memcache_fetch_callback); &memcache_connect; $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdamemcache - memcache performance metrics domain agent (PMDA) =head1 DESCRIPTION This PMDA extracts performance data from memcached, a distributed memory caching daemon commonly used to improve web serving performance. A farm of memcached processes over multiple servers can be utilised by a single web application, increasing the total available object cache size, and decreasing the database load associated with smaller cache sizes. This system is described in detail at http://www.danga.com/memcached. =head1 INSTALLATION Configure B to extract the values from set of hosts used in the memcache farm. These hosts can be listed in the $PCP_PMDAS_DIR/memcache/memcache.conf file, in the format (i.e. Perl array) described at the top of pmdamemcache.pl. A custom refresh rate can also be configured using this mechanism. # cd $PCP_PMDAS_DIR/memcache # [ edit memcache.conf ] Once this is setup, you can access the names and values for the memcache performance metrics by doing the following as root: # cd $PCP_PMDAS_DIR/memcache # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/memcache # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/memcache/memcache.conf configuration file listing monitored memcache instances =item $PCP_PMDAS_DIR/memcache/Install installation script for the B agent =item $PCP_PMDAS_DIR/memcache/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/memcache.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1) and memcached(1). pcp-3.8.12ubuntu1/src/pmdas/cisco/0000775000000000000000000000000012272262620013577 5ustar pcp-3.8.12ubuntu1/src/pmdas/cisco/cisco.h0000664000000000000000000000447612272262501015061 0ustar /* * Instance Domain Data Structures, suitable for a PMDA * * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _CISCO_H #define _CISCO_H #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" typedef struct { char *host; /* CISCO hostname */ struct sockaddr_in ipaddr; /* IP address for 'host' */ char *username; /* username */ char *passwd; /* password */ char *prompt; /* command prompt */ FILE *fout; /* write cmds here */ FILE *fin; /* read output here */ } cisco_t; typedef struct { cisco_t *cp; /* which CISCO? */ char *interface; /* interface name, e.g. s0 or e10/10 */ int fetched; /* valid stats? */ __uint32_t bandwidth; /* peak bandwidth */ __uint32_t rate_in; __uint32_t rate_out; __uint64_t bytes_in; /* stats */ __uint64_t bytes_out; __uint64_t bytes_out_bcast; } intf_t; extern cisco_t *cisco; extern int n_cisco; extern intf_t *intf; extern int n_intf; /* * Supported Cisco Interfaces */ typedef struct { char *type; /* NULL to skip, else unique per interface * type */ char *name; /* full name as per "show" */ } intf_tab_t; extern intf_tab_t intf_tab[]; extern int num_intf_tab; #define CISCO_INDOM 0 extern pmdaIndom indomtab[]; extern pmdaInstid *_router; #define PWPROMPT "Password:" #define USERPROMPT "Username:" extern int conn_cisco(cisco_t *); extern int grab_cisco(intf_t *); extern int dousername(cisco_t *, char **); extern int dopasswd(cisco_t *, char *); extern char *mygetwd(FILE *, char *); extern int parse_only; #endif /* _CISCO_H */ pcp-3.8.12ubuntu1/src/pmdas/cisco/Cisco.pmchart0000664000000000000000000000031512272262501016214 0ustar #pmchart Version 1.2 host dynamic Chart Style plot Plot Color #-cycle Host * Metric cisco.rate_in Chart Style plot Plot Color #-cycle Host * Metric cisco.rate_out # # Created Mon Sep 1 11:34:14 1997 pcp-3.8.12ubuntu1/src/pmdas/cisco/telnet.c0000664000000000000000000004100012272262501015227 0ustar /* * Copyright (c) 1995-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "./cisco.h" extern int port; int conn_cisco(cisco_t * cp) { int fd; int i; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { fprintf(stderr, "conn_cisco(%s) socket: %s\n", cp->host, netstrerror()); return -1; } i = 1; if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &i, (__pmSockLen)sizeof(i)) < 0) { fprintf(stderr, "conn_cisco(%s): setsockopt: %s\n", cp->host, netstrerror()); close(fd); return -1; } if (connect(fd, (struct sockaddr *)&cp->ipaddr, sizeof(cp->ipaddr)) < 0) { fprintf(stderr, "conn_cisco(%s): connect: %s\n", cp->host, netstrerror()); close(fd); return -1; } return fd; } static void skip2eol(FILE *f) { int c; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "skip2eol:"); #endif while ((c = fgetc(f)) != EOF) { if (c == '\n') break; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "%c", c); #endif } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fputc('\n', stderr); #endif } char * mygetwd(FILE *f, char *prompt) { char *p; int c; static char buf[1024]; int len_prompt = strlen(prompt); int found_prompt = 0; p = buf; while ((c = fgetc(f)) != EOF) { if (c == '\r' || c == '\n' || c == ' ' || c == '\t') { if (p == buf) continue; break; } *p++ = c; if (p-buf >= len_prompt && strncmp(&p[-len_prompt], prompt, len_prompt) == 0) { found_prompt = 1; break; } } *p = '\0'; if (feof(f)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "mygetwd: EOF fd=%d\n", fileno(f)); #endif return NULL; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "mygetwd: fd=%d wd=\"%s\"%s\n", fileno(f), buf, found_prompt ? " [prompt]" : ""); #endif return buf; } /* * The CISCO "show interface" command output is parsed. * * See the file Samples for examples. * * The parser is a Finite State Automaton (FSA) that follows these * rules: * * SHOW_INT style ... uses "show int " command * state token next state * NOISE IN_REPORT * IN_REPORT Description: skip rest of line, IN_REPORT * IN_REPORT DONE * IN_REPORT minute RATE * IN_REPORT second RATE * IN_REPORT input, BYTES_IN * IN_REPORT output, BYTES_OUT * IN_REPORT BW BW * RATE input skip next token, RATE_IN * RATE output skip next token, RATE_OUT * RATE_IN (rate_in) IN_REPORT * RATE_OUT (rate_out) IN_REPORT * BYTES_IN (bytes_in) IN_REPORT * BYTES_OUT (bytes_out) IN_REPORT * BW (bandwidth) IN_REPORT * * SHOW_FRAME style ... uses "show frame pvc int " command * state token next state * NOISE IN_REPORT * IN_REPORT Description: skip rest of line, IN_REPORT * IN_REPORT DONE * IN_REPORT 1st bytes BYTES_IN * IN_REPORT 2nd bytes BYTES_OUT * IN_REPORT 3rd bytes BYTES_OUT_BCAST * BYTES_IN (bytes_in) IN_REPORT * BYTES_OUT (bytes_out) IN_REPORT * BYTES_OUT_BCAST (bytes_out_bcast) IN_REPORT * * Note lines are terminated with \r */ #define DONE -1 #define NOISE 0 #define IN_REPORT 1 #define RATE 2 #define RATE_IN 3 #define RATE_OUT 4 #define BYTES_IN 5 #define BYTES_OUT 6 #define BW 7 #define BYTES_OUT_BCAST 8 #ifdef PCP_DEBUG static char *statestr[] = { "done", "noise", "in_report", "rate", "rate_in", "rate_out", "bytes_in", "bytes_out", "bw", "bytes_out_bcast" }; #endif int dousername(cisco_t *cp, char **pw_prompt) { char *w; int len, done = 0; int len_prompt = strlen(cp->prompt); for ( ; ; ) { w = mygetwd(cp->fin, cp->prompt); if (w == NULL) break; if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0) break; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "Username:? got - %s\n", w); #endif if (strcmp(w, USERPROMPT) == 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "Send username: %s\n", cp->username); } #endif fprintf(cp->fout, "%s\n", cp->username); fflush(cp->fout); for ( ; ; ) { w = mygetwd(cp->fin, cp->prompt); if (w == NULL || strcmp(w, USERPROMPT) == 0) /* closed connection or Username re-prompt */ break; len = strlen(w); if ((len >= len_prompt && strncmp(&w[len-len_prompt], cp->prompt, len_prompt) == 0) || w[len-1] == ':') { /* command prompt or passwd */ if (w[len-1] == ':') *pw_prompt = w; done = 1; break; } } break; } } if (done == 0) { fprintf(stderr, "Error: Cisco username negotiation failed for \"%s\"\n", cp->host); fprintf(stderr, "To check that a username is required, enter the following command:\n" " $ telnet %s\n" "If the prompt \"%s\" does not appear, no username is required.\n" "Otherwise, enter the username \"%s\" to check that this\n" "is correct.\n", cp->host, USERPROMPT, cp->username); } return done; } int dopasswd(cisco_t *cp, char *pw_prompt) { char *w; int done = 0; int len_prompt = strlen(cp->prompt); for ( ; ; ) { if (pw_prompt) /* dousername may have read passwd prompt */ w = pw_prompt; else w = mygetwd(cp->fin, cp->prompt); pw_prompt = NULL; if (w == NULL) break; if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0) break; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "Password:? got - %s\n", w); #endif if (strcmp(w, PWPROMPT) == 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "Send passwd: %s\n", cp->passwd); } #endif fprintf(cp->fout, "%s\n", cp->passwd); fflush(cp->fout); for ( ; ; ) { w = mygetwd(cp->fin, cp->prompt); if (w == NULL || strcmp(w, PWPROMPT) == 0) /* closed connection or user-level password re-prompt */ break; if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0) { /* command prompt */ done = 1; break; } } break; } } if (done == 0) { fprintf(stderr, "Error: Cisco user-level password negotiation failed for \"%s\"\n", cp->host); fprintf(stderr, "To check that a user-level password is required, enter the following command:\n" " $ telnet %s\n" "If the prompt \"%s\" does not appear, no user-level password is required.\n" "Otherwise, enter the user-level password \"%s\" to check that this\n" "is correct.\n", cp->host, PWPROMPT, cp->passwd); } return done; } static int timeout; void onalarm(int dummy) { timeout = 1; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "Alarm timeout!\n"); } #endif } static int get_fr_bw(cisco_t *cp, char *interface) { int state = NOISE; int bandwidth = -1; char *w; int len_prompt = strlen(cp->prompt); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "Send: s%s\n", interface); } #endif fprintf(cp->fout, "show int s%s\n", interface); fflush(cp->fout); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "BW Parse:"); #endif while (state != DONE) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "[%s] ", statestr[state+1]); #endif w = mygetwd(cp->fin, cp->prompt); if (w == NULL || timeout) { /* * End of File (telenet timeout?) */ alarm(0); return -1; } switch (state) { case NOISE: if (strncmp(w, "Serial", 6) == 0 && strcmp(&w[6], interface) == 0) state = IN_REPORT; break; case IN_REPORT: if (strcmp(w, "Description:") == 0) skip2eol(cp->fin); else if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0) state = DONE; else if (strcmp(w, "BW") == 0) state = BW; break; case BW: sscanf(w, "%d", &bandwidth); bandwidth *= 1000; /* Kbit -> bytes/sec */ bandwidth /= 8; state = IN_REPORT; break; } } alarm(0); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "Extracted bandwidth: %d bytes/sec\n", bandwidth); } #endif return bandwidth; } #define SHOW_INT 1 #define SHOW_FRAME 2 int grab_cisco(intf_t *ip) { int style; int next_state; int state = NOISE; int skip = 0; int i; int namelen; char *pw_prompt = NULL; char *w; int fd; int fd2; int nval = 0; cisco_t *cp = ip->cp; intf_t tmp; int len_prompt = strlen(cp->prompt); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "grab_cisco(%s:%s):\n", cp->host, ip->interface); } #endif tmp.bandwidth = tmp.rate_in = tmp.rate_out = -1; tmp.bytes_in = tmp.bytes_out = tmp.bytes_out_bcast = -1; if (cp->fin == NULL) { fd = conn_cisco(cp); if (fd < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "grab_cisco(%s:%s): connect failed: %s\n", cp->host, ip->interface, netstrerror()); #endif return -1; } else { cp->fin = fdopen (fd, "r"); if ((fd2 = dup(fd)) < 0) { perror("dup"); exit(1); } cp->fout = fdopen (fd2, "w"); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "grab_cisco(%s:%s): connected fin=%d fout=%d", cp->host, ip->interface, fileno(cp->fin), fileno(cp->fout)); if (cp->username != NULL) fprintf(stderr, " username=%s", cp->username); else fprintf(stderr, " NO username"); if (cp->passwd != NULL) fprintf(stderr, " passwd=%s", cp->passwd); else fprintf(stderr, " NO passwd"); fputc('\n', stderr); } #endif if (cp->username != NULL) { /* * Username stuff ... */ if (dousername(cp, &pw_prompt) == 0) { fclose(cp->fin); fclose(cp->fout); cp->fin = cp->fout = NULL; return -1; } } if (cp->passwd != NULL) { /* * User-level password stuff ... */ if (dopasswd(cp, pw_prompt) == 0) { fclose(cp->fin); fclose(cp->fout); cp->fin = cp->fout = NULL; return -1; } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "Send: \n"); } #endif fprintf(cp->fout, "\n"); fflush(cp->fout); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "Send: terminal length 0\n"); } #endif fprintf(cp->fout, "terminal length 0\n"); fflush(cp->fout); } timeout = 0; signal(SIGALRM, onalarm); /* * Choice of timeout here is somewhat arbitrary ... for a long * time this was 5 (seconds), but then testing with an entry * level Model 800 ADSL router revealed that up to 20 seconds * was required to generate the expected output. */ alarm(20); style = SHOW_INT; /* default Cisco command */ if (ip->interface[0] == 's' && strchr(ip->interface, '.') != NULL) { /* * Frame-relay PVC on subinterface for s2/3.7 style interface name */ style = SHOW_FRAME; if (ip->bandwidth == -2) { /* * one-trip initialzation ... need show int s2/3.7 to * get bandwidth */ ip->bandwidth = get_fr_bw(cp, &ip->interface[1]); } tmp.bandwidth = ip->bandwidth; if (tmp.bandwidth != -1) nval++; } if (style == SHOW_FRAME) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "Send: show frame pvc int s%s\n", &ip->interface[1]); } #endif fprintf(cp->fout, "show frame pvc int s%s\n", &ip->interface[1]); next_state = BYTES_IN; } else { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "Send: show int %s\n", ip->interface); } #endif fprintf(cp->fout, "show int %s\n", ip->interface); } fflush(cp->fout); state = NOISE; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "Parse:"); fflush(stderr); } #endif while (state != DONE) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "[%s] ", statestr[state+1]); fflush(stderr); } #endif w = mygetwd(cp->fin, cp->prompt); if (w == NULL || timeout) { /* * End of File (telenet timeout?) * ... mark as closed, and try again at next request */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "grab_cisco(%s:%s): forced disconnect fin=%d\n", cp->host, ip->interface, fileno(cp->fin)); #endif fclose(cp->fin); fclose(cp->fout); cp->fin = cp->fout = NULL; alarm(0); return -1; } switch (state) { case NOISE: for (i = 0; i < num_intf_tab; i++) { namelen = strlen(intf_tab[i].name); if (strncmp(w, intf_tab[i].name, namelen) == 0) { state = IN_REPORT; break; } } break; case IN_REPORT: if (strcmp(w, "Description:") == 0) skip2eol(cp->fin); if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0) state = DONE; else if (style == SHOW_INT) { if (strcmp(w, "minute") == 0 || strcmp(w, "second") == 0) state = RATE; else if (strcmp(w, "input,") == 0) state = BYTES_IN; else if (strcmp(w, "output,") == 0) state = BYTES_OUT; else if (strcmp(w, "BW") == 0) state = BW; } else if (style == SHOW_FRAME) { if (strcmp(w, "bytes") == 0) { if (next_state == BYTES_IN) { state = BYTES_IN; next_state = BYTES_OUT; } else if (next_state == BYTES_OUT) { state = BYTES_OUT; next_state = BYTES_OUT_BCAST; } else if (next_state == BYTES_OUT_BCAST) { state = BYTES_OUT_BCAST; next_state = IN_REPORT; } else state = next_state; } } break; case RATE: if (strcmp(w, "input") == 0) { skip = 1; state = RATE_IN; } else if (strcmp(w, "output") == 0) { skip = 1; state = RATE_OUT; } break; case RATE_IN: if (skip-- == 0) { tmp.rate_in = atol(w) / 8; nval++; state = IN_REPORT; } break; case RATE_OUT: if (skip-- == 0) { tmp.rate_out = atol(w) / 8; nval++; state = IN_REPORT; } break; case BYTES_IN: tmp.bytes_in = strtoull(w, NULL, 10); nval++; state = IN_REPORT; break; case BYTES_OUT: tmp.bytes_out = strtoull(w, NULL, 10); nval++; state = IN_REPORT; break; case BYTES_OUT_BCAST: tmp.bytes_out_bcast = strtoull(w, NULL, 10); nval++; state = IN_REPORT; break; case BW: sscanf(w, "%d", &tmp.bandwidth); tmp.bandwidth *= 1000; /* Kbit -> bytes/sec */ tmp.bandwidth /= 8; nval++; state = IN_REPORT; break; } } alarm(0); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "Extracted %d values ...\n", nval); if (tmp.bandwidth != 0xffffffff) fprintf(stderr, "bandwidth: %d bytes/sec\n", tmp.bandwidth); else fprintf(stderr, "bandwidth: ? bytes/sec\n"); fprintf(stderr, "recent rate (bytes/sec):"); if (tmp.rate_in != 0xffffffff) fprintf(stderr, " %d in", tmp.rate_in); else fprintf(stderr, " ? in"); if (tmp.rate_out != 0xffffffff) fprintf(stderr, " %d out", tmp.rate_out); else fprintf(stderr, " ? out"); fprintf(stderr, "\ntotal bytes:"); if (tmp.bytes_in != 0xffffffffffffffffLL) fprintf(stderr, " %llu in", (unsigned long long)tmp.bytes_in); else fprintf(stderr, " ? in"); if (tmp.bytes_out != 0xffffffffffffffffLL) fprintf(stderr, " %llu out", (unsigned long long)tmp.bytes_out); else fprintf(stderr, " ? out"); if (tmp.bytes_out_bcast != 0xffffffffffffffffLL) fprintf(stderr, " %llu out_bcast", (unsigned long long)tmp.bytes_out_bcast); else fprintf(stderr, " ? out_bcast"); fprintf(stderr, "\n\n"); } #endif /* pretend this is atomic */ ip->bandwidth = tmp.bandwidth; ip->rate_in = tmp.rate_in; ip->rate_out = tmp.rate_out; ip->bytes_in = tmp.bytes_in; ip->bytes_out = tmp.bytes_out; ip->bytes_out_bcast = tmp.bytes_out_bcast; return nval; } pcp-3.8.12ubuntu1/src/pmdas/cisco/README0000664000000000000000000000502512272262501014457 0ustar Performance Co-Pilot PMDA for Monitoring Cisco Routers ====================================================== This PMDA is capable of collecting throughput measures from Cisco routers throughout a network. The PMDA needs to be configured to collect performance data from a designated set of interfaces on nominated Cisco routers. There is one instance of the metrics for nominated each router-interface pair. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT cisco Installation ============ + # cd $PCP_PMDAS_DIR/cisco + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + The Cisco PMDA is one that polls the Cisco routers, and caches the most recent value for the performance metrics. The cached values are the ones returned via the PMCD to clients requesting Cisco performance metrics. The default polling rate is once every two minutes to each Cisco interface being monitored, if you wish to change this, edit Install and change the value of pollrate near the start of the script. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options. You will be prompted to identify the Cisco routers and interfaces you wish to monitor. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/cisco # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/cisco.log) should be checked for any warnings or errors. + The configured interfaces on a particular Cisco may be discovered using the $PCP_PMDAS_DIR/cisco/probe application. See pmdacisco(1) for more details. + The $PCP_PMDAS_DIR/cisco/parse application supports the same command line options as pmdacisco for identifying interfaces on Cisco devices and shares the parser for the output from the Cisco "show interface" command; this application may be used to gain diagnostic traces of the interaction between the parser code and the Cisco device in the event that metrics values are not being returned by the Cisco PMDA. See pmdacisco(1) for more details. pcp-3.8.12ubuntu1/src/pmdas/cisco/Tested0000664000000000000000000000341712272262501014755 0ustar Cisco Model : MGS Interface(s) e2 Cisco Model: Cisco 7000 Interface(s) e1/2 f2/0 Cisco Model: Cisco 7000 Interface(s) e0/0 e0/1 e0/2 e0/3 e0/4 e0/5 f2/0 f4/0 Cisco Model : 4500 Interface(s) e0 f1 Cisco Model : 2500 (68030) processor (revision A) 3000 Software Interface(s) e0 s0 Cisco Model : 4000M Interface(s) e0#starchild e1 -P starchild f0 -P starchild s0 -P starchild s1#starchild s2#starchild Cisco Model : 4500 Interface(s) e0 e1 f0 f1 Cisco Model : 7513 Interface(s) e0/0 e0/1 e0/2 e0/3 e0/4 e0/5 E1/0 E1/1 s2/0 s2/1 s2/2 s2/3 h3/0 f5/0 f8/0 f9/0 f10/0 f11/0 a12/0 Cisco Model : 7000 Interface(s) e0/0 e0/1 e0/2 e0/3 e0/4 e0/5 e1/0 e1/1 e1/2 e1/3 e1/4 e1/5 e2/0 e2/1 e2/2 e2/3 e2/4 e2/5 f3/0 a4/0 Cisco Model : 2500 Interfaces e0?cisco e1 s0 s1 Cisco Model : 3640 IOS 3600 Version 11.3(6), RELEASE SOFTWARE (fc1) Interface(s) e0/0 s1/0 s1/1 s1/2 s1/3 Cisco Model: Cat6k-MSFC Interfaces Vlan32 Vlan33 Vlan34 Vlan35 Vlan36 Vlan37 Vlan38 Vlan39 Vlan41 Vlan43 Vlan44 Vlan47 Vlan48 Vlan50 Vlan51 Vlan140 Vlan149 Vlan156 Vlan240 Vlan249 Vlan256 Cisco Model: Catalyst 6509 Interfaces Vl2 Vl3 Vl4 Vl5 Vl6 Vl7 Vl8 Vl14 Vl15 Vl16 Vl17 Vl18 Vl19 Vl20 Vl21 Vl22 Vl23 Vl101 Vl109 Vl110 Vl111 Vl112 Vl113 Vl156 Vl209 Vl210 Vl211 Vl212 Vl213 Vl256 Cisco Model: C2960 IOS Version 12.2(25)SEE2, RELEASE SOFTWARE (fc1) Interfaces Vl1 Vl50 E0/1 E0/2 E0/3 E0/4 E0/5 E0/6 E0/7 E0/8 E0/9 E0/10 E0/11 E0/12 E0/13 E0/14 E0/15 E0/16 E0/17 E0/18 E0/19 E0/20 E0/21 E0/22 E0/23 E0/24 E0/25 E0/26 E0/27 E0/28 E0/29 E0/30 E0/31 E0/32 E0/33 E0/34 E0/35 E0/36 E0/37 E0/38 E0/39 E0/40 E0/41 E0/42 E0/43 E0/44 E0/45 E0/46 E0/47 E0/48 G0/1 G0/2 pcp-3.8.12ubuntu1/src/pmdas/cisco/Remove0000664000000000000000000000202312272262501014752 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the cisco PMDA and/or PMNS # # Get standard environment . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=cisco # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/cisco/cisco.out_util.pmie0000664000000000000000000000255512272262501017423 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) rule cisco.out_util summary = "$rule$" enumerate = hosts predicate = "some_inst ( 100 * cisco.rate_out $hosts$ / cisco.bandwidth $hosts$ > $threshold$ )" enabled = no version = 1 help = "Some Cisco router interface exceeded threshold percent of its peak bandwidth sending data during the last sample interval. Use the command: $ pminfo -f cisco.bandwidth to discover the list of Cisco router interfaces currently being monitored by the Cisco PMDA - pmdacisco(1)."; string rule default = "Cisco router outbound bandwidth saturation" modify = no display = no; percent threshold default = 90 help = "Threshold percentage for Cisco router saturation, in the range 0 (idle) to 100 (operating at peak bandwidth)"; string action_expand default = %v%util[%i]@%h display = no modify = no; string email_expand default = "host: %h Cisco router: %i outbound utilization: %v%" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x200094" display = no modify = no; # for EnlightenDSM integration: string enln_test default = cisco.out_util display = no modify = no; string enln_units default = %util[%i] display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmdas/cisco/Install0000664000000000000000000001055012272262501015127 0ustar #! /bin/sh # # Copyright (c) 1997-2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the cisco PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=cisco pmda_interface=2 forced_restart=false # Do it # pmdaSetup check_delay=20 pollrate=120 # poll each Cisco interface once every 120 seconds # -- change this if desired # special cisco PMDA args if $do_pmda then args="-r$pollrate" default="wanptg" while true do no_host=true while $no_host do echo $PCP_ECHO_PROG $PCP_ECHO_N "Cisco hostname or IP address? [return to quit Cisco selection] ""$PCP_ECHO_C" read host [ "X$host" = X ] && break echo ' A username and/or user-level password may be required for the Cisco "show interface" command. If you are unsure, try the command $ telnet '$host' and if the prompt "Username:" appears, then a username is required, and if the prompt "Password:" appears, a user-level password is required, otherwise respond with an empty line for the next two questions. Once logged in, we need to know the termination string for the command line prompt (one or more unique characters at the end of the prompt) - the default is ">", but if this is not correct, enter the prompt termination string also. ' $PCP_ECHO_PROG $PCP_ECHO_N "Cisco username? ""$PCP_ECHO_C" read username userarg="" [ "X$username" != X ] && userarg="-U$username" $PCP_ECHO_PROG $PCP_ECHO_N "User-level Cisco password? ""$PCP_ECHO_C" read passwd passarg="" [ "X$passwd" != X ] && passarg="-P$passwd" $PCP_ECHO_PROG $PCP_ECHO_N "Cisco command line prompt termination? [>] ""$PCP_ECHO_C" read prompt promptarg="" [ "X$prompt" != X ] && promptarg="-s'$prompt'" echo "Probing Cisco for list of interfaces ..." for try in 1 2 3 do intf=`eval ./probe $userarg $passarg $promptarg $host 2>$tmp/err` [ ! -z "$intf" ] && break sleep 2 done if [ -z "$intf" ] then echo ' There appears to be a problem ... after three attempts could not get interfaces. Output at the last attempt was:' sed -e 's/^/ /' <$tmp/err echo ' You may wish to try the following commands to identify the configured interfaces for this Cisco. $ telnet '$host' ....> terminal length 0 ....> show interface ....> quit ' else no_host=false fi done [ "X$host" = X ] && break if [ -z "$username" ] then login="" else login="@$username" fi [ ! -z "$passwd" ] && login="$login?$passwd" [ ! -z "$prompt" ] && login="$login!$prompt" echo ' Enter interfaces to monitor, one per line in the format tX where "t" is a type and one of "e" (Ethernet), "E" (FastEthernet), "f" (Fddi), "s" (Serial), "a" (ATM), "B" (ISDN BRI) or "h" (HSSC) and "X" is an interface identifier which is either an integer (e.g. 4000 Series routers) or two integers separated by a slash (e.g. 7000 Series routers).' while true do echo echo 'The currently unselected interfaces for the Cisco "'$host'" are:' echo "$intf" | fmt | sed -e 's/^/ /' echo 'Enter "*" to select all, "quit" to terminate selections for this Cisco.' first=`echo "$intf" | sed -e 's/ .*//'` [ -z "$first" ] && first=quit $PCP_ECHO_PROG $PCP_ECHO_N "Interface? [$first] ""$PCP_ECHO_C" read ans [ "X$ans" = Xquit ] && break if [ "X$ans" = "X*" ] then # do them all for ans in `echo "$intf"` do args="$args $host:$ans$login" login='' done break fi [ -z "$ans" ] && ans="$first" if echo " $intf" | grep " $ans" >/dev/null then sed_ans=`echo $ans | sed -e 's;/;\\\\/;g'` intf=`echo " $intf" | sed -e "s/ $sed_ans//" -e 's/^ //'` else echo "Warning: $ans is not in the list, I hope you know what you're doing" fi args="$args $host:$ans$login" login='' [ -z "$intf" ] && break done done fi pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/cisco/GNUmakefile0000664000000000000000000000425012272262501015650 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = cisco DOMAIN = CISCO TARGETS = $(IAM)$(EXECSUFFIX) probe$(EXECSUFFIX) parse$(EXECSUFFIX) CFILES = cisco.c pmda.c interface.c telnet.c HFILES = cisco.h DFILES = README LSRCFILES=Install Remove root pmns Cisco.pmchart help Samples Tested $(DFILES) \ cisco.in_util.pmie cisco.out_util.pmie probe.c LLDLIBS = $(PCP_PMDALIB) $(LIB_FOR_PTHREADS) PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) PMCHART = $(PCP_VAR_DIR)/config/pmchart PMIEDIR = $(PCP_VAR_DIR)/config/pmieconf/$(IAM) LDIRT = domain.h cisco.log *.dir *.pag so_locations a.out parse.? probe.o \ $(TARGETS) default: build-me include $(BUILDRULES) ifneq "$(TARGET_OS)" "mingw" build-me: $(TARGETS) install: build-me $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) $(INSTALL) -m 755 probe parse Install Remove $(PMDADIR) $(INSTALL) -m 644 $(DFILES) root help pmns domain.h $(PMDADIR) $(INSTALL) -m 644 Cisco.pmchart $(PMCHART)/Cisco $(INSTALL) -m 755 -d $(PMIEDIR) $(INSTALL) -m 644 cisco.in_util.pmie $(PMIEDIR)/in_util $(INSTALL) -m 644 cisco.out_util.pmie $(PMIEDIR)/out_util else build-me: install: endif $(IAM)$(EXECSUFFIX): $(OBJECTS) parse$(EXECSUFFIX): parse.o cisco.o interface.o telnet.o $(CCF) -o $@ $(LDFLAGS) parse.o cisco.o interface.o telnet.o $(LDLIBS) parse.c: pmda.c ln -s pmda.c parse.c parse.o: parse.c $(CCF) -c -DPARSE_ONLY parse.c probe$(EXECSUFFIX): probe.o interface.o telnet.o $(CCF) -o $@ $(LDFLAGS) probe.o interface.o telnet.o $(LDLIBS) cisco.o: domain.h domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmdas/cisco/root0000664000000000000000000000016212272262501014502 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { cisco } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/cisco/pmns0000664000000000000000000000174612272262501014505 0ustar /* * Metrics for cisco PMDA * * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ cisco { bandwidth CISCO:0:5 bytes_in CISCO:0:1 bytes_out CISCO:0:2 bytes_out_bcast CISCO:0:6 rate_in CISCO:0:3 rate_out CISCO:0:4 } pcp-3.8.12ubuntu1/src/pmdas/cisco/cisco.in_util.pmie0000664000000000000000000000255212272262501017217 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) rule cisco.in_util summary = "$rule$" enumerate = hosts predicate = "some_inst ( 100 * cisco.rate_in $hosts$ / cisco.bandwidth $hosts$ > $threshold$ )" enabled = no version = 1 help = "Some Cisco router interface exceeded threshold percent of its peak bandwidth receiving data during the last sample interval. Use the command: $ pminfo -f cisco.bandwidth to discover the list of Cisco router interfaces currently being monitored by the Cisco PMDA - pmdacisco(1)."; string rule default = "Cisco router inbound bandwidth saturation" modify = no display = no; percent threshold default = 90 help = "Threshold percentage for Cisco router saturation, in the range 0 (idle) to 100 (operating at peak bandwidth)"; string action_expand default = %v%util[%i]@%h display = no modify = no; string email_expand default = "host: %h Cisco router: %i inbound utilization: %v%" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x200093" display = no modify = no; # for EnlightenDSM integration: string enln_test default = cisco.in_util display = no modify = no; string enln_units default = %util[%i] display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmdas/cisco/probe.c0000664000000000000000000001674612272262501015066 0ustar /* * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "./cisco.h" int port = 23; int seen_fr = 0; char *prompt = ">"; /* unique suffix to IOS prompt */ char * mygetfirstwd(FILE *f) { char *p; int c; char line[1024]; char *lp; for ( ; ; ) { c = fgetc(f); if (c == EOF) break; if (c == '\r' || c == '\n') continue; if (c != ' ') { ungetc(c, f); break; } lp = line; while ((c = fgetc(f)) != EOF) { *lp++ = c; if (c == '\r' || c == '\n') { *lp = '\0'; break; } } /* * some interesting things to look for here ... */ if (strncmp(&line[1], "Encapsulation FRAME-RELAY", strlen("Encapsulation FRAME-RELAY")) == 0) { seen_fr = 1; } } /* either EOF, or line starts with a non-space */ p = mygetwd(f, prompt); if (p != NULL && (strlen(p) < strlen(prompt) || strcmp(&p[strlen(p)-strlen(prompt)], prompt)) != 0) { /* skip to end of line, ready for next one */ while ((c = fgetc(f)) != EOF) { if (c == '\r' || c == '\n') break; } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) fprintf(stderr, "mygetfirstwd: %s\n", p == NULL ? "" : p); #endif return p; } #define PREAMBLE 1 #define IN_BODY 2 static void probe_cisco(cisco_t * cp) { char *w; int fd; int fd2; int first = 1; char *pass = NULL; int defer = 0; int state = PREAMBLE; int i; int namelen; char *ctype = NULL; char *name = NULL; if (cp->fin == NULL) { fd = conn_cisco(cp); if (fd == -1) { fprintf(stderr, "grab_cisco(%s): connect failed: %s\n", cp->host, osstrerror()); return; } else { cp->fin = fdopen (fd, "r"); if ((fd2 = dup(fd)) < 0) { perror("dup"); exit(1); } cp->fout = fdopen (fd2, "w"); if (cp->username != NULL) { /* * Username stuff ... */ if (dousername(cp, &pass) == 0) { exit(1); } } if (cp->passwd != NULL) { /* * User-level password stuff ... */ if (dopasswd(cp, pass) == 0) { exit(1); } } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "Send: \n"); fprintf(stderr, "Send: terminal length 0\n"); } #endif fprintf(cp->fout, "\n"); fflush(cp->fout); fprintf(cp->fout, "terminal length 0\n"); fflush(cp->fout); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "Send: show int\n"); } #endif fprintf(cp->fout, "show int\n"); fflush(cp->fout); } else { /* * parsing text from a file, not a TCP/IP connection to a * Cisco device */ ; } for ( ; ; ) { w = mygetfirstwd(cp->fin); if (defer && ctype != NULL && name != NULL) { if (seen_fr) { if (first) first = 0; else putchar(' '); printf("%s%s", ctype, name); free(name); name = NULL; } } defer = 0; if (w == NULL) { /* * End of File (telenet timeout?) */ fprintf(stderr, "grab_cisco(%s): forced disconnect fin=%d\n", cp->host, fileno(cp->fin)); return; } if (*w == '\0') continue; if (state == PREAMBLE) { if (strcmp(w, "show") == 0) state = IN_BODY; else if (strcmp(w, PWPROMPT) == 0) { fprintf(stderr, "Error: user-level password required for \"%s\"\n", cp->host); exit(1); } continue; } else { if (strlen(w) >= strlen(prompt) && strcmp(&w[strlen(w)-strlen(prompt)], prompt) == 0) break; ctype = NULL; for (i = 0; i < num_intf_tab; i++) { namelen = strlen(intf_tab[i].name); if (strncmp(w, intf_tab[i].name, namelen) == 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "Match: if=%s word=%s\n", intf_tab[i].name, w); } #endif name = strdup(&w[namelen]); ctype = intf_tab[i].type; if (intf_tab[i].type != NULL && strcmp(intf_tab[i].type, "a") == 0) { /* * skip ATMN.M ... need ATMN */ if (strchr(&w[namelen], '.') != NULL) ctype = NULL; } else if (intf_tab[i].type != NULL && strcmp(intf_tab[i].type, "s") == 0) { /* * skip SerialN.M ... need SerialN, unless frame-relay */ if (strchr(&w[namelen], '.') != NULL) defer = 1; } break; } } if (i == num_intf_tab) fprintf(stderr, "%s: Warning, unknown interface: %s\n", pmProgname, w); if (ctype != NULL && name != NULL && !defer) { if (first) first = 0; else putchar(' '); printf("%s%s", ctype, name); free(name); name = NULL; } } } putchar('\n'); /* close CISCO telnet session */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "Send: exit\n"); } #endif fprintf(cp->fout, "exit\n"); fflush(cp->fout); return; } int main(int argc, char **argv) { int errflag = 0; int c; int sts; char *endnum; char *passwd = NULL; char *username = NULL; struct hostent *hostInfo; __pmSetProgname(argv[0]); while ((c = getopt(argc, argv, "D:P:s:U:x:?")) != EOF) { switch (c) { case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case 'P': /* passwd */ passwd = optarg; break; case 's': /* prompt */ prompt = optarg; break; case 'U': /* username */ username = optarg; break; case 'x': port = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0') { fprintf(stderr, "%s: -x requires numeric argument\n", pmProgname); errflag++; } break; case '?': errflag++; } } if (errflag || optind != argc-1) { fprintf(stderr, "Usage: %s [-U username] [-P passwd] [-s prompt] [-x port] host\n\n", pmProgname); exit(1); } if ((hostInfo = gethostbyname(argv[optind])) == NULL) { FILE *f; if ((f = fopen(argv[optind], "r")) == NULL) { fprintf(stderr, "%s: unknown hostname or filename %s: %s\n", pmProgname, argv[optind], hoststrerror()); exit(1); } else { cisco_t c; fprintf(stderr, "%s: assuming file %s contains output from \"show int\" command\n", pmProgname, argv[optind]); c.host = argv[optind]; c.username = NULL; c.passwd = NULL; c.fin = f; c.fout = fopen("/dev/null", "w"); c.prompt = prompt; probe_cisco(&c); } } else { cisco_t c; struct sockaddr_in *sinp = & c.ipaddr; c.host = argv[optind]; c.username = username; c.passwd = passwd; c.fin = NULL; c.fout = NULL; c.prompt = prompt; memset(sinp, 0, sizeof(c.ipaddr)); sinp->sin_family = AF_INET; memcpy(&sinp->sin_addr, hostInfo->h_addr, hostInfo->h_length); sinp->sin_port = htons(23); /* telnet */ probe_cisco(&c); } exit(0); } pcp-3.8.12ubuntu1/src/pmdas/cisco/Samples0000664000000000000000000003462312272262501015134 0ustar Serial 0 is up, line protocol is up Hardware is MK5025 Description: frame-relay to MtVA, Tokyo, Hong Kong Internet address is 155.11.201.172, subnet mask is 255.255.255.128 MTU 1500 bytes, BW 64 Kbit, DLY 20000 usec, rely 255/255, load 15/255 Encapsulation FRAME-RELAY, loopback not set, keepalive set (10 sec) LMI DLCI 0, LMI sent 346516, LMI stat recvd 345070, LMI upd recvd 2 LMI type is ANSI Annex D Last input 0:00:01, output 0:00:00, output hang never Last clearing of "show interface" counters never Output queue 0/8, 298580 drops; input queue 0/75, 0 drops Five minute input rate 60000 bits/sec, 16 packets/sec Five minute output rate 4000 bits/sec, 12 packets/sec 18139408 packets input, 2763796661 bytes, 0 no buffer Received 0 broadcasts, 0 runts, 0 giants 189 input errors, 189 CRC, 0 frame, 0 overrun, 0 ignored, 0 abort 15860554 packets output, 3098844973 bytes, 0 underruns 0 output errors, 0 collisions, 668 interface resets, 0 restarts 686 carrier transitions Ethernet 0 is up, line protocol is up Hardware is Lance, address is 0000.0c03.ed85 (bia 0000.0c03.ed85) Description: Sydney, Australia Internet address is 155.11.226.3, subnet mask is 255.255.255.128 MTU 1500 bytes, BW 10000 Kbit, DLY 1000 usec, rely 255/255, load 1/255 Encapsulation ARPA, loopback not set, keepalive set (10 sec) ARP type: ARPA, ARP Timeout 4:00:00 Last input 0:00:00, output 0:00:00, output hang never Last clearing of "show interface" counters never Output queue 0/40, 19188 drops; input queue 1/75, 0 drops Five minute input rate 5000 bits/sec, 10 packets/sec Five minute output rate 60000 bits/sec, 13 packets/sec 12884820 packets input, 1321046112 bytes, 0 no buffer Received 1570813 broadcasts, 0 runts, 0 giants 891 input errors, 891 CRC, 634 frame, 0 overrun, 0 ignored, 0 abort 14717105 packets output, 870622060 bytes, 0 underruns 98605 output errors, 1883820 collisions, 1 interface resets, 0 restarts Fddi2/0 is up, line protocol is up Hardware is cxBus FDDI, address is 0000.0c38.4360 (bia 0000.0c38.4360) Internet address is 192.26.80.22, subnet mask is 255.255.255.0 MTU 4470 bytes, BW 100000 Kbit, DLY 100 usec, rely 255/255, load 1/255 Encapsulation SNAP, loopback not set, keepalive not set ARP type: SNAP, ARP Timeout 4:00:00 Phy-A state is connect, neighbor is unk, cmt signal bits 008/000, status QLS Phy-B state is active, neighbor is M, cmt signal bits 20C/00E, status ILS CFM is wrap B, token rotation 5000 usec, ring operational 0:00:58 Upstream neighbor 0800.6904.155d, downstream neighbor 0040.0b80.a052 Last input 0:00:00, output 0:00:00, output hang never Last clearing of "show interface" counters 1w0d Output queue 0/40, 85 drops; input queue 0/75, 33437 drops Five minute input rate 160000 bits/sec, 39 packets/sec Five minute output rate 93000 bits/sec, 108 packets/sec 33780622 packets input, 4009491185 bytes, 87 no buffer Received 3768432 broadcasts, 0 runts, 0 giants 2 input errors, 1 CRC, 1 frame, 0 overrun, 19 ignored, 0 abort 83194423 packets output, 612803885 bytes, 492 underruns 0 output errors, 0 collisions, 0 interface resets, 0 restarts 21602 transitions, 0 traces, 11625 claims, 0 beacon Serial1 is up, line protocol is up Hardware is HD64570 Description: Frame-relay, MtV, Hong Kong, Sydney MTU 1500 bytes, BW 1544 Kbit, DLY 20000 usec, rely 255/255, load 5/255 Encapsulation FRAME-RELAY, loopback not set, keepalive set (10 sec) LMI enq sent 14998, LMI stat recvd 14885, LMI upd recvd 0, DTE LMI up LMI enq recvd 0, LMI stat sent 0, LMI upd sent 0 LMI DLCI 0 LMI type is ANSI Annex D frame relay DTE Broadcast queue 0/200, broadcasts sent/dropped 508604/0 Last input 0:00:00, output 0:00:00, output hang never Last clearing of "show interface" counters never Output queue 0/40, 947 drops; input queue 0/75, 0 drops Five minute input rate 117000 bits/sec, 29 packets/sec Five minute output rate 32000 bits/sec, 20 packets/sec 2578327 packets input, 1105345262 bytes, 0 no buffer Received 0 broadcasts, 0 runts, 0 giants 54 input errors, 4 CRC, 0 frame, 0 overrun, 1 ignored, 4 abort 1975049 packets output, 675844616 bytes, 0 underruns 0 output errors, 0 collisions, 142 interface resets, 0 restarts 3 carrier transitions DCD=up DSR=up DTR=up RTS=up CTS=up Ethernet3/5 is up, line protocol is up Hardware is cxBus Ethernet, address is 0000.0c38.436d (bia 0000.0c38.436d) Internet address is 198.29.108.4, subnet mask is 255.255.255.0 MTU 1500 bytes, BW 10000 Kbit, DLY 1000 usec, rely 255/255, load 2/255 Encapsulation ARPA, loopback not set, keepalive set (10 sec) ARP type: ARPA, ARP Timeout 4:00:00 Last input 0:00:03, output 0:00:01, output hang never Last clearing of "show interface" counters 6w2d Output queue 0/40, 54880 drops; input queue 0/75, 1492 drops 5 minute input rate 1000 bits/sec, 0 packets/sec 5 minute output rate 91000 bits/sec, 98 packets/sec 24627812 packets input, 1448819515 bytes, 862 no buffer Received 3959194 broadcasts, 79 runts, 4 giants 292 input errors, 195 CRC, 14 frame, 0 overrun, 0 ignored, 0 abort 0 input packets with dribble condition detected 150470373 packets output, 3227527737 bytes, 0 underruns 1274 output errors, 11605581 collisions, 0 interface resets, 0 restarts ATM12/0 is up, line protocol is up Hardware is cxBus ATM Internet address is 150.166.230.24 255.255.255.0 MTU 4470 bytes, BW 156250 Kbit, DLY 80 usec, rely 255/255, load 1/255 Encapsulation ATM, loopback not set, keepalive set (10 sec) Encapsulation(s): AAL5, PVC mode 256 TX buffers, 256 RX buffers, 2048 maximum active VCs, 1024 VCs per VP, 15 current VCCs Last input 0:00:00, output 0:00:00, output hang never Last clearing of "show interface" counters never Output queue 0/40, 511 drops; input queue 0/75, 10612 drops 5 minute input rate 181000 bits/sec, 116 packets/sec 5 minute output rate 160000 bits/sec, 68 packets/sec 658262505 packets input, 1239748718 bytes, 199 no buffer Received 0 broadcasts, 0 runts, 0 giants 2570 input errors, 2569 CRC, 1 frame, 0 overrun, 0 ignored, 0 abort 788426419 packets output, 4188341273 bytes, 0 underruns 0 output errors, 0 collisions, 21 interface resets, 0 restarts 0 output buffer failures, 63 output buffers swapped out Hssi3/0 is administratively down, line protocol is down Hardware is cxBus HSSI Description: 45 Meg Microwave Link to Building 27 Internet address is 150.166.124.1 255.255.255.0 MTU 4470 bytes, BW 45045 Kbit, DLY 200 usec, rely 255/255, load 1/255 Encapsulation HDLC, loopback not set, keepalive set (10 sec) Last input 1:07:12, output 1:07:08, output hang never Last clearing of "show interface" counters never Output queue 0/40, 2 drops; input queue 0/75, 37 drops 5 minute input rate 0 bits/sec, 0 packets/sec 5 minute output rate 0 bits/sec, 0 packets/sec 306700515 packets input, 1443052046 bytes, 5 no buffer Received 1118787 broadcasts, 0 runts, 0 giants 0 parity 241 input errors, 0 CRC, 241 frame, 0 overrun, 0 ignored, 0 abort 246381377 packets output, 3684064154 bytes, 0 underruns 0 output errors, 0 applique, 210 interface resets, 0 restarts 0 output buffer failures, 83 output buffers swapped out 8214 carrier transitions FastEthernet1/0 is up, line protocol is up Hardware is cyBus FastEthernet Interface, address is 0060.3eb0.8c20 (bia 0060.3eb0.8c20) Internet address is 192.111.17.1 255.255.255.0 MTU 1500 bytes, BW 100000 Kbit, DLY 100 usec, rely 255/255, load 1/255 Encapsulation ARPA, loopback not set, keepalive set (10 sec), fdx, MII ARP type: ARPA, ARP Timeout 4:00:00 Last input 0:00:05, output 0:00:05, output hang never Last clearing of "show interface" counters never Output queue 0/40, 0 drops; input queue 0/75, 362 drops 5 minute input rate 8000 bits/sec, 1 packets/sec 5 minute output rate 11000 bits/sec, 0 packets/sec 4615550 packets input, 1942263093 bytes, 33 no buffer Received 1947224 broadcasts, 0 runts, 8 giants 30351 input errors, 30351 CRC, 15187 frame, 0 overrun, 0 ignored, 0 abort 0 watchdog, 27381 multicast 0 input packets with dribble condition detected 11521698 packets output, 1811832796 bytes, 0 underruns 0 output errors, 0 collisions, 2 interface resets, 0 restarts 0 babbles, 0 late collision, 0 deferred 0 lost carrier, 0 no carrier 0 output buffer failures, 0 output buffers swapped out Serial1/0 is up, line protocol is up Hardware is M4T Description: frame-relay using subinterfaces MTU 1500 bytes, BW 64 Kbit, DLY 20000 usec, rely 255/255, load 11/255 Encapsulation FRAME-RELAY, loopback not set, keepalive set (10 sec) LMI enq sent 10084, LMI stat recvd 9997, LMI upd recvd 0, DTE LMI up LMI enq recvd 0, LMI stat sent 0, LMI upd sent 0 LMI DLCI 0 LMI type is ANSI Annex D frame relay DTE FR SVC disabled, LAPF state down Broadcast queue 0/200, broadcasts sent/dropped 53152/0, interface broadcasts 49826 Last input 00:00:01, output 00:00:00, output hang never Last clearing of "show interface" counters never Queueing strategy: fifo Output queue 0/8, 0 drops; input queue 0/75, 0 drops 5 minute input rate 3000 bits/sec, 4 packets/sec 5 minute output rate 3000 bits/sec, 4 packets/sec 429076 packets input, 132623595 bytes, 0 no buffer Received 0 broadcasts, 0 runts, 1 giants, 0 throttles 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored, 0 abort 474808 packets output, 73186481 bytes, 0 underruns 0 output errors, 0 collisions, 31 interface resets 0 output buffer failures, 0 output buffers swapped out 35 carrier transitions DCD=up DSR=up DTR=up RTS=up CTS=up Serial1/0 is up, line protocol is up Hardware is M4T Description: frame-relay using subinterfaces MTU 1500 bytes, BW 64 Kbit, DLY 20000 usec, rely 255/255, load 31/255 Encapsulation FRAME-RELAY, loopback not set, keepalive set (10 sec) LMI enq sent 39756, LMI stat recvd 39753, LMI upd recvd 0, DTE LMI up LMI enq recvd 0, LMI stat sent 0, LMI upd sent 0 LMI DLCI 0 LMI type is ANSI Annex D frame relay DTE FR SVC disabled, LAPF state down Broadcast queue 0/200, broadcasts sent/dropped 91696/0, interface broadcasts 85069 Last input 00:00:00, output 00:00:00, output hang never Last clearing of "show interface" counters never Queueing strategy: fifo Output queue 0/8, 0 drops; input queue 0/75, 0 drops 30 second input rate 62000 bits/sec, 9 packets/sec 30 second output rate 8000 bits/sec, 5 packets/sec 2238005 packets input, 630502832 bytes, 0 no buffer Received 0 broadcasts, 0 runts, 0 giants, 0 throttles 111 input errors, 108 CRC, 0 frame, 0 overrun, 0 ignored, 3 abort 2274950 packets output, 230325061 bytes, 0 underruns 0 output errors, 0 collisions, 2 interface resets 0 output buffer failures, 0 output buffers swapped out 3 carrier transitions DCD=up DSR=up DTR=up RTS=up CTS=up >show int s2/2.1 Serial2/2.1 is up, line protocol is up Hardware is M4T Description: Frame Relay to Sydney (134.14.63.129) Internet address is 134.14.63.130/30 MTU 1500 bytes, BW 512 Kbit, DLY 20000 usec, reliability 255/255, txload 2/255, rxload 17/255 Encapsulation FRAME-RELAY CIR is BW 512 Kbit == 512*1024/10 bytes/sec (?) This number is hand typed, but there is no alternative for the CIR. For FrameRelay, utilization > 50% of CIR for alarm. >show frame pvc int s2/3.7 PVC Statistics for interface Serial2/3.7 (Frame Relay DTE) Active Inactive Deleted Static Local 2 0 0 0 Switched 0 0 0 0 Unused 0 0 0 0 DLCI = 17, DLCI USAGE = LOCAL, PVC STATUS = ACTIVE, INTERFACE = Serial2/3.7 input pkts 1287959 output pkts 1446754 in bytes 811690634 out bytes 187572881 dropped pkts 0 in FECN pkts 2333 in BECN pkts 0 out FECN pkts 0 out BECN pkts 0 in DE pkts 0 out DE pkts 0 out bcast pkts 43801 out bcast bytes 13172828 pvc create time 8w3d, last time pvc status changed 1w2d >show int Vlan256 Vlan256 is up, line protocol is up Hardware is Cat6k RP Virtual Ethernet, address is 0030.b630.b318 (bia 0030.b630.b318) Description: Uplink to CTC tipctc2 (Area 2) Internet address is 192.132.156.72/26 MTU 1500 bytes, BW 10000 Kbit, DLY 1000 usec, reliablility 255/255, txload 1/255, rxload 44/255 Encapsulation ARPA, loopback not set ARP type: ARPA, ARP Timeout 04:00:00 Last input 00:00:00, output never, output hang never Last clearing of "show interface" counters never Queueing strategy: fifo Output queue 0/40, 2 drops; input queue 0/75, 1027 drops 5 minute input rate 1754000 bits/sec, 158 packets/sec 5 minute output rate 9000 bits/sec, 6 packets/sec 3087365859 packets input, 816292345 bytes, 224 no buffer Received 3085491728 broadcasts, 0 runts, 0 giants, 0 throttles 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored 110141390 packets output, 3736073981 bytes, 0 underruns 0 output errors, 3 interface resets 0 output buffer failures, 0 output buffers swapped out >show int e1/0 Ethernet1/0 is up, line protocol is up Hardware is AmdP2, address is 0050.7343.f011 (bia 0050.7343.f011) Description: >>> Connecion to melbourne pix-e1 <<< Internet address is 134.14.71.241/30 MTU 1500 bytes, BW 10000 Kbit, DLY 1000 usec, reliability 255/255, txload 3/255, rxload 1/255 Encapsulation ARPA, loopback not set Keepalive set (10 sec) ARP type: ARPA, ARP Timeout 04:00:00 Last input 00:09:05, output 00:00:00, output hang never Last clearing of "show interface" counters never Queueing strategy: fifo Output queue 0/40, 0 drops; input queue 0/75, 0 drops 30 second input rate 26000 bits/sec, 4 packets/sec 30 second output rate 118000 bits/sec, 97 packets/sec 3657465 packets input, 2161281566 bytes, 0 no buffer Received 79047 broadcasts, 0 runts, 0 giants, 0 throttles 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored 0 input packets with dribble condition detected 13202080 packets output, 4162655553 bytes, 0 underruns 6 output errors, 249819 collisions, 11 interface resets 0 babbles, 0 late collision, 207020 deferred 6 lost carrier, 0 no carrier 0 output buffer failures, 0 output buffers swapped out pcp-3.8.12ubuntu1/src/pmdas/cisco/pmda.c0000664000000000000000000002625412272262501014673 0ustar /* * Copyright (c) 2012 Red Hat. * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * Cisco PMDA, based on generic driver for a daemon-based PMDA * - cisco interfaces to monitor are named in the command line as * hostname:tX[@username] * hostname:tX[?passwd] * hostname:tX[@username?passwd] * hostname:tX[!prompt] * hostname:tX[@username!prompt] * hostname:tX[?passwd!prompt] * hostname:tX[@username?passwd!prompt] * * where t identifies an interface type as defined by intf_tab[] in * interface.c * and X is either the ordinal i/f number (base 0, for Series 4000) * or the card/port number (Series 7000 routers) * e.g sydcisco.sydney:s0 (Frame-Relay to Mtn View) * sydcisco.sydney:s1 (ISDN to Melbourne) * cisco.melbourne:s0 (ISDN to Sydney) * b8u-cisco1-e15.corp:e0 (Ethernet in Bldg 8 upper) * b9u-cisco1-81.engr.sgi.com:f2/0 * wanbris.brisbane:B0 (BRI ISDN) * If specified the username (after the @ delimiter) and/or the * user-level password (after the ? delimiter) and/or the prompt (after * the ! delimiter) over-rides the global username and/or user-level * password and/or prompt, as specified via -U and/or -P and/or -s * options and applies for all occurrences of the hostname. */ #include #include #include #include #include #include #include #include #include "./cisco.h" pmdaInstid *_router; cisco_t *cisco; int n_cisco; intf_t *intf; int n_intf; int refreshdelay = 120; /* default poll every two minutes */ char *pmdausername; /* username for the pmda */ char *username; /* username */ char *passwd; /* user-level password */ char *prompt = ">"; /* command prompt */ int port = 23; int parse_only; extern void cisco_init(pmdaInterface *); extern void cisco_done(void); int main(int argc, char **argv) { int err = 0; int sep = __pmPathSeparator(); char *endnum; pmdaInterface dispatch; int n; int i; int c; char helptext[MAXPATHLEN]; __pmSetProgname(argv[0]); __pmGetUsername(&pmdausername); #ifdef PARSE_ONLY pmDebug = DBG_TRACE_APPL0; parse_only = 1; #endif snprintf(helptext, sizeof(helptext), "%s%c" "cisco" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_3, pmProgname, CISCO, "cisco.log", parse_only ? NULL : helptext); while ((c = pmdaGetOpt(argc, argv, "D:d:h:i:l:pu:6:" "M:P:r:s:U:x:?", &dispatch, &err)) != EOF) { switch (c) { case 'P': /* passwd */ passwd = optarg; break; case 'r': refreshdelay = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0') { fprintf(stderr, "%s: -r requires numeric (number of seconds) argument\n", pmProgname); err++; } break; case 's': /* command prompt */ prompt = optarg; break; case 'M': /* username (for the PMDA) */ pmdausername = optarg; break; case 'U': /* username (for the Cisco) */ username = optarg; break; case 'x': port = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0') { fprintf(stderr, "%s: -x requires numeric argument\n", pmProgname); err++; } break; case '?': err++; } } n_intf = argc - optind; if (n_intf == 0 || err) { fprintf(stderr, "Usage: %s [options] host:{a|B|E|e|f|h|s}N[/M[.I]] [...]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -i port expect PMCD to connect on given inet port (number or name)\n" " -l logfile redirect diagnostics and trace output to logfile\n" " -M username user account to run PMDA under (default \"pcp\")\n" " -p expect PMCD to supply stdin/stdout (pipe)\n" " -P password default user-level Cisco password\n" " -r refresh update metrics every refresh seconds\n" " -s prompt Cisco command prompt [default >]\n" " -u socket expect PMCD to connect on given unix domain socket\n" " -U username Cisco username\n" " -x port telnet port [default 23]\n" " -6 port expect PMCD to connect on given ipv6 port (number or name)\n", stderr); exit(1); } #ifdef PARSE_ONLY #else /* force errors from here on into the log */ pmdaOpenLog(&dispatch); __pmSetProcessIdentity(pmdausername); #endif /* * build the instance domain and cisco data structures from the * command line arguments. */ if ((_router = (pmdaInstid *)malloc(n_intf * sizeof(pmdaInstid))) == NULL) { __pmNoMem("main.router", n_intf * sizeof(pmdaInstid), PM_FATAL_ERR); } if ((intf = (intf_t *)malloc(n_intf * sizeof(intf_t))) == NULL) { __pmNoMem("main.intf", n_intf * sizeof(intf_t), PM_FATAL_ERR); } /* pre-allocated cisco[] to avoid realloc and ptr movement */ if ((cisco = (cisco_t *)malloc(n_intf * sizeof(cisco_t))) == NULL) { __pmNoMem("main.cisco", n_intf * sizeof(cisco_t), PM_FATAL_ERR); } indomtab[CISCO_INDOM].it_numinst = n_intf; indomtab[CISCO_INDOM].it_set = _router; for (n = 0 ; optind < argc; optind++, n++) { char *p = strdup(argv[optind]); char *q; char *myusername; char *mypasswd; char *myprompt; myprompt = strchr(p, '!'); if (myprompt) { /* save prompt for later */ *myprompt++ = '\0'; } else myprompt = NULL; mypasswd = strchr(p, '?'); if (mypasswd) { /* save user-level password for later */ *mypasswd++ = '\0'; } else mypasswd = passwd; myusername = strchr(p, '@'); if (myusername) { /* save username for later */ *myusername++ = '\0'; } else myusername = username; _router[n].i_inst = n; _router[n].i_name = strdup(p); if ((q = strchr(p, ':')) == NULL) goto badintfspec; *q++ = '\0'; for (i = 0; i < num_intf_tab; i++) { if (strncmp(q, intf_tab[i].type, strlen(intf_tab[i].type)) == 0) break; } if (i == num_intf_tab) goto badintfspec; if (strcmp(intf_tab[i].type, "E") == 0) { /* * Cisco parser is case insensitive, so 'E' means "Ethernet" * and 'F' means "Fddi", need to use "FastEthernet" here */ q++; intf[n].interface = (char *)malloc(strlen("FastEthernet")+strlen(q)+1); if ((intf[n].interface = (char *)malloc(strlen("FastEthernet")+strlen(q)+1)) == NULL) { __pmNoMem("main.cisco", strlen("FastEthernet")+strlen(q)+1, PM_FATAL_ERR); } strcpy(intf[n].interface, "FastEthernet"); strcat(intf[n].interface, q); } else intf[n].interface = q; for (i = 0; i < n_cisco; i++) { if (strcmp(p, cisco[i].host) == 0) break; } if (i == n_cisco) { struct hostent *hostInfo; if ((hostInfo = gethostbyname(p)) == NULL) { #ifdef PARSE_ONLY /* * for debugging, "host" may be a file ... */ FILE *f; if ((f = fopen(p, "r")) == NULL) { fprintf(stderr, "%s: unknown hostname or filename %s: %s\n", pmProgname, argv[optind], hoststrerror()); /* abandon this host (cisco) */ continue; } else { fprintf(stderr, "%s: assuming file %s contains output from \"show int\" command\n", pmProgname, p); cisco[i].host = p; cisco[i].username = myusername != NULL ? myusername : username; cisco[i].passwd = mypasswd != NULL ? mypasswd : passwd; cisco[i].prompt = myprompt != NULL ? myprompt : prompt; cisco[i].fin = f; cisco[i].fout = stdout; n_cisco++; } #else fprintf(stderr, "%s: unknown hostname %s: %s\n", pmProgname, p, hoststrerror()); /* abandon this host (cisco) */ continue; #endif } else { struct sockaddr_in *sinp = & cisco[i].ipaddr; cisco[i].host = p; cisco[i].username = myusername != NULL ? myusername : username; cisco[i].passwd = mypasswd != NULL ? mypasswd : passwd; cisco[i].prompt = myprompt != NULL ? myprompt : prompt; cisco[i].fin = NULL; cisco[i].fout = NULL; memset(sinp, 0, sizeof(cisco[i].ipaddr)); sinp->sin_family = AF_INET; memcpy(&sinp->sin_addr, hostInfo->h_addr, hostInfo->h_length); sinp->sin_port = htons(port); /* telnet */ n_cisco++; fprintf (stderr, "Adding new host %s\n", p); fflush (stderr); } } else { if (cisco[i].username == NULL) { if (myusername != NULL) /* username on 2nd or later interface ... applies to all */ cisco[i].username = myusername; } else { if (myusername != NULL) { if (strcmp(cisco[i].username, myusername) != 0) { fprintf(stderr, "%s: conflicting usernames (\"%s\" " "and \"%s\") for cisco \"%s\"\n", pmProgname, cisco[i].username, myusername, cisco[i].host); exit(1); } } } if (cisco[i].passwd == NULL) { if (mypasswd != NULL) /* passwd on 2nd or later interface ... applies to all */ cisco[i].passwd = mypasswd; } else { if (mypasswd != NULL) { if (strcmp(cisco[i].passwd, mypasswd) != 0) { fprintf(stderr, "%s: conflicting user-level passwords (\"%s\" " "and \"%s\") for cisco \"%s\"\n", pmProgname, cisco[i].passwd, mypasswd, cisco[i].host); exit(1); } } } if (cisco[i].prompt == NULL) { if (myprompt != NULL) /* prompt on 2nd or later interface ... applies to all */ cisco[i].prompt = myprompt; } else { if (myprompt != NULL) { if (strcmp(cisco[i].prompt, myprompt) != 0) { fprintf(stderr, "%s: conflicting user-level prompts (\"%s\" " "and \"%s\") for cisco \"%s\"\n", pmProgname, cisco[i].prompt, myprompt, cisco[i].host); exit(1); } } } } intf[n].cp = cisco+i; /* * special one-trip initialization for Frame-Relay over serial * lines ... see grab_cisco() */ intf[n].bandwidth = -2; fprintf (stderr, "Interface %s(%d) is on host %s\n", intf[n].interface, n, cisco[i].host); fflush (stderr); continue; badintfspec: fprintf(stderr, "%s: bad interface specification \"%s\"\n", pmProgname, argv[optind]); fprintf(stderr, " should be like sydcisco.sydney:s1 or b9u-cisco1-81.engr.sgi.com:f2/0\n"); fprintf(stderr, " or cisco.melbourne:e0?secret\n"); exit(1); } if (! n_cisco ) { fprintf(stderr, "%s: Nothing to monitor\n", pmProgname); exit(1); } #ifdef PARSE_ONLY dispatch.version.two.text = NULL; #endif /* initialize */ cisco_init(&dispatch); #ifdef PARSE_ONLY for (i = 0; i < n_intf; i++) intf[i].fetched = 0; fprintf(stderr, "Sleeping while sproc does the work ... SIGINT to terminate\n"); pause(); #else /* set up connection to PMCD */ pmdaConnect(&dispatch); pmdaMain(&dispatch); #endif cisco_done(); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/cisco/cisco.c0000664000000000000000000001416212272262501015045 0ustar /* * Copyright (c) 1995-2000 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "cisco.h" #if defined(HAVE_SYS_RESOURCE_H) #include #endif #if defined(HAVE_SYS_WAIT_H) #include #endif #if defined(HAVE_PTHREAD_H) #include #endif #if defined(HAVE_PRCTL_H) #include #endif extern int refreshdelay; #ifdef HAVE_SPROC static pid_t sproc_pid = 0; #elif defined (HAVE_PTHREAD_H) #include static pthread_t sproc_pid; #else #error "Need sproc or pthreads here!" #endif /* * all metrics supported in this PMD - one table entry for each */ static pmdaMetric metrictab[] = { /* 0,0 ... for direct map, sigh */ { NULL, { PMDA_PMID(0,0), 0, 0, 0, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* bytes-in */ { NULL, { PMDA_PMID(0,1), PM_TYPE_U64, CISCO_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, /* bytes-out */ { NULL, { PMDA_PMID(0,2), PM_TYPE_U64, CISCO_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, /* rate-in */ { NULL, { PMDA_PMID(0,3), PM_TYPE_U32, CISCO_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_SEC,0) } }, /* rate-out */ { NULL, { PMDA_PMID(0,4), PM_TYPE_U32, CISCO_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_SEC,0) } }, /* bandwidth */ { NULL, { PMDA_PMID(0,5), PM_TYPE_U32, CISCO_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_SEC,0) } }, /* bytes_out_bcast */ { NULL, { PMDA_PMID(0,6), PM_TYPE_U64, CISCO_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, }; /* filled in from command line args in main() ... */ pmdaIndom indomtab[] = { { 0, 0, 0 }, }; #ifdef HAVE_SPROC static RETSIGTYPE onhup(int s) { signal(SIGHUP, onhup); exit(0); } #endif /* * the sproc starts here to refresh the metric values periodically */ void refresh(void *dummy) { int i; #ifdef HAVE_SPROC #if HAVE_PRCTL signal(SIGHUP, onhup); #if HAVE_PR_TERMCHILD prctl(PR_TERMCHILD); /* SIGHUP when the parent dies */ #elif HAVE_PR_SET_PDEATHSIG prctl(PR_SET_PDEATHSIG, SIGHUP); #endif #endif #endif #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "Starting sproc ...\n"); for (i = 0; i < n_cisco; i++) { int j; fprintf(stderr, "cisco[%d] host: %s username: %s passwd: %s prompt: %s intf:", i, cisco[i].host, cisco[i].username, cisco[i].passwd, cisco[i].prompt); for (j = 0; j < n_intf; j++) { if (intf[j].cp == (cisco+i)) fprintf(stderr, " %d-%s", j, intf[j].interface); } fputc('\n', stderr); } } #endif for ( ; ; ) { for (i = 0; i < n_intf; i++) { if (grab_cisco(intf+i) != -1) { intf[i].fetched = 1; } else intf[i].fetched = 0; } if (parse_only) exit(0); for (i = 0; i < n_cisco; i++) { if (cisco[i].fout != NULL) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "... %s voluntary disconnect fout=%d\n", cisco[i].host, fileno(cisco[i].fout)); #endif /* close CISCO telnet session */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "Send: exit\n"); } #endif fprintf(cisco[i].fout, "exit\n"); fclose(cisco[i].fout); cisco[i].fout = NULL; } if (cisco[i].fin != NULL) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "... %s close fin=%d\n", cisco[i].host, fileno(cisco[i].fin)); #endif fclose(cisco[i].fin); cisco[i].fin = NULL; } } sleep(refreshdelay); } } static int cisco_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *avp) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); #ifndef HAVE_SPROC /* Check is refresh thread is still with us */ int err; if ( (err = pthread_kill (sproc_pid, 0)) != 0 ) { exit (1); } #endif if (!intf[inst].fetched) return PM_ERR_AGAIN; switch (idp->item) { case 1: /* bytes_in */ if (intf[inst].bytes_in == -1) return 0; avp->ull = intf[inst].bytes_in; break; case 2: /* bytes_out */ if (intf[inst].bytes_out == -1) return 0; avp->ull = intf[inst].bytes_out; break; case 3: /* rate_in */ if (intf[inst].rate_in == -1) return 0; avp->ul = intf[inst].rate_in; break; case 4: /* rate_out */ if (intf[inst].rate_out == -1) return 0; avp->ul = intf[inst].rate_out; break; case 5: /* bandwidth */ if (intf[inst].bandwidth == -1) return 0; avp->ul = intf[inst].bandwidth; break; case 6: /* bytes_out_bcast */ if (intf[inst].bytes_out_bcast == -1) return 0; avp->ull = intf[inst].bytes_out_bcast; break; default: return PM_ERR_PMID; } return 1; } void cisco_init(pmdaInterface *dp) { int i; pmdaSetFetchCallBack(dp, cisco_fetchCallBack); pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), metrictab, sizeof(metrictab)/sizeof(metrictab[0])); for (i = 0; i < n_intf; i++) intf[i].fetched = 0; /* start the sproc for async fetches */ #ifdef HAVE_SPROC i = sproc_pid = sproc(refresh, PR_SADDR); #elif defined (HAVE_PTHREAD_H) i = pthread_create(&sproc_pid, NULL, (void (*))refresh, NULL); #else #error "Need sproc or pthread here!" #endif if (i < 0) dp->status = i; else dp->status = 0; } void cisco_done(void) { int i; if (sproc_pid > 0) { #ifndef HAVE_SPROC pthread_kill(sproc_pid, SIGHUP); #else kill(sproc_pid, SIGHUP); #endif while (wait(&i) >= 0) ; } } pcp-3.8.12ubuntu1/src/pmdas/cisco/help0000664000000000000000000000635212272262501014456 0ustar # # Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # cisco PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric-name oneline-text # help test goes # here over multiple lines # ... # # the metric-name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ CISCO.1 Interfaces on Cisco router There is one instance in this domain for each interface on a Cisco router that the Cisco PMDA (Performance Metrics Domain Agent) has been told about when the PMDA is started. The names of the instances are of the form hostname:tX where "t" is one of "a" for ATM, "B" for ISDN BRI, "e" for Ethernet, "E" (FastEthernet), "f" for Fddi, "h" for HSSC, "s" for Serial or "Vl" for Vlan. The "X" is the interface identifier which is either an integer (e.g. 4000 Series routers) or two integers separated by a slash (e.g. 7000 Series routers) or three integers separated by a slash and a period (Frame-Relay PVCs on serial line subinterfaces). @ cisco.bytes_in Total Kbytes input to the Cisco Total number of Kbytes input to the Cisco on this interface. Note that due to network delays in extracting the metrics from the Cisco routers, any rate computed from this metric over small deltas in time are likely to be subject to wide variance. @ cisco.bytes_out Total Kbytes output from the Cisco Total number of Kbytes output from the Cisco on this interface. Note that due to network delays in extracting the metrics from the Cisco routers, any rate computed from this metric over small deltas in time are likely to be subject to wide variance. @ cisco.bytes_out_bcast Total broadcast Kbytes output from the Cisco Total number of broadcast Kbytes output from the Cisco on this interface. Note that due to network delays in extracting the metrics from the Cisco routers, any rate computed from this metric over small deltas in time are likely to be subject to wide variance. @ cisco.rate_in 5 minutes average input rate in bytes (not bits!) per second Cisco's computed average input rate in bytes per second, over the recent past, for this interface. @ cisco.rate_out 5 minutes average output rate in bytes (not bits!) per second Cisco's computed average output rate in bytes per second, over the recent past, for this interface. @ cisco.bandwidth peak interface bandwidth in bytes per second pcp-3.8.12ubuntu1/src/pmdas/cisco/interface.c0000664000000000000000000000265612272262501015712 0ustar /* * Known Cisco Interfaces * * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "./cisco.h" /* * first letter defines command line argument for interface type * (0 means not allowed in command line) * full name of interface is as found in "show interface" command * output. */ intf_tab_t intf_tab[] = { { "s", "Serial" }, { "e", "Ethernet" }, { "E", "FastEthernet" }, { "f", "Fddi" }, { "h", "Hssi" }, { "a", "ATM" }, { "B", "BRI" }, { "Vl", "Vlan" }, { "G", "GigabitEthernet" }, { NULL, "Controller" }, { NULL, "Port-channel" }, { NULL, "Dialer" }, { NULL, "Loopback" }, }; int num_intf_tab = sizeof(intf_tab) / sizeof(intf_tab[0]); pcp-3.8.12ubuntu1/src/pmdas/nginx/0000775000000000000000000000000012272262620013622 5ustar pcp-3.8.12ubuntu1/src/pmdas/nginx/pmdanginx.pl0000775000000000000000000000761712272262501016160 0ustar # # Copyright (c) 2013 Ryan Doyle. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; use LWP::UserAgent; my @nginx_status = (); my $nginx_status_url = "http://localhost/nginx_status"; my $nginx_fetch_timeout = 1; my $http_client = LWP::UserAgent->new; # Configuration files for overriding the above settings for my $file (pmda_config('PCP_PMDAS_DIR') . '/nginx/nginx.conf', 'nginx.conf') { eval `cat $file` unless ! -f $file; } $http_client->agent('pmdanginx'); $http_client->timeout($nginx_fetch_timeout); sub update_nginx_status { my $response = $http_client->get($nginx_status_url); if ($response->is_success) { # All the content on the status page are digits. Map the array # index to the metric item ID. @nginx_status = ($response->decoded_content =~ m/(\d+)/gm); } else { @nginx_status = undef; } } sub nginx_fetch_callback { my ($cluster, $item, $inst) = @_; if ($cluster == 0 && defined($nginx_status[$item])){ return ($nginx_status[$item], 1); } return (PM_ERR_PMID, 0); } my $pmda = PCP::PMDA->new('nginx', 117); $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'nginx.active', 'Number of active connections', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'nginx.accepts_count', 'Total number of accepted connections', ''); $pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'nginx.handled_count', 'Total number of handled connections', ''); $pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'nginx.requests_count', 'Total number of requests', ''); $pmda->add_metric(pmda_pmid(0,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'nginx.reading', 'Reading the request header', ''); $pmda->add_metric(pmda_pmid(0,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'nginx.writing', 'Reading the request body, processing the request or writing response', ''); $pmda->add_metric(pmda_pmid(0,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'nginx.waiting', 'Keepalive connections', ''); $pmda->set_fetch_callback(\&nginx_fetch_callback); $pmda->set_refresh(\&update_nginx_status); $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdanginx - nginx performance metrics domain agent (PMDA) =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from nginx. =head1 INSTALLATION This PMDA requires that the nginx stub_status module is active and available at http://localhost/nginx_status Install the nginx PMDA by using the B script as root: # cd $PCP_PMDAS_DIR/nginx # ./Install To uninstall, do the following as root: # cd $PCP_PMDAS_DIR/nginx # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/nginx/nginx.conf optional configuration file for B =item $PCP_PMDAS_DIR/nginx/Install installation script for the B agent =item $PCP_PMDAS_DIR/nginx/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/nginx.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1). pcp-3.8.12ubuntu1/src/pmdas/nginx/Remove0000775000000000000000000000120212272262501014776 0ustar #! /bin/sh # # Copyright (c) 2013 Ryan Doyle. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=nginx pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/nginx/Install0000775000000000000000000000146612272262501015163 0ustar #!/bin/sh # # Copyright (c) 2013 Ryan Doyle. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=nginx perl_opt=true daemon_opt=false forced_restart=false perl -e "use LWP::UserAgent" 2>/dev/null if test $? -ne 0 then echo "LWP::UserAgent perl module is not installed" exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/nginx/GNUmakefile0000664000000000000000000000277212272262501015702 0ustar #!gmake # # Copyright (c) 2013 Ryan Doyle. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = nginx DOMAIN = NGINX PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl $(IAM).conf ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif LDIRT = domain.h root pmns *.log $(MAN_PAGES) default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl $(INSTALL) -m 644 $(IAM).conf $(PMDADIR)/$(IAM).conf @$(INSTALL_MAN) default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/nginx/nginx.conf0000664000000000000000000000012112272262501015604 0ustar #$nginx_status_url = "http://localhost/nginx_status"; #$nginx_fetch_timeout = 1; pcp-3.8.12ubuntu1/src/pmdas/weblog/0000775000000000000000000000000012272262620013756 5ustar pcp-3.8.12ubuntu1/src/pmdas/weblog/weblog.h0000664000000000000000000000724312272262501015412 0ustar /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _WEBLOG_H #define _WEBLOG_H #include "pmapi.h" #include "impl.h" #include "pmda.h" #include #include enum HTTP_Methods { wl_httpGet, wl_httpHead, wl_httpPost, wl_httpOther, wl_numMethods }; enum HistSizes { wl_zero, wl_le3k, wl_le10k, wl_le30k, wl_le100k, wl_le300k, wl_le1m, wl_le3m, wl_gt3m, wl_unknownSize, wl_numSizes }; #define FIBUFSIZE 16*1024 #define DORMANT_WARN 86400 typedef struct { char* fileName; int filePtr; struct stat fileStat; char buf[FIBUFSIZE]; char *bp; char *bend; u_int format; /* index into regex for parsing file */ time_t lastActive; /* time in sec when last active */ } FileInfo; typedef struct { __uint32_t methodReq[wl_numMethods]; __uint64_t methodBytes[wl_numMethods]; __uint32_t sizeReq[wl_numSizes]; __uint64_t sizeBytes[wl_numSizes]; __uint32_t cached_sizeReq[wl_numSizes]; __uint64_t cached_sizeBytes[wl_numSizes]; __uint32_t uncached_sizeReq[wl_numSizes]; __uint64_t uncached_sizeBytes[wl_numSizes]; __uint32_t sumReq; __uint32_t client_sumReq; __uint32_t cached_sumReq; __uint32_t uncached_sumReq; __uint64_t sumBytes; __uint64_t cached_sumBytes; __uint64_t uncached_sumBytes; __uint32_t errors; __uint32_t active; __uint32_t numLogs; __uint32_t modTime; __uint32_t extendedp; } WebCount; typedef struct { int update; /* flag for updating this server */ WebCount counts; FileInfo access; FileInfo error; } WebServer; typedef struct { int id; pid_t pid; int firstServer; int lastServer; int inFD[2]; int outFD[2]; char *methodStr; char *sizeStr; char *c_statusStr; char *s_statusStr; int strLength; } WebSproc; typedef struct { char* name; #ifdef NON_POSIX_REGEX char *np_regex; #endif regex_t* regex; int methodPos; int sizePos; int c_statusPos; int s_statusPos; int posix_regexp; } WebRegex; extern WebServer *wl_servers; extern WebSproc *wl_sproc; extern WebRegex *wl_regexTable; extern pmdaInstid *wl_serverInst; extern pmdaIndom wl_indomTable[]; extern __uint32_t wl_numServers; extern __uint32_t wl_numActive; extern __uint32_t wl_refreshDelay; extern __uint32_t wl_chkDelay; extern __uint32_t wl_sprocThresh; extern __uint32_t wl_numSprocs; extern __uint32_t wl_catchupTime; extern __uint32_t wl_numRegex; extern int wl_updateAll; extern time_t wl_timeOfProbe; extern char *wl_logFile; extern char wl_helpFile[]; extern int wl_isDSO; int openLogFile(FileInfo*); void probe(void); void refresh(WebSproc*); void refreshAll(void); void sprocMain(void*); void web_init(pmdaInterface*); void logmessage(int, const char *, ...); #define wl_close(fd) do { if (fd >= 0) close(fd); fd = -1; } while (0) #endif /* _WEBLOG_H */ pcp-3.8.12ubuntu1/src/pmdas/weblog/sproc.c0000664000000000000000000000232012272262501015243 0ustar /* * Web PMDA, based on generic driver for a daemon-based PMDA * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "weblog.h" #if defined(HAVE_PTHREAD_H) #include #endif #if defined(HAVE_SCHED_H) #include #endif #if defined(HAVE_PTHREAD_H) static pthread_t sproc_thread; int sproc (void (*entry) (void *), int flags, void *arg) { int retval; retval = pthread_create(&sproc_thread, NULL, (void (*))entry, NULL); return retval; } #endif pcp-3.8.12ubuntu1/src/pmdas/weblog/server.sh0000775000000000000000000007144012272262501015627 0ustar #! /bin/sh # # Copyright (c) 2000-2001,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Get standard environment . $PCP_DIR/etc/pcp.env # Setup some default paths _logdir=/var/log _msgfil=messages # # Every supported server defines 10 variables which are used by addServer() # and installFiles() to create a server specification for the weblog PMDA # and a URL for the webping PMDA, respectively. # # access The full path to the access log # accessRegex The regex for the access log # errors The full path to the error log # errorRegex The regex for the error log # serverPath The server path # serverDesc A desciption of the type of server # serverName The name for the server (must be unique) # serverPort Port the server is bound to # docs The full path to the document root # "$noDocs" - indicates there is no document root # http The URL for the server # files How to put the HTML files into the doc root # "link" - create a soft link # "copy" - copy the files # "skip" - do not create URLs for this server # do_logs=false do_files=false do_auto=false do_verbose=false debug=false noDocs="???" unknownDocs="" docsDir="$PCP_DOC_DIR/pcpweb/" link="pcpweb" file1="index.html" file2="planning.html" file3="tasks.html" pfx=" " skipping="${pfx}skipping..." tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 trap "rm -rf $tmp; exit" 0 1 2 3 15 # Duplicate entry check file # rm -f $tmp/dup touch $tmp/dup # pv 816562 - try to work around $PCP_DOC_DIR confusion [ ! -x $docsDir -a -x /usr/pcp/doc/pcpweb/ ] && docsDir=/usr/pcp/doc/pcpweb/ LOCALHOSTNAME=`hostname` # web server attribute names (global) # ATTRLIST="serverPort serverName docs access errors" # look for netscape stuff here # NSROOTPATH="${NSROOTPATH-/usr/ns-home:/var/netscape/suitespot:/var/netscape/fasttrack}" # the Netscape server types we know how to handle # NSTYPE="httpd https proxy" # look for old outbox # OUTBOXPATH="${OUTBOXPATH-/var/mc-httpd}" # look for old Netscape Proxy Servers here # NSPROXYPATH="${NSPROXYPATH-/var/ns-proxy}" # look for NCSA servers here # NCSAPATH="${NCSAPATH-/var/www}" # look for Zeus servers here # ZEUSPATH="${ZEUSPATH-/usr/local/zeus}" # look for Squid Object caches here # SQUIDPATH="${SQUIDPATH-/usr/local/squid}" # look for Apache servers here # APACHEPATH="${APACHEPATH-/etc/apache2:/etc/httpd}" # look for anonymous ftp here # FTPPATH="${FTPPATH:-$_logdir}" # look for password file here (to determine ~ftp) # PASSWDPATH="${PASSWDPATH-/etc/passwd}" # look for SYSLOG here # SYSLOGPATH="${SYSLOGPATH:-$_logdir/$_msgfil}" # look for xferlog here (for wu_ftp) # XFERLOG is default for wu_ftp XFERLOG="${XFERLOG:-$_logdir/xferlog}" # WUFTPLOG is used in sgi freeware wu_ftp WUFTPLOG="${WUFTPLOG-$_logdir/wu-ftpd.log}" _getLogFiles() { $PCP_ECHO_PROG $PCP_ECHO_N "Full path to access log [$access] ""$PCP_ECHO_C" read ans if [ -n "$ans" ] then access="$ans" if [ ! -f "$access" ] then echo "Warning: $access does not exist at this time." fi fi $PCP_ECHO_PROG $PCP_ECHO_N "Full path to error log [$errors] ""$PCP_ECHO_C" read ans if [ -n "$ans" ] then errors="$ans" if [ ! -f "$errors" ] then echo "Warning: $errors does not exist at this time." fi fi } # _addServer_check # 1: servername # 2: other args for log file # 3: server description _addServer_check() { if grep "$1" $tmp/dup > /dev/null 2>&1 then echo "${pfx}Error: already found a server with the name \"$1\"" if $do_auto then echo "$skipping" else $PCP_ECHO_PROG $PCP_ECHO_N "New name for server (or return to skip this server): ""$PCP_ECHO_C" read ans if [ -n "$ans" ] then if grep "$ans" $tmp/dup > /dev/null 2>&1 then echo "${pfx}Error: new server name already exists" echo "$skipping" else echo >> $logFile echo "# $3." >> $logFile echo "server $ans $2" >> $logFile echo "$1" >> $tmp/dup fi else echo "$skipping" fi fi else echo >> $logFile echo "# $3." >> $logFile echo "server $1 $2" >> $logFile echo "$1" >> $tmp/dup fi } _addServer() { echo "Found $serverDesc at $serverPath" if [ \( -f "$access" -o -c "$access" \) -a \( -f "$errors" -o -c "$errors" \) ] then found="true" if [ -z "$serverPort" ] then echo "${pfx}identified as $serverName" _addServer_check "$serverName" "on $accessRegex $access $errorRegex $errors" "$serverDesc" else echo "${pfx}identified as $serverName:$serverPort" _addServer_check "$serverName:$serverPort" "on $accessRegex $access $errorRegex $errors" "$serverDesc" fi echo else echo "${pfx}Error: log files are not in the expected place:" echo "${pfx} $access" echo "${pfx} $errors" if $do_auto then echo "$skipping" else echo echo "Do you want to specify an alternate location for the log files" $PCP_ECHO_PROG $PCP_ECHO_N "(otherwise this server will be ignored) [y] ""$PCP_ECHO_C" read ans if [ -z "$ans" -o "$ans" = "y" -o "$ans" = "Y" ] then _getLogFiles if [ -z "$serverPort" ] then _addServer_check "$serverName" "on $accessRegex $access $errorRegex $errors" "$serverDesc" else _addServer_check "$serverName:$serverPort" "on $accessRegex $access $errorRegex $errors" "$serverDesc" fi else echo "$skipping" fi fi echo fi } _installFiles() { echo echo "Found $serverDesc at $serverPath" if [ "$docs" != "$noDocs" ] then if [ "$docs" = "$unknownDocs" ] then echo "${pfx}Error: unable to determine document root" if $do_auto then docs=$unknownDocs echo "$skipping" else echo $PCP_ECHO_PROG $PCP_ECHO_N "Path to document root (return to skip HTML link for this server): ""$PCP_ECHO_C" read ans if [ -n "$ans" ] then if [ -d "$ans" ] then docs="$ans" else echo "\"$ans\" is not a directory." echo "No link to HTML files will be created for this server." fi fi fi elif [ ! -d "$docs" ] then echo "${pfx}Error: document root cannot be found at:" echo "${pfx} $docs" if $do_auto then docs=$unknownDocs echo "$skipping" else echo echo "Path to document root (return to skip HTML link for this server)" $PCP_ECHO_PROG $PCP_ECHO_N "$docs: ""$PCP_ECHO_C" read ans if [ -n "$ans" ] then if [ -d $ans ] then docs=$ans else echo "${pfx}Error: \"$ans\" is not a directory." docs=$unknownDocs echo "$skipping" fi else docs=$unknownDocs fi fi else echo "${pfx}document root found at:" echo "${pfx}$docs" fi if [ "$docs" != "$unknownDocs" ] then if [ ! -f $docs/$link/$file1 -o ! -f $docs/$link/$file2 -o ! -f $docs/$link/$file3 ] then if [ "$files" = "link" ] then $PCP_ECHO_PROG $PCP_ECHO_N "Do you want a link to some sample HTML files created in this directory [y] ""$PCP_ECHO_C" elif [ "$files" = "copy" ] then $PCP_ECHO_PROG $PCP_ECHO_N "Do you want some sample HTML files installed in this directory [y] ""$PCP_ECHO_C" fi read ans if [ -z "$ans" -o "$ans" = "y" -o "$ans" = "Y" ] then if [ "$files" = "link" ] then [ -L $docs/$link ] && rm -f $docs/$link if [ -f $docs/$link ] then echo "${pfx}Error: $docs/$link already exists." echo "$skipping" else ln -s $docsDir $docs/$link fi elif [ "$files" = "copy" ] then if [ ! -f $docs/$link -o -d $docs/$link ] then cp $docsDir/$file1 $docs/$link/$file1 cp $docsDir/$file2 $docs/$link/$file2 cp $docsDir/$file3 $docs/$link/$file3 else echo "${pfx}Error: $docs/$link is not a directory." echo "$skipping" fi fi if [ -z "$http" ] then echo "$http/$link/$file1" >> $logFile echo "$http/$link/$file2" >> $logFile echo "$http/$link/$file3" >> $logFile fi fi else echo "${pfx}Note: the link to the sample HTML files already exists." if [ -n "$http" ] then echo "$http/$link/$file1" >> $logFile echo "$http/$link/$file2" >> $logFile echo "$http/$link/$file3" >> $logFile fi fi else if [ "$docs" != "$unknownDocs" ] then echo "$skipping" fi fi else echo "${pfx}Error: no document root, cannot install files." echo "$skipping" fi echo } _switchAction() { if $do_verbose then echo "------------------------------------------------------------" echo "access = $access" echo "accessRegex = $accessRegex" echo "errors = $errors" echo "errorRegex = $errorRegex" echo "serverPath = $serverPath" echo "serverDesc = $serverDesc" echo "serverName = $serverName" echo "serverPort = $serverPort" echo "docs = $docs" echo "http = $http" echo "files = $files" echo "------------------------------------------------------------" echo fi if $do_logs then _addServer else _installFiles fi } _scan_config() { serverPort= serverName= errors= access= docs= eval `cat $* 2>/dev/null | $PCP_AWK_PROG ' NF == 2 && tolower($1) == "port" { print "serverPort=" $2; next } NF == 2 && tolower($1) == "errorlog" { print "errors=" $2; next } NF == 2 && tolower($1) == "servername" { print "serverName=" $2; next } tolower($1) == "init" { for (i=1; i<=NF; i++) { if (match($i, "^access=")) print $i if (match($i, "^global=")) printf "access=%s ",substr($i,8,length($i)-7) } next } tolower($0) ~ /fn="document-root"/ || tolower($0) ~ /fn=document-root/ { for (i=1; i<=NF; i++) { if (match($i, "^root=")) printf "docs=%s ",substr($i,6,length($i)-5) } next }'` } _netscape_extract() { here=`pwd` echo >$tmp/ns for root in `echo "$NSROOTPATH" | sed -e 's/:/ /g'` do for type in $NSTYPE do for dir in $root/$type-* do [ -L "$dir" ] && continue if [ -d "$dir" ] then cd $dir check=`pwd` cd $here match=`grep "^$check " $tmp/ns` if [ ! -z "$match" ] then echo "$match $dir" | $PCP_AWK_PROG ' { if ($1 == $2) printf "The server at %s appears to be a link to %s which is already monitored as %s\n", $3, $2, $1 else if ($1 == $3) { printf "The server at %s was already detected,\n", $1 printf "using the link %s. ", $2 } else { printf "The server at %s was already detected,\n", $1 printf "using the link %s. The link %s,\n", $2, $3 printf "which is also to this server, will be ignored.\n" } }' echo "$skipping" continue fi echo "$check $dir" >>$tmp/ns access= errors= docs= serverName= serverPort= if [ ! -f $dir/config/obj.conf ] then echo "Found Netscape $type Server at $dir" echo "${pfx}Error: unable to find configuration file:" echo "${pfx} $dir/config/obj.conf" echo "$skipping" echo continue elif [ ! -f $dir/config/magnus.conf ] then echo "Found Netscape $type Server at $dir" echo "${pfx}Error: unable to find configuration file:" echo "${pfx} $dir/config/magnus.conf" echo "$skipping" echo continue fi _scan_config $dir/config/obj.conf $dir/config/magnus.conf # fix server name as Netscape often adds a trailing '.' serverName=`echo $serverName | sed -e 's/\.$//'` if [ -z "$serverName" -o -z "$serverPort" ] then echo "Found Netscape $type Server at $dir" echo "${pfx}Error: unable to determine server name or port from:" echo "${pfx} $dir/config/magnus.conf" echo "$skipping" echo continue fi if [ -z "$access" ] then access=$dir/logs/access echo "Found Netscape $type Server at $dir" echo "${pfx}Warning: unable to determine access log name, assuming:" echo "${pfx} $access" echo fi if [ -z "$errors" ] then errors=$dir/logs/errors echo "Found Netscape $type Server at $dir" echo "${pfx}Warning: unable to determine error log name, assuming:" echo "${pfx} $errors" echo fi # # figure out if this is a caching server or not # if [ -f $access ] then num_lines=`wc -l $access | $PCP_AWK_PROG '{print $1}'` if [ $num_lines -gt 1 ] then num_fields=`tail -n 1 $access | cut -f3 -d\" | wc -w` if [ $num_fields -eq 11 ] then accessRegex="NS_PROXY" else accessRegex="CERN" fi else accessRegex="CERN" fi fi errorRegex="CERN_err" serverPath="$dir" serverDesc="Netscape $type Server" http="GET http://$serverName:$serverPort" files="link" _switchAction fi done done done } _zeus_extract() { if [ -d $ZEUSPATH ] then if [ -f $ZEUSPATH/server.ini ] then rm -f $tmp/zeus touch $tmp/zeus $PCP_AWK_PROG < $ZEUSPATH/server.ini -v hostname=$LOCALHOSTNAME -v out=$tmp/zeus -v ini=$ZEUSPATH/server.ini -F'=' ' BEGIN { mode = 0; port = 0; name = ""; access = "???"; errors = "???"; docs = "???"; host = hostname; } /^port/ { if (mode == 0) port=$2; next } $1 ~ /\[Admin/ { mode = 1; next } $1 ~ /\[Server/ { if (mode == 2) { printf("%s %s %s %d %s %s\n", name, access, errors, port, host, docs) > out; name=""; access="???"; errors="???"; docs="???"; host = hostname } else mode = 2; i = match($1, " .*]"); if (i == 0) { mode = 1 } else { name = substr($1, RSTART+1, RLENGTH-2); } next } /^logdir/ { if (mode == 2) { access = sprintf("%s/transfer", $2); errors = sprintf("%s/errors", $2); } next } /^docroot/ { if (mode == 2) docs = $2; next } /^ipname/ { if (mode == 2) host = $2; next } END { if (mode == 2) printf("%s %s %s %d %s %s\n", name, access, errors, port, host, docs) > out; }' if [ -f $tmp/zeus -a -s $tmp/zeus ] then accessRegex=CERN errorRegex=CERN_err serverPath=$ZEUSPATH files="link" lines=`wc -l $tmp/zeus | $PCP_AWK_PROG '{ print $1 }'` count=1 while [ $count -le $lines ] do eval `$PCP_AWK_PROG < $tmp/zeus -v line=$count ' NR == line { printf("serverName=%s\naccess=%s\nerrors=%s\nserverPort=%d\nhttp=%s\ndocs=%s\n", $1, $2, $3, $4, $5, $6); exit }'` serverDesc="Zeus Server $serverName" serverName="zeus-$serverName" http="GET http://$http:$serverPort" if [ "$access" = "???" ] then access=$ZEUSPATH/log/transfer echo "Found $serverDesc at $serverPath" echo "${pfx}Warning: unable to determine access log name, assuming:" echo "${pfx} $access" echo fi if [ "$errors" = "???" ] then errors=$ZEUSPATH/log/errors echo "Found $serverDesc at $serverPath" echo "${pfx}Warning: unable to determine error log name, assuming:" echo "${pfx} $errors" echo fi if [ "$docs" = "???" ] then docs=$ZEUSPATH/docroot echo "Found $serverDesc at $serverPath" echo "${pfx}Warning: unable to determine document root, assuming:" echo "${pfx} $docs" echo fi _switchAction count=`expr $count + 1` done else echo "Found Zeus Server/s at $ZEUSPATH" echo "${pfx}Error: could not detect any servers in configuration file:" echo "${pfx} $ZEUSPATH/server.ini" echo "$skipping" fi else echo "Found Zeus Server at $ZEUSPATH" echo "${pfx}Error: unable to find configuration file:" echo "${pfx} $ZEUSPATH/server.ini" echo "$skipping" fi fi } _squid_extract() { if [ -d $SQUIDPATH ] then if [ -f $SQUIDPATH/etc/squid.conf ] then rm -f $tmp/squid touch $tmp/squid $PCP_AWK_PROG < $SQUIDPATH/etc/squid.conf -v hostname=${LOCALHOSTNAME} -v out=$tmp/squid ' BEGIN { port = 3128; name = hostname; access = "/usr/local/squid/logs/access.log"; errors = "/dev/null"; host = hostname; } $1 == "emulate_httpd_log" { if ( $2 == "on" ) mode = 1; } $1 == "cache_access_log" { access = $2; } $1 == "http_port" { port = $2; } $1 == "visible_hostname" { name = $2; } END { if (mode == 0) printf("SQUID %s %s %s %d %s\n", name, access, errors, port, host) > out; else printf("CERN %s %s %s %d %s\n", name, access, errors, port, host) > out; }' if [ -f $tmp/squid -a -s $tmp/squid ] then grep CERN $tmp/squid >/dev/null if [ $? -eq 0 ] then accessRegex=CERN else accessRegex=SQUID fi errorRegex=CERN_err serverPath=$SQUIDPATH files="skip" eval `$PCP_AWK_PROG < $tmp/squid ' { printf("serverName=%s\naccess=%s\nerrors=%s\nserverPort=%d\nhttp=%s\n", $2, $3, $4, $5, $6); exit }'` serverDesc="Squid Server $serverName" serverName="squid-$serverName" http="GET http://$http:$serverPort" docs=$noDocs if [ "$access" = "???" ] then access=$SQUIDPATH/log/transfer echo "Found $serverDesc at $serverPath" echo "${pfx}Warning: unable to determine access log name, assuming:" echo "${pfx} $access" echo fi if [ "$errors" = "???" ] then errors=$SQUIDPATH/log/errors echo "Found $serverDesc at $serverPath" echo "${pfx}Warning: unable to determine error log name, assuming:" echo "${pfx} $errors" echo fi _switchAction else echo "Found Squid Server/s at $SQUIDPATH" echo "${pfx}Error: could not detect any servers in configuration file:" echo "${pfx} $SQUIDPATH/squid.conf" echo "$skipping" fi else echo "Found Squid Server at $SQUIDPATH" echo "${pfx}Error: unable to find configuration file:" echo "${pfx} $SQUIDPATH/squid.conf" echo "$skipping" fi fi } _apache_extract() { for apchroot in `echo "$APACHEPATH" | sed -e 's/:/ /g'` do $debug && echo "_apache_extract: apachroot=$apchroot" if [ -d "$apchroot/sites-available" ] then config="$apchroot/sites-available/" elif [ -d "$apchroot/vhosts.d" ] then config="$apchroot/vhosts.d/" elif [ -d "$apchroot/conf" ] then config="$apchroot/conf/" elif [ -f "$apchroot/httpd.conf" ] then config="$apchroot/httpd.conf" else continue fi for config in `echo ${config}*` do $debug && echo "_apache_extract: config=$config" [ -f "$config" ] || continue cat $config \ | sed -e's/#.*//' -e'/^$/d' \ | $PCP_AWK_PROG -v def=`hostname` ' BEGIN { curnam=def; names[def] = curnam; ports[def] = 80; } $1 == "", "", $2); n = split ($2, nm, ":"); if ( n == 1 ) { curnam=$2; port=ports[def]; } else { if ( length (nm[1]) && nm[1] != "*" ) { curnam = nm[1]; } else { curnam = def; } if ( length (nm[2]) ) { port = nm[2]; } else { port = ports[def]; } } cn=sprintf("%s:%d", curnam, port); names[cn] = curnam; ports[cn] = port; curnam = cn; } $1 == "ServerName" { names[curnam] = $2; } $1 == "Port" { ports[curnam] = $2; } $1 == "" { curnam=def; } $1 == "ErrorLog" { path = $2 sub (/\$\{APACHE_LOG_DIR\}/, "/var/log/apache2", path) if ( match (path, "/") != 1 ) { erlog[curnam] = sprintf ("%s/%s", "'$apchroot'", path); } else { erlog[curnam] = path; } } $1 == "DocumentRoot" { path = $2 sub (/\$\{APACHE_LOG_DIR\}/, "/var/log/apache2", path) if ( match (path, "/") != 1 ) { docs[curnam] = sprintf ("%s/%s", "'$apchroot'", path); } else { docs[curnam] = path; } } $1 == "TransferLog" { path = $2 sub (/\$\{APACHE_LOG_DIR\}/, "/var/log/apache2", path) if ( match (path, "/") != 1 ) { tlog[curnam] = sprintf ("%s/%s", "'$apchroot'", path); } else { tlog[curnam] = path; } } $1 == "CustomLog" && ($3 == "common" || $3 == "combined") { path = $2 sub (/\$\{APACHE_LOG_DIR\}/, "/var/log/apache2", path) if ( match (path, "/") != 1 ) { tlog[curnam] = sprintf ("%s/%s", "'$apchroot'", path); } else { tlog[curnam] = path; } } END { for ( n in names ) { print names[n], ports[n], tlog[n], erlog[n], docs[n]; } }'\ | while read serverName serverPort access errors docs ; do $debug && echo "_apache_extract: serverName=$serverName serverPort=$serverPort access=$access errors=$errors docs=$docs" accessRegex=CERN errorRegex=CERN_err serverPath="$apchroot" serverDesc="Apache Server" files="copy" _switchAction done done done } while [ $# -gt 0 ] do case $1 in -d) # debug debug=true ;; -f) # install dummy HTML files in server document root do_files=true if [ $# -gt 1 ] then shift logFile=$1 else echo "-f requires the name of log file" exit 1 fi ;; -l) # generate pmdaweblog configuration file do_logs=true if [ $# -gt 1 ] then shift logFile=$1 else echo "-l requires the name of log file" exit 1 fi ;; -q) # do not prompt for misconfigured servers do_auto=true ;; -v) # verbose do_verbose=true ;; *) # USAGE echo "Usage: server.sh [-dqv] [-f logFile] [-l logFile]" exit 1 ;; esac shift done if [ "$do_logs" = "true" -a "$do_files" = "true" ] then echo "May only perform one of the two options at any one time" exit 1 fi if $do_files then if [ ! -f $docsDir/$file1 -o ! -f $docsDir/$file2 -o ! -f $docsDir/$file3 ] then echo "Some or all of the sample HTML files ($file1, $file2, $file3)" echo "are missing. Cannot continue!" exit 1 fi fi _netscape_extract # Another common place for Netscape servers if [ -d $OUTBOXPATH ] then access=$OUTBOXPATH/logs/access accessRegex="CERN" errors=$OUTBOXPATH/logs/errors errorRegex="CERN_err" serverPath=$OUTBOXPATH serverDesc="Outbox Server" serverName="outbox-$LOCALHOSTNAME" serverPort= docs="$OUTBOXPATH/html" http="GET http://$LOCALHOSTNAME" files="link" _switchAction fi # Netscape Proxy Server if [ -d $NSPROXYPATH/logs ] then access=$NSPROXYPATH/logs/access accessRegex="CERN" errors=$NSPROXYPATH/logs/errors errorRegex="CERN_err" serverPath=$NSPROXYPATH serverDesc="Old Netscape proxy Server" serverName="proxy-$LOCALHOSTNAME" serverPort= docs=$noDocs http="" files="skip" _switchAction fi # Netscape SOCKS Proxy Server if [ -f $NSROOTPATH/proxy-server/logs/sockd ] then access=$NSROOTPATH/proxy-server/logs/sockd accessRegex="NS_SOCKS" errors=/dev/null errorRegex="NS_SOCKS_err" serverPath=$NSROOTPATH/proxy-server serverDesc="Netscape SOCKS Proxy Server" serverName="socks-$LOCALHOSTNAME" serverPort= docs=$noDocs http="" files="skip" _switchAction if [ "$do_logs" = "true" ] then echo $PCP_ECHO_PROG $PCP_ECHO_N "Would you like to log SOCKS ftp transactions [y] ""$PCP_ECHO_C" read ans if [ -z "$ans" -o "$ans" = "y" -o "$ans" = "Y" ] then access=$NSROOTPATH/proxy-server/logs/sockd accessRegex="NS_FTP" errors=/dev/null errorRegex="NS_FTP_err" serverPath=$NSROOTPATH/proxy-server serverDesc="FTP through Netscape SOCKS Server" serverName="ftp-socks-$LOCALHOSTNAME" serverPort= docs=$noDocs http="" files="skip" _switchAction fi fi fi if [ -f $NSPROXYPATH/logs/sockd ] then access=$NSPROXYPATH/logs/sockd accessRegex="NS_SOCKS" errors=/dev/null errorRegex="NS_SOCKS_err" serverPath=$NSPROXYPATH serverDesc="Netscape SOCKS Proxy Server" serverName="socks-$LOCALHOSTNAME" serverPort= docs=$noDocs http="" files="skip" _switchAction if [ "$do_logs" = "true" ] then echo $PCP_ECHO_PROG $PCP_ECHO_N "Would you like to log SOCKS ftp transactions [y] ""$PCP_ECHO_C" read ans if [ -z "$ans" -o "$ans" = "y" -o "$ans" = "Y" ] then access=$NSPROXYPATH/logs/sockd accessRegex="NS_FTP" errors=/dev/null errorRegex="NS_FTP_err" serverPath=$NSPROXYPATH serverDesc="FTP through Netscape SOCKS Server" serverName="ftp-socks-$LOCALHOSTNAME" serverPort= docs=$noDocs http="" files="skip" _switchAction fi fi fi # NCSA (or derived) Server if [ -d $NCSAPATH/server ] then access=$NCSAPATH/server/logs/access_log accessRegex="CERN" errors=$NCSAPATH/server/logs/error_log errorRegex="CERN_err" serverPath=$NCSAPATH/server serverDesc="NCSA (or derived) Server" serverName="ncsa-$LOCALHOSTNAME" serverPort= docs="$NCSAPATH/htdocs" http="GET http://$LOCALHOSTNAME" files="link" _switchAction fi # Zeus Server _zeus_extract # Squid Server _squid_extract # Apache Server _apache_extract # Oracle Webserver if [ -n "$ORACLE_HOME" ] then if [ -d $ORACLE_HOME/ows ] then serverPath=$ORACLE_HOME/ows for i in `ls $serverPath/log/sv*.log*` do serverPort=`basename $i | sed 's/sv//' | sed 's/\.log//'` access=$i accessRegex="CERN" errors="$serverPath/ows/log/sv$serverPort.err" errorRegex="CERN_err" serverDesc="Oracle Webserver" serverName="ows-$serverPort" docs="$serverPath/doc" http="GET http://${LOCALHOSTNAME}:$serverPort" files="link" _switchAction done fi fi # Harvest Cache if [ -n "$HARVEST_HOME" ] then serverPath=$HARVEST_HOME serverPort=80 access=$serverPath/cache.access.log accessRegex="CERN" errors="$serverPath/cache.log" errorRegex="CERN_err" serverDesc="Harvest Cache" serverName="harvest-cache" docs="$noDocs" http="" files="skip" _switchAction elif [ -d /usr/local/harvest ] then serverPath=/usr/local/harvest serverPort=80 access=$serverPath/cache.access.log accessRegex="CERN" errors="$serverPath/cache.log" errorRegex="CERN_err" serverDesc="Harvest Cache" serverName="harvest-cache" docs="$noDocs" http="" files="skip" _switchAction fi # FTP if [ -n "$QUIET_INSTALL" ]; then ans=y else echo if [ "$do_logs" = "true" ] then $PCP_ECHO_PROG $PCP_ECHO_N "Do you also want to monitor ftp transactions [y] ""$PCP_ECHO_C" else $PCP_ECHO_PROG $PCP_ECHO_N "Would you like the sample HTML files installed for anonymous ftp [y] ""$PCP_ECHO_C" fi read ans fi if [ -z "$ans" -o "$ans" = "y" -o "$ans" = "Y" ] then echo if [ -f $PASSWDPATH ] then if [ -n "$QUIET_INSTALL" ] ; then ans=y else $PCP_ECHO_PROG $PCP_ECHO_N "Do you want to monitor wu_ftp [n] ""$PCP_ECHO_C" read ans echo fi if [ "$ans" = "y" -o "$ans" = "Y" ] then wulog="$WUFTPLOG" if [ -f "$WUFTPLOG" ] then wulog="$WUFTPLOG" elif [ -f "$XFERLOG" ] then wulog="$XFERLOG" else if $do_auto then echo "${pfx}Error: log files are not in the expected place:" echo "$pfx $XFERLOG" echo "$pfx or $WUFTPLOG" echo "$skipping" wulog="" fi fi access="$wulog" accessRegex="WU_FTP" errors="$SYSLOGPATH" errorRegex="WU_FTP_err" serverDesc="WU_FTP Server" serverName="wu_ftp" serverPath=$FTPPATH serverPort= else access=$SYSLOGPATH accessRegex="SYSLOG_FTP" errors=$SYSLOGPATH errorRegex="SYSLOG_FTP_err" serverDesc="FTP Server" serverName="ftpd" serverPath=$FTPPATH serverPort= fi if [ ! -z "$access" ] then docs="" docs=`$PCP_AWK_PROG -F: '$1 == "ftp" { print $6 "/pub"; exit }' < ${PASSWDPATH}` if [ -z "$docs" ] then echo "Found FTP Server at $FTPPATH" echo "${pfx}Error: user ftp is not listed in the password file:" echo "${pfx} $PASSWDPATH" echo "$skipping" else http="GET ftp://$LOCALHOSTNAME/pub" files="copy" _switchAction fi fi else echo "Found FTP Server at $FTPPATH" echo "${pfx}Error: unable to find password file:" echo "${pfx} $PASSWDPATH" echo "$skipping" fi fi if $do_logs then : else [ -f "$logFile" ] && sort -u $logFile -o $logFile fi pcp-3.8.12ubuntu1/src/pmdas/weblog/weblog.c0000664000000000000000000031435612272262501015413 0ustar /* * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "weblog.h" #include "domain.h" #include #include #if defined(HAVE_SYS_RESOURCE_H) #include #endif #if defined(HAVE_SYS_PRCTL_H) #include #endif #if defined(HAVE_SYS_WAIT_H) #include #endif /* * Types of metrics, used by fetch to more efficiently calculate metrics */ enum MetaType { wl_globalPtr, wl_offset32, wl_offset64, wl_totalAggregate, wl_serverAggregate, wl_requestMethod, wl_bytesMethod, wl_requestSize, wl_requestCachedSize, wl_requestUncachedSize, wl_bytesSize, wl_bytesCachedSize, wl_bytesUncachedSize, wl_watched, wl_numAlive, wl_nosupport, wl_numMetaTypes }; /* * Return code of checkLogFile() */ enum LogFileCode { wl_ok, wl_opened, wl_reopened, wl_closed, wl_unableToOpen, wl_unableToStat, wl_irregularFile, wl_dormant }; static WebCount dummyCount; /* * Instance domain table * This is completed when parsing the config file */ pmdaIndom wl_indomTable[] = { #define WEBLOG_INDOM 0 { WEBLOG_INDOM, 0, 0 } }; /* * Metric specific data to help identify each metric during a fetch * * MG: Note: must be in the same order as wl_metric table below. * */ typedef struct { int m_type; __psint_t m_offset; } WebMetric; WebMetric wl_metricInfo[] = { /* config.numservers */ { wl_globalPtr, (__psint_t)&wl_numServers }, /* config.catchup */ { wl_globalPtr, (__psint_t)&wl_refreshDelay }, /* config.catchuptime */ { wl_globalPtr, (__psint_t)&wl_catchupTime }, /* config.check */ { wl_globalPtr, (__psint_t)&wl_chkDelay }, /* allserves.numwatched */ { wl_globalPtr, (__psint_t)&wl_numActive }, /* allserves.numalive */ { wl_numAlive, (__psint_t)0 }, /* allservers.errors */ { wl_totalAggregate, (__psint_t)0 }, /* allservers.requests.total */ { wl_totalAggregate, (__psint_t)1 }, /* allservers.requests.get */ { wl_requestMethod, (__psint_t)wl_httpGet }, /* allservers.requests.head */ { wl_requestMethod, (__psint_t)wl_httpHead }, /* allservers.requests.post */ { wl_requestMethod, (__psint_t)wl_httpPost }, /* allservers.requests.other */ { wl_requestMethod, (__psint_t)wl_httpOther }, /* allservers.bytes.total */ { wl_totalAggregate, (__psint_t)2 }, /* allservers.bytes.get */ { wl_bytesMethod, (__psint_t)wl_httpGet }, /* allservers.bytes.head */ { wl_bytesMethod, (__psint_t)wl_httpHead }, /* allservers.bytes.post */ { wl_bytesMethod, (__psint_t)wl_httpPost }, /* allservers.bytes.other */ { wl_bytesMethod, (__psint_t)wl_httpOther }, /* allservers.requests.size.zero */ { wl_requestSize, (__psint_t)wl_zero }, /* allservers.requests.size.le3k */ { wl_requestSize, (__psint_t)wl_le3k }, /* allservers.requests.size.le10k */ { wl_requestSize, (__psint_t)wl_le10k }, /* allservers.requests.size.le30k */ { wl_requestSize, (__psint_t)wl_le30k }, /* allservers.requests.size.le100k */ { wl_requestSize, (__psint_t)wl_le100k }, /* allservers.requests.size.le300k */ { wl_requestSize, (__psint_t)wl_le300k }, /* allservers.requests.size.le1m */ { wl_requestSize, (__psint_t)wl_le1m }, /* allservers.requests.size.le3m */ { wl_requestSize, (__psint_t)wl_le3m }, /* allservers.requests.size.gt3m */ { wl_requestSize, (__psint_t)wl_gt3m }, /* allservers.requests.size.unknown */ { wl_requestSize, (__psint_t)wl_unknownSize }, /* allservers.requests.client.total */ { wl_totalAggregate, (__psint_t)3 }, /* allservers.requests.cached.total */ { wl_totalAggregate, (__psint_t)4 }, /* allservers.requests.cached.size.zero */ { wl_requestCachedSize, (__psint_t)wl_zero }, /* allservers.requests.cached.size.le3k */ { wl_requestCachedSize, (__psint_t)wl_le3k }, /* allservers.requests.cached.size.le10k */ { wl_requestCachedSize, (__psint_t)wl_le10k }, /* allservers.requests.cached.size.le30k */ { wl_requestCachedSize, (__psint_t)wl_le30k }, /* allservers.requests.cached.size.le100k */ { wl_requestCachedSize, (__psint_t)wl_le100k }, /* allservers.requests.cached.size.le300k */ { wl_requestCachedSize, (__psint_t)wl_le300k }, /* allservers.requests.cached.size.le1m */ { wl_requestCachedSize, (__psint_t)wl_le1m }, /* allservers.requests.cached.size.le3m */ { wl_requestCachedSize, (__psint_t)wl_le3m }, /* allservers.requests.cached.size.gt3m */ { wl_requestCachedSize, (__psint_t)wl_gt3m }, /* allservers.requests.cached.size.unknown */ { wl_requestCachedSize, (__psint_t)wl_unknownSize }, /* allservers.requests.uncached.total */ { wl_totalAggregate, (__psint_t)5 }, /* allservers.requests.uncached.size.zero */ { wl_requestUncachedSize, (__psint_t)wl_zero }, /* allservers.requests.uncached.size.le3k */ { wl_requestUncachedSize, (__psint_t)wl_le3k }, /* allservers.requests.uncached.size.le10k */ { wl_requestUncachedSize, (__psint_t)wl_le10k }, /* allservers.requests.uncached.size.le30k */ { wl_requestUncachedSize, (__psint_t)wl_le30k }, /* allservers.requests.uncached.size.le100k */ { wl_requestUncachedSize, (__psint_t)wl_le100k }, /* allservers.requests.uncached.size.le300k */ { wl_requestUncachedSize, (__psint_t)wl_le300k }, /* allservers.requests.uncached.size.le1m */ { wl_requestUncachedSize, (__psint_t)wl_le1m }, /* allservers.requests.uncached.size.le3m */ { wl_requestUncachedSize, (__psint_t)wl_le3m }, /* allservers.requests.uncached.size.gt3m */ { wl_requestUncachedSize, (__psint_t)wl_gt3m }, /* allservers.requests.uncached.size.unknown */ { wl_requestUncachedSize, (__psint_t)wl_unknownSize }, /* allservers.bytes.size.zero */ { wl_bytesSize, (__psint_t)wl_zero }, /* allservers.bytes.size.le3k */ { wl_bytesSize, (__psint_t)wl_le3k }, /* allservers.bytes.size.le10k */ { wl_bytesSize, (__psint_t)wl_le10k }, /* allservers.bytes.size.le30k */ { wl_bytesSize, (__psint_t)wl_le30k }, /* allservers.bytes.size.le100k */ { wl_bytesSize, (__psint_t)wl_le100k }, /* allservers.bytes.size.le300k */ { wl_bytesSize, (__psint_t)wl_le300k }, /* allservers.bytes.size.le1m */ { wl_bytesSize, (__psint_t)wl_le1m }, /* allservers.bytes.size.le3m */ { wl_bytesSize, (__psint_t)wl_le3m }, /* allservers.bytes.size.gt3m */ { wl_bytesSize, (__psint_t)wl_gt3m }, /* allservers.bytes.cached.total */ { wl_totalAggregate, (__psint_t)6 }, /* allservers.bytes.cached.size.zero */ { wl_bytesCachedSize, (__psint_t)wl_zero }, /* allservers.bytes.cached.size.le3k */ { wl_bytesCachedSize, (__psint_t)wl_le3k }, /* allservers.bytes.cached.size.le10k */ { wl_bytesCachedSize, (__psint_t)wl_le10k }, /* allservers.bytes.cached.size.le30k */ { wl_bytesCachedSize, (__psint_t)wl_le30k }, /* allservers.bytes.cached.size.le100k */ { wl_bytesCachedSize, (__psint_t)wl_le100k }, /* allservers.bytes.cached.size.le300k */ { wl_bytesCachedSize, (__psint_t)wl_le300k }, /* allservers.bytes.cached.size.le1m */ { wl_bytesCachedSize, (__psint_t)wl_le1m }, /* allservers.bytes.cached.size.le3m */ { wl_bytesCachedSize, (__psint_t)wl_le3m }, /* allservers.bytes.cached.size.gt3m */ { wl_bytesCachedSize, (__psint_t)wl_gt3m }, /* allservers.bytes.uncached.total */ { wl_totalAggregate, (__psint_t)7 }, /* allservers.bytes.uncached.size.zero */ { wl_bytesUncachedSize, (__psint_t)wl_zero }, /* allservers.bytes.uncached.size.le3k */ { wl_bytesUncachedSize, (__psint_t)wl_le3k }, /* allservers.bytes.uncached.size.le10k */ { wl_bytesUncachedSize, (__psint_t)wl_le10k }, /* allservers.bytes.uncached.size.le30k */ { wl_bytesUncachedSize, (__psint_t)wl_le30k }, /* allservers.bytes.uncached.size.le100k */ { wl_bytesUncachedSize, (__psint_t)wl_le100k }, /* allservers.bytes.uncached.size.le300k */ { wl_bytesUncachedSize, (__psint_t)wl_le300k }, /* allservers.bytes.uncached.size.le1m */ { wl_bytesUncachedSize, (__psint_t)wl_le1m }, /* allservers.bytes.uncached.size.le3m */ { wl_bytesUncachedSize, (__psint_t)wl_le3m }, /* allservers.bytes.uncached.size.gt3m */ { wl_bytesUncachedSize, (__psint_t)wl_gt3m }, /* perserver.watched */ { wl_watched, (__psint_t)&dummyCount.active }, /* perserver.numlogs */ { wl_offset32, (__psint_t)&dummyCount.numLogs }, /* perserver.errors */ { wl_offset32, (__psint_t)&dummyCount.errors }, /* perserver.requests.total */ { wl_serverAggregate, (__psint_t)0 }, /* perserver.requests.get */ { wl_requestMethod, (__psint_t)wl_httpGet }, /* perserver.requests.head */ { wl_requestMethod, (__psint_t)wl_httpHead }, /* perserver.requests.post */ { wl_requestMethod, (__psint_t)wl_httpPost }, /* perserver.requests.other */ { wl_requestMethod, (__psint_t)wl_httpOther }, /* perserver.bytes.total */ { wl_serverAggregate, (__psint_t)1 }, /* perserver.bytes.get */ { wl_bytesMethod, (__psint_t)wl_httpGet }, /* perserver.bytes.head */ { wl_bytesMethod, (__psint_t)wl_httpHead }, /* perserver.bytes.post */ { wl_bytesMethod, (__psint_t)wl_httpPost }, /* perserver.bytes.other */ { wl_bytesMethod, (__psint_t)wl_httpOther }, /* perserver.requests.size.zero */ { wl_requestSize, (__psint_t)wl_zero }, /* perserver.requests.size.le3k */ { wl_requestSize, (__psint_t)wl_le3k }, /* perserver.requests.size.le10k */ { wl_requestSize, (__psint_t)wl_le10k }, /* perserver.requests.size.le30k */ { wl_requestSize, (__psint_t)wl_le30k }, /* perserver.requests.size.le100k */ { wl_requestSize, (__psint_t)wl_le100k }, /* perserver.requests.size.le300k */ { wl_requestSize, (__psint_t)wl_le300k }, /* perserver.requests.size.le1m */ { wl_requestSize, (__psint_t)wl_le1m }, /* perserver.requests.size.le3m */ { wl_requestSize, (__psint_t)wl_le3m }, /* perserver.requests.size.gt3m */ { wl_requestSize, (__psint_t)wl_gt3m }, /* perserver.requests.size.unknown */ { wl_requestSize, (__psint_t)wl_unknownSize }, /* perserver.requests.client.total */ { wl_serverAggregate, (__psint_t)2 }, /* perserver.requests.cached.total */ { wl_serverAggregate, (__psint_t)3 }, /* perserver.requests.cached.size.zero */ { wl_requestCachedSize, (__psint_t)wl_zero }, /* perserver.requests.cached.size.le3k */ { wl_requestCachedSize, (__psint_t)wl_le3k }, /* perserver.requests.cached.size.le10k */ { wl_requestCachedSize, (__psint_t)wl_le10k }, /* perserver.requests.cached.size.le30k */ { wl_requestCachedSize, (__psint_t)wl_le30k }, /* perserver.requests.cached.size.le100k */ { wl_requestCachedSize, (__psint_t)wl_le100k }, /* perserver.requests.cached.size.le300k */ { wl_requestCachedSize, (__psint_t)wl_le300k }, /* perserver.requests.cached.size.le1m */ { wl_requestCachedSize, (__psint_t)wl_le1m }, /* perserver.requests.cached.size.le3m */ { wl_requestCachedSize, (__psint_t)wl_le3m }, /* perserver.requests.cached.size.gt3m */ { wl_requestCachedSize, (__psint_t)wl_gt3m }, /* perserver.requests.cached.size.unknown */ { wl_requestCachedSize, (__psint_t)wl_unknownSize }, /* perserver.requests.uncached.total */ { wl_serverAggregate, (__psint_t)4 }, /* perserver.requests.uncached.size.zero */ { wl_requestUncachedSize, (__psint_t)wl_zero }, /* perserver.requests.uncached.size.le3k */ { wl_requestUncachedSize, (__psint_t)wl_le3k }, /* perserver.requests.uncached.size.le10k */ { wl_requestUncachedSize, (__psint_t)wl_le10k }, /* perserver.requests.uncached.size.le30k */ { wl_requestUncachedSize, (__psint_t)wl_le30k }, /* perserver.requests.uncached.size.le100k */ { wl_requestUncachedSize, (__psint_t)wl_le100k }, /* perserver.requests.uncached.size.le300k */ { wl_requestUncachedSize, (__psint_t)wl_le300k }, /* perserver.requests.uncached.size.le1m */ { wl_requestUncachedSize, (__psint_t)wl_le1m }, /* perserver.requests.uncached.size.le3m */ { wl_requestUncachedSize, (__psint_t)wl_le3m }, /* perserver.requests.uncached.size.gt3m */ { wl_requestUncachedSize, (__psint_t)wl_gt3m }, /* perserver.requests.uncached.size.unknown */ { wl_requestUncachedSize, (__psint_t)wl_unknownSize }, /* perserver.bytes.size.zero */ { wl_bytesSize, (__psint_t)wl_zero }, /* perserver.bytes.size.le3k */ { wl_bytesSize, (__psint_t)wl_le3k }, /* perserver.bytes.size.le10k */ { wl_bytesSize, (__psint_t)wl_le10k }, /* perserver.bytes.size.le30k */ { wl_bytesSize, (__psint_t)wl_le30k }, /* perserver.bytes.size.le100k */ { wl_bytesSize, (__psint_t)wl_le100k }, /* perserver.bytes.size.le300k */ { wl_bytesSize, (__psint_t)wl_le300k }, /* perserver.bytes.size.le1m */ { wl_bytesSize, (__psint_t)wl_le1m }, /* perserver.bytes.size.le3m */ { wl_bytesSize, (__psint_t)wl_le3m }, /* perserver.bytes.size.gt3m */ { wl_bytesSize, (__psint_t)wl_gt3m }, /* perserver.bytes.cached.total */ { wl_serverAggregate, (__psint_t)5 }, /* perserver.bytes.cached.size.zero */ { wl_bytesCachedSize, (__psint_t)wl_zero }, /* perserver.bytes.cached.size.le3k */ { wl_bytesCachedSize, (__psint_t)wl_le3k }, /* perserver.bytes.cached.size.le10k */ { wl_bytesCachedSize, (__psint_t)wl_le10k }, /* perserver.bytes.cached.size.le30k */ { wl_bytesCachedSize, (__psint_t)wl_le30k }, /* perserver.bytes.cached.size.le100k */ { wl_bytesCachedSize, (__psint_t)wl_le100k }, /* perserver.bytes.cached.size.le300k */ { wl_bytesCachedSize, (__psint_t)wl_le300k }, /* perserver.bytes.cached.size.le1m */ { wl_bytesCachedSize, (__psint_t)wl_le1m }, /* perserver.bytes.cached.size.le3m */ { wl_bytesCachedSize, (__psint_t)wl_le3m }, /* perserver.bytes.cached.size.gt3m */ { wl_bytesCachedSize, (__psint_t)wl_gt3m }, /* perserver.bytes.uncached.total */ { wl_serverAggregate, (__psint_t)6 }, /* perserver.bytes.uncached.size.zero */ { wl_bytesUncachedSize, (__psint_t)wl_zero }, /* perserver.bytes.uncached.size.le3k */ { wl_bytesUncachedSize, (__psint_t)wl_le3k }, /* perserver.bytes.uncached.size.le10k */ { wl_bytesUncachedSize, (__psint_t)wl_le10k }, /* perserver.bytes.uncached.size.le30k */ { wl_bytesUncachedSize, (__psint_t)wl_le30k }, /* perserver.bytes.uncached.size.le100k */ { wl_bytesUncachedSize, (__psint_t)wl_le100k }, /* perserver.bytes.uncached.size.le300k */ { wl_bytesUncachedSize, (__psint_t)wl_le300k }, /* perserver.bytes.uncached.size.le1m */ { wl_bytesUncachedSize, (__psint_t)wl_le1m }, /* perserver.bytes.uncached.size.le3m */ { wl_bytesUncachedSize, (__psint_t)wl_le3m }, /* perserver.bytes.uncached.size.gt3m */ { wl_bytesUncachedSize, (__psint_t)wl_gt3m }, /* perserver.logidletime */ { wl_offset32, (__psint_t)&dummyCount.modTime }, }; /* * all metrics supported in this PMDA - one table entry for each */ static pmdaMetric wl_metrics[] = { /* * web.config */ /* config.numservers */ { (void *)0, { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, 0) } }, /* config.catchup */ { (void *)0, { PMDA_PMID(0,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0) } }, /* config.catchuptime */ { (void *)0, { PMDA_PMID(0,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0) } }, /* config.check */ { (void *)0, { PMDA_PMID(0,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0) } }, /* * web.allservers */ /* allserves.numwatched */ { (void *)0, { PMDA_PMID(0,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, 0) } }, /* allserves.numalive */ { (void *)0, { PMDA_PMID(0,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, 0) } }, /* allservers.errors */ { (void *)0, { PMDA_PMID(1,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.total */ { (void *)0, { PMDA_PMID(1,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.get */ { (void *)0, { PMDA_PMID(1,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.head */ { (void *)0, { PMDA_PMID(1,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.post */ { (void *)0, { PMDA_PMID(1,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.other */ { (void *)0, { PMDA_PMID(1,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.bytes.total */ { (void *)0, { PMDA_PMID(1,12), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.get */ { (void *)0, { PMDA_PMID(1,13), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.head */ { (void *)0, { PMDA_PMID(1,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.post */ { (void *)0, { PMDA_PMID(1,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.other */ { (void *)0, { PMDA_PMID(1,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.requests.size.zero */ { (void *)0, { PMDA_PMID(1,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.size.le3k */ { (void *)0, { PMDA_PMID(1,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.size.le10k */ { (void *)0, { PMDA_PMID(1,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.size.le30k */ { (void *)0, { PMDA_PMID(1,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.size.le100k */ { (void *)0, { PMDA_PMID(1,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.size.le300k */ { (void *)0, { PMDA_PMID(1,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.size.le1m */ { (void *)0, { PMDA_PMID(1,23), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.size.le3m */ { (void *)0, { PMDA_PMID(1,24), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.size.gt3m */ { (void *)0, { PMDA_PMID(1,25), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.size.unknown */ { (void *)0, { PMDA_PMID(1,66), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.client.total */ { (void *)0, { PMDA_PMID(3,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.cached.total */ { (void *)0, { PMDA_PMID(3,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.cached.size.zero */ { (void *)0, { PMDA_PMID(3,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.cached.size.le3k */ { (void *)0, { PMDA_PMID(3,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.cached.size.le10k */ { (void *)0, { PMDA_PMID(3,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.cached.size.le30k */ { (void *)0, { PMDA_PMID(3,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.cached.size.le100k */ { (void *)0, { PMDA_PMID(3,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.cached.size.le300k */ { (void *)0, { PMDA_PMID(3,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.cached.size.le1m */ { (void *)0, { PMDA_PMID(3,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.cached.size.le3m */ { (void *)0, { PMDA_PMID(3,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.cached.size.gt3m */ { (void *)0, { PMDA_PMID(3,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.cached.size.unknown */ { (void *)0, { PMDA_PMID(3,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.uncached.total */ { (void *)0, { PMDA_PMID(3,31), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.uncached.size.zero */ { (void *)0, { PMDA_PMID(3,32), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.uncached.size.le3k */ { (void *)0, { PMDA_PMID(3,33), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.uncached.size.le10k */ { (void *)0, { PMDA_PMID(3,34), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.uncached.size.le30k */ { (void *)0, { PMDA_PMID(3,35), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.uncached.size.le100k */ { (void *)0, { PMDA_PMID(3,36), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.uncached.size.le300k */ { (void *)0, { PMDA_PMID(3,37), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.uncached.size.le1m */ { (void *)0, { PMDA_PMID(3,38), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.uncached.size.le3m */ { (void *)0, { PMDA_PMID(3,39), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.uncached.size.gt3m */ { (void *)0, { PMDA_PMID(3,40), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.requests.uncached.size.unknown */ { (void *)0, { PMDA_PMID(3,41), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* allservers.bytes.size.zero */ { (void *)0, { PMDA_PMID(1,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.size.le3k */ { (void *)0, { PMDA_PMID(1,27), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.size.le10k */ { (void *)0, { PMDA_PMID(1,28), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.size.le30k */ { (void *)0, { PMDA_PMID(1,29), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.size.le100k */ { (void *)0, { PMDA_PMID(1,30), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.size.le300k */ { (void *)0, { PMDA_PMID(1,31), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.size.le1m */ { (void *)0, { PMDA_PMID(1,32), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.size.le3m */ { (void *)0, { PMDA_PMID(1,33), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.size.gt3m */ { (void *)0, { PMDA_PMID(1,34), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.cached.total */ { (void *)0, { PMDA_PMID(3,51), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.cached.size.zero */ { (void *)0, { PMDA_PMID(3,52), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.cached.size.le3k */ { (void *)0, { PMDA_PMID(3,53), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.cached.size.le10k */ { (void *)0, { PMDA_PMID(3,54), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.cached.size.le30k */ { (void *)0, { PMDA_PMID(3,55), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.cached.size.le100k */ { (void *)0, { PMDA_PMID(3,56), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.cached.size.le300k */ { (void *)0, { PMDA_PMID(3,57), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.cached.size.le1m */ { (void *)0, { PMDA_PMID(3,58), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.cached.size.le3m */ { (void *)0, { PMDA_PMID(3,59), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.cached.size.gt3m */ { (void *)0, { PMDA_PMID(3,60), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.uncached.total */ { (void *)0, { PMDA_PMID(3,71), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.uncached.size.zero */ { (void *)0, { PMDA_PMID(3,72), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.uncached.size.le3k */ { (void *)0, { PMDA_PMID(3,73), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.uncached.size.le10k */ { (void *)0, { PMDA_PMID(3,74), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.uncached.size.le30k */ { (void *)0, { PMDA_PMID(3,75), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.uncached.size.le100k */ { (void *)0, { PMDA_PMID(3,76), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.uncached.size.le300k */ { (void *)0, { PMDA_PMID(3,77), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.uncached.size.le1m */ { (void *)0, { PMDA_PMID(3,78), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.uncached.size.le3m */ { (void *)0, { PMDA_PMID(3,79), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* allservers.bytes.uncached.size.gt3m */ { (void *)0, { PMDA_PMID(3,80), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* * web.perserver */ /* perserver.watched */ { (void *)0, { PMDA_PMID(0,35), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) } }, /* perserver.numlogs */ { (void *)0, { PMDA_PMID(2,36), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.errors */ { (void *)0, { PMDA_PMID(2,37), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.total */ { (void *)0, { PMDA_PMID(2,38), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.get */ { (void *)0, { PMDA_PMID(2,39), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.head */ { (void *)0, { PMDA_PMID(2,40), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.post */ { (void *)0, { PMDA_PMID(2,41), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.other */ { (void *)0, { PMDA_PMID(2,42), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.bytes.total */ { (void *)0, { PMDA_PMID(2,43), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.get */ { (void *)0, { PMDA_PMID(2,44), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.head */ { (void *)0, { PMDA_PMID(2,45), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.post */ { (void *)0, { PMDA_PMID(2,46), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.other */ { (void *)0, { PMDA_PMID(2,47), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.requests.size.zero */ { (void *)0, { PMDA_PMID(2,48), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.size.le3k */ { (void *)0, { PMDA_PMID(2,49), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.size.le10k */ { (void *)0, { PMDA_PMID(2,50), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.size.le30k */ { (void *)0, { PMDA_PMID(2,51), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.size.le100k */ { (void *)0, { PMDA_PMID(2,52), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.size.le300k */ { (void *)0, { PMDA_PMID(2,53), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.size.le1m */ { (void *)0, { PMDA_PMID(2,54), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.size.le3m */ { (void *)0, { PMDA_PMID(2,55), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.size.gt3m */ { (void *)0, { PMDA_PMID(2,56), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.size.unknown */ { (void *)0, { PMDA_PMID(2,67), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.client.total */ { (void *)0, { PMDA_PMID(4,1), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.cached.total */ { (void *)0, { PMDA_PMID(4,11), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.cached.size.zero */ { (void *)0, { PMDA_PMID(4,12), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.cached.size.le3k */ { (void *)0, { PMDA_PMID(4,13), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.cached.size.le10k */ { (void *)0, { PMDA_PMID(4,14), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.cached.size.le30k */ { (void *)0, { PMDA_PMID(4,15), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.cached.size.le100k */ { (void *)0, { PMDA_PMID(4,16), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.cached.size.le300k */ { (void *)0, { PMDA_PMID(4,17), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.cached.size.le1m */ { (void *)0, { PMDA_PMID(4,18), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.cached.size.le3m */ { (void *)0, { PMDA_PMID(4,19), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.cached.size.gt3m */ { (void *)0, { PMDA_PMID(4,20), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.cached.size.unknown */ { (void *)0, { PMDA_PMID(4,21), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.uncached.total */ { (void *)0, { PMDA_PMID(4,31), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.uncached.size.zero */ { (void *)0, { PMDA_PMID(4,32), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.uncached.size.le3k */ { (void *)0, { PMDA_PMID(4,33), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.uncached.size.le10k */ { (void *)0, { PMDA_PMID(4,34), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.uncached.size.le30k */ { (void *)0, { PMDA_PMID(4,35), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.uncached.size.le100k */ { (void *)0, { PMDA_PMID(4,36), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.uncached.size.le300k */ { (void *)0, { PMDA_PMID(4,37), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.uncached.size.le1m */ { (void *)0, { PMDA_PMID(4,38), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.uncached.size.le3m */ { (void *)0, { PMDA_PMID(4,39), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.uncached.size.gt3m */ { (void *)0, { PMDA_PMID(4,40), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.requests.uncached.size.unknown */ { (void *)0, { PMDA_PMID(4,41), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* perserver.bytes.size.zero */ { (void *)0, { PMDA_PMID(2,57), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.size.le3k */ { (void *)0, { PMDA_PMID(2,58), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.size.le10k */ { (void *)0, { PMDA_PMID(2,59), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.size.le30k */ { (void *)0, { PMDA_PMID(2,60), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.size.le100k */ { (void *)0, { PMDA_PMID(2,61), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.size.le300k */ { (void *)0, { PMDA_PMID(2,62), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.size.le1m */ { (void *)0, { PMDA_PMID(2,63), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.size.le3m */ { (void *)0, { PMDA_PMID(2,64), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.size.gt3m */ { (void *)0, { PMDA_PMID(2,65), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.cached.total */ { (void *)0, { PMDA_PMID(4,51), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.cached.size.zero */ { (void *)0, { PMDA_PMID(4,52), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.cached.size.le3k */ { (void *)0, { PMDA_PMID(4,53), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.cached.size.le10k */ { (void *)0, { PMDA_PMID(4,54), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.cached.size.le30k */ { (void *)0, { PMDA_PMID(4,55), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.cached.size.le100k */ { (void *)0, { PMDA_PMID(4,56), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.cached.size.le300k */ { (void *)0, { PMDA_PMID(4,57), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.cached.size.le1m */ { (void *)0, { PMDA_PMID(4,58), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.cached.size.le3m */ { (void *)0, { PMDA_PMID(4,59), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.cached.size.gt3m */ { (void *)0, { PMDA_PMID(4,60), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.uncached.total */ { (void *)0, { PMDA_PMID(4,71), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.uncached.size.zero */ { (void *)0, { PMDA_PMID(4,72), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.uncached.size.le3k */ { (void *)0, { PMDA_PMID(4,73), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.uncached.size.le10k */ { (void *)0, { PMDA_PMID(4,74), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.uncached.size.le30k */ { (void *)0, { PMDA_PMID(4,75), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.uncached.size.le100k */ { (void *)0, { PMDA_PMID(4,76), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.uncached.size.le300k */ { (void *)0, { PMDA_PMID(4,77), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.uncached.size.le1m */ { (void *)0, { PMDA_PMID(4,78), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.uncached.size.le3m */ { (void *)0, { PMDA_PMID(4,79), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* perserver.bytes.uncached.size.gt3m */ { (void *)0, { PMDA_PMID(4,80), PM_TYPE_U64, WEBLOG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* * Added in PCPWEB 1.1.1 */ /* perserver.logidletime */ { (void *)0, { PMDA_PMID(2,68), PM_TYPE_U32, WEBLOG_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0) } }, }; /* number of metrics */ static int numMetrics = (sizeof(wl_metrics)/sizeof(wl_metrics[0])); /* number of instance domains */ static int numIndoms = sizeof(wl_indomTable)/sizeof(wl_indomTable[0]); /* mask to get the cluster from a PMID */ static int _clusterMask = (1<<22) - (1<<10); /* refresh all logs if wl_updateAll != 0 */ int wl_updateAll = 0; /* time in milliseconds to update all the logs */ __uint32_t wl_catchupTime = 0; /* time log refresh was started */ time_t wl_timeOfRefresh = 0; /* flag to indicate DSO or Daemon */ int wl_isDSO = 0; /* request size categories */ long wl_sizes[] = { 0, 3*1024, 10*1024, 30*1024, 100*1024, 300*1024, 1024*1024, 3*1024*1024, 0 }; #define BUFFER_LEN 2048 static pmdaExt *extp; /* set in web_init() */ #ifdef HAVE_SIGHUP /* * Signal handler for an sproc receiving TERM (probably from parent) */ static void onhup(int s) { _exit(s != SIGHUP); } #endif /* * Replacement for fgets using the FileInfo structure */ int wl_gets(FileInfo *fip, char **line) { char *p; int nch; int sts; if (fip->filePtr < 0) { return -1; } p = fip->bp; more: while (p < fip->bend) { if (*p == '\n') { /* newline, we are done */ *p++ = '\0'; *line = fip->bp; fip->bp = p; return p - *line; } p++; } /* out the end of the buffer, and no newline */ nch = fip->bend - fip->bp; if (nch == FIBUFSIZE) { /* buffer full, and no newline! ... truncate and return */ fip->buf[FIBUFSIZE-1] = '\n'; p = &fip->buf[FIBUFSIZE-1]; goto more; } if (nch) /* shuffle partial line to start of buffer */ memcpy(fip->buf, fip->bp, nch); fip->bp = fip->buf; fip->bend = &fip->buf[nch]; /* refill */ sts = read(fip->filePtr, fip->bend, FIBUFSIZE-nch); if (sts <= 0) { /* no more, either terminate last line, or really return status */ if (nch) { *fip->bend = '\n'; sts = 1; } else { return sts; } } p = fip->bend; fip->bend = &fip->bend[sts]; goto more; } /* * Open a log file and seek to the end */ int openLogFile(FileInfo *theFile) { int diff = theFile->filePtr; char *line = (char *)0; theFile->filePtr = open(theFile->fileName, O_RDONLY); if (theFile->filePtr == -1) { if (theFile->filePtr != diff) { logmessage(LOG_ERR, "openLogFile: open %s: %s\n", theFile->fileName, osstrerror()); } return -1; } if (fstat(theFile->filePtr, &(theFile->fileStat)) < 0) { logmessage(LOG_ERR, "openLogFile: stat for %s: %s\n", theFile->fileName, osstrerror()); wl_close(theFile->filePtr); return -1; } logmessage(LOG_INFO, "%s opened (fd=%d, inode=%d)\n", theFile->fileName, theFile->filePtr, theFile->fileStat.st_ino); /* throw away last line in file */ if (theFile->fileStat.st_size != 0) { lseek(theFile->filePtr, -2L, SEEK_END); wl_gets(theFile, &line); } if (fstat(theFile->filePtr, &(theFile->fileStat)) < 0) { logmessage(LOG_ERR, "openLogFile: update stat for %s: %s\n", theFile->fileName, osstrerror()); wl_close(theFile->filePtr); return -1; } /* * Check and warn if a log file has not been modified in the last 24 hours, * as this may indicate something is wrong with the PMDA's configuration, * or the Web server's configuration */ diff = time((time_t*)0) - theFile->fileStat.st_mtime; if (diff > DORMANT_WARN) { logmessage(LOG_WARNING, "log file %s has not been modified for at least %d days", theFile->fileName, diff / DORMANT_WARN); } return 0; } /* * Check the log file is still the correct log file. * * If the file has not been modified in wl_chkDelay seconds, then reopen * the file and compare the inodes. * Otherwise the current inode and size of the file are checked. * * Returns a LogFileCode indicating the status of the log file. */ static int checkLogFile(FileInfo *theFile, struct stat *tmpStat) { int tmpFd = -1; int result = wl_ok; /* * File is closed, if enough time has elasped since last attempt, try to * open it */ if (theFile->filePtr < 0) { if (wl_timeOfRefresh - theFile->lastActive > wl_chkDelay) { theFile->lastActive = wl_timeOfRefresh; if (openLogFile(theFile) < 0) result = wl_unableToOpen; else result = wl_opened; } else result = wl_closed; } /* Get the file stat info on the open file */ if (theFile->filePtr >= 0) { if (fstat(theFile->filePtr, tmpStat) < 0) { logmessage(LOG_ERR, "checkLogFile: stat on open %s: %s\n", theFile->fileName, osstrerror()); wl_close(theFile->filePtr); result = wl_unableToStat; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { logmessage(LOG_DEBUG, "checkLogFile: could not stat %s\n", theFile->fileName); } #endif } } /* * Check that we are dealing with a regular file. If is a character * device or directory etc just ignore it. */ if (result == wl_ok && !(theFile->fileStat.st_mode & S_IFREG)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) logmessage(LOG_DEBUG, "%s is not a regular file. Skipping...\n", theFile->fileName); #endif result = wl_irregularFile; } /* * Check that the size hasn't gotten any smaller e.g. from ftruncate(2) */ if (result == wl_ok && tmpStat->st_size < theFile->fileStat.st_size) { logmessage(LOG_WARNING, "%s stat - inode %d, size %d -> %d\n", theFile->fileName, theFile->fileStat.st_ino, theFile->fileStat.st_size, tmpStat->st_size); result = wl_reopened; } /* * File was already open, check to see if it hasn't been modified, and * that the last time we checked it was > wl_chkDelay ago. */ if (result == wl_ok && tmpStat->st_mtime == theFile->fileStat.st_mtime && wl_timeOfRefresh - theFile->lastActive > wl_chkDelay) { tmpFd = open(theFile->fileName, O_RDONLY); if (tmpFd < 0) { logmessage(LOG_ERR, "checkLogFile: 2nd open to %s: %s\n", theFile->fileName, osstrerror()); wl_close(theFile->filePtr); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { logmessage(LOG_DEBUG, "checkLogFile: could not check %s\n", theFile->fileName); } #endif } else if (fstat(tmpFd, tmpStat) < 0) { logmessage(LOG_ERR, "checkLogFile: stat on inactive %s: %s\n", theFile->fileName, osstrerror()); wl_close(theFile->filePtr); result = wl_unableToStat; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { logmessage(LOG_DEBUG, "checkLogFile: could not stat inactive %s\n", theFile->fileName); } #endif } else if (tmpStat->st_ino != theFile->fileStat.st_ino) { logmessage(LOG_WARNING, "%s inactive - inode %d -> %d\n", theFile->fileName, theFile->fileStat.st_ino, tmpStat->st_ino); result = wl_reopened; } else theFile->lastActive = wl_timeOfRefresh; if (tmpFd >= 0) close(tmpFd); } /* * File needs to be reopened due to change in inode, smaller size, or lack * of activity */ if (result == wl_reopened) { theFile->lastActive = wl_timeOfRefresh; wl_close(theFile->filePtr); if (openLogFile(theFile) < 0) { logmessage(LOG_WARNING, "checkLogFile: unable to reopen %s\n", theFile->fileName); result = wl_unableToOpen; } /* update the stat information using new file desc */ else if (fstat(theFile->filePtr, tmpStat) < 0) { logmessage(LOG_ERR, "checkLogFile - stat on reopened %s: %s\n", theFile->fileName, osstrerror()); wl_close(theFile->filePtr); result = wl_unableToStat; } } /* if the size has increased in the logs, then change the lastActive time */ if (result == wl_ok && tmpStat->st_mtime > theFile->fileStat.st_mtime) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) logmessage(LOG_DEBUG, "%s grew %d bytes\n", theFile->fileName, tmpStat->st_size - theFile->fileStat.st_size); #endif theFile->lastActive = wl_timeOfRefresh; } return result; } /* * Main function for sprocs. Contains an infinite loop selecting on the pipe from the * main process. Anything on the pipe indicates a refresh is required. */ void sprocMain(void *sprocNum) { int mySprocNum = *((int*)sprocNum); int i = 0; int sts = 0; WebSproc *sprocData = &wl_sproc[mySprocNum]; WebServer *server = (WebServer*)0; /* Pause a sec' so the output log doesn't get mucked up */ sleep(1); #ifdef HAVE_SIGHUP /* SIGHUP when the parent dies */ signal(SIGHUP, onhup); #endif #ifdef HAVE_PRCTL #ifdef HAVE_PR_TERMCHILD prctl(PR_TERMCHILD); #elif HAVE_PR_SET_PDEATHSIG prctl(PR_SET_PDEATHSIG, SIGHUP); #endif #endif /* close channel to pmcd */ if (__pmSocketIPC(extp->e_infd)) __pmCloseSocket(extp->e_infd); else if (close(extp->e_infd) < 0) { logmessage(LOG_ERR, "sprocMain: pmcd ch. close(fd=%d) failed: %s\n", extp->e_infd, osstrerror()); } if (__pmSocketIPC(extp->e_outfd)) __pmCloseSocket(extp->e_outfd); else if (close(extp->e_outfd) < 0) { logmessage(LOG_ERR, "sprocMain: pmcd ch. close(fd=%d) failed: %s\n", extp->e_outfd, osstrerror()); } /* close pipes to main process which are not to be used */ if(close(sprocData->inFD[1]) < 0) { logmessage(LOG_ERR, "sprocMain[%d]: pipe close(fd=%d) failed: %s\n", mySprocNum, sprocData->inFD[1], osstrerror()); } if(close(sprocData->outFD[0]) < 0) { logmessage(LOG_ERR, "sprocMain[%d]: pipe close(fd=%d) failed: %s\n", mySprocNum, sprocData->outFD[0], osstrerror()); } /* open up all file descriptors */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) logmessage(LOG_DEBUG, "Sproc %d started for servers %d to %d\n", mySprocNum, sprocData->firstServer, sprocData->lastServer); #endif for (i=sprocData->firstServer; i<=sprocData->lastServer; i++) { server = &wl_servers[i]; if (server->counts.active) { openLogFile(&(server->access)); openLogFile(&(server->error)); } } /* wait for message from pmda to probe files */ for (;;) { sts = read(sprocData->inFD[0], &i, sizeof(i)); if (sts <= 0) { logmessage(LOG_ERR, "Sproc[%d] read(fd=%d) failed: %s\n", mySprocNum, sprocData->inFD[0], osstrerror()); exit(1); } refresh(sprocData); sts = write(sprocData->outFD[1], &i, sizeof(i)); if (sts <= 0) { logmessage(LOG_ERR, "Sproc[%d] write(fd=%d) failed: %s\n", sprocData->outFD[1], mySprocNum, osstrerror()); exit(1); } } } /* * Refresh all the server log files that this process monitors. * Any entries are parsed, categorised and added to the appropriate metrics. */ void refresh(WebSproc* proc) { struct stat tmpStat; WebServer *server = (WebServer *)0; WebCount *count = (WebCount *)0; FileInfo *accessFile = (FileInfo *)0; FileInfo *errorFile = (FileInfo *)0; char *line = (char *)0; char *end = (char *)0; int httpMethod = 0; long size = 0; int sizeIndex = 0; int newLength = 0; int i = 0; int sts = 0; int result = wl_ok; int ok = 0; time_t currentTime; size_t nmatch = 5; regmatch_t pmatch[5]; currentTime = time((time_t*)0); /* iterate through each flagged server */ for (i=proc->firstServer; i<=proc->lastServer; i++) { server = &(wl_servers[i]); accessFile = &(server->access); errorFile = &(server->error); if ((server->update || wl_updateAll) && server->counts.active) { server->counts.numLogs = 0; /* check access log still exists */ result = checkLogFile(accessFile, &tmpStat); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) logmessage(LOG_DEBUG, "checkLogFile returned %d for server %d (access)\n", result, i); #endif /* scan access log */ if (result == wl_ok || result == wl_reopened || result == wl_opened) { server->counts.numLogs++; server->counts.modTime = (__uint32_t)(currentTime - tmpStat.st_mtime); while (accessFile->fileStat.st_size < tmpStat.st_size) { sts = wl_gets(accessFile, &line); if (sts <= 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) logmessage(LOG_DEBUG, "Short read of %s by %d bytes\n", accessFile->fileName, tmpStat.st_size - accessFile->fileStat.st_size); #endif if (sts == 0) { logmessage(LOG_WARNING, "refresh %s: unexpected eof\n", accessFile->fileName); } else { logmessage(LOG_ERR, "refresh %s: %s\n", accessFile->fileName, osstrerror()); } wl_close(accessFile->filePtr); accessFile->lastActive -= wl_chkDelay; break; } accessFile->fileStat.st_size += sts; if (proc->strLength == 0 || proc->strLength <= sts) newLength = sts > 255 ? ((sts / 256) + 1) * 256 : 256; else newLength = proc->strLength; if (newLength > proc->strLength) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { logmessage(LOG_DEBUG, "Resizing strings from %d to %d bytes\n", proc->strLength, newLength); } #endif proc->methodStr = (char*)realloc(proc->methodStr, newLength * sizeof(char)); proc->sizeStr = (char*)realloc(proc->sizeStr, newLength * sizeof(char)); proc->c_statusStr = (char*)realloc(proc->c_statusStr, newLength * sizeof(char)); proc->s_statusStr = (char*)realloc(proc->s_statusStr, newLength * sizeof(char)); proc->strLength = newLength; } if (proc->methodStr == (char *)0 || proc->sizeStr == (char *)0 || proc->c_statusStr == (char *)0 || proc->s_statusStr == (char *)0 ) { logmessage(LOG_ERR, "Unable to allocate %d bytes to strings", newLength); proc->strLength = 0; if (proc->methodStr != (char *)0) free(proc->methodStr); if (proc->sizeStr != (char *)0) free(proc->sizeStr); if (proc->c_statusStr != (char *)0) free(proc->c_statusStr); if (proc->s_statusStr != (char *)0) free(proc->s_statusStr); break; } ok = 0; if (wl_regexTable[accessFile->format].posix_regexp) { if (regexec(wl_regexTable[accessFile->format].regex, line, nmatch, pmatch, 0) == 0) { if(pmatch[1].rm_so < 0 || pmatch[2].rm_so < 0) { logmessage(LOG_ERR, "failed to match method and size: %s\n", line); continue; } if(server->counts.extendedp) { if(pmatch[3].rm_so < 0 || pmatch[4].rm_so < 0) { logmessage(LOG_ERR, "failed to match status codes: %s\n", line); continue; } } line[pmatch[wl_regexTable[accessFile->format].methodPos].rm_eo] = '\0'; strncpy(proc->methodStr, &line[pmatch[wl_regexTable[accessFile->format].methodPos].rm_so], (pmatch[wl_regexTable[accessFile->format].methodPos].rm_eo - pmatch[wl_regexTable[accessFile->format].methodPos].rm_so) + 1); line[pmatch[wl_regexTable[accessFile->format].sizePos].rm_eo] = '\0'; strncpy(proc->sizeStr, &line[pmatch[wl_regexTable[accessFile->format].sizePos].rm_so], (pmatch[wl_regexTable[accessFile->format].sizePos].rm_eo - pmatch[wl_regexTable[accessFile->format].sizePos].rm_so) + 1); if(server->counts.extendedp) { line[pmatch[wl_regexTable[accessFile->format].c_statusPos].rm_eo] = '\0'; strncpy(proc->c_statusStr, &line[pmatch[wl_regexTable[accessFile->format].c_statusPos].rm_so], (pmatch[wl_regexTable[accessFile->format].c_statusPos].rm_eo - pmatch[wl_regexTable[accessFile->format].c_statusPos].rm_so) + 1); line[pmatch[wl_regexTable[accessFile->format].s_statusPos].rm_eo] = '\0'; strncpy(proc->s_statusStr, &line[pmatch[wl_regexTable[accessFile->format].s_statusPos].rm_so], (pmatch[wl_regexTable[accessFile->format].s_statusPos].rm_eo - pmatch[wl_regexTable[accessFile->format].s_statusPos].rm_so) + 1); } else { proc->c_statusStr[0] = '\0'; proc->s_statusStr[0] = '\0'; } ok = 1; } #ifdef PCP_DEBUG else if (pmDebug & DBG_TRACE_APPL2) logmessage(LOG_DEBUG, "Regex failed on %s\n", line); #endif } #ifdef NON_POSIX_REGEX else if (regex(wl_regexTable[accessFile->format].np_regex, line, proc->methodStr, proc->sizeStr, proc->c_statusStr, proc->s_statusStr) != NULL) { ok = 1; } #ifdef PCP_DEBUG else if (pmDebug & DBG_TRACE_APPL2) logmessage(LOG_DEBUG, "Regex failed on %s\n", line); #endif #endif if ( ok ) { for (line = proc->methodStr; *line; line++) *line = toupper((int)*line); httpMethod = wl_httpOther; switch(proc->methodStr[0]) { case 'G': if(strcmp(proc->methodStr, "GET") == 0) { httpMethod = wl_httpGet; } break; case 'O': if(strcmp(proc->methodStr, "O") == 0) { httpMethod = wl_httpGet; } break; case 'H': if(strcmp(proc->methodStr, "HEAD") == 0) { httpMethod = wl_httpHead; } break; case 'P': if(strcmp(proc->methodStr, "POST") == 0 || strcmp(proc->methodStr, "PUT") == 0) { httpMethod = wl_httpPost; } break; case 'I': if(strcmp(proc->methodStr, "I") == 0) { httpMethod = wl_httpPost; } break; } if (strcmp(proc->sizeStr, "-") == 0 || strcmp(proc->sizeStr, " ") == 0) { size = 0; sizeIndex = wl_unknownSize; } else { size = strtol(proc->sizeStr, &end, 10); if (*end != '\0') { logmessage(LOG_ERR, "Bad size (%s) @ %s", proc->sizeStr, line); continue; } for (sizeIndex = 0; sizeIndex < wl_gt3m && size > wl_sizes[sizeIndex]; sizeIndex++); } count = &(server->counts); count->methodReq[httpMethod]++; count->methodBytes[httpMethod] += size; count->sizeReq[sizeIndex]++; count->sizeBytes[sizeIndex] += size; count->sumReq++; count->sumBytes += size; if(server->counts.extendedp == 1) { /* common extended format */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { logmessage(LOG_DEBUG, "Access: Server=%d, line=%s [CEF]\n M: %s S: %s CS: %s, SS: %s", i, line, proc->methodStr, proc->sizeStr, proc->c_statusStr, proc->s_statusStr); } #endif /* * requested page is not in client/browser cache, nor in the * server's cache so it has been fetched from the remote server */ if(strcmp(proc->c_statusStr, "200") == 0 && strcmp(proc->s_statusStr, "200") == 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { logmessage(LOG_DEBUG, "Access: Server=%d, REMOTE fetch: of %.0f bytes\n", i, atof(proc->sizeStr)); } #endif /* * now bucket the size */ if (strcmp(proc->sizeStr, "-") == 0 || strcmp(proc->sizeStr, " ") == 0) { size = 0; sizeIndex = wl_unknownSize; } else { size = strtol(proc->sizeStr, &end, 10); if (*end != '\0') { logmessage(LOG_ERR, "Bad size (%s) @ %s", proc->sizeStr, line); continue; } for (sizeIndex = 0; sizeIndex < wl_gt3m && size > wl_sizes[sizeIndex]; sizeIndex++); } count->uncached_sumReq++; count->uncached_sumBytes += size; count->uncached_sizeReq[sizeIndex]++; count->uncached_sizeBytes[sizeIndex] += size; } /* * requested page is not in client/browser cache, but is in the * server's cache so it is just returned to the client (a cache hit) */ if(strcmp(proc->c_statusStr, "200") == 0 && (strcmp(proc->s_statusStr, "304") == 0 || strcmp(proc->s_statusStr, "-") == 0)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { logmessage(LOG_DEBUG, "Access: Server=%d, CACHE return: of %.0f bytes\n", i, atof(proc->sizeStr)); } #endif /* * now bucket the size */ if (strcmp(proc->sizeStr, "-") == 0 || strcmp(proc->sizeStr, " ") == 0) { size = 0; sizeIndex = wl_unknownSize; } else { size = strtol(proc->sizeStr, &end, 10); if (*end != '\0') { logmessage(LOG_ERR, "Bad size (%s) @ %s", proc->sizeStr, line); continue; } for (sizeIndex = 0; sizeIndex < wl_gt3m && size > wl_sizes[sizeIndex]; sizeIndex++); } count->cached_sumReq++; count->cached_sumBytes += size; count->cached_sizeReq[sizeIndex]++; count->cached_sizeBytes[sizeIndex] += size; } /* * requested page is in client/browser cache */ if(strcmp(proc->c_statusStr, "304") == 0 && (strcmp(proc->s_statusStr, "304") == 0 || strcmp(proc->s_statusStr, "-") == 0)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { logmessage(LOG_DEBUG, "Access: Server=%d, CLIENT hit\n", i); } #endif count->client_sumReq++; } } else if(server->counts.extendedp == 2) { /* default squid format */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { logmessage(LOG_DEBUG, "Access: Server=%d, line=%s [squid]\n M: %s S: %s CS: %s, SS: %s", i, line, proc->methodStr, proc->sizeStr, proc->c_statusStr, proc->s_statusStr); } #endif /* * requested page is not in client/browser cache, nor in the * server's cache so it has been fetched from the remote server */ if(strcmp(proc->c_statusStr, "200") == 0 && (strstr(proc->s_statusStr, "_MISS") != NULL || strstr(proc->s_statusStr, "_CLIENT_REFRESH") != NULL || strstr(proc->s_statusStr, "_SWAPFAIL") != NULL)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { logmessage(LOG_DEBUG, "Access: Server=%d, REMOTE fetch: of %.0f bytes\n", i, atof(proc->sizeStr)); } #endif /* * now bucket the size */ if (strcmp(proc->sizeStr, "-") == 0 || strcmp(proc->sizeStr, " ") == 0) { size = 0; sizeIndex = wl_unknownSize; } else { size = strtol(proc->sizeStr, &end, 10); if (*end != '\0') { logmessage(LOG_ERR, "Bad size (%s) @ %s", proc->sizeStr, line); continue; } for (sizeIndex = 0; sizeIndex < wl_gt3m && size > wl_sizes[sizeIndex]; sizeIndex++); } count->uncached_sumReq++; count->uncached_sumBytes += size; count->uncached_sizeReq[sizeIndex]++; count->uncached_sizeBytes[sizeIndex] += size; } /* * requested page is not in client/browser cache, but is in the * server's cache so it is just returned to the client (a cache hit) */ if(strcmp(proc->c_statusStr, "200") == 0 && strstr(proc->s_statusStr, "_HIT") != NULL) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { logmessage(LOG_DEBUG, "Access: Server=%d, CACHE return: of %.0f bytes\n", i, atof(proc->sizeStr)); } #endif /* * now bucket the size */ if (strcmp(proc->sizeStr, "-") == 0 || strcmp(proc->sizeStr, " ") == 0) { size = 0; sizeIndex = wl_unknownSize; } else { size = strtol(proc->sizeStr, &end, 10); if (*end != '\0') { logmessage(LOG_ERR, "Bad size (%s) @ %s", proc->sizeStr, line); continue; } for (sizeIndex = 0; sizeIndex < wl_gt3m && size > wl_sizes[sizeIndex]; sizeIndex++); } count->cached_sumReq++; count->cached_sumBytes += size; count->cached_sizeReq[sizeIndex]++; count->cached_sizeBytes[sizeIndex] += size; } /* * requested page is in client/browser cache */ if(strcmp(proc->c_statusStr, "304") == 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { logmessage(LOG_DEBUG, "Access: Server=%d, CLIENT hit\n", i); } #endif count->client_sumReq++; } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { logmessage(LOG_DEBUG, "Access: Server=%d, line=%s\n method=%s [%d], size=%s=%d [%d]\n", i, line, proc->methodStr, httpMethod, proc->sizeStr, size, sizeIndex); } #endif } } accessFile->fileStat = tmpStat; } result = checkLogFile(errorFile, &tmpStat); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) logmessage(LOG_DEBUG, "checkLogFile returned %d for server %d (error)\n", result, i); #endif /* scan error log */ if (result == wl_ok || result == wl_reopened || result == wl_opened) { server->counts.numLogs++; while (errorFile->fileStat.st_size < tmpStat.st_size) { sts = wl_gets(errorFile, &line); if (sts <= 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) logmessage(LOG_DEBUG, "%s was %d bytes short\n", errorFile->fileName, tmpStat.st_size - errorFile->fileStat.st_size); #endif if (sts < 0) { logmessage(LOG_ERR, "refresh %s: %s\n", errorFile->fileName, osstrerror()); } else { logmessage(LOG_WARNING, "refresh %s: unexpected eof\n", errorFile->fileName); } wl_close(errorFile->filePtr); errorFile->lastActive -= wl_chkDelay; break; } errorFile->fileStat.st_size += sts; if(wl_regexTable[errorFile->format].posix_regexp) { if (regexec(wl_regexTable[errorFile->format].regex, line, nmatch, pmatch, 0) == 0) { server->counts.errors++; } #ifdef NON_POSIX_REGEX } else { if (regex(wl_regexTable[errorFile->format].np_regex, line, proc->methodStr, proc->sizeStr) != NULL) { server->counts.errors++; } #endif } } errorFile->fileStat = tmpStat; } } /* check to see if a server is inactive but has a file open. It may have just been deactivated */ else if ((server->update || wl_updateAll) && !server->counts.active) { if (accessFile->filePtr >= 0) { logmessage(LOG_WARNING, "Closing inactive server %d access file: %s\n", i, accessFile->fileName); wl_close(accessFile->filePtr); } if (errorFile->filePtr >= 0) { logmessage(LOG_WARNING, "Closing inactive server %d error file: %s\n", i, errorFile->fileName); wl_close(errorFile->filePtr); } } } } /* * Initialise the indom and meta tables * Check that we can do direct mapping. */ /* * Mark servers that are required in the latest profile. */ static int web_profile(__pmProfile *prof, pmdaExt *ext) { pmdaIndom *idp = wl_indomTable; int j; ext->e_prof = prof; for (j = 0; j < idp->it_numinst; j++) { if (__pmInProfile(idp->it_indom, prof, idp->it_set[j].i_inst)) wl_servers[j].update = 1; else wl_servers[j].update = 0; } return 0; } /* * Probe servers for log file changes. * Only those servers that are marked will be requsted. Therefore, if an sproc does * not have any marked servers, it will not be signalled. * NOTE: The main process completes its refresh before signalling the other sprocs. */ void probe(void) { int i = 0; int j = 0; int sts = 0; int dummy = 1; int sprocsUsed = 0; int nfds = 0; fd_set rfds; fd_set tmprfds; int thisFD; WebSproc *sprocData = (WebSproc*)0; struct timeval theTime; __pmtimevalNow(&theTime); wl_timeOfRefresh = theTime.tv_sec; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) logmessage(LOG_DEBUG, "Starting probe at %d\n", wl_timeOfRefresh); #endif FD_ZERO(&rfds); /* * Determine which sprocs have servers that must be refreshed. * Add those sprocs pipes to the file descriptor list. */ for (i=1; i<=wl_numSprocs; i++) { sprocData = &wl_sproc[i]; if (!wl_updateAll) { for (j=sprocData->firstServer; j<=sprocData->lastServer; j++) if (wl_servers[j].update) break; } else { for (j=sprocData->firstServer; j<=sprocData->lastServer; j++) if (wl_servers[j].counts.active) break; } if (j > sprocData->lastServer) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) logmessage(LOG_DEBUG, "Skipping sproc %d\n", i); #endif continue; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) logmessage(LOG_DEBUG, "Told sproc %d to probe for at least server %d\n", i, j); #endif sprocsUsed++; thisFD = sprocData->outFD[0]; sts = write(sprocData->inFD[1], &dummy, sizeof(dummy)); if (sts < 0) { logmessage(LOG_ERR, "Error on fetch write(fd=%d): %s", sprocData->inFD[1], osstrerror()); exit(1); } FD_SET(thisFD, &rfds); nfds = nfds < (thisFD + 1) ? thisFD + 1 : nfds; } /* * Check that we have to update the main process servers */ sprocData = &wl_sproc[0]; if (!wl_updateAll) { for (j=sprocData->firstServer; j<=sprocData->lastServer; j++) if (wl_servers[j].update) break; } else { for (j=sprocData->firstServer; j<=sprocData->lastServer; j++) if (wl_servers[j].counts.active) break; } if (j <= sprocData->lastServer) { refresh(&wl_sproc[0]); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) logmessage(LOG_DEBUG, "Done probe for 0 to %d\n", sprocData->lastServer); #endif } #ifdef PCP_DEBUG else if (pmDebug & DBG_TRACE_APPL2) logmessage(LOG_DEBUG, "Skipping refresh of main process\n"); #endif #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { logmessage(LOG_DEBUG, "Waiting for reply from %d out of %d sprocs\n", sprocsUsed, wl_numSprocs); } #endif /* * Wait for all sprocs to reply * Note: This could get into a hard select loop if an sproc losses it */ for (i=0; ioutFD[0]; if (FD_ISSET(thisFD, &tmprfds)) { FD_CLR(sprocData->outFD[0], &rfds); sts = read(thisFD, &dummy, sizeof(dummy)); if (sts < 0) { logmessage(LOG_ERR, "Error on fetch read: %s", osstrerror()); exit(1); } } } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) logmessage(LOG_DEBUG, "Finished probe\n"); #endif } /* * Refresh all servers * Usually called if no fetches have been received after a set time */ void refreshAll(void) { struct timeval before; struct timeval after; wl_updateAll = 1; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { logmessage(LOG_DEBUG, "Starting a refreshAll\n"); } #endif __pmtimevalNow(&before); probe(); __pmtimevalNow(&after); wl_catchupTime = (after.tv_sec - before.tv_sec) * 1000; wl_catchupTime += (after.tv_usec - before.tv_usec) / 1000; wl_updateAll = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) logmessage(LOG_DEBUG, "Probed all logs, took %d msec\n", wl_catchupTime); #endif } /* * Build a pmResult table of the requested metrics */ static int web_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *ext) { int i; /* over pmidlist[] */ int j; /* over vset->vlist[] */ int s; /* over server */ int sts; int need; int inst; int numval; static pmResult *res = (pmResult *)0; static int maxnpmids = 0; pmValueSet *vset = (pmValueSet *)0; pmDesc *dp = (pmDesc *)0; __pmID_int *pmidp; pmAtomValue atom; int haveValue = 0; int type; __psint_t m_offset = 0; /* initialize to pander to gcc */ int m_type = 0; /* initialize to pander to gcc */ int cluster; __uint32_t tmp32; __uint64_t tmp64; /* determine if the total aggregates are required, which forces a refresh of all servers, and if a probe is require at all */ j = 0; for (i = 0; i < numpmid; i++) { pmidp = (__pmID_int *)&pmidlist[i]; if (pmidp->cluster == 1) break; else j += pmidp->cluster; } if (i < numpmid) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) logmessage(LOG_DEBUG, "web_fetch: refreshAll\n"); #endif refreshAll(); } else if (j) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) logmessage(LOG_DEBUG, "web_fetch: probe\n"); #endif probe(); } #ifdef PCP_DEBUG else if (pmDebug & DBG_TRACE_APPL1) logmessage(LOG_DEBUG, "web_fetch: no probes required\n"); #endif if (numpmid > maxnpmids) { if (res != (pmResult *)0) free(res); /* (numpmid - 1) because there's room for one valueSet in a pmResult */ need = sizeof(pmResult) + (numpmid - 1) * sizeof(pmValueSet *); if ((res = (pmResult *) malloc(need)) == (pmResult *)0) return -oserror(); maxnpmids = numpmid; } res->timestamp.tv_sec = 0; res->timestamp.tv_usec = 0; res->numpmid = numpmid; /* * Get each corresponding metric from the meta table. * Check that the metric has the correct cluster */ for (i = 0; i < numpmid; i++) { pmidp = (__pmID_int*)&pmidlist[i]; dp = (pmDesc *)0; if (ext->e_direct) { if (pmidp->item < numMetrics && pmidlist[i] == wl_metrics[pmidp->item].m_desc.pmid) { dp = &wl_metrics[pmidp->item].m_desc; m_offset = wl_metricInfo[pmidp->item].m_offset; m_type = wl_metricInfo[pmidp->item].m_type; } } else { for (j = 0; jindom != PM_INDOM_NULL) { numval = 0; __pmdaStartInst(dp->indom, ext); while(__pmdaNextInst(&inst, ext)) { numval++; } } else { numval = 1; } } /* Must use individual malloc()s because of pmFreeResult() */ if (numval >= 1) res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue)); else res->vset[i] = vset = (pmValueSet*)malloc(sizeof(pmValueSet) - sizeof(pmValue)); if (vset == (pmValueSet *)0) { if (i) { res->numpmid = i; __pmFreeResultValues(res); } return -oserror(); } vset->pmid = pmidlist[i]; vset->numval = numval; vset->valfmt = PM_VAL_INSITU; if (vset->numval <= 0) continue; if (dp->indom == PM_INDOM_NULL) inst = PM_IN_NULL; else { __pmdaStartInst(dp->indom, ext); __pmdaNextInst(&inst, ext); } type = dp->type; pmidp = (__pmID_int *)&pmidlist[i]; j = 0; do { if (j == numval) { /* more instances than expected! */ numval++; res->vset[i] = vset = (pmValueSet *)realloc(vset, sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue)); if (vset == (pmValueSet *)0) { if (i) { res->numpmid = i; __pmFreeResultValues(res); } return -oserror(); } } vset->vlist[j].inst = inst; cluster = (dp->pmid & _clusterMask) >> 10; haveValue = 1; switch(m_type) { case wl_globalPtr: atom.ul = *(__uint32_t *)(m_offset); break; case wl_offset32: if (wl_servers[inst].counts.active) atom.ul = *((__uint32_t *)(((__psint_t)(&(wl_servers[inst].counts))) + m_offset)); else haveValue = 0; break; case wl_offset64: if (wl_servers[inst].counts.active) atom.ull = *((__uint64_t *)(((__psint_t)(&(wl_servers[inst].counts))) + m_offset)); else haveValue = 0; break; case wl_totalAggregate: if (wl_numActive == 0) haveValue = 0; else { switch(m_offset) { case 0: /* errors */ tmp32 = 0; for (s = 0; s < wl_numServers; s++) { if (wl_servers[s].counts.active) { tmp32 += wl_servers[s].counts.errors; } } atom.ul = tmp32; break; case 1: /* requests */ tmp32 = 0; for (s = 0; s < wl_numServers; s++) { if (wl_servers[s].counts.active) { tmp32 += wl_servers[s].counts.sumReq; } } atom.ul = tmp32; break; case 2: /* bytes */ tmp64 = 0; for (s = 0; s < wl_numServers; s++) { if (wl_servers[s].counts.active) { tmp64 += wl_servers[s].counts.sumBytes; } } atom.ull = tmp64; break; case 3: /* client hit requests */ tmp32 = haveValue = 0; for (s = 0; s < wl_numServers; s++) { if (wl_servers[s].counts.active && wl_servers[s].counts.extendedp) { haveValue = 1; tmp32 += wl_servers[s].counts.client_sumReq; } } atom.ul = tmp32; break; case 4: /* cached hit requests */ tmp32 = haveValue = 0; for (s = 0; s < wl_numServers; s++) { if (wl_servers[s].counts.active && wl_servers[s].counts.extendedp) { haveValue = 1; tmp32 += wl_servers[s].counts.cached_sumReq; } } atom.ul = tmp32; break; case 5: /* cached hit requests */ tmp32 = haveValue = 0; for (s = 0; s < wl_numServers; s++) { if (wl_servers[s].counts.active && wl_servers[s].counts.extendedp) { haveValue = 1; tmp32 += wl_servers[s].counts.uncached_sumReq; } } atom.ul = tmp32; break; case 6: /* cached hit bytes */ tmp64 = haveValue = 0; for (s = 0; s < wl_numServers; s++) { if (wl_servers[s].counts.active && wl_servers[s].counts.extendedp) { haveValue = 1; tmp64 += wl_servers[s].counts.cached_sumBytes; } } atom.ull = tmp64; break; case 7: /* uncached bytes */ tmp64 = haveValue = 0; for (s = 0; s < wl_numServers; s++) { if (wl_servers[s].counts.active && wl_servers[s].counts.extendedp) { haveValue = 1; tmp64 += wl_servers[s].counts.uncached_sumBytes; } } atom.ull = tmp64; break; default: break; } } break; case wl_serverAggregate: if (wl_servers[inst].counts.active == 0) haveValue = 0; else switch(m_offset) { case 0: /* requests */ atom.ul = wl_servers[inst].counts.sumReq; break; case 1: /* bytes */ atom.ull = wl_servers[inst].counts.sumBytes; break; case 2: /* client hit requests */ if( wl_servers[inst].counts.extendedp ) { atom.ul = wl_servers[inst].counts.client_sumReq; } else haveValue = 0; break; case 3: /* cache hit requests */ if( wl_servers[inst].counts.extendedp ) { atom.ul = wl_servers[inst].counts.cached_sumReq; } else haveValue = 0; break; case 4: /* uncached requests */ if( wl_servers[inst].counts.extendedp ) { atom.ul = wl_servers[inst].counts.uncached_sumReq; } else haveValue = 0; break; case 5: /* cached bytes */ if( wl_servers[inst].counts.extendedp ) { atom.ull = wl_servers[inst].counts.cached_sumBytes; } else haveValue = 0; break; case 6: /* uncached bytes */ if( wl_servers[inst].counts.extendedp ) { atom.ull = wl_servers[inst].counts.uncached_sumBytes; } else haveValue = 0; default: break; } break; case wl_requestMethod: if (cluster == 1) { /* all servers */ if (wl_numActive == 0) haveValue = 0; else { tmp32 = 0; for (s = 0; s < wl_numServers; s++) if (wl_servers[s].counts.active) tmp32 += wl_servers[s].counts.methodReq[m_offset]; atom.ul = tmp32; } } else if (wl_servers[inst].counts.active) atom.ul = wl_servers[inst].counts.methodReq[m_offset]; else haveValue = 0; break; case wl_bytesMethod: if (cluster == 1) { /* all servers */ if (wl_numActive == 0) haveValue = 0; else { tmp64 = 0; for (s = 0; s < wl_numServers; s++) if (wl_servers[s].counts.active) tmp64 += wl_servers[s].counts.methodBytes[m_offset]; atom.ull = tmp64; } } else if (wl_servers[inst].counts.active) atom.ull = wl_servers[inst].counts.methodBytes[m_offset]; else haveValue = 0; break; case wl_requestSize: if (cluster == 1) { /* all servers */ if (wl_numActive == 0) haveValue = 0; else { tmp32 = 0; for (s = 0; s < wl_numServers; s++) if (wl_servers[s].counts.active) tmp32 += wl_servers[s].counts.sizeReq[m_offset]; atom.ul = tmp32; } } else if (wl_servers[inst].counts.active) atom.ul = wl_servers[inst].counts.sizeReq[m_offset]; else haveValue = 0; break; case wl_bytesSize: if (cluster == 1) { /* all servers */ if (wl_numActive == 0) haveValue = 0; else { tmp64 = 0; for (s = 0; s < wl_numServers; s++) if (wl_servers[s].counts.active) tmp64 += wl_servers[s].counts.sizeBytes[m_offset]; atom.ull = tmp64; } } else if (wl_servers[inst].counts.active) atom.ull = wl_servers[inst].counts.sizeBytes[m_offset]; else haveValue = 0; break; case wl_requestCachedSize: haveValue = 0; if (cluster == 3) { /* all servers */ tmp32 = 0; for (s = 0; s < wl_numServers; s++) if (wl_servers[s].counts.active && wl_servers[s].counts.extendedp) { haveValue = 1; tmp32 += wl_servers[s].counts.cached_sizeReq[m_offset]; } atom.ul = tmp32; } else if (wl_servers[inst].counts.active && wl_servers[inst].counts.extendedp) { haveValue = 1; atom.ul = wl_servers[inst].counts.cached_sizeReq[m_offset]; } break; case wl_bytesCachedSize: haveValue = 0; if (cluster == 3) { /* all servers */ tmp64 = 0; for (s = 0; s < wl_numServers; s++) { if (wl_servers[s].counts.active && wl_servers[s].counts.extendedp) { haveValue = 1; tmp64 += wl_servers[s].counts.cached_sizeBytes[m_offset]; } } atom.ull = tmp64; } else if (wl_servers[inst].counts.active && wl_servers[inst].counts.extendedp) { haveValue = 1; atom.ull = wl_servers[inst].counts.cached_sizeBytes[m_offset]; } break; case wl_requestUncachedSize: haveValue = 0; if (cluster == 3) { /* all servers */ tmp32 = 0; for (s = 0; s < wl_numServers; s++) { if (wl_servers[s].counts.active && wl_servers[s].counts.extendedp ) { haveValue = 1; tmp32 += wl_servers[s].counts.uncached_sizeReq[m_offset]; } } atom.ul = tmp32; } else if (wl_servers[inst].counts.active && wl_servers[inst].counts.extendedp) { haveValue = 1; atom.ul = wl_servers[inst].counts.uncached_sizeReq[m_offset]; } break; case wl_bytesUncachedSize: haveValue = 0; if (cluster == 3) { /* all servers */ tmp64 = 0; for (s = 0; s < wl_numServers; s++) { if (wl_servers[s].counts.active && wl_servers[s].counts.extendedp) { haveValue = 1; tmp64 += wl_servers[s].counts.uncached_sizeBytes[m_offset]; } } atom.ull = tmp64; } else if (wl_servers[inst].counts.active && wl_servers[inst].counts.extendedp) { haveValue = 1; atom.ull = wl_servers[inst].counts.uncached_sizeBytes[m_offset]; } break; case wl_watched: atom.ul = *((__uint32_t *)(((__psint_t)(&(wl_servers[inst].counts))) + m_offset)); break; case wl_numAlive: tmp32 = 0; for (s = 0; s < wl_numServers; s++) { if (wl_servers[s].counts.active) tmp32 += wl_servers[s].counts.numLogs > 0 ?1:0; } atom.ul = tmp32; break; case wl_nosupport: haveValue = 0; break; default: logmessage(LOG_CRIT, "Illegal Meta Type (%d) for metric %d\n", m_type, pmidp->item); exit(1); } if (haveValue) { sts = __pmStuffValue(&atom, &vset->vlist[j], type); if (sts < 0) { __pmFreeResultValues(res); return sts; } vset->valfmt = sts; j++; /* next element in vlist[] for next instance */ } } while (dp->indom != PM_INDOM_NULL && __pmdaNextInst(&inst, ext)); vset->numval = j; } *resp = res; return 0; } /* * Store into one of three metrics: * web.activity.config.catchup, web.activity.config.check and web.activity.server.watched */ static int web_store(pmResult *result, pmdaExt *ext) { int i; int j; pmValueSet *vsp; int sts = 0; __pmID_int *pmidp; WebServer *server = (WebServer*)0; for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; pmidp = (__pmID_int *)&vsp->pmid; if (pmidp->cluster == 0) { if (pmidp->item == 1) { /* web.activity.config.catchup */ int val = vsp->vlist[0].value.lval; if (val < 0) { sts = PM_ERR_SIGN; val = 20; } wl_refreshDelay = val; } else if (pmidp->item == 3) {/* web.activity.config.check */ int val = vsp->vlist[0].value.lval; if (val < 0) { sts = PM_ERR_SIGN; val = 20; } wl_chkDelay = val; } else if (pmidp->item == 35) {/* web.activity.server.watched */ for (j = 0; j < vsp->numval; j++) { int val = vsp->vlist[j].value.lval; if (val < 0) { sts = PM_ERR_SIGN; val = 1; } server = &wl_servers[vsp->vlist[j].inst]; if (val > 0 && server->counts.active == 0) { wl_numActive++; server->counts.active = 1; } else if (val == 0 && server->counts.active > 0){ wl_numActive--; server->counts.active = 0; } } } else { sts = PM_ERR_PMID; break; } } else { /* not one of the metrics we are willing to change */ sts = PM_ERR_PMID; break; } } return sts; } /* * Initialise the callback table, and open the help text. * This also calls the routine that to initialise the indom and meta tables. */ void web_init(pmdaInterface *dp) { int m; int type; extp = dp->version.two.ext; if (wl_isDSO) pmdaDSO(dp, PMDA_INTERFACE_2, "weblog DSO", wl_helpFile); if (dp->status != 0) return; dp->version.two.profile = web_profile; dp->version.two.fetch = web_fetch; dp->version.two.store = web_store; if (numMetrics != (sizeof(wl_metricInfo)/sizeof(wl_metricInfo[0]))) { logmessage(LOG_CRIT, "Metric and Metric Info tables are not the same size\n"); dp->status = -1; return; } pmdaInit(dp, wl_indomTable, numIndoms, wl_metrics, numMetrics); for (m = 0; m < numMetrics; m++) { type = wl_metricInfo[m].m_type; if (type == wl_offset32 || type == wl_offset64 || type == wl_watched) { wl_metricInfo[m].m_offset -= (__psint_t)&dummyCount; } } return; } pcp-3.8.12ubuntu1/src/pmdas/weblog/README0000664000000000000000000001570512272262501014644 0ustar Performance Co-Pilot Weblog PMDA for Monitoring of Web Server logs ================================================================== This PMDA is capable of monitoring the activity of multiple Web servers, in terms of requests and bytes, in real time. The PMDA can also monitor proxy server, SOCKS server and ftpd logs. Site configuration is discussed in the online HTML documentation located at $PCP_DOC_DIR/pcpweb. This should be read before proceeding any further with installing this PMDA. The file $PCP_DOC_DIR/pcpweb/README contains instructions for installing this documentation. During the installation process, you may be prompted for several parameters which will affect the behavior of the weblog PMDA. These are discussed in the pmdaweblog(1) man page. Installation of the Weblog PMDA =============================== 1. Check that there is no clash with the Performance Metrics Domain number defined in domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit domain.h and choose another domain number. 2. Ensure that the web server control files can be correctly located as follows. Web Server Default Directory Environment Search for Config Type Variable File(s) and/or Logs Below the Default Directory Netscape /usr/ns-home $NSROOTPATH httpd-*/obj.conf and httpd-*/magnus.conf /var/netscape/suitespot https-*/obj.conf https-*/magnus.conf proxy-*/obj.conf proxy-*/magnus.conf Netscape /usr/ns-home $NSROOTPATH proxy-server/logs/sockd Proxy Netscape /var/ns-proxy $NSPROXYPATH logs/access Proxy logs/errors logs/sockd Outbox /var/www/htdocs/outbox $OUTBOXPATH logs/access logs/errors NCSA /var/www $NCSAPATH server/logs/access_log server/logs/error_log Zeus /usr/local/zeus $ZEUSPATH server.ini log/transfer log/errors Apache /usr/apache $APACHEPATH conf/httpd.conf conf/srm.conf log/access_log log/error_log Anon FTP /etc/passwd $PASSWDPATH [file, not dir] for ~ftp /var/adm/SYSLOG $SYSLOGPATH [file, not dir] for access and errors To over-ride the Default Directory for a particular type of Web server, set the corresponding Environment Variable to the absolute pathname of the directory. As a special case $NSROOTPATH for the non-proxy Netscape Web server can be set to a colon (:) separated list of directory names to be searched (in the style of the $PATH for /bin/sh). 3. Then run the Install script (as root) # cd $PCP_PMDAS_DIR/weblog # ./Install 4. The installation script will prompt if this is a collector and/or monitor installation. Briefly: o if there are Web servers on this host, then this is a collector host. o if monitoring tools (pmchart(1), pmlogger(1) etc.) will be run on this host, then this is a monitoring host. Consult the HTML documentation for more details. A monitoring host installation will install only the namespace and some application configuration files. 5. The next prompt will ask if this is a default installation. The default installation will search for known Web server configurations and install the PMDA to monitor any logs that are found. This is appropriate for first time installations. The non-default installation is described in points 6 to 8. 6. The configuration file for the weblog PMDA must be found and checked. The Install script will look in the likely places for an existing file and prompt for confirmation. Otherwise, a configuration file can be automatically generated by searching known Web server configuration files and directories. 7. The second stage of the Install script prompts for the pmdaweblog(1) parameters. The default values should be adequate for an initial installation. 8. The final stage will install the agent and restart PMCD (the Performance Metrics Collection Daemon). The Install script should report that the Metrics are OK. De-installation =============== Simply use (as root) # cd $PCP_PMDAS_DIR/weblog # ./Remove Changing the settings ===================== The safest way to alter any settings that were entered in the Install script is to re-run the Install script. Changes to the weblog.conf file can be also be registered by running the Install script. To quickly test changes to the configuration files, the agent and pmcd can be restarted as follows: To register any changes made to the weblog.conf file, the agent must be killed and restarted: # pmsignal -a -s KILL pmdaweblog # pmsignal -a -s HUP pmcd To register any changes to the $PCP_PMCDCONF_PATH file you must restart PMCD: # $PCP_RC_DIR/pcp start Troubleshooting =============== 0. If there is trouble locating the Web server access and error logs, try running the server.sh script with diagnostics: $ cd $PCP_PMDAS_DIR/weblog $ ./server.sh -q -v #include #if defined(HAVE_REGEX_H) #include #endif #include int main(int argc, char *argv[]) { FILE *fc; char buf[1024]; char *p; char *q; #ifdef HAVE_REGEX char *comp = NULL; char sub0[1024]; char sub1[1024]; char sub2[1024]; char sub3[1024]; #endif int lno = 0; int regex_posix = 0; int cern_format = 0; int common_extended_format = 0; int squid_format = 0; int methodpos = 1, c_statuspos = 2, sizepos = 2, s_statuspos = 2; long client_cache_hits, proxy_cache_hits, remote_fetches; double proxy_bytes, remote_bytes; #if (defined HAVE_REGEXEC) && (defined HAVE_REGCOMP) regex_t re = {0}; regmatch_t pmatch[5]; size_t nmatch = 5; #endif if (argc < 3 || argc > 4) { fprintf(stderr, "Usage: check_match configfile pat_name [input]\n"); exit(1); } if ((fc = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "check_match: cannot open configfile \"%s\": %s\n", argv[1], osstrerror()); exit(1); } if (argc == 4) { if (freopen(argv[3], "r", stdin) == NULL) { fprintf(stderr, "check_match: cannot open input \"%s\": %s\n", argv[3], osstrerror()); exit(1); } } while (fgets(buf, sizeof(buf), fc) != NULL) { lno++; if (strncmp(buf, "regex", 5) != 0) continue; if (strncmp(buf, "regex_posix", 11) == 0) { regex_posix = 1; p = &buf[11]; } else { regex_posix = 0; p = &buf[5]; } while (*p && isspace((int)*p)) p++; if (*p == '\0') continue; q = p++; while (*p && !isspace((int)*p)) p++; if (*p == '\0') continue; *p = '\0'; cern_format = squid_format = common_extended_format = 0; if (strcmp(q, argv[2]) == 0) { if(regex_posix) { q = ++p; while (*p && !isspace((int)*p)) p++; if (*p == '\0') continue; *p = '\0'; fprintf(stderr, "args are (%s)\n", q); if(strncmp(q, "method,size", 11) == 0) { cern_format = 1; methodpos = 1; sizepos = 2; } else if(strncmp(q, "size,method", 11) == 0) { methodpos = 2; sizepos = 1; } else { char *str; int pos; pos = 1; str=q; do { switch(str[0]) { case '1': methodpos = pos++; break; case '2': sizepos = pos++; break; case '3': c_statuspos = pos++; break; case '4': s_statuspos = pos++; break; case '-': methodpos = 1; sizepos = 2; str[0] = '\0'; break; case ',': case '\0': break; default: fprintf(stderr, "could figure out arg order params (%s)\n", str); exit(1); } } while ( *str++ ); if(c_statuspos > 0 && s_statuspos > 0) { if(strcmp(argv[2], "SQUID") == 0) squid_format = 1; else common_extended_format = 1; } else cern_format = 1; } fprintf(stderr, "cern: %d, cef: %d, squid: %d, MP: %d, SP: %d, CSP: %d, SSP: %d\n", cern_format, common_extended_format, squid_format, methodpos, sizepos, c_statuspos, s_statuspos); } q = ++p; while (*p && *p != '\n') p++; while (p >= q && isspace((int)*p)) p--; p[1] = '\0'; if(regex_posix) { #ifdef HAVE_REGCOMP fprintf(stderr, "%s[%d]: regex_posix: %s\n", argv[1], lno, q); fclose(fc); if(regcomp(&re, q, REG_EXTENDED) != 0 ) { fprintf(stderr, "Error: bad regular expression\n"); exit(1); } #else fprintf(stderr, "%s[%d]: no support for POSIX regexp\n", argv[1], lno); #endif } else { #ifdef HAVE_REGCMP if(strcmp(argv[2], "CERN") == 0) cern_format = 1; else if (strcmp(argv[2], "NS_PROXY") == 0) common_extended_format = 1; else if (strcmp(argv[2], "SQUID") == 0) squid_format = 1; fprintf(stderr, "%s[%d]: regex: %s\n", argv[1], lno, q); fclose(fc); comp = regcmp(q, NULL); if (comp == NULL) { fprintf(stderr, "Error: bad regular expression\n"); exit(1); } #else fprintf(stderr, "%s[%d]: regcmp is not available\n", argv[1], lno); #endif } break; } } lno = 0; remote_fetches = proxy_cache_hits = client_cache_hits = 0; remote_bytes = proxy_bytes = 0.0; while (fgets(buf, sizeof(buf), stdin) != NULL) { lno++; if(regex_posix) { #ifdef HAVE_REGEXEC if(regexec(&re, buf, nmatch, pmatch, 0) == 0) { buf[pmatch[methodpos].rm_eo] = '\0'; buf[pmatch[sizepos].rm_eo] = '\0'; if(common_extended_format || squid_format) { buf[pmatch[c_statuspos].rm_eo] = '\0'; buf[pmatch[s_statuspos].rm_eo] = '\0'; } if(common_extended_format) { fprintf(stderr,"[%d] M: %s, S: %s, CS: %s, SS: %s\n", lno, &buf[pmatch[methodpos].rm_so], &buf[pmatch[sizepos].rm_so], &buf[pmatch[c_statuspos].rm_so], &buf[pmatch[s_statuspos].rm_so]); if(strcmp(&buf[pmatch[c_statuspos].rm_so], "200") == 0 && strcmp(&buf[pmatch[s_statuspos].rm_so], "200") == 0) { fprintf(stderr,"\tREMOTE fetch of %.0f bytes\n", atof(&buf[pmatch[sizepos].rm_so])); remote_fetches++; remote_bytes += atof(&buf[pmatch[sizepos].rm_so]); } if(strcmp(&buf[pmatch[c_statuspos].rm_so], "200") == 0 && (strcmp(&buf[pmatch[s_statuspos].rm_so], "304") == 0 || strcmp(&buf[pmatch[s_statuspos].rm_so], "-") == 0)) { fprintf(stderr,"\tCACHE return of %.0f bytes\n", atof(&buf[pmatch[sizepos].rm_so])); proxy_cache_hits++; proxy_bytes += atof(&buf[pmatch[sizepos].rm_so]); } if(strcmp(&buf[pmatch[c_statuspos].rm_so], "304") == 0 && (strcmp(&buf[pmatch[s_statuspos].rm_so], "304") == 0 || strcmp(&buf[pmatch[s_statuspos].rm_so], "-") == 0)) { fprintf(stderr,"\tCLIENT hit of %.0f bytes\n", atof(&buf[pmatch[sizepos].rm_so])); client_cache_hits++; } } else if(squid_format) { fprintf(stderr,"[%d] M: %s, S: %s, CS: %s, SS: %s\n", lno, &buf[pmatch[methodpos].rm_so], &buf[pmatch[sizepos].rm_so], &buf[pmatch[c_statuspos].rm_so], &buf[pmatch[s_statuspos].rm_so]); if(strcmp(&buf[pmatch[c_statuspos].rm_so], "200") == 0 && (strstr(&buf[pmatch[s_statuspos].rm_so], "_MISS")!=NULL || strstr(&buf[pmatch[s_statuspos].rm_so], "_CLIENT_REFRESH")!=NULL || strstr(&buf[pmatch[s_statuspos].rm_so], "_SWAPFAIL")!=NULL)){ fprintf(stderr,"\tREMOTE fetch of %.0f bytes (code: %s, Squid result code: %s)\n", atof(&buf[pmatch[sizepos].rm_so]), &buf[pmatch[c_statuspos].rm_so], &buf[pmatch[s_statuspos].rm_so]); remote_fetches++; remote_bytes += atof(&buf[pmatch[sizepos].rm_so]); } if(strcmp(&buf[pmatch[c_statuspos].rm_so], "200") == 0 && strstr(&buf[pmatch[s_statuspos].rm_so], "_HIT") != NULL) { fprintf(stderr,"\tCACHE return of %.0f bytes (code: %s, Squid result code: %s)\n", atof(&buf[pmatch[sizepos].rm_so]), &buf[pmatch[c_statuspos].rm_so], &buf[pmatch[s_statuspos].rm_so]); proxy_cache_hits++; proxy_bytes += atof(&buf[pmatch[sizepos].rm_so]); } if(strcmp(&buf[pmatch[c_statuspos].rm_so], "304") == 0 && strstr(&buf[pmatch[s_statuspos].rm_so], "_HIT") != NULL) { fprintf(stderr,"\tCLIENT hit of %.0f bytes (code: %s, Squid result code: %s)\n", atof(&buf[pmatch[sizepos].rm_so]), &buf[pmatch[c_statuspos].rm_so], &buf[pmatch[s_statuspos].rm_so]); client_cache_hits++; } } else { fprintf(stderr, "[%d] match: method=\"%s\" size=\"%s\"\n", lno, &buf[pmatch[methodpos].rm_so], &buf[pmatch[sizepos].rm_so]); } } else fprintf(stderr, "[%d] no match: %s\n", lno, buf); #else fprintf(stderr, "[%d] - no regexec()\n", lno); #endif } else { #ifdef HAVE_REGEX if (regex(comp, buf, sub0, sub1, sub2, sub3) != NULL) { if(common_extended_format) { fprintf(stderr,"[%d] M: %s, S: %s, CS: %s, SS: %s\n", lno, sub0, sub1, sub2, sub3); if(strcmp(sub2, "200") == 0 && strcmp(sub3, "200") == 0 ) { fprintf(stderr,"\tREMOTE fetch of %s bytes\n", sub1); remote_fetches++; remote_bytes += atof(sub1); } if(strcmp(sub2, "200") == 0 && (strcmp(sub3, "304") == 0 || strcmp(sub3, "-") == 0)) { fprintf(stderr,"\tCACHE return of %s bytes\n", sub1); proxy_cache_hits++; proxy_bytes += atof(sub1); } if(strcmp(sub2, "304") == 0 && (strcmp(sub3, "304") == 0 || strcmp(sub3, "-") == 0)) { fprintf(stderr,"\tCLIENT hit of %s bytes\n", sub1); client_cache_hits++; } } else if(squid_format) { fprintf(stderr,"[%d] M: %s, S: %s, CS: %s, SS: %s\n", lno, sub0, sub1, sub2, sub3); if(strcmp(sub2, "200") == 0 && (strstr(sub3, "_MISS") != NULL || strstr(sub3, "_CLIENT_REFRESH")!= NULL || strstr(sub3, "_SWAPFAIL") != NULL)){ fprintf(stderr,"\tREMOTE fetch of %.0f bytes (code: %s, Squid result code: %s)\n", atof(sub1), sub2, sub3); remote_fetches++; remote_bytes += atof(sub1); } if(strcmp(sub2, "200") == 0 && strstr(sub3, "_HIT") != NULL) { fprintf(stderr,"\tCACHE return of %.0f bytes (code: %s, Squid result code: %s)\n", atof(sub1), sub2, sub3); proxy_cache_hits++; proxy_bytes += atof(sub1); } if(strcmp(sub2, "304") == 0 && strstr(sub3, "_HIT") != NULL) { fprintf(stderr,"\tCLIENT hit of %.0f bytes (code: %s, Squid result code: %s)\n", atof(sub3), sub2, sub3); client_cache_hits++; } } else { fprintf(stderr, "[%d] match: method=\"%s\" size=\"%s\"\n", lno, sub0, sub1); } } else fprintf(stderr, "[%d] no match: %s\n", lno, buf); #else fprintf(stderr, "[%d] - no regex()\n", lno); #endif } } if(common_extended_format || squid_format) { fprintf(stderr,"Proxy Cache Summary Report\n\n"); fprintf(stderr, "# requests %ld\n# client cache hits %ld\n# cache hits %ld\n# remote fetches %ld\n", (client_cache_hits + proxy_cache_hits + remote_fetches), client_cache_hits, proxy_cache_hits, remote_fetches); fprintf(stderr, "\nTotal Mbytes %f bytes\nFrom proxy cache %f Mbytes\nFrom remote sites %f Mbytes\n\n", (proxy_bytes + remote_bytes)/1000000.0, proxy_bytes/1000000.0, remote_bytes/1000000.0); fprintf(stderr, "Client Cache %% hit rate: %.2f\n", 100.0*(float)client_cache_hits/(float)(client_cache_hits + proxy_cache_hits + remote_fetches)); fprintf(stderr, "Proxy Cache %% hit rate: %.2f\n", 100.0*(float)proxy_cache_hits/(float)(client_cache_hits + proxy_cache_hits + remote_fetches)); fprintf(stderr, "Local Cache %% hit rate: %.2f\n", 100.0*(float)(client_cache_hits + proxy_cache_hits)/ (float)(client_cache_hits + proxy_cache_hits + remote_fetches)); fprintf(stderr, "\nAverage fetch size: Proxy -> Client: %.2f Kb\n", proxy_bytes/proxy_cache_hits/1000.0); fprintf(stderr, "Average fetch size: Remote -> Client : %.2f Kb\n", remote_bytes/remote_fetches/1000.0); fprintf(stderr,"\nClient Cache bandwidth reduction effectiveness: UNKNOWN\n"); fprintf(stderr, "Proxy Cache bandwidth reduction effectiveness: %f%%\n", 100.0*proxy_bytes/(proxy_bytes + remote_bytes)); } exit(0); } pcp-3.8.12ubuntu1/src/pmdas/weblog/Web.Requests.pmchart0000664000000000000000000000257012272262501017667 0ustar #pmchart # # Web statistics (request rates) # # This file is installed by the script $PCP_PMDAS_DIR/weblog/Install # Version 2.0 host dynamic Chart Title "Requests by HTTP method" Style stacking Plot Color rgbi:1.0/1.0/0.0 Host * Metric web.allservers.requests.get Plot Color rgbi:0.0/1.0/1.0 Host * Metric web.allservers.requests.post Plot Color rgbi:1.0/0.0/1.0 Host * Metric web.allservers.requests.head Plot Color rgbi:1.0/1.0/0.6 Host * Metric web.allservers.requests.other Chart Title "Requests by request size" Style stacking Plot Color rgbi:1.0/0.8/0.6 Host * Metric web.allservers.requests.size.zero Plot Color rgbi:0.6/1.0/0.6 Host * Metric web.allservers.requests.size.le3k Plot Color rgbi:0.8/0.6/1.0 Host * Metric web.allservers.requests.size.le10k Plot Color rgbi:1.0/0.65/0.3 Host * Metric web.allservers.requests.size.le30k Plot Color rgbi:0.3/1.0/0.3 Host * Metric web.allservers.requests.size.le100k Plot Color rgbi:0.65/0.3/1.0 Host * Metric web.allservers.requests.size.le300k Plot Color rgbi:1.0/0.5/0.0 Host * Metric web.allservers.requests.size.le1m Plot Color rgbi:0.0/1.0/0.0 Host * Metric web.allservers.requests.size.le3m Plot Color rgbi:0.6/0.0/0.9 Host * Metric web.allservers.requests.size.gt3m Plot Color rgbi:1.0/0.35/0.0 Host * Metric web.allservers.requests.size.unknown # # Created Thu Jul 2 10:48:19 1998 pcp-3.8.12ubuntu1/src/pmdas/weblog/Web.Allservers.pmchart0000775000000000000000000000522612272262501020202 0ustar #!/bin/sh . $PCP_DIR/etc/pcp.env tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1 trap "rm -rf $tmp; exit" 0 1 2 3 15 echo "/\"/s///g" >$tmp/sed pmprobe -I $* web.perserver.bytes.cached.total web.perserver.bytes.total > $tmp/pmprobe l1=`head -n 1 $tmp/pmprobe` l2=`tail -n 1 $tmp/pmprobe` num_caches=`echo $l1 | cut -f2 -d\ ` num_servers=`echo $l2 | cut -f2 -d\ ` if [ $num_servers -gt 0 ] then caches=`echo $l1 | cut -f3- -d\ ` servers=`echo $l2 | cut -f3- -d\ ` # hostname=`echo $servers | cut -f1 -d: | sed -f $tmp/sed` if [ $num_caches -le 0 ] then # an old pmda - quietly handle all servers as if they were CERN - show only totals caches="NeVeR_MaTcH" num_caches=0 fi elif [ $num_servers -eq 0 ] then $PCP_XCONFIRM_PROG -c -B OK -header "No Active Servers - cannot continue" \ -t "$message" \ -icon info > /dev/null exit else message=`pmerr $num_servers | cut -f5- -d\ ` $PCP_XCONFIRM_PROG -c -B OK -header "Fatal error - cannot continue" \ -t "$message" \ -icon error > /dev/null exit fi # # if too many instances, turn off all legends # legendp=on if [ $num_servers -gt 6 ] then legendp=off fi if [ $num_servers -gt 12 ] then $PCP_XCONFIRM_PROG -c -B Cancel -b Continue -header \ "Too many charts" \ -t "There is 1 chart per server, more than can reasonably be displayed on the screen" \ -icon warning | grep Cancel >/dev/null if [ $? -eq 0 ] then exit fi fi # chart preamble # cat > $tmp/base <> $tmp/base echo Plot Color \#FF3030 Host \* Metric web.allservers.requests.total >> $tmp/base echo Chart Title \"Total Bytes sent by all servers \" Style bars Legend off>> $tmp/base echo Plot Color \#FF3030 Host \* Metric web.allservers.bytes.total >> $tmp/base fi if [ $num_caches -gt 0 ] then echo Chart Title \"Total Requests serviced by caching servers \" Style stacking Legend $legendp >> $tmp/base echo Plot Color \#FFFF30 Host \* Metric web.allservers.requests.client.total >> $tmp/base echo Plot Color \#3030FF Host \* Metric web.allservers.requests.cached.total >> $tmp/base echo Plot Color \#FF3030 Host \* Metric web.allservers.requests.uncached.total >> $tmp/base echo Chart Title \"Total Bytes sent by caching servers \" Style stacking Legend $legendp >> $tmp/base echo Plot Color \#3030FF Host \* Metric web.allservers.bytes.cached.total >> $tmp/base echo Plot Color \#FF3030 Host \* Metric web.allservers.bytes.uncached.total >> $tmp/base fi cat $tmp/base rm -rf $tmp pcp-3.8.12ubuntu1/src/pmdas/weblog/Remove0000664000000000000000000000212512272262501015134 0ustar #! /bin/sh # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the weblog PMDA # # Get standard environment . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=weblog # Do it # #_setup pmdaSetup pmns_name=web # metric names differ from PMDA name #_remove pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/weblog/Web.Perserver.Requests.pmchart0000775000000000000000000000451412272262501021646 0ustar #!/bin/sh . $PCP_DIR/etc/pcp.env tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1 trap "rm -rf $tmp; exit" 0 1 2 3 15 echo "/\"/s///g" >$tmp/sed pmprobe -I $* web.perserver.bytes.cached.total web.perserver.bytes.total > $tmp/pmprobe l1=`head -n 1 $tmp/pmprobe` l2=`tail -n 1 $tmp/pmprobe` num_caches=`echo $l1 | cut -f2 -d\ ` num_servers=`echo $l2 | cut -f2 -d\ ` if [ $num_servers -gt 0 ] then caches=`echo $l1 | cut -f3- -d\ ` servers=`echo $l2 | cut -f3- -d\ ` if [ $num_caches -lt 0 ] then # an old pmda - quietly handle all servers as if they were CERN - show only totals caches="NeVeR_MaTcH" num_caches=0 fi elif [ $num_servers -eq 0 ] then $PCP_XCONFIRM_PROG -c -B OK -header "No Active Servers - cannot continue" \ -t "$message" \ -icon info > /dev/null exit else message=`pmerr $num_servers | cut -f5- -d\ ` $PCP_XCONFIRM_PROG -c -B OK -header "Fatal error - cannot continue" \ -t "$message" \ -icon error > /dev/null exit fi # # if too many instances, turn off all legends # legendp=on if [ $num_servers -gt 6 ] then legendp=off fi if [ $num_servers -gt 12 ] then $PCP_XCONFIRM_PROG -c -B Cancel -b Continue -header \ "Too many charts" \ -t "There is 1 chart per server, more than can reasonably be displayed on the screen" \ -icon warning | grep Cancel >/dev/null if [ $? -eq 0 ] then exit fi fi # chart preamble # cat > $tmp/base </dev/null if [ $? -eq 0 ] then j=`echo $server | sed -f $tmp/sed` echo Chart Title \"Requests satisfied by $j\" Style stacking Legend $legendp >> $tmp/base echo Plot Color \#FFFF30 Host \* Metric web.perserver.requests.client.total Instance $j >> $tmp/base echo Plot Color \#3030FF Host \* Metric web.perserver.requests.cached.total Instance $j >> $tmp/base echo Plot Color \#FF3030 Host \* Metric web.perserver.requests.uncached.total Instance $j >> $tmp/base else j=`echo $server | sed -f $tmp/sed` echo Chart Title \"Total Requests satisfied by $j\" Style bars Legend off>> $tmp/base echo Plot Color \#FF3030 Host \* Metric web.perserver.requests.total Instance $j >> $tmp/base fi i=`expr $i + 1` done cat $tmp/base rm -rf $tmp pcp-3.8.12ubuntu1/src/pmdas/weblog/Install0000664000000000000000000004347212272262501015317 0ustar #! /bin/sh # # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the weblog PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh # Override function from pmdaproc.sh __choose_mode() { if [ -n "$QUIET_INSTALL" ] ; then do_pmda=true else __def=m $do_pmda && __def=b echo \ 'You will need to choose an appropriate configuration for installation of the "'$iam'" Performance Metrics Domain Agent (PMDA). collector collect performance statistics on this system monitor allow this system to monitor local and/or remote systems both collector and monitor configuration for this system ' while true do $PCP_ECHO_PROG $PCP_ECHO_N 'Please enter c(ollector) or m(onitor) or b(oth) ['$__def'] '"$PCP_ECHO_C" read ans case "$ans" in "") break ;; c|collector|b|both) do_pmda=true break ;; m|monitor) do_pmda=false break ;; *) echo "Sorry, that is not acceptable response ..." ;; esac done echo fi } iam=weblog pmda_interface=2 forced_restart=false pmdaSetup pmns_name=web # metric names differ from PMDA name daemon_opt=true # can install as daemon dso_opt=false pipe_opt=true # pipe IPC - YES socket_opt=false # socket IPC - NO socket_inet_def=2080 # default TCP port for Internet socket IPC check_delay=10 # give the PMDA a chance to set itself up # PMDA specific constants # configDir=$PCP_VAR_DIR/config/web # PMDA variables # tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 trap "rm -rf $tmp; exit" 0 1 2 3 15 debugFlag=0 do_debug=false configFile="" delay=15 chkDelay=20 maxserv=80 # --- start functions --- # _parseDefaults() { echo "Extracting options from current installation ..." while getopts D:d:i:l:n:pS:t:u: c do case $c in \?) echo "Warning: Unrecognized option in $PCP_PMCDCONF_PATH" echo " Remove line for pmdaweblog in $PCP_PMCDCONF_PATH and re-run ./Install" exit 2;; D) debugFlag=$OPTARG;; n) chkDelay=$OPTARG;; t) delay=$OPTARG;; S) maxserv=$OPTARG;; *) # old or boring flags, silently ignore ;; esac done shift `expr $OPTIND - 1` if [ $# -eq 1 ] then configFile=$1 elif [ $# -eq 0 ] then configFile="" else echo "Warning: unrecognized format for old specification in $PCP_PMCDCONF_PATH" echo " Remove line for pmdaweblog in $PCP_PMCDCONF_PATH and re-run ./Install" exit 2 fi } _defaultRegex() { touch $1 echo ' # Common regular expressions specifications for parsing access and error logs # Each regular expression specification should have a name (one word), # specify the order of regex parameters (method and size), and # a regular expression. Regular expressions for access logs require two # arguments to be set while errors logs require only a match. # # Set the online HTML Users and Administrators Guide, pmdaweblog(1) and # regexec(3) for more details. # # pattern for CERN, NCSA, Netscape, Apache etc Access Logs regex_posix CERN method,size ][ \\]+"([A-Za-z][-A-Za-z]+) [^"]*" [-0-9]+ ([-0-9]+) # pattern for CERN, NCSA, Netscape etc Error Logs regex_posix CERN_err - . # pattern for Proxy Server Extended Log Format regex_posix NS_PROXY 1,3,2,4 ][ ]+"([A-Za-z][-A-Za-z]+) [^"]*" ([-0-9]+) ([-0-9]+) ([-0-9]+) # pattern for Squid Cache logs regex_posix SQUID 4,3,2,1 [0-9]+\.[0-9]+[ ]+[0-9]+ [a-zA-Z0-9\.]+ ([_A-Z]+)\/([0-9]+) ([0-9]+) ([A-Z]+) # pattern for Netscape SOCKS Server Access logs regex_posix NS_SOCKS method,size (sockd)\[.*, ([0-9]+) bytes from .* \(http\) # pattern for Netscape SOCKS Server Error logs regex_posix NS_SOCKS_err - . # pattern for FTP through a Netscape SOCKS Server Access log regex_posix NS_FTP method,size (sockd)\[.*, ([0-9]+) bytes from .* \([0-9]+\) # pattern for FTP through a Netscape SOCKS Server Error logs regex_posix NS_FTP_err - . # pattern for FTP Server access logs (normally in SYSLOG) regex_posix SYSLOG_FTP method,size ftpd\[.*\]: ([gp][-A-Za-z]+)( ) # pattern for FTP Server error logs (normally in SYSLOG) regex_posix SYSLOG_FTP_err - FTP LOGIN FAILED # pattern for WU_FTP Server access logs (normally in xferlog) regex_posix WU_FTP size,method :[0-9][0-9] [0-9]+ [0-9]+ .+ ([0-9]+) .+ [ba] .+ ([io]) [arg] # pattern for WU_FTP Server error logs (normally in SYSLOG/messages) regex_posix WU_FTP_err - failed login # Server specifications. The format of each specification is # "server" serverName on|off accessRegex accessFile errorRegex errorFile # # Set the online HTML Users and Administrators Guide and pmdaweblog(1) # for more details. #' >> $1 } _parse_server() { egrep "^server" | $PCP_AWK_PROG ' { i=index($2, ":"); if (i == 0) { name = $2; port = ""; } else { name = substr($2,1,i-1); port = sprintf("Port %d", substr($2, i+1, length($2) - i)); } printf("Server %s %s\n", name, port); printf(" Access Log: %s (%s)\n", $5, $4); printf(" Error Log: %s (%s)\n\n", $7, $6); }' } _default_config () { rm -f $tmp/conf touch $tmp/conf _defaultRegex $tmp/conf ./server.sh -q -l $tmp/conf egrep "^server" $tmp/conf > /dev/null 2>&1 _st=$? if [ $_st -eq 0 ] then ./pmdaweblog -C $tmp/conf >$tmp/out 2>&1 _st=$? if [ $_st -eq 0 ] ; then if [ -z "$configFile" ] then configFile=$configDir/$iam.conf fi rm -f $configFile cp $tmp/conf $configFile args="-D $debugFlag -t $delay -n $chkDelay -S $maxserv $configFile" socket_opt=false fi fi return $_st } # # --- end functions --- if $do_pmda then [ ! -d $configDir ] && mkdir -p $configDir if [ -n "$QUIET_INSTALL" ] ; then _default_config if [ $? -eq 0 ] ; then pmdaInstall exit $? else exit 1 fi else echo "----------------------------------------------------------------" echo echo "The default installation of the weblog PMDA will search for known" echo "Web server configurations on this host and will setup the weblog" echo "PMDA to monitor all associated Web server log files." echo echo "Otherwise, you will be prompted for the required information." echo $PCP_ECHO_PROG $PCP_ECHO_N "Do you want a default weblog PMDA installation [y] ""$PCP_ECHO_C" read ans echo if [ "X$ans" = X -o "X$ans" = Xy -o "X$ans" = XY ] then _default_config if [ $? -eq 0 ] ; then pmdaInstall exit $? else echo echo "Unable to find any Web servers!" echo "Reverting to detailed installation..." fi fi echo "----------------------------------------------------------------" echo $PCP_ECHO_PROG $PCP_ECHO_N "Checking for a previous PMDA installation ...""$PCP_ECHO_C" # weblogs -> weblog can be removed once all 1.0 betas are known to # have gone away ans=`$PCP_AWK_PROG < $PCP_PMCDCONF_PATH ' $1 == "'$iam'" { printf "%s",$6 for (i=7;i<=NF;i++) printf " %s",$i print "" }'` if [ -n "$ans" ] then echo " found" _parseDefaults $ans else echo " appears to be a first-time install" fi if [ -n "$configFile" ] then if [ -f "$configFile" ] then if [ $PCP_PLATFORM = linux ] && \ egrep '^regex ' $configFile > /dev/null then echo "Warning: previous configuration file \"$configFile\"" echo " appears to be an incompatible version." $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to automatically update the configuration file? [y] ""$PCP_ECHO_C" read ans if [ "X$ans" = X -o "$ans" = "y" -o "$ans" = "Y" ] then ./weblogconv.sh $configFile $tmp/conf if ./pmdaweblog -C $tmp/conf > /dev/null 2>&1 then cp $tmp/conf $configFile else echo "Warning: automatic conversion failed." echo "You can either continue, and use the default configuration file or exit" echo "this install procedure to manually update your existing configuration." $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to continue with the default configuration? [n] ""$PCP_ECHO_C" read ans if [ "$ans" = "y" -o "$ans" = "Y" ] then configFile="" else exit 1 fi fi fi else echo "Using previous configuration file \"$configFile\"" fi else echo "Warning: previous configuration file \"$configFile\" no longer" echo " exists, reverting to default" configFile="" fi fi if [ "X$configFile" = X -a -f $configDir/$iam.conf ] then configFile=$configDir/$iam.conf echo "Using previous configuration file \"$configFile\"" fi if [ "X$configFile" != X ] then if [ -f $configFile ] then echo "The inital configuration file contains the following Web server details:" echo cat $configFile | _parse_server | ${PAGER-more} echo echo "------------------------------------------------------------------------------" if ./pmdaweblog -C $configFile >$tmp/out 2>&1 then : else echo "Warning: parsing this configuration file produced the following errors," echo " and this file will be ignored." cat $tmp/out echo if [ "X$configFile" = "X$tmp/default" ] then echo "Arrgh ... this is the default configuration, I cannot recover from here!" exit 1 fi configFile="" fi fi fi echo echo "A configuration file can be automatically generated. This can" echo "be used to compare or replace an existing configuration file." echo if [ "X$configFile" = X ] then $PCP_ECHO_PROG $PCP_ECHO_N "Do you want a configuration file to be automatically generated [y] ""$PCP_ECHO_C" read ans if [ "X$ans" = X ] then ans="y" fi else $PCP_ECHO_PROG $PCP_ECHO_N "Do you want a configuration file to be automatically generated [n] ""$PCP_ECHO_C" read ans if [ "X$ans" = X ] then ans="n" fi fi if [ "X$ans" = "Xy" -o "X$ans" = "XY" ] then echo echo "Now scanning for Web servers ..." echo if [ ! -x ./server.sh ] then echo "Unable to scan for Web servers as ./server.sh is missing!" else rm -f $tmp/conf touch $tmp/conf _defaultRegex $tmp/conf ./server.sh -l $tmp/conf if egrep "^server" $tmp/conf > /dev/null 2>&1 then echo echo "This is a possible configuration file for your system:" echo cat $tmp/conf | _parse_server | ${PAGER-more} echo echo "------------------------------------------------------------------------------" echo if ./pmdaweblog -C $tmp/conf > /dev/null 2>&1 then if [ "X$configFile" = X ] then $PCP_ECHO_PROG $PCP_ECHO_N "Would you like to use this configuration file [y] ""$PCP_ECHO_C" read ans if [ "X$ans" = "Xy" -o "X$ans" = "XY" -o "X$ans" = X ] then cp $tmp/conf $configDir/$iam.conf configFile=$configDir/$iam.conf fi else echo "Would you like to replace your existing configuration file with" $PCP_ECHO_PROG $PCP_ECHO_N "the generated file [n] ""$PCP_ECHO_C" read ans if [ "X$ans" != "Xn" -a "X$and" != "XN" -a "X$ans" != X ] then cp $tmp/conf $configFile fi fi else echo "Automated configuration file generation is broken!" if [ "X$configFile" = X ] then echo "Please consult the manual on how to create a configuration file." echo "Installation failed." exit 1 else echo "Ignoring this file." fi fi else echo echo "I could not find any Web servers." fi echo fi fi echo "------------------------------------------------------------------------------" echo if [ "X$configFile" = X ] then $PCP_ECHO_PROG $PCP_ECHO_N "Do you want to specify some Web servers [n]: ""$PCP_ECHO_C" serverAdded="false" else $PCP_ECHO_PROG $PCP_ECHO_N "Do you want to specify some more Web servers [n]: ""$PCP_ECHO_C" serverAdded="true" fi read ans while [ "X$ans" = "Xy" -o "X$ans" = "XY" ] do if [ "X$configFile" = X ] then if [ "X$configFile" = X -a -f $configDir/$iam.conf ] then echo "Replacing existing configuration file $configDir/$iam.conf" rm -f $configDir/$iam.conf else echo "Creating configuration file $configDir/$iam.conf" fi _defaultRegex $configDir/$iam.conf configFile="$configDir/$iam.conf" fi echo serverName=`hostname` $PCP_ECHO_PROG $PCP_ECHO_N "The name of the Web server [$serverName]: ""$PCP_ECHO_C" read ans if [ "X$ans" = X ] then serverName=`hostname` else serverName=$ans fi echo accessPath="" while [ "X$accessPath" = X ] do $PCP_ECHO_PROG $PCP_ECHO_N "The path to the access log: ""$PCP_ECHO_C" read accessPath if [ "X$accessPath" != X ] then if [ -f $accessPath ] then : else echo "$accessPath does not exist or is not a regular file" accessPath="" fi fi done echo errorPath="" while [ "X$errorPath" = X ] do $PCP_ECHO_PROG $PCP_ECHO_N "The path to the error log: ""$PCP_ECHO_C" read errorPath if [ "X$errorPath" != X ] then if [ -f $errorPath ] then : else echo "$errorPath does not exist or is not a regular file" errorPath="" fi fi done echo echo "The configuration file contains these specifications:" echo ${PAGER-more} $configFile echo echo "Does the configuration file contain appropriate regular expressions" $PCP_ECHO_PROG $PCP_ECHO_N "for the \"$serverName\" Web server [y]: ""$PCP_ECHO_C" read ans echo if [ "X$ans" = "Xn" -o "X$ans" = "XN" ] then $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to quit the installation to add new regular expressions [y]: ""$PCP_ECHO_C" read ans if [ "$Xans" = "Xy" -o "X$ans" = "XY" -o "X$ans" = X ] then echo "Edit $configFile and then rerun this Install script." exit 1 echo echo "Skipping $serverName ..." fi else accessRegex="" while [ "X$accessRegex" = X ] do if egrep "^regex_posix CERN " $configFile > /dev/null 2>&1 then $PCP_ECHO_PROG $PCP_ECHO_N "The regex for the access log [CERN]: ""$PCP_ECHO_C" accessRegex="CERN" else $PCP_ECHO_PROG $PCP_ECHO_N "The regex for the access log: ""$PCP_ECHO_C" accessRegex="" fi read ans if [ "X$ans" != X ] then accessRegex=$ans fi if [ "X$accessRegex" != X ] then if egrep "^regex_posix $accessRegex " $configFile > /dev/null 2>&1 then : else echo "Could not find $accessRegex in $configFile" accessRegex="" fi fi done echo errorRegex="" while [ "X$errorRegex" = X ] do if egrep "^regex_posix CERN_err " $configFile > /dev/null 2>&1 then $PCP_ECHO_PROG $PCP_ECHO_N "The regex for the error log [CERN_err]: ""$PCP_ECHO_C" errorRegex="CERN_err" else $PCP_ECHO_PROG $PCP_ECHO_N "The regex for the error log: ""$PCP_ECHO_C" errorRegex="" fi read ans if [ "X$ans" != X ] then errorRegex=$ans fi if [ "X$errorRegex" != X ] then if egrep "^regex_posix $errorRegex " $configFile > /dev/null 2>&1 then : else echo "Could not find $errorRegex in $configFile" errorRegex="" fi fi done echo echo "You have specified the following Web server:" echo server="server $serverName on $accessRegex $accessPath $errorRegex $errorPath" echo "$server" echo $PCP_ECHO_PROG $PCP_ECHO_N "Is this correct [y]: ""$PCP_ECHO_C" read ans if [ "X$ans" = "Xy" -o "X$ans" = "XY" -o "X$ans" = X ] then echo >> $configFile echo "# User configured server called \"$serverName\"" >> $configFile echo $server >> $configFile serverAdded="true" fi fi echo $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to specify another Web Server [n]: ""$PCP_ECHO_C" read ans echo done if [ "$serverAdded" = "false" ] then rm -f $configFile configFile="" fi if [ "X$configFile" = X ] then echo "Please consult the manual on how to create a configuration file." echo "Installation failed as no servers were specified." exit 1 fi echo echo "You may modify the configuration file by hand and add servers" echo "that are not currently listed, change their names, etc." echo $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to exit and modify the configuration file [n] ""$PCP_ECHO_C" read ans if [ "X$ans" != "Xn" -a "X$ans" != "XN" -a "X$ans" != X ] then echo echo "Edit $configFile and then rerun this Install script." exit 1 fi echo echo "------------------------------------------------------------------------------" echo $PCP_ECHO_PROG $PCP_ECHO_N "The delay in seconds between forced reads of the log files [$delay] ""$PCP_ECHO_C" read ans if [ "X$ans" != X ] then delay=$ans fi echo $PCP_ECHO_PROG $PCP_ECHO_N "Number of seconds of inactivity before checking for log rotation [$chkDelay] ""$PCP_ECHO_C" read ans if [ "X$ans" != X ] then chkDelay=$ans fi echo $PCP_ECHO_PROG $PCP_ECHO_N "The maximum number of servers per agent process [$maxserv] ""$PCP_ECHO_C" read ans if [ "X$ans" != X ] then maxserv=$ans fi if [ "$do_debug" = true ] then echo $PCP_ECHO_PROG $PCP_ECHO_N "the Debugging Flag (see pmdbg(1)) [$debugFlag] ""$PCP_ECHO_C" read ans if [ "X$ans" != X ] then debugFlag=$ans fi fi args="-D $debugFlag -t $delay -n $chkDelay -S $maxserv $configFile" echo echo "------------------------------------------------------------------------------" echo fi fi pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/weblog/GNUmakefile0000664000000000000000000000446712272262501016041 0ustar # # Copyright (c) 2000-2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = weblog DOMAIN = WEBSERVER TARGETS = $(IAM)$(EXECSUFFIX) check_match$(EXECSUFFIX) CFILES = weblog.c pmda.c sproc.c HFILES = weblog.h SCRIPTS = Install Remove server.sh weblogconv.sh CHARTS = Web.Alarms.pmchart Web.Requests.pmchart Web.Volume.pmchart \ Web.Allservers.pmchart Web.Perserver.Bytes.pmchart \ Web.Perserver.Requests.pmchart DFILES = README LSRCFILES = pmns help $(DFILES) root $(SCRIPTS) check_match.c $(CHARTS) LDIRT = domain.h $(TARGETS) check_match.o PMDADIR = $(PCP_PMDAS_DIR)/weblog PMCHARTDIR = $(PCP_VAR_DIR)/config/pmchart CONFDIR = $(PCP_VAR_DIR)/config/web LDLIBS = $(PCP_PMDALIB) $(LIB_FOR_PTHREADS) default: build-me include $(BUILDRULES) ifneq "$(TARGET_OS)" "mingw" build-me: $(TARGETS) install: build-me # $(INSTALL) -d $(CONFDIR) # $(INSTALL) -m 644 weblog.conf $(CONFDIR)/weblog.conf $(INSTALL) -d $(PMDADIR) $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) $(INSTALL) -m 755 check_match $(SCRIPTS) $(PMDADIR) $(INSTALL) -m 644 $(DFILES) root help pmns domain.h $(PMDADIR) $(INSTALL) -m 644 Web.Alarms.pmchart $(PMCHARTDIR)/Web.Alarms $(INSTALL) -m 644 Web.Requests.pmchart $(PMCHARTDIR)/Web.Requests $(INSTALL) -m 644 Web.Volume.pmchart $(PMCHARTDIR)/Web.Volume $(INSTALL) -m 755 Web.Allservers.pmchart $(PMCHARTDIR)/Web.Allservers $(INSTALL) -m 755 Web.Perserver.Bytes.pmchart $(PMCHARTDIR)/Web.Perserver.Bytes $(INSTALL) -m 755 Web.Perserver.Requests.pmchart $(PMCHARTDIR)/Web.Perserver.Requests else build-me: install: endif weblog$(EXECSUFFIX): $(OBJECTS) weblog.o: domain.h check_match$(EXECSUFFIX): check_match.o $(CCF) -o $@ $(LDFLAGS) check_match.o $(LDLIBS) domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmdas/weblog/root0000664000000000000000000000016012272262501014657 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { web } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/weblog/pmns0000664000000000000000000001533612272262501014664 0ustar /* * Web Performance Metric Domain (PMD) Identifiers * * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Cluster numbers are used by agent to indicate: * * 0 - Does not require any servers to be updated * 1 - Requires all servers to be updated * 2 - Requires only this server to be updated * * Changes to this file must also be carried into the help file and weblog.c * (especially the meta table, web_fetch and web_store). * */ web { config allservers perserver } web.config { numservers WEBSERVER:0:0 /* in the PMDA configuration file */ catchup WEBSERVER:0:1 /* maximum catch-up period (secs) */ catchuptime WEBSERVER:0:2 /* time spent in catchup (msecs) */ check WEBSERVER:0:3 /* inactivity period (secs), before trying to re-open files */ } web.allservers { numwatched WEBSERVER:0:4 /* number to be watched */ numalive WEBSERVER:0:5 /* number of the watched servers that are apparently alive */ requests bytes errors WEBSERVER:1:6 } web.allservers.requests { total WEBSERVER:1:7 get WEBSERVER:1:8 head WEBSERVER:1:9 post WEBSERVER:1:10 other WEBSERVER:1:11 size client cached uncached } web.allservers.bytes { total WEBSERVER:1:12 get WEBSERVER:1:13 head WEBSERVER:1:14 post WEBSERVER:1:15 other WEBSERVER:1:16 size cached uncached } web.allservers.requests.size { zero WEBSERVER:1:17 le3k WEBSERVER:1:18 le10k WEBSERVER:1:19 le30k WEBSERVER:1:20 le100k WEBSERVER:1:21 le300k WEBSERVER:1:22 le1m WEBSERVER:1:23 le3m WEBSERVER:1:24 gt3m WEBSERVER:1:25 unknown WEBSERVER:1:66 } web.allservers.bytes.size { zero WEBSERVER:1:26 le3k WEBSERVER:1:27 le10k WEBSERVER:1:28 le30k WEBSERVER:1:29 le100k WEBSERVER:1:30 le300k WEBSERVER:1:31 le1m WEBSERVER:1:32 le3m WEBSERVER:1:33 gt3m WEBSERVER:1:34 } web.allservers.requests.client { total WEBSERVER:3:1 } web.allservers.requests.cached { total WEBSERVER:3:11 size } web.allservers.requests.cached.size { zero WEBSERVER:3:12 le3k WEBSERVER:3:13 le10k WEBSERVER:3:14 le30k WEBSERVER:3:15 le100k WEBSERVER:3:16 le300k WEBSERVER:3:17 le1m WEBSERVER:3:18 le3m WEBSERVER:3:19 gt3m WEBSERVER:3:20 unknown WEBSERVER:3:21 } web.allservers.requests.uncached { total WEBSERVER:3:31 size } web.allservers.requests.uncached.size { zero WEBSERVER:3:32 le3k WEBSERVER:3:33 le10k WEBSERVER:3:34 le30k WEBSERVER:3:35 le100k WEBSERVER:3:36 le300k WEBSERVER:3:37 le1m WEBSERVER:3:38 le3m WEBSERVER:3:39 gt3m WEBSERVER:3:40 unknown WEBSERVER:3:41 } web.allservers.bytes.cached { total WEBSERVER:3:51 size } web.allservers.bytes.cached.size { zero WEBSERVER:3:52 le3k WEBSERVER:3:53 le10k WEBSERVER:3:54 le30k WEBSERVER:3:55 le100k WEBSERVER:3:56 le300k WEBSERVER:3:57 le1m WEBSERVER:3:58 le3m WEBSERVER:3:59 gt3m WEBSERVER:3:60 } web.allservers.bytes.uncached { total WEBSERVER:3:71 size } web.allservers.bytes.uncached.size { zero WEBSERVER:3:72 le3k WEBSERVER:3:73 le10k WEBSERVER:3:74 le30k WEBSERVER:3:75 le100k WEBSERVER:3:76 le300k WEBSERVER:3:77 le1m WEBSERVER:3:78 le3m WEBSERVER:3:79 gt3m WEBSERVER:3:80 } web.perserver { watched WEBSERVER:0:35 /* is this server being watched? */ numlogs WEBSERVER:2:36 /* number of logs I can read */ requests bytes errors WEBSERVER:2:37 logidletime WEBSERVER:2:68 } web.perserver.requests { total WEBSERVER:2:38 /* per server */ get WEBSERVER:2:39 head WEBSERVER:2:40 post WEBSERVER:2:41 other WEBSERVER:2:42 size client cached uncached } web.perserver.bytes { total WEBSERVER:2:43 /* per server */ get WEBSERVER:2:44 head WEBSERVER:2:45 post WEBSERVER:2:46 other WEBSERVER:2:47 size cached uncached } web.perserver.requests.size { zero WEBSERVER:2:48 le3k WEBSERVER:2:49 le10k WEBSERVER:2:50 le30k WEBSERVER:2:51 le100k WEBSERVER:2:52 le300k WEBSERVER:2:53 le1m WEBSERVER:2:54 le3m WEBSERVER:2:55 gt3m WEBSERVER:2:56 unknown WEBSERVER:2:67 } web.perserver.bytes.size { zero WEBSERVER:2:57 le3k WEBSERVER:2:58 le10k WEBSERVER:2:59 le30k WEBSERVER:2:60 le100k WEBSERVER:2:61 le300k WEBSERVER:2:62 le1m WEBSERVER:2:63 le3m WEBSERVER:2:64 gt3m WEBSERVER:2:65 } web.perserver.requests.client { total WEBSERVER:4:1 } web.perserver.requests.cached { total WEBSERVER:4:11 size } web.perserver.requests.cached.size { zero WEBSERVER:4:12 le3k WEBSERVER:4:13 le10k WEBSERVER:4:14 le30k WEBSERVER:4:15 le100k WEBSERVER:4:16 le300k WEBSERVER:4:17 le1m WEBSERVER:4:18 le3m WEBSERVER:4:19 gt3m WEBSERVER:4:20 unknown WEBSERVER:4:21 } web.perserver.requests.uncached { total WEBSERVER:4:31 size } web.perserver.requests.uncached.size { zero WEBSERVER:4:32 le3k WEBSERVER:4:33 le10k WEBSERVER:4:34 le30k WEBSERVER:4:35 le100k WEBSERVER:4:36 le300k WEBSERVER:4:37 le1m WEBSERVER:4:38 le3m WEBSERVER:4:39 gt3m WEBSERVER:4:40 unknown WEBSERVER:4:41 } web.perserver.bytes.cached { total WEBSERVER:4:51 size } web.perserver.bytes.cached.size { zero WEBSERVER:4:52 le3k WEBSERVER:4:53 le10k WEBSERVER:4:54 le30k WEBSERVER:4:55 le100k WEBSERVER:4:56 le300k WEBSERVER:4:57 le1m WEBSERVER:4:58 le3m WEBSERVER:4:59 gt3m WEBSERVER:4:60 } web.perserver.bytes.uncached { total WEBSERVER:4:71 size } web.perserver.bytes.uncached.size { zero WEBSERVER:4:72 le3k WEBSERVER:4:73 le10k WEBSERVER:4:74 le30k WEBSERVER:4:75 le100k WEBSERVER:4:76 le300k WEBSERVER:4:77 le1m WEBSERVER:4:78 le3m WEBSERVER:4:79 gt3m WEBSERVER:4:80 } pcp-3.8.12ubuntu1/src/pmdas/weblog/weblogconv.sh0000775000000000000000000000321112272262501016455 0ustar #! /bin/sh # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # weblogconv: convert weblog.conf files to posix regex # # only needed on Linux progname=$0 if [ $# -gt 0 -a "$1" = "-?" ]; then echo "Usage: $progname infile [outfile]" exit 0 fi if [ $# -gt 2 ]; then echo "$progname: Too many arguments." exit 1 fi if [ $# -lt 1 ] ; then infile="" else infile=$1 fi if [ $# -lt 2 ]; then outfile="" else outfile="> $2" fi if [ -n "$infile" -a ! -r "$infile" ]; then echo "$progname: cannot read $infile" exit 1 fi sed \ -e '/)\$[01]/!s/^regex[ \t][ \t]*\([^ \t][^ \t]*\)[ \t][ \t]*/regex_posix \1 - /' \ -e 's/^regex[ \t][ \t]*\([^ \t][^ \t]*\)[ \t][ \t]*\(.*$0.*$1.*\)/regex_posix \1 method,size \2/' \ -e 's/^regex[ \t][ \t]*\([^ \t][^ \t]*\)[ \t][ \t]*\(.*$1.*$0.*\)/regex_posix \1 size,method \2/' \ -e 's/)$0/)/g' \ -e 's/)$1/)/g' $infile | eval cat $outfile exit 0 pcp-3.8.12ubuntu1/src/pmdas/weblog/Web.Volume.pmchart0000664000000000000000000000226212272262501017321 0ustar #pmchart # # Web Statistics (data volume) # # This file is installed by the script $PCP_PMDAS_DIR/weblog/Install # Version 2.0 host dynamic Chart Title "Bytes sent by HTTP method" Style stacking Plot Color rgbi:1.0/1.0/0.0 Host * Metric web.allservers.bytes.get Plot Color rgbi:0.0/1.0/1.0 Host * Metric web.allservers.bytes.post Plot Color rgbi:1.0/0.0/1.0 Host * Metric web.allservers.bytes.head Plot Color rgbi:1.0/1.0/0.6 Host * Metric web.allservers.bytes.other Chart Title "Bytes sent by request size" Style stacking Plot Color rgbi:0.6/1.0/0.6 Host * Metric web.allservers.bytes.size.le3k Plot Color rgbi:0.8/0.6/1.0 Host * Metric web.allservers.bytes.size.le10k Plot Color rgbi:1.0/0.65/0.3 Host * Metric web.allservers.bytes.size.le30k Plot Color rgbi:0.3/1.0/0.3 Host * Metric web.allservers.bytes.size.le100k Plot Color rgbi:0.65/0.3/1.0 Host * Metric web.allservers.bytes.size.le300k Plot Color rgbi:1.0/0.5/0.0 Host * Metric web.allservers.bytes.size.le1m Plot Color rgbi:0.0/1.0/0.0 Host * Metric web.allservers.bytes.size.le3m Plot Color rgbi:0.6/0.0/0.9 Host * Metric web.allservers.bytes.size.gt3m # # Created Thu Jul 2 10:47:51 1998 pcp-3.8.12ubuntu1/src/pmdas/weblog/Web.Perserver.Bytes.pmchart0000775000000000000000000000431012272262501021113 0ustar #!/bin/sh . $PCP_DIR/etc/pcp.env tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1 trap "rm -rf $tmp; exit" 0 1 2 3 15 echo "/\"/s///g" >$tmp/sed pmprobe -I $* web.perserver.bytes.cached.total web.perserver.bytes.total > $tmp/pmprobe l1=`head -n 1 $tmp/pmprobe` l2=`tail -n 1 $tmp/pmprobe` num_caches=`echo $l1 | cut -f2 -d\ ` num_servers=`echo $l2 | cut -f2 -d\ ` if [ $num_servers -gt 0 ] then caches=`echo $l1 | cut -f3- -d\ ` servers=`echo $l2 | cut -f3- -d\ ` if [ $num_caches -lt 0 ] then # an old pmda - quietly handle all servers as if they were CERN - show only totals caches="NeVeR_MaTcH" num_caches=0 fi elif [ $num_servers -eq 0 ] then $PCP_XCONFIRM_PROG -c -B OK -header "No Active Servers - cannot continue" \ -t "$message" \ -icon info > /dev/null exit else message=`pmerr $num_servers | cut -f5- -d\ ` $PCP_XCONFIRM_PROG -c -B OK -header "Fatal error - cannot continue" \ -t "$message" \ -icon error > /dev/null exit fi # # if too many instances, turn off all legends # legendp=on if [ $num_servers -gt 6 ] then legendp=off fi if [ $num_servers -gt 12 ] then $PCP_XCONFIRM_PROG -c -B Cancel -b Continue -header \ "Too many charts" \ -t "There is 1 chart per server, more than can reasonably be displayed on the screen" \ -icon warning | grep Cancel >/dev/null if [ $? -eq 0 ] then exit fi fi # chart preamble # cat > $tmp/base </dev/null if [ $? -eq 0 ] then j=`echo $server | sed -f $tmp/sed` echo Chart Title \"Bytes sent by $j\" Style stacking Legend $legendp >> $tmp/base echo Plot Color \#3030FF Host \* Metric web.perserver.bytes.cached.total Instance $j >> $tmp/base echo Plot Color \#FF3030 Host \* Metric web.perserver.bytes.uncached.total Instance $j >> $tmp/base else j=`echo $server | sed -f $tmp/sed` echo Chart Title \"Total Bytes sent by $j\" Style bars Legend off>> $tmp/base echo Plot Color \#FF3030 Host \* Metric web.perserver.bytes.total Instance $j >> $tmp/base fi i=`expr $i + 1` done cat $tmp/base rm -rf $tmp pcp-3.8.12ubuntu1/src/pmdas/weblog/pmda.c0000664000000000000000000006614612272262501015056 0ustar /* * Web PMDA, based on generic driver for a daemon-based PMDA * * Copyright (c) 2012 Red Hat. * Copyright (c) 2000-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "weblog.h" #include "domain.h" #if defined(HAVE_REGEX_H) #include #endif #if defined(HAVE_SYS_WAIT_H) #include #endif #if defined(HAVE_SCHED_H) #include #endif #ifdef IS_SOLARIS #define CLONE_VM 0x00000100 #elif !defined(CLONE_VM) #define CLONE_VM 0x0 #endif #ifndef HAVE_SPROC int sproc (void (*entry) (void *), int flags, void *arg); #endif /* path to the configuration file */ static char *configFileName = (char*)0; /* line number of configuration file */ static int line = 0; /* number of errors in configuration file */ static int err = 0; /* configured for num of servers */ __uint32_t wl_numServers = 0; /* number of active servers */ __uint32_t wl_numActive = 0; /* check logs every 15 seconds by default */ __uint32_t wl_refreshDelay = 15; /* re-open logs if unchanged in this number of seconds */ __uint32_t wl_chkDelay = 20; /* max servers per sproc */ __uint32_t wl_sprocThresh = 80; /* number of sprocs spawned */ __uint32_t wl_numSprocs = 0; /* number of regex parsed */ __uint32_t wl_numRegex = 0; /* list of web servers */ WebServer *wl_servers = (WebServer*)0; /* list of regular expressions */ WebRegex *wl_regexTable = (WebRegex*)0; /* instance table of web servers */ pmdaInstid *wl_serverInst = (pmdaInstid*)0; /* list of sprocs spawned from the main process */ WebSproc *wl_sproc; /* default name for log file */ char *wl_logFile = "weblog.log"; /* default path to help file */ char wl_helpFile[MAXPATHLEN]; /* default user name for PMDA */ char *wl_username; /* * Usage Information */ void usage(void) { fprintf(stderr, "Usage: %s [options] configfile\n\ \n\ Options\n\ -C check configuration and exit\n\ -d domain PMDA domain number\n\ -h helpfile get help text from helpfile rather than default path\n\ -i port expect PMCD to connect on given inet port (number or name)\n\ -l logfile redirect diagnostics and trace output (default weblog.log)\n\ -n idlesec number of seconds of weblog inactivity before checking for\n\ log rotation\n\ -p expect PMCD to supply stdin/stdout (pipe)\n\ -S num number of web servers per sproc\n\ -t delay maximum number of seconds between reading weblog files\n\ -u socket expect PMCD to connect on given unix domain socket\n\ -U username user account to run under (default \"pcp\")\n\ -6 port expect PMCD to connect on given ipv6 port (number or name)\n\ \n\ If none of the -i, -p or -u options are given, the configuration file is\n\ checked and then %s terminates.\n", pmProgname, pmProgname); exit(1); } void logmessage(int priority, const char *format, ...) { va_list arglist; char buffer[2048]; char *level; char *p; time_t now; buffer[0] = '\0'; time(&now); switch (priority) { case LOG_EMERG : level = "Emergency"; break; case LOG_ALERT : level = "Alert"; break; case LOG_CRIT : level = "Critical"; break; case LOG_ERR : level = "Error"; break; case LOG_WARNING : level = "Warning"; break; case LOG_NOTICE : level = "Notice"; break; case LOG_INFO : level = "Info"; break; case LOG_DEBUG : level = "Debug"; break; default: level = "???"; break; } va_start (arglist, format); vsnprintf (buffer, sizeof(buffer), format, arglist); for (p = buffer; *p; p++); if (*(--p) == '\n') *p = '\0'; fprintf (stderr, "[%.19s] %s(%" FMT_PID ") %s: %s\n", ctime(&now), pmProgname, getpid(), level, buffer) ; va_end (arglist) ; } /* * Errors message during parsing of config file */ static void yyerror(char *s) { fprintf(stderr, "[%s:%d] Error: %s\n", configFileName, line, s); err++; } /* * Warning message during parsing of config file */ static void yywarn(char *s) { fprintf(stderr, "[%s:%d] Warning: %s\n", configFileName, line, s); } /* * skip remaining characters on this line */ static void skip_to_eol(FILE *f) { int c; while ((c = fgetc(f)) != EOF) { if (c == '\n') return; } return; } /* * Are we at the end of the line (sucks up spaces and tabs which may preceed * EOL) */ static void check_to_eol(FILE *f) { int c; int i = 0; while ((c = fgetc(f)) != EOF) { if (c == '\n') break; if (c == ' ' || c == '\t') continue; i++; } if (i) yywarn("additional words in line, ignored"); return; } /* * Get a word. A word if any text until a whitespace */ static int getword(FILE *f, char *buf, int len) { int c; char *bend = &buf[len-1]; while ((c = fgetc(f)) != EOF) { if (c == ' ' || c == '\t') continue; ungetc(c, f); break; } while ((c = fgetc(f)) != EOF) { if (c == ' ' || c == '\t') break; if (c == '\n') { ungetc(c, f); break; } if (buf < bend) { *buf++ = c; continue; } else { yyerror("word too long, remainder of line ignored"); return -1; } } *buf = '\0'; return c == EOF ? 0 : 1; } /* * Get the next line from buffer */ static int get_to_eol(FILE *f, char *buf, int len) { int c; char *bend = &buf[len-1]; while ((c = fgetc(f)) != EOF) { if (c == ' ' || c == '\t') continue; ungetc(c, f); break; } while ((c = fgetc(f)) != EOF) { if (c == '\n') break; if (buf < bend) { *buf++ = c; continue; } else { yyerror("list of words too long, remainder of line ignored"); return -1; } } *buf = '\0'; return c == EOF ? 0 : 1; } /* * Replacement for pmdaMainLoop * Has a select loop on pipe from PMCD, reads in PDUs and acts on them * appropriately. */ static void receivePDUs(pmdaInterface *dispatch) { int nfds = 0; time_t interval = 0; int sts = 0; struct timeval timeout; fd_set rfds; FD_ZERO(&rfds); nfds = fileno(stdin)+1; for (;;) { FD_SET(fileno(stdin), &rfds); __pmtimevalNow(&timeout); timeout.tv_usec = 0; interval = (time_t)wl_refreshDelay - (timeout.tv_sec % (time_t)wl_refreshDelay); timeout.tv_sec = interval; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) logmessage(LOG_DEBUG, "Select set for %d seconds\n", interval); #endif sts = select(nfds, &rfds, (fd_set*)0, (fd_set*)0, &timeout); if (sts < 0) { logmessage(LOG_ERR, "Error on fetch select: %s", netstrerror()); exit(1); } if (sts == 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) logmessage(LOG_DEBUG, "Select timed out\n"); #endif refreshAll(); continue; } if (__pmdaMainPDU(dispatch) < 0){ exit(1); } if (interval == 0) { refreshAll(); } } } /* * Catch an SPROC dying, report what we know, and exit * -- when main exits, other sprocs will get SIGHUP and exit quietly */ static void onchld(int dummy) { int done; int waitStatus; int sprocNum; while ((done = waitpid(-1, &waitStatus, WNOHANG)) > 0) { for (sprocNum = 1; wl_sproc[sprocNum].pid != done && sprocNum <= wl_numSprocs; sprocNum++); if (sprocNum > wl_numSprocs) { logmessage(LOG_INFO, "Unexpected child process (pid=%d) died!\n", done); continue; } if (WIFEXITED(waitStatus)) { if (WEXITSTATUS(waitStatus) == 0) logmessage(LOG_INFO, "Sproc %d (pid=%d) exited normally\n", sprocNum, done); else logmessage(LOG_INFO, "Sproc %d (pid=%d) exited with status = %d\n", sprocNum, done, WEXITSTATUS(waitStatus)); } else if (WIFSIGNALED(waitStatus)) { #ifdef WCOREDUMP if (WCOREDUMP(waitStatus)) logmessage(LOG_INFO, "Sproc %d (pid=%d) received signal = %d and dumped core\n", sprocNum, done, WTERMSIG(waitStatus)); #endif logmessage(LOG_INFO, "Sproc %d (pid=%d) received signal = %d\n", sprocNum, done, WTERMSIG(waitStatus)); } else { logmessage(LOG_INFO, "Sproc %d (pid=%d) died, reason unknown\n", sprocNum, done); } logmessage(LOG_INFO, "Sproc %d managed servers %d to %d\n", sprocNum, wl_sproc[sprocNum].firstServer, wl_sproc[sprocNum].lastServer); } logmessage(LOG_INFO, "Main process exiting\n"); exit(0); } /* * Parse command line args and the configuration file. Also sets up and fires * off the required sprocs */ int main(int argc, char **argv) { WebServer *server = (WebServer *)0; WebSproc *proc = (WebSproc *)0; char *endnum = (char*)0; char buf1[FILENAME_MAX]; char buf2[FILENAME_MAX]; char emess[120]; char *pstart, *pend; char argsDone, argFound; char *err_msg; int i = 0; int argCount = 0; int checkOnly = 0; int sts = 0; int sep = __pmPathSeparator(); int n = 0; int serverTableSize = 0; int regexTableSize = 0; FILE *configFile = (FILE*)0; FILE *tmpFp = (FILE*)0; pmdaInterface desc; struct timeval delta; struct { int *argPos; char *argString; } regexargs[2]; #ifdef PCP_DEBUG struct timeval start; struct timeval end; double startTime; #endif __pmSetProgname(argv[0]); __pmGetUsername(&wl_username); #ifdef PCP_DEBUG __pmtimevalNow(&start); #endif wl_isDSO = 0; snprintf(wl_helpFile, sizeof(wl_helpFile), "%s%c" "weblog" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&desc, PMDA_INTERFACE_2, pmProgname, WEBSERVER, wl_logFile, wl_helpFile); while ((n = pmdaGetOpt(argc, argv, "CD:d:h:i:l:n:pS:t:u:U:6:?", &desc, &err)) != EOF) { switch (n) { case 'C': checkOnly = 1; break; case 'S': wl_sprocThresh = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0') { fprintf(stderr, "%s: -S requires numeric argument\n", pmProgname); err++; } break; case 'n': if (pmParseInterval(optarg, &delta, &err_msg) < 0) { (void)fprintf(stderr, "%s: -n requires a time interval: %s\n", err_msg, pmProgname); free(err_msg); err++; } else { wl_chkDelay = delta.tv_sec; } break; case 't': if (pmParseInterval(optarg, &delta, &err_msg) < 0) { (void)fprintf(stderr, "%s: -t requires a time interval: %s\n", err_msg, pmProgname); free(err_msg); err++; } else { wl_refreshDelay = delta.tv_sec; } break; case 'U': wl_username = optarg; break; default: fprintf(stderr, "%s: Unknown option \"-%c\"", pmProgname, (char)n); err++; break; } } if (err || optind != argc-1) { usage(); } line = 0; configFileName = argv[optind]; configFile = fopen(configFileName, "r"); if (configFile == (FILE*)0) { fprintf(stderr, "Unable to open config file %s\n", configFileName); usage(); } if (checkOnly == 0) { /* * if doing more than just parsing, force errors from here * on into the logfile */ pmdaOpenLog(&desc); __pmSetProcessIdentity(wl_username); } /* * Parse the configuration file */ /* These settings should be reflected below */ regexargs[0].argString = strdup("method"); regexargs[1].argString = strdup("size"); while(!feof(configFile)) { sts = getword(configFile, buf1, sizeof(buf1)); if (sts == 0) { /* End of File */ break; } line++; if (sts < 0) { /* error, reported in getword() */ skip_to_eol(configFile); continue; } if (buf1[0] == '\0' || buf1[0] == '#') { /* comment, or nothing in the line, next line please */ skip_to_eol(configFile); continue; } if (strcasecmp(buf1, "regex_posix") == 0) { /* * Parse a regex specification */ if (wl_numRegex == regexTableSize) { regexTableSize += 2; wl_regexTable = (WebRegex*)realloc(wl_regexTable, regexTableSize * sizeof(WebRegex)); if (wl_regexTable == (WebRegex*)0) { __pmNoMem("main.wl_regexInst", (wl_numRegex + 1) * sizeof(WebRegex), PM_FATAL_ERR); } } sts = getword(configFile, buf1, sizeof(buf1)); if (sts <= 0 || buf1[0] == '\0') { if (sts >= 0) yyerror("unable to extract regex name"); skip_to_eol(configFile); continue; } wl_regexTable[wl_numRegex].name = strdup(buf1); if (wl_numRegex) { for (n = 0; n < wl_numRegex; n++) { if (strcmp(wl_regexTable[n].name, wl_regexTable[wl_numRegex].name) == 0) { snprintf(emess, sizeof(emess), "duplicate regex name (%s)", wl_regexTable[wl_numRegex].name); yyerror(emess); break; } } if (n < wl_numRegex) { skip_to_eol(configFile); continue; } } sts = getword(configFile, buf1, sizeof(buf1)); if (sts <= 0 || buf1[0] == '\0') { if (sts >= 0) yyerror("unable to extract regex match parameters"); skip_to_eol(configFile); continue; } regexargs[0].argPos = &(wl_regexTable[wl_numRegex].methodPos); regexargs[1].argPos = &(wl_regexTable[wl_numRegex].sizePos); wl_regexTable[wl_numRegex].methodPos = 0; wl_regexTable[wl_numRegex].sizePos = 0; wl_regexTable[wl_numRegex].sizePos = 0; wl_regexTable[wl_numRegex].s_statusPos = 0; pstart = buf1; argCount = 0; do { argFound = 0; argsDone = 1; argCount++; for(pend = pstart; *pend; pend++) { if(*pend == ',') { *pend = '\0'; argsDone = 0; break; } } for(i = 0; i < sizeof(regexargs) / sizeof(regexargs[0]); i++) { if(strcmp(pstart, regexargs[i].argString) == 0) { *regexargs[i].argPos = argCount; argFound = 1; break; } } if(!argFound) { /* not the old method,size style */ switch(pstart[0]) { case '1': wl_regexTable[wl_numRegex].methodPos = argCount; argFound = 1; break; case '2': wl_regexTable[wl_numRegex].sizePos = argCount; argFound = 1; break; case '3': wl_regexTable[wl_numRegex].c_statusPos = argCount; argFound = 1; break; case '4': wl_regexTable[wl_numRegex].s_statusPos = argCount; argFound = 1; break; case '-': wl_regexTable[wl_numRegex].methodPos = argCount++; wl_regexTable[wl_numRegex].sizePos = argCount; argFound = 1; argsDone = 1; break; default: break; } } pstart = pend + 1; } while(argsDone == 0 && argFound != 0); if(argFound == 0) { yyerror("invalid keyword in regex match parameters"); skip_to_eol(configFile); continue; } sts = get_to_eol(configFile, buf1, sizeof(buf1)); if (sts <= 0 || buf1[0] == '\0') { if (sts >= 0) yyerror("unable to extract regex"); else skip_to_eol(configFile); continue; } wl_regexTable[wl_numRegex].regex = malloc(sizeof(*wl_regexTable[wl_numRegex].regex)); if(wl_regexTable[wl_numRegex].regex == NULL) { __pmNoMem("main.wl_regex", sizeof(*wl_regexTable[wl_numRegex].regex), PM_FATAL_ERR); } if (regcomp(wl_regexTable[wl_numRegex].regex, buf1, REG_EXTENDED) != 0) { yyerror("unable to compile regex"); continue; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) logmessage(LOG_DEBUG, "%d regex %s: %s\n", wl_numRegex, wl_regexTable[wl_numRegex].name, buf1); #endif wl_regexTable[wl_numRegex].posix_regexp = 1; wl_numRegex++; } #ifdef NON_POSIX_REGEX else if (strcasecmp(buf1, "regex") == 0) { /* * Parse a regex specification */ if (wl_numRegex == regexTableSize) { regexTableSize += 2; wl_regexTable = (WebRegex*)realloc(wl_regexTable, regexTableSize * sizeof(WebRegex)); if (wl_regexTable == (WebRegex*)0) { __pmNoMem("main.wl_regexInst", (wl_numRegex + 1) * sizeof(WebRegex), PM_FATAL_ERR); } } sts = getword(configFile, buf1, sizeof(buf1)); if (sts <= 0 || buf1[0] == '\0') { if (sts >= 0) yyerror("unable to extract regex name"); skip_to_eol(configFile); continue; } wl_regexTable[wl_numRegex].name = strdup(buf1); if (wl_numRegex) { for (n = 0; n < wl_numRegex; n++) { if (strcmp(wl_regexTable[n].name, wl_regexTable[wl_numRegex].name) == 0) { snprintf(emess, sizeof(emess), "duplicate regex name (%s)", wl_regexTable[wl_numRegex].name); yyerror(emess); break; } } if (n < wl_numRegex) { skip_to_eol(configFile); continue; } } sts = get_to_eol(configFile, buf1, sizeof(buf1)); if (sts <= 0 || buf1[0] == '\0') { if (sts >= 0) yyerror("unable to extract regex"); else skip_to_eol(configFile); continue; } if(strstr(buf1, "$2") != NULL && strstr(buf1, "$3") != NULL ) { /* * extended caching server format * * although these aren't used in the non-regex code, they * are a good enough placeholder until server->counts.extendedp * is set below */ wl_regexTable[wl_numRegex].c_statusPos = 1; wl_regexTable[wl_numRegex].s_statusPos = 1; } wl_regexTable[wl_numRegex].np_regex = regcmp(buf1, (char*)0); if (wl_regexTable[wl_numRegex].np_regex == (char*)0) { yyerror("unable to compile regex"); continue; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) logmessage(LOG_DEBUG, "%d NON POSIX regex %s: %s\n", wl_numRegex, wl_regexTable[wl_numRegex].name, buf1); #endif wl_regexTable[wl_numRegex].posix_regexp = 0; wl_numRegex++; } #endif else if (strcasecmp(buf1, "server") == 0) { /* * Parse a server specification */ if (wl_numServers == serverTableSize) { serverTableSize += 4; wl_serverInst = (pmdaInstid*)realloc(wl_serverInst, serverTableSize * sizeof(pmdaInstid)); if (wl_serverInst == (pmdaInstid*)0) { __pmNoMem("main.wl_serverInst", (wl_numServers + 1) * sizeof(pmdaInstid), PM_FATAL_ERR); } wl_servers = (WebServer*)realloc(wl_servers, serverTableSize * sizeof(WebServer)); if (wl_servers == (WebServer*)0) { __pmNoMem("main.wl_servers", (wl_numServers + 1) * sizeof(WebServer), PM_FATAL_ERR); } } /* Get server name */ sts = getword(configFile, buf1, sizeof(buf1)); if (sts <= 0 || buf1[0] == '\0') { if (sts >= 0) yyerror("unable to extract server name"); skip_to_eol(configFile); continue; } if (wl_numServers) { for (n = 0; n < wl_numServers; n++) { if (strcmp(buf1, wl_serverInst[n].i_name) == 0) { snprintf(emess, sizeof(emess), "duplicate server name (%s)", buf1); yyerror(emess); break; } } if (n < wl_numServers) { skip_to_eol(configFile); continue; } } wl_serverInst[wl_numServers].i_name = strdup(buf1); wl_serverInst[wl_numServers].i_inst = wl_numServers; server = &(wl_servers[wl_numServers]); memset(server, 0, sizeof(*server)); server->access.filePtr = -1; server->error.filePtr = -1; /* Get server active flag */ sts = getword(configFile, buf1, sizeof(buf1)); if (sts <= 0 || buf1[0] == '\0') { if (sts >= 0) yyerror("unable to extract active flag"); skip_to_eol(configFile); continue; } if (strcasecmp(buf1, "on") == 0) { server->counts.active = 1; } else if (strcasecmp(buf1, "off") == 0) { server->counts.active = 0; } else { yyerror("illegal active flag"); skip_to_eol(configFile); continue; } /* Get access log regex and file name */ sts = getword(configFile, buf1, sizeof(buf1)); if (sts <= 0 || buf1[0] == '\0') { if (sts >= 0) yyerror("unable to extract access log regex"); skip_to_eol(configFile); continue; } sts = getword(configFile, buf2, sizeof(buf2)); if (sts <= 0 || buf2[0] == '\0') { if (sts >= 0) yyerror("unable to extract access log name"); skip_to_eol(configFile); continue; } for (n = 0; n < wl_numRegex; n++) if (strcmp(buf1, wl_regexTable[n].name) == 0) break; if (n == wl_numRegex) { snprintf(emess, sizeof(emess), "access log regex \"%s\" not defined", buf1); yyerror(emess); skip_to_eol(configFile); continue; } else if(wl_regexTable[n].c_statusPos > 0 && wl_regexTable[n].s_statusPos > 0) { /* common extended format or one that uses the same codes */ server->counts.extendedp = 1; if(strcmp(wl_regexTable[n].name, "SQUID") == 0) { /* * default squid format - uses text codes not numerics * so it *has* to be a special case */ server->counts.extendedp = 2; } } server->access.format = n; server->access.fileName = strdup(buf2); if (server->counts.active) { tmpFp = fopen(server->access.fileName, "r"); if (tmpFp == (FILE*)0) { snprintf(emess, sizeof(emess), "cannot open access log \"%s\"", buf2); yywarn(emess); server->access.filePtr = -1; } else fclose(tmpFp); } /* Get error log regex and file name */ sts = getword(configFile, buf1, sizeof(buf1)); if (sts <= 0 || buf1[0] == '\0') { if (sts >= 0) yyerror("unable to extract error log regex"); skip_to_eol(configFile); continue; } sts = getword(configFile, buf2, sizeof(buf2)); if (sts <= 0 || buf2[0] == '\0') { if (sts >= 0) yyerror("unable to extract error log name"); skip_to_eol(configFile); continue; } for (n = 0; n < wl_numRegex; n++) if (strcmp(buf1, wl_regexTable[n].name) == 0) break; if (n == wl_numRegex) { snprintf(emess, sizeof(emess), "error log regex \"%s\" not defined", buf1); yyerror(emess); skip_to_eol(configFile); continue; } server->error.format = n; server->error.fileName = strdup(buf2); if (server->counts.active) { tmpFp = fopen(server->error.fileName, "r"); if (tmpFp == (FILE*)0) { snprintf(emess, sizeof(emess), "cannot open error log \"%s\"", buf2); yywarn(emess); server->error.filePtr = -1; } else fclose(tmpFp); } check_to_eol(configFile); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { logmessage(LOG_DEBUG, "%d Server %s, %d, %d, %s, %d, %s\n", wl_numServers, wl_serverInst[wl_numServers].i_name, server->counts.active, server->access.format, server->access.fileName, server->error.format, server->error.fileName); } #endif if (server->counts.active) wl_numActive++; wl_numServers++; } else { snprintf(emess, sizeof(emess), "illegal keyword \"%s\"", buf1); yyerror(emess); skip_to_eol(configFile); continue; } } if (wl_numServers == 0) { yyerror("no servers were specified in the configuration file!"); } fclose(configFile); if (checkOnly || err) { /* errors, or parse only, no PMCD communication option */ exit(err); } wl_indomTable[0].it_numinst = wl_numServers; wl_indomTable[0].it_set = wl_serverInst; web_init(&desc); pmdaConnect(&desc); /* catch any sprocs dying */ signal(SIGCHLD, onchld); /* fire off all the sprocs that we need */ wl_numSprocs = (wl_numServers-1) / wl_sprocThresh; wl_sproc = (WebSproc*)malloc((wl_numSprocs+1) * sizeof(WebSproc)); if (wl_sproc == NULL) { logmessage(LOG_ERR, "wl_numServers = %d, wl_sprocThresh = %d", wl_numServers, wl_sprocThresh); __pmNoMem("main.wl_sproc", (wl_numSprocs+1) * sizeof(WebSproc), PM_FATAL_ERR); } for (n = 0; n <= wl_numSprocs; n++) { proc = &wl_sproc[n]; proc->pid = -1; proc->methodStr = (char *)0; proc->sizeStr = (char *)0; proc->c_statusStr = (char *)0; proc->s_statusStr = (char *)0; proc->strLength = 0; } if (wl_numSprocs) { for (n=1; n<=wl_numSprocs; n++) { proc = &wl_sproc[n]; sts = pipe1(proc->inFD); if (sts) { logmessage(LOG_ERR, "Cannot allocate fileDes 1 for sproc[%d]", n); exit(1); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) logmessage(LOG_DEBUG, "Creating in pipe (in=%d, out=%d) for sproc %d\n", proc->inFD[0], proc->inFD[1], n); #endif sts = pipe1(proc->outFD); if (sts) { logmessage(LOG_ERR, "Cannot allocate fileDes 2 for sproc[%d]", n); exit(1); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) logmessage(LOG_DEBUG, "Creating out pipe (in=%d, out=%d) for sproc %d\n", proc->outFD[0], proc->outFD[1], n); #endif proc->firstServer = (n)*wl_sprocThresh; if (n != wl_numSprocs) proc->lastServer = proc->firstServer + wl_sprocThresh - 1; else proc->lastServer = wl_numServers - 1; logmessage(LOG_INFO, "Creating sproc [%d] for servers %d to %d\n", n, proc->firstServer, proc->lastServer); proc->id = n; #ifndef HAVE_SPROC proc->pid = sproc(sprocMain, CLONE_VM, (void*)(&proc->id)); #else proc->pid = sproc(sprocMain, PR_SADDR, (void*)(&proc->id)); #endif if (proc->pid < 0) { logmessage(LOG_ERR, "main: error creating sproc %d: %s\n", n, osstrerror()); exit(1); } #ifdef PCP_DEBUG if(pmDebug & DBG_TRACE_APPL0) { logmessage(LOG_INFO, "main: created sproc %d: pid %" FMT_PID "\n", n, proc->pid); } #endif /* close off unwanted pipes */ if(close(proc->inFD[0]) < 0) { logmessage(LOG_WARNING, "main: pipe close(fd=%d) failed: %s\n", proc->inFD[0], osstrerror()); } if(close(proc->outFD[1]) < 0) { logmessage(LOG_WARNING, "main: pipe close(fd=%d) failed: %s\n", proc->outFD[1], osstrerror()); } } } wl_sproc[0].firstServer = 0; wl_sproc[0].lastServer = (wl_numServers <= wl_sprocThresh) ? wl_numServers - 1 : wl_sprocThresh - 1; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) logmessage(LOG_DEBUG, "Main process will monitor servers 0 to %d\n", wl_sproc[0].lastServer); #endif for (n=0; n <= wl_sproc[0].lastServer; n++) { if (wl_servers[n].counts.active) { openLogFile(&(wl_servers[n].access)); openLogFile(&(wl_servers[n].error)); } } #ifdef PCP_DEBUG __pmtimevalNow(&end); startTime = (end.tv_sec - start.tv_sec) + ((end.tv_usec - start.tv_usec) / 1000000.0); if (pmDebug & DBG_TRACE_APPL0) logmessage(LOG_DEBUG, "Agent started in %f seconds", startTime); #endif receivePDUs(&desc); logmessage(LOG_INFO, "Connection to PMCD closed by PMCD\n"); logmessage(LOG_INFO, "Last fetch took %d msec\n", wl_catchupTime); logmessage(LOG_INFO, "Exiting...\n"); return 0; } pcp-3.8.12ubuntu1/src/pmdas/weblog/help0000664000000000000000000007313412272262501014637 0ustar # # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # @ web.config.numservers number of servers in configuration file The number of Web servers specified in the configuration file. The log files for these Web servers may or may not be monitored, see web.perserver.watched and web.allservers.numwatched. @ web.config.catchup maximum time (secs) before Web server logs are probed The time in seconds after which monitored Web server logs will be examined, even if there have been no requests for performance metrics from those logs. The "catch up" process spreads the load and minimizes the latency at the first requests for metrics that have not been requested for a long time. This metric has the initial value of the -t delay option to pmdaweblog, and may be altered using pmStore(1). @ web.config.catchuptime time (secs) to perform catchup Accumulated elapsed time in which the Web logs PMDA has been performing the "catch up" process to examine all Web server logs. @ web.config.check time (secs) after which stationary logs will be re-opened Web server log files that are not changing are periodically closed and re-opened to detect possible log file rotation. This metric controls how often a stationary log file will be re-opened. This metric has the initial value of the -n idlesec option to pmdaweblog, and may be altered using pmStore(1). @ web.allservers.numwatched number of servers being monitored The number of Web servers that are being monitored, as opposed the number specified in the configuration file. See also web.config.numservers and web.perserver.watched. @ web.allservers.numalive number of watched servers that are alive The number of servers that are being watchedly watched that have both logs files. @ web.allservers.errors number of errors reported by all watched servers The number of errors reported by all watched servers. @ web.allservers.requests.total requests processed by all servers The total number of HTTP requests processed by all watched servers. @ web.allservers.bytes.total bytes sent by all servers The total number of bytes sent by all watched servers. @ web.allservers.requests.get GET requests handled by all watched servers The number of HTTP GET requests that were processed by all watched servers. @ web.allservers.bytes.get bytes sent in reply by all servers to GET requests The number of bytes that have been sent by all watched servers in reply to HTTP GET requests. @ web.allservers.requests.head HEAD requests handled by all watched servers The number of HTTP HEAD requests that were processed by all watched servers. @ web.allservers.bytes.head bytes sent in reply by all servers to HEAD requests The number of bytes that have been sent by all watched servers in reply to HTTP HEAD requests. @ web.allservers.requests.post POST requests handled by all watched servers The number of HTTP POST requests that were processed by all watched servers. @ web.allservers.bytes.post bytes sent in reply by all servers to POST requests The number of bytes that have been sent by all watched servers in reply to HTTP POST requests. @ web.allservers.requests.other other requests handled by all watch servers The number of HTTP requests, other than GET, HEAD and POST, that were processed by all watched servers. @ web.allservers.bytes.other bytes sent in reply by servers to other requests The number of bytes that have been sent by this server in reply to HTTP requests other than GET, HEAD or POST. @ web.allservers.requests.size.zero replies of 0 bytes sent by all servers The total number of HTTP requests that required a response of 0 bytes from all watched servers. @ web.allservers.bytes.size.zero total bytes sent in 0k replies The total number of bytes sent in replies of 0k by all watched servers. This metric is always zero and is provided for consistency only. @ web.allservers.requests.size.le3k replies of <= 3k sent by all servers The number of HTTP requests that required a response of less than or equal to 3k from all watched servers. @ web.allservers.bytes.size.le3k total bytes sent in <= 3k replies The total number of bytes sent in replies of less than or equal to 3k in size by all watched servers. @ web.allservers.requests.size.le10k replies of <= 10k sent by all servers The number of HTTP requests that required a response of less than or equal to 10k from all watched servers. @ web.allservers.bytes.size.le10k total bytes sent in <= 10k replies The total number of bytes sent in replies of less than or equal to 10k in size by all watched servers. @ web.allservers.requests.size.le30k replies of <= 30k sent by all servers The number of HTTP requests that required a response of less than or equal to 30k from all watched servers. @ web.allservers.bytes.size.le30k total bytes sent in <= 30k replies The total number of bytes sent in replies of less than or equal to 30k in size by all watched servers. @ web.allservers.requests.size.le100k replies of <= 100k sent by all servers The number of HTTP requests that required a response of less than or equal to 100k from all watched servers. @ web.allservers.bytes.size.le100k total bytes sent in <= 100k replies The total number of bytes sent in replies of less than or equal to 100k in size by all watched servers. @ web.allservers.requests.size.le300k replies of <= 300k sent by all servers The number of HTTP requests that required a response of less than or equal to 300k from all watched servers. @ web.allservers.bytes.size.le300k total bytes sent in <= 300k replies The total number of bytes sent in replies of less than or equal to 300k in size by all watched servers. @ web.allservers.requests.size.le1m replies of <= 1M sent by all servers The number of HTTP requests that required a response of less than or equal to 1M from all watched servers. @ web.allservers.bytes.size.le1m total bytes sent in <= 1M replies The total number of bytes sent in replies of less than or equal to 1M in size by all watched servers. @ web.allservers.requests.size.le3m replies of <= 3M sent by all servers The number of HTTP requests that required a response of less than or equal to 3M from all watched servers. @ web.allservers.bytes.size.le3m total bytes sent in <= 3M replies The total number of bytes sent in replies of less than or equal to 3M in size by all watched servers. @ web.allservers.requests.size.gt3m replies of > 3M sent by all servers The number of HTTP requests that required a response of greater than 3M from all watched servers. @ web.allservers.bytes.size.gt3m total bytes sent > 3M replies The total number of bytes sent in replies of greater than 3M in size by all watched servers. @ web.allservers.requests.size.unknown replies of unknown size by all servers The number of HTTP requests that required a response of unknown size from all watched servers. @ web.allservers.requests.client.total requests satisfied by client caches for all cacheing servers The total number of HTTP GET/IMS requests that resulted in "Not Modified" responses from cache (and remote if checked). These are client cache hits. @ web.allservers.requests.cached.total requests satisfied by server caches for all cacheing servers The total number of HTTP GET/IMS requests that resulted in "Not Modified" responses from the remote site or were deemed cache hits via other mechanisms such as recency. These are server cache hits and result in data transferred from cache to client. @ web.allservers.requests.cached.size.zero replies of 0 bytes sent by all caches The number of HTTP GET cache hits that required a response of 0 bytes from all watched caches. @ web.allservers.requests.cached.size.le3k replies of <= 3k sent by all caches The number of HTTP GET cache hits that required a response of less than or equal to 3k from all watched caches. @ web.allservers.requests.cached.size.le10k replies of <= 10k sent by all caches The number of HTTP GET cache hits that required a response of less than or equal to 10k from all watched caches. @ web.allservers.requests.cached.size.le30k replies of <= 30k sent by all caches The number of HTTP GET cache hits that required a response of less than or equal to 30k from all watched caches. @ web.allservers.requests.cached.size.le100k replies of <= 100k sent by all caches The number of HTTP GET cache hits that required a response of less than or equal to 100k from all watched caches. @ web.allservers.requests.cached.size.le300k replies of <= 300k sent by all caches The number of HTTP GET cache hits that required a response of less than or equal to 300k from all watched caches. @ web.allservers.requests.cached.size.le1m replies of <= 1M sent by all caches The number of HTTP GET cache hits that required a response of less than or equal to 1M from all watched caches. @ web.allservers.requests.cached.size.le3m replies of <= 3M sent by all caches The number of HTTP GET cache hits that required a response of less than or equal to 3M from all watched caches. @ web.allservers.requests.cached.size.gt3m replies of > 3M sent by all caches The number of HTTP GET cache hits that required a response of greater than 3M from all watched caches. @ web.allservers.requests.cached.size.unknown replies of unknown size by all caches The number of HTTP GET cache hits that required a response of unknown size from all watched caches. @ web.allservers.requests.uncached.total requests satisfied by remote server for all cacheing servers The total number of HTTP GET/IMS requests that resulted in a real data transfer from the remote server. These are either cache misses, or the remote file had been modified since the cache entry was made. @ web.allservers.requests.uncached.size.zero replies of 0 bytes sent by all caches The number of HTTP GET remote fetches that required a response of 0 bytes from all watched caches. @ web.allservers.requests.uncached.size.le3k replies of <= 3k sent by all caches The number of HTTP GET remote fetches that required a response of less than or equal to 3k through all watched caches. @ web.allservers.requests.uncached.size.le10k replies of <= 10k sent by all caches The number of HTTP GET remote fetches that required a response of less than or equal to 10k through all watched caches. @ web.allservers.requests.uncached.size.le30k replies of <= 30k sent by all caches The number of HTTP GET remote fetches that required a response of less than or equal to 30k through all watched caches. @ web.allservers.requests.uncached.size.le100k replies of <= 100k sent by all caches The number of HTTP GET remote fetches that required a response of less than or equal to 100k through all watched caches. @ web.allservers.requests.uncached.size.le300k replies of <= 300k sent by all caches The number of HTTP GET remote fetches that required a response of less than or equal to 300k through all watched caches. @ web.allservers.requests.uncached.size.le1m replies of <= 1M sent by all caches The number of HTTP GET remote fetches that required a response of less than or equal to 1M through all watched caches. @ web.allservers.requests.uncached.size.le3m replies of <= 3M sent by all caches The number of HTTP GET remote fetches that required a response of less than or equal to 3M through all watched caches. @ web.allservers.requests.uncached.size.gt3m replies of > 3M sent by all caches The number of HTTP GET remote fetches that required a response of greater than 3M through all watched caches. @ web.allservers.requests.uncached.size.unknown replies of unknown size by all caches The number of HTTP GET requests that required a response of unknown size through all watched caches. @ web.allservers.bytes.cached.total bytes sent by caches as a result of cache hits for all cacheing servers The total number of bytes sent to client due to HTTP GET/IMS requests that resulted in "Not Modified"responses from the remote site or were deemed cache hits via other mechanisms such as recency. @ web.allservers.bytes.cached.size.zero total bytes sent in 0k replies The total number of bytes sent to client by cache hit replies of 0k by all watched caches. This metric is always zero and is provided for consistency only. @ web.allservers.bytes.cached.size.le3k total bytes sent in <= 3k replies The total number of bytes sent to client by cache hit replies of less than or equal to 3k in size by all watched caches. @ web.allservers.bytes.cached.size.le10k total bytes sent in <= 10k replies The total number of bytes sent to client by cache hit replies of less than or equal to 10k in size by all watched caches. @ web.allservers.bytes.cached.size.le30k total bytes sent in <= 30k replies The total number of bytes sent to client by cache hit replies of less than or equal to 30k in size by all watched caches. @ web.allservers.bytes.cached.size.le100k total bytes sent in <= 100k replies The total number of bytes sent to client by cache hit replies of less than or equal to 100k in size by all watched caches. @ web.allservers.bytes.cached.size.le300k total bytes sent in <= 300k replies The total number of bytes sent to client by cache hit replies of less than or equal to 300k in size by all watched caches. @ web.allservers.bytes.cached.size.le1m total bytes sent in <= 1M replies The total number of bytes sent to client by cache hit replies of less than or equal to 1M in size by all watched caches. @ web.allservers.bytes.cached.size.le3m total bytes sent in <= 3M replies The total number of bytes sent to client by cache hit replies of less than or equal to 3M in size by all watched caches. @ web.allservers.bytes.cached.size.gt3m total bytes sent > 3M replies The total number of bytes sent to client by cache hit replies of greater than 3M in size by all watched caches. @ web.allservers.bytes.uncached.total bytes sent by remote servers as a result of cache misses for all cacheing servers The total number of bytes sent to client from the remote server. These are either cache misses, or the remote file had been modified since the cache entry was made. @ web.allservers.bytes.uncached.size.zero total bytes sent in 0k replies The total number of bytes sent to client from the remote server of 0k by all watched caches. This metric is always zero and is provided for consistency only. @ web.allservers.bytes.uncached.size.le3k total bytes sent in <= 3k replies The total number of bytes sent to client from the remote server of less than or equal to 3k in size by all watched caches. @ web.allservers.bytes.uncached.size.le10k total bytes sent in <= 10k replies The total number of bytes sent to client from the remote server of less than or equal to 10k in size by all watched caches. @ web.allservers.bytes.uncached.size.le30k total bytes sent in <= 30k replies The total number of bytes sent to client from the remote server of less than or equal to 30k in size by all watched caches. @ web.allservers.bytes.uncached.size.le100k total bytes sent in <= 100k replies The total number of bytes sent to client from the remote server of less than or equal to 100k in size by all watched caches. @ web.allservers.bytes.uncached.size.le300k total bytes sent in <= 300k replies The total number of bytes sent to client from the remote server of less than or equal to 300k in size by all watched caches. @ web.allservers.bytes.uncached.size.le1m total bytes sent in <= 1M replies The total number of bytes sent to client from the remote server of less than or equal to 1M in size by all watched caches. @ web.allservers.bytes.uncached.size.le3m total bytes sent in <= 3M replies The total number of bytes sent to client from the remote server of less than or equal to 3M in size by all watched caches. @ web.allservers.bytes.uncached.size.gt3m total bytes sent > 3M replies The total number of bytes sent to client from the remote server of greater than 3M in size by all watched caches. @ web.perserver.watched flag set to 1 if monitoring this server A flag which is set to 1 if this server is being monitored. This metric may be altered using pmStore(1). @ web.perserver.numlogs number of readable log files for this server The number of log files that are readable for the server. @ web.perserver.errors number of logged errors by this server The number of errors (and other administrative messages) that have been logged in the error log by this server. @ web.perserver.requests.total requests processed by this server The number of HTTP requests processed by this server. @ web.perserver.bytes.total bytes sent by this server The number of bytes this server has sent. @ web.perserver.requests.get GET requests handled by server The number of HTTP GET requests that were processed by this server. @ web.perserver.bytes.get bytes sent in reply to GET requests The number of bytes that have been sent by this server in reply to HTTP GET requests. @ web.perserver.requests.head HEAD requests handled by server The number of HTTP HEAD requests that were processed by this server. @ web.perserver.bytes.head bytes sent in reply to HEAD requests The number of bytes that have been sent by this server in reply to HTTP HEAD requests. @ web.perserver.requests.post POST requests handled by server The number of HTTP POST requests that were processed by this server. @ web.perserver.bytes.post bytes sent in reply to POST requests The number of bytes that have been sent by this server in reply to HTTP POST requests. @ web.perserver.requests.other other requests handled by server The number of HTTP requests, other than GET, HEAD and POST, that were processed by this server. @ web.perserver.bytes.other bytes sent in reply to other requests The number of bytes that have been sent by this server in reply to HTTP requests other than GET, HEAD or POST. @ web.perserver.requests.size.zero requests requiring 0 bytes in reply The number of HTTP requests that required a response of 0 bytes from this server. @ web.perserver.bytes.size.zero total bytes sent in 0k replies. The total number of bytes sent in replies of 0k by this server. This metric is always 0 and is provided for consistency only. @ web.perserver.requests.size.le3k requests requiring <= 3k replies The number of HTTP requests that required a response of less than or equal to 3k from this server. @ web.perserver.bytes.size.le3k total bytes sent in <= 3k replies The total number of bytes sent in replies of less than or equal to 3k in size. @ web.perserver.requests.size.le10k requests requiring <= 10k replies The number of HTTP requests that required a response of less than or equal to 10k from this server. @ web.perserver.bytes.size.le10k total bytes sent in <= 10k replies The total number of bytes sent in replies of less than or equal to 10k in size. @ web.perserver.requests.size.le30k requests requiring <= 30k replies The number of HTTP requests that required a response of less than or equal to 30k from this server. @ web.perserver.bytes.size.le30k total bytes sent in <= 30k replies The total number of bytes sent in replies of less than or equal to 30k in size. @ web.perserver.requests.size.le100k requests requiring <= 100k replies The number of HTTP requests that required a response of less than or equal to 100k from this server. @ web.perserver.bytes.size.le100k total bytes sent in <= 100k replies The total number of bytes sent in replies of less than or equal to 100k in size. @ web.perserver.requests.size.le300k requests requiring <= 300k replies The number of HTTP requests that required a response of less than or equal to 300k from this server. @ web.perserver.bytes.size.le300k total bytes sent in <= 300k replies The total number of bytes sent in replies of less than or equal to 300k in size. @ web.perserver.requests.size.le1m requests requiring <= 1M replies The number of HTTP requests that required a response of less than or equal to 1M from this server. @ web.perserver.bytes.size.le1m total bytes sent in <= 1M replies The total number of bytes sent in replies of less than or equal to 1M in size. @ web.perserver.requests.size.le3m requests requiring <= 3M replies The number of HTTP requests that required a response of less than or equal to 3M from this server. @ web.perserver.bytes.size.le3m total bytes sent in <= 3M replies The total number of bytes sent in replies of less than or equal to 3M in size. @ web.perserver.requests.size.gt3m requests requiring > 3M replies The number of HTTP requests that required a response of greater than 3M from this server. @ web.perserver.bytes.size.gt3m total bytes sent > 3M replies The total number of bytes sent in replies of greater than 3M in size. @ web.perserver.requests.size.unknown requests of unknown size The number of HTTP requests that required a response of unknown size from this server. @ web.perserver.logidletime seconds since log last modified The number of seconds since the access log for this server was modified. @ web.perserver.requests.client.total requests satisfied by client caches for this cache The total number of HTTP GET/IMS requests that resulted in "Not Modified" responses from cache (and remote if checked). These are client cache hits. @ web.perserver.requests.cached.total requests satisfied by server caches for this cache The total number of HTTP GET/IMS requests that resulted in "Not Modified" responses from the remote site or were deemed cache hits via other mechanisms such as recency. These are server cache hits and result in data transferred from cache to client. @ web.perserver.requests.cached.size.zero replies of 0 bytes sent by this cache The number of HTTP GET cache hits that required a response of 0 bytes from this cache. @ web.perserver.requests.cached.size.le3k replies of <= 3k sent by this cache The number of HTTP GET cache hits that required a response of less than or equal to 3k from this cache. @ web.perserver.requests.cached.size.le10k replies of <= 10k sent by this cache The number of HTTP GET cache hits that required a response of less than or equal to 10k from this cache. @ web.perserver.requests.cached.size.le30k replies of <= 30k sent by this cache The number of HTTP GET cache hits that required a response of less than or equal to 30k from this cache. @ web.perserver.requests.cached.size.le100k replies of <= 100k sent by this cache The number of HTTP GET cache hits that required a response of less than or equal to 100k from this cache. @ web.perserver.requests.cached.size.le300k replies of <= 300k sent by this cache The number of HTTP GET cache hits that required a response of less than or equal to 300k from this cache. @ web.perserver.requests.cached.size.le1m replies of <= 1M sent by this cache The number of HTTP GET cache hits that required a response of less than or equal to 1M from this cache. @ web.perserver.requests.cached.size.le3m replies of <= 3M sent by this cache The number of HTTP GET cache hits that required a response of less than or equal to 3M from this cache. @ web.perserver.requests.cached.size.gt3m replies of > 3M sent by this cache The number of HTTP GET cache hits that required a response of greater than 3M from this cache. @ web.perserver.requests.cached.size.unknown replies of unknown size by this cache The number of HTTP GET cache hits that required a response of unknown size from this cache. @ web.perserver.requests.uncached.total requests satisfied by remote server for this cache The total number of HTTP GET/IMS requests that resulted in a real data transfer from the remote server. These are either cache misses, or the remote file had been modified since the cache entry was made. @ web.perserver.requests.uncached.size.zero replies of 0 bytes sent by this cache The number of HTTP GET remote fetches that required a response of 0 bytes from this cache. @ web.perserver.requests.uncached.size.le3k replies of <= 3k sent by this cache The number of HTTP GET remote fetches that required a response of less than or equal to 3k through this cache. @ web.perserver.requests.uncached.size.le10k replies of <= 10k sent by this cache The number of HTTP GET remote fetches that required a response of less than or equal to 10k through this cache. @ web.perserver.requests.uncached.size.le30k replies of <= 30k sent by this cache The number of HTTP GET remote fetches that required a response of less than or equal to 30k through this cache. @ web.perserver.requests.uncached.size.le100k replies of <= 100k sent by this cache The number of HTTP GET remote fetches that required a response of less than or equal to 100k through this cache. @ web.perserver.requests.uncached.size.le300k replies of <= 300k sent by this cache The number of HTTP GET remote fetches that required a response of less than or equal to 300k through this cache. @ web.perserver.requests.uncached.size.le1m replies of <= 1M sent by this cache The number of HTTP GET remote fetches that required a response of less than or equal to 1M through this cache. @ web.perserver.requests.uncached.size.le3m replies of <= 3M sent by this cache The number of HTTP GET remote fetches that required a response of less than or equal to 3M through this cache. @ web.perserver.requests.uncached.size.gt3m replies of > 3M sent by this cache The number of HTTP GET remote fetches that required a response of greater than 3M through this cache. @ web.perserver.requests.uncached.size.unknown replies of unknown size by this cache The number of HTTP GET requests that required a response of unknown size through this cache. @ web.perserver.bytes.cached.total bytes sent by caches as a result of cache hits for this cache The total number of bytes sent to client due to HTTP GET/IMS requests that resulted in "Not Modified"responses from the remote site or were deemed cache hits via other mechanisms such as recency. @ web.perserver.bytes.cached.size.zero total bytes sent in 0k replies The total number of bytes sent to client by cache hit replies of 0k by this cache. This metric is always zero and is provided for consistency only. @ web.perserver.bytes.cached.size.le3k total bytes sent in <= 3k replies The total number of bytes sent to client by cache hit replies of less than or equal to 3k in size by this cache. @ web.perserver.bytes.cached.size.le10k total bytes sent in <= 10k replies The total number of bytes sent to client by cache hit replies of less than or equal to 10k in size by this cache. @ web.perserver.bytes.cached.size.le30k total bytes sent in <= 30k replies The total number of bytes sent to client by cache hit replies of less than or equal to 30k in size by this cache. @ web.perserver.bytes.cached.size.le100k total bytes sent in <= 100k replies The total number of bytes sent to client by cache hit replies of less than or equal to 100k in size by this cache. @ web.perserver.bytes.cached.size.le300k total bytes sent in <= 300k replies The total number of bytes sent to client by cache hit replies of less than or equal to 300k in size by this cache. @ web.perserver.bytes.cached.size.le1m total bytes sent in <= 1M replies The total number of bytes sent to client by cache hit replies of less than or equal to 1M in size by this cache. @ web.perserver.bytes.cached.size.le3m total bytes sent in <= 3M replies The total number of bytes sent to client by cache hit replies of less than or equal to 3M in size by this cache. @ web.perserver.bytes.cached.size.gt3m total bytes sent > 3M replies The total number of bytes sent to client by cache hit replies of greater than 3M in size by this cache. @ web.perserver.bytes.uncached.total bytes sent by remote servers as a result of cache misses for this cache The total number of bytes sent to client from the remote server. These are either cache misses, or the remote file had been modified since the cache entry was made. @ web.perserver.bytes.uncached.size.zero total bytes sent in 0k replies The total number of bytes sent to client from the remote server of 0k by this cache. This metric is always zero and is provided for consistency only. @ web.perserver.bytes.uncached.size.le3k total bytes sent in <= 3k replies The total number of bytes sent to client from the remote server of less than or equal to 3k in size by this cache. @ web.perserver.bytes.uncached.size.le10k total bytes sent in <= 10k replies The total number of bytes sent to client from the remote server of less than or equal to 10k in size by this cache. @ web.perserver.bytes.uncached.size.le30k total bytes sent in <= 30k replies The total number of bytes sent to client from the remote server of less than or equal to 30k in size by this cache. @ web.perserver.bytes.uncached.size.le100k total bytes sent in <= 100k replies The total number of bytes sent to client from the remote server of less than or equal to 100k in size by this cache. @ web.perserver.bytes.uncached.size.le300k total bytes sent in <= 300k replies The total number of bytes sent to client from the remote server of less than or equal to 300k in size by this cache. @ web.perserver.bytes.uncached.size.le1m total bytes sent in <= 1M replies The total number of bytes sent to client from the remote server of less than or equal to 1M in size by this cache. @ web.perserver.bytes.uncached.size.le3m total bytes sent in <= 3M replies The total number of bytes sent to client from the remote server of less than or equal to 3M in size by this cache. @ web.perserver.bytes.uncached.size.gt3m total bytes sent > 3M replies The total number of bytes sent to client from the remote server of greater than 3M in size by this cache. pcp-3.8.12ubuntu1/src/pmdas/weblog/Web.Alarms.pmchart0000664000000000000000000000140212272262501017264 0ustar #pmchart # # Web statistics (error rates) # # This file is installed by the script $PCP_PMDAS_DIR/weblog/Install # Version 2.0 host dynamic Chart Title "Web Alarms" Style stacking Plot Color #-cycle Host * Metric web.allservers.errors Plot Color #-cycle Host * Metric network.tcp.drops Plot Color #-cycle Host * Metric network.tcp.conndrops Plot Color #-cycle Host * Metric network.tcp.timeoutdrop Plot Color #-cycle Host * Metric network.tcp.sndrexmitpack Plot Color #-cycle Host * Metric network.tcp.rcvbadsum Plot Color #-cycle Host * Metric network.tcp.rexmttimeo Plot Color #-cycle Host * Metric network.mbuf.failed Plot Color #-cycle Host * Metric network.mbuf.waited Plot Color #-cycle Host * Metric swap.pagesout # # Created Thu Jul 2 10:48:36 1998 pcp-3.8.12ubuntu1/src/pmdas/netbsd/0000775000000000000000000000000012272262620013756 5ustar pcp-3.8.12ubuntu1/src/pmdas/netbsd/netif.c0000664000000000000000000001527412272262501015236 0ustar /* * NetBSD Kernel PMDA - network interface metrics * * Copyright (c) 2012,2013 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #if 0 #include #include #include #include #include #endif #include "netbsd.h" #define WARN_INIT 1 #define WARN_READ_HEAD 2 void refresh_netif_metrics(void) { #if 0 int i; int sts; unsigned long kaddr; struct ifnethead ifnethead; struct ifnet ifnet; struct ifnet *ifp; static int warn = 0; /* warn once control */ /* * Not sure that the order of chained netif structs is invariant, * especially if interfaces are added to the configuration after * initial system boot ... so mark all the instances as inactive * and re-match based on the interface name */ pmdaCacheOp(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_INACTIVE); kaddr = symbols[KERN_IFNET].n_value; if (kvmp == NULL || kaddr == 0) { /* no network interface metrics for us today ... */ if ((warn & WARN_INIT) == 0) { fprintf(stderr, "refresh_netif_metrics: Warning: cannot get any network interface metrics\n"); warn |= WARN_INIT; } return; } /* * Kernel data structures for the linked list of network interface * information. * * _ifnet -> struct ifnethead { * struct ifnet *tqh_first; * struct ifnet **tqh_last; * ... * } * * and within an ifnet struct (declared in ) we find * the linked list maintained in if_link, the external interface * name in if_xname[] and if_data which is a nested if_data stuct * (declared in ) that contains many of the goodies we're * after, e.g. u_char ifi_type, u_long ifi_mtu, u_long ifi_baudrate, * u_long ifi_ipackets, u_long ifi_opackets, u_long ifi_ibytes, * u_long ifi_obytes, etc. */ if (kvm_read(kvmp, kaddr, (char *)&ifnethead, sizeof(ifnethead)) != sizeof(ifnethead)) { if ((warn & WARN_READ_HEAD) == 0) { fprintf(stderr, "refresh_netif_metrics: Warning: kvm_read: ifnethead: %s\n", kvm_geterr(kvmp)); warn |= WARN_READ_HEAD; } return; } for (i = 0; ; i++) { if (i == 0) kaddr = (unsigned long)TAILQ_FIRST(&ifnethead); else kaddr = (unsigned long)TAILQ_NEXT(&ifnet, if_link); if (kaddr == 0) break; if (kvm_read(kvmp, kaddr, (char *)&ifnet, sizeof(ifnet)) != sizeof(ifnet)) { fprintf(stderr, "refresh_netif_metrics: Error: kvm_read: ifnet[%d]: %s\n", i, kvm_geterr(kvmp)); return; } /* skip network interfaces that are not interesting ... */ if (strcmp(ifnet.if_xname, "lo0") == 0) continue; sts = pmdaCacheLookupName(indomtab[NETIF_INDOM].it_indom, ifnet.if_xname, NULL, (void **)&ifp); if (sts == PMDA_CACHE_ACTIVE) { fprintf(stderr, "refresh_netif_metrics: Warning: duplicate name (%s) in network interface indom\n", ifnet.if_xname); continue; } else if (sts == PMDA_CACHE_INACTIVE) { /* reactivate an existing entry */ pmdaCacheStore(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_ADD, ifnet.if_xname, (void *)ifp); } else { /* new entry */ ifp = (struct ifnet *)malloc(sizeof(*ifp)); if (ifp == NULL) { fprintf(stderr, "Error: struct ifnet alloc failed for network interface \"%s\"\n", ifnet.if_xname); __pmNoMem("refresh_netif_metrics", sizeof(*ifp), PM_FATAL_ERR); /*NOTREACHED*/ } pmdaCacheStore(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_ADD, ifnet.if_xname, (void *)ifp); } memcpy((void *)ifp, (void *)&ifnet, sizeof(*ifp)); } #endif } int do_netif_metrics(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { #if 0 struct ifnet *ifp; int sts; if (inst != PM_IN_NULL) { /* * per-network interface metrics */ sts = pmdaCacheLookup(indomtab[NETIF_INDOM].it_indom, inst, NULL, (void **)&ifp); if (sts == PMDA_CACHE_ACTIVE) { sts = 1; /* cluster and domain already checked, just need item ... */ switch (pmid_item(mdesc->m_desc.pmid)) { case 0: /* network.interface.mtu */ atom->ul = (__uint32_t)ifp->if_data.ifi_mtu; break; case 1: /* network.interface.up */ atom->ul = (ifp->if_flags & IFF_UP) == IFF_UP; break; case 2: /* network.interface.baudrate */ atom->ull = ifp->if_data.ifi_baudrate; break; case 3: /* network.interface.in.bytes */ atom->ull = ifp->if_data.ifi_ibytes; break; case 4: /* network.interface.in.packets */ atom->ull = ifp->if_data.ifi_ipackets; break; case 5: /* network.interface.in.mcasts */ atom->ull = ifp->if_data.ifi_imcasts; break; case 6: /* network.interface.in.errors */ atom->ull = ifp->if_data.ifi_ierrors; break; case 7: /* network.interface.in.drops */ atom->ull = ifp->if_data.ifi_iqdrops; break; case 8: /* network.interface.out.bytes */ atom->ull = ifp->if_data.ifi_obytes; break; case 9: /* network.interface.out.packets */ atom->ull = ifp->if_data.ifi_opackets; break; case 10: /* network.interface.out.mcasts */ atom->ull = ifp->if_data.ifi_omcasts; break; case 11: /* network.interface.out.errors */ atom->ull = ifp->if_data.ifi_oerrors; break; case 12: /* network.interface.out.collisions */ atom->ull = ifp->if_data.ifi_collisions; break; case 13: /* network.interface.total.bytes */ atom->ull = ifp->if_data.ifi_ibytes + ifp->if_data.ifi_obytes; break; case 14: /* network.interface.total.packets */ atom->ull = ifp->if_data.ifi_ipackets + ifp->if_data.ifi_opackets; break; case 15: /* network.interface.total.mcasts */ atom->ull = ifp->if_data.ifi_imcasts + ifp->if_data.ifi_omcasts; break; case 16: /* network.interface.total.errors */ atom->ull = ifp->if_data.ifi_ierrors + ifp->if_data.ifi_oerrors; break; default: sts = PM_ERR_PMID; break; } } else sts = 0; } return sts; #else return PM_ERR_PMID; #endif } pcp-3.8.12ubuntu1/src/pmdas/netbsd/netbsd.h0000664000000000000000000000244312272262501015407 0ustar /* * * Copyright (c) 2012 Ken McDonell All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * instance domains control */ #define LOADAV_INDOM 0 #define CPU_INDOM 1 #define DISK_INDOM 2 #define NETIF_INDOM 3 extern pmdaIndom indomtab[]; extern void refresh_disk_metrics(void); extern int do_disk_metrics(pmdaMetric *, unsigned int, pmAtomValue *); extern void refresh_netif_metrics(void); extern int do_netif_metrics(pmdaMetric *, unsigned int, pmAtomValue *); /* * kernel memory reader pieces */ #include #include extern kvm_t *kvmp; #define KERN_IFNET 0 extern struct nlist symbols[]; pcp-3.8.12ubuntu1/src/pmdas/netbsd/GNUmakefile0000664000000000000000000000373312272262501016034 0ustar # # Copyright (c) 2000,2003,2004,2008 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2007-2010 Aconex. All Rights Reserved. # Copyright (c) 2012 Ken McDonell. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = netbsd DOMAIN = NETBSD CMDTARGET = pmdanetbsd LIBTARGET = pmda_netbsd.so PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) CONF_LINE = "netbsd 116 dso netbsd_init $(PMDADIR)/$(LIBTARGET)" CFILES = netbsd.c disk.c netif.c HFILES = netbsd.h LSRCFILES = help root_netbsd LDIRT = help.dir help.pag help.sed help.tmp domain.h $(IAM).log LLDLIBS = $(PCP_PMDALIB) -lkvm default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "netbsd" build-me: domain.h $(LIBTARGET) $(CMDTARGET) help.dir help.pag @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 644 domain.h help help.dir help.pag $(PMDADIR) $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(PMDADIR) $(INSTALL) -m 644 root_netbsd $(PCP_VAR_DIR)/pmns/root_netbsd else build-me: install: endif help.dir help.pag : domain.h help $(SED) help.sed -n -e '/#define/s/#define[ ]*\([A-Z][A-Z]*\)[ ]*\([0-9][0-9]*\)/s@\1@\2@/p' $(SED) -f help.sed help.tmp $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_netbsd -v 2 -o help #include #include #include #include #include #include #include "domain.h" #include "netbsd.h" /* static instances */ static pmdaInstid loadav_indom[] = { { 1, "1 minute" }, { 5, "5 minute" }, { 15, "15 minute" } }; /* instance domains */ pmdaIndom indomtab[] = { { LOADAV_INDOM, sizeof(loadav_indom)/sizeof(loadav_indom[0]), loadav_indom }, { CPU_INDOM, 0, NULL }, { DISK_INDOM, 0, NULL }, { NETIF_INDOM, 0, NULL }, }; static int indomtablen = sizeof(indomtab) / sizeof(indomtab[0]); #define CL_SYSCTL 0 #define CL_SPECIAL 1 #define CL_DISK 2 #define CL_NETIF 3 /* * All the PCP metrics. * * For sysctl metrics, m_user (the first field) is set the the PCP * name of the metric, and during initialization this is replaced by * a pointer to the corresponding entry in mib[] (based on matching, * or prefix matching (see matchname()) the PCP name here with * m_pcpname[] in the mib[] entries. * * cluster map * CL_SYSCTL simple sysctl() metrics, either one metric per mib, or * one struct per mib * CL_SPECIAL trickier sysctl() metrics involving synthesis or arithmetic * or other methods * CL_DISK disk metrics * CL_NETIF network interface metrics */ static pmdaMetric metrictab[] = { { (void *)"hinv.ncpu", { PMDA_PMID(CL_SYSCTL,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, { (void *)"hinv.physmem", { PMDA_PMID(CL_SYSCTL,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { (void *)"kernel.all.load", { PMDA_PMID(CL_SYSCTL,2), PM_TYPE_FLOAT, LOADAV_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, { (void *)"kernel.all.cpu.user", { PMDA_PMID(CL_SYSCTL,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.all.cpu.nice", { PMDA_PMID(CL_SYSCTL,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.all.cpu.sys", { PMDA_PMID(CL_SYSCTL,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.all.cpu.intr", { PMDA_PMID(CL_SYSCTL,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.all.cpu.idle", { PMDA_PMID(CL_SYSCTL,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.percpu.cpu.user", { PMDA_PMID(CL_SYSCTL,8), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.percpu.cpu.nice", { PMDA_PMID(CL_SYSCTL,9), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.percpu.cpu.sys", { PMDA_PMID(CL_SYSCTL,10), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.percpu.cpu.intr", { PMDA_PMID(CL_SYSCTL,11), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.percpu.cpu.idle", { PMDA_PMID(CL_SYSCTL,12), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.all.hz", { PMDA_PMID(CL_SYSCTL,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,1,0,0,PM_TIME_USEC,0) } }, { (void *)"hinv.cpu.vendor", { PMDA_PMID(CL_SYSCTL,15), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, { (void *)"hinv.cpu.model", { PMDA_PMID(CL_SYSCTL,16), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, { (void *)"hinv.cpu.arch", { PMDA_PMID(CL_SYSCTL,17), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, { (void *)"swap.pagesin", { PMDA_PMID(CL_SYSCTL,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"swap.pagesout", { PMDA_PMID(CL_SYSCTL,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"swap.in", { PMDA_PMID(CL_SYSCTL,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"swap.in", { PMDA_PMID(CL_SYSCTL,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"kernel.all.pswitch", { PMDA_PMID(CL_SYSCTL,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"kernel.all.syscall", { PMDA_PMID(CL_SYSCTL,23), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"kernel.all.intr", { PMDA_PMID(CL_SYSCTL,24), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"swap.length", { PMDA_PMID(CL_SYSCTL,25), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { (void *)"swap.used", { PMDA_PMID(CL_SYSCTL,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* hinv.ndisk */ { PMDA_PMID(CL_SPECIAL,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* * swap.free is the difference between sysctl variables vm.swap_total * and vm.swap_reserved, so it is important they are kept together * in mib[] below */ { (void *)"swap.length", /* swap.free */ { PMDA_PMID(CL_SPECIAL,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* hinv.pagesize */ { PMDA_PMID(CL_SPECIAL,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { (void *)"mem.util.all", { PMDA_PMID(CL_SPECIAL,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* * mem.util.used is computed from several of the vm.stats.vm.v_*_count * sysctl metrics, so it is important they are kept together in mib[] * below */ { (void *)"mem.util.all", /* mem.util.used */ { PMDA_PMID(CL_SPECIAL,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { (void *)"mem.util.free", { PMDA_PMID(CL_SPECIAL,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { (void *)"mem.util.bufmem", { PMDA_PMID(CL_SPECIAL,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { (void *)"mem.util.cached", { PMDA_PMID(CL_SPECIAL,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { (void *)"mem.util.wired", { PMDA_PMID(CL_SPECIAL,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { (void *)"mem.util.active", { PMDA_PMID(CL_SPECIAL,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { (void *)"mem.util.inactive", { PMDA_PMID(CL_SPECIAL,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* * mem.util.avail is computed from several of the vm.stats.vm.v_*_count * sysctl metrics, so it is important they are kept together in mib[] * below */ { (void *)"mem.util.all", /* mem.util.avail */ { PMDA_PMID(CL_SPECIAL,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { NULL, /* disk.dev.read */ { PMDA_PMID(CL_DISK,0), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.dev.write */ { PMDA_PMID(CL_DISK,1), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.dev.total */ { PMDA_PMID(CL_DISK,2), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.dev.read_bytes */ { PMDA_PMID(CL_DISK,3), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* disk.dev.write_bytes */ { PMDA_PMID(CL_DISK,4), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* disk.dev.total_bytes */ { PMDA_PMID(CL_DISK,5), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* disk.all.read */ { PMDA_PMID(CL_DISK,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.all.write */ { PMDA_PMID(CL_DISK,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.all.total */ { PMDA_PMID(CL_DISK,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.all.read_bytes */ { PMDA_PMID(CL_DISK,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* disk.all.write_bytes */ { PMDA_PMID(CL_DISK,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* disk.all.total_bytes */ { PMDA_PMID(CL_DISK,11), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* disk.dev.blkread */ { PMDA_PMID(CL_DISK,12), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.dev.blkwrite */ { PMDA_PMID(CL_DISK,13), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.dev.blktotal */ { PMDA_PMID(CL_DISK,14), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.all.blkread */ { PMDA_PMID(CL_DISK,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.all.blkwrite */ { PMDA_PMID(CL_DISK,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.all.blktotal */ { PMDA_PMID(CL_DISK,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.mtu */ { PMDA_PMID(CL_NETIF,0), PM_TYPE_U32, NETIF_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, { NULL, /* network.interface.up */ { PMDA_PMID(CL_NETIF,1), PM_TYPE_U32, NETIF_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, { NULL, /* network.interface.baudrate */ { PMDA_PMID(CL_NETIF,2), PM_TYPE_U64, NETIF_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, { NULL, /* network.interface.in.bytes */ { PMDA_PMID(CL_NETIF,3), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* network.interface.in.packets */ { PMDA_PMID(CL_NETIF,4), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.in.mcasts */ { PMDA_PMID(CL_NETIF,5), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.in.errors */ { PMDA_PMID(CL_NETIF,6), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.in.drops */ { PMDA_PMID(CL_NETIF,7), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.out.bytes */ { PMDA_PMID(CL_NETIF,8), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* network.interface.out.packets */ { PMDA_PMID(CL_NETIF,9), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.out.mcasts */ { PMDA_PMID(CL_NETIF,10), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.out.errors */ { PMDA_PMID(CL_NETIF,11), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.out.collisions */ { PMDA_PMID(CL_NETIF,12), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.total.bytes */ { PMDA_PMID(CL_NETIF,13), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* network.interface.total.packets */ { PMDA_PMID(CL_NETIF,14), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.total.mcasts */ { PMDA_PMID(CL_NETIF,15), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.total.errors */ { PMDA_PMID(CL_NETIF,16), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, }; static int metrictablen = sizeof(metrictab) / sizeof(metrictab[0]); /* * mapping between PCP metrics and sysctl metrics * * initialization note ... all elments after m_pcpname and m_name are OK * to be 0 or NULL */ typedef struct { const char *m_pcpname; /* PCP metric name or prefix (see matchname() */ const char *m_name; /* sysctl metric name */ size_t m_miblen; /* number of elements in m_mib[] */ int *m_mib; int m_fetched; /* 1 if m_data is current and valid */ size_t m_datalen; /* number of bytes in m_data[] */ void *m_data; /* value from sysctl */ } mib_t; static mib_t map[] = { { "hinv.ncpu", "hw.ncpu" }, { "hinv.physmem", "hw.physmem" }, { "hinv.cpu.vendor", "hw.machine" }, { "hinv.cpu.model", "hw.model" }, { "hinv.cpu.arch", "hw.machine_arch" }, { "kernel.all.load", "vm.loadavg" }, { "kernel.all.hz", "kern.clockrate" }, { "kernel.all.cpu.*", "kern.cp_time" }, // need special logic for kern.cp_time.0 ? { "kernel.percpu.cpu.*", "kern.cp_times." }, // not here? { "swap.pagesin", "vm.stats.vm.v_swappgsin" }, // not here? { "swap.pagesout", "vm.stats.vm.v_swappgsout" }, // not here? { "swap.in", "vm.stats.vm.v_swapin" }, { "swap.out", "vm.swapout" }, // not here? { "kernel.all.pswitch", "vm.stats.sys.v_swtch" }, // not here? { "kernel.all.syscall", "vm.stats.sys.v_syscall" }, // not here? { "kernel.all.intr", "vm.stats.sys.v_intr" }, { "mem.util.bufmem", "vfs.bufspace" }, /* * DO NOT MOVE next 2 entries ... see note above for swap.free */ // not here? { "swap.length", "vm.swap_total" }, // not here? { "swap.used", "vm.swap_reserved" }, /* * DO NOT MOVE next 6 entries ... see note above for mem.util.avail * and mem.util.used */ // not here? { "mem.util.all", "vm.stats.vm.v_page_count" }, // not here? { "mem.util.free", "vm.stats.vm.v_free_count" }, // not here? { "mem.util.cached", "vm.stats.vm.v_cache_count" }, // not here? { "mem.util.wired", "vm.stats.vm.v_wire_count" }, // not here? { "mem.util.active", "vm.stats.vm.v_active_count" }, // not here? { "mem.util.inactive", "vm.stats.vm.v_inactive_count" }, }; static int maplen = sizeof(map) / sizeof(map[0]); static mib_t bad_mib = { "bad.mib", "bad.mib", 0, NULL, 0, 0, NULL }; static char *username; static int isDSO = 1; /* =0 I am a daemon */ static int cpuhz; /* frequency for CPU time metrics */ static int ncpu; /* number of cpus in kern.cp_times.* data */ static int pagesize; /* vm page size */ /* * Fetch values from sysctl() * * Expect the result to be xpect bytes to match the PCP data size or * anticipated structure size, unless xpect is ==0 in which case the * size test is skipped. */ static int do_sysctl(mib_t *mp, size_t xpect) { /* * Note zero trip if mp->m_data and mp->datalen are already valid * and current */ for ( ; mp->m_fetched == 0; ) { int sts; sts = sysctl(mp->m_mib, (u_int)mp->m_miblen, mp->m_data, &mp->m_datalen, NULL, 0); fprintf(stderr, "sysctl(%s%s) -> %d (datalen=%d)\n", mp->m_name, mp->m_data == NULL ? " firstcall" : "", sts, (int)mp->m_datalen); if (sts == 0 && mp->m_data != NULL) { mp->m_fetched = 1; break; } if ((sts == -1 && errno == ENOMEM) || (sts == 0 && mp->m_data == NULL)) { /* first call for this one, or data changed size */ mp->m_data = realloc(mp->m_data, mp->m_datalen); if (mp->m_data == NULL) { fprintf(stderr, "Error: %s: buffer alloc failed for sysctl metric \"%s\"\n", mp->m_pcpname, mp->m_name); __pmNoMem("do_sysctl", mp->m_datalen, PM_FATAL_ERR); /*NOTREACHED*/ } } else return -errno; } if (xpect > 0 && mp->m_datalen != xpect) { fprintf(stderr, "Error: %s: sysctl(%s) datalen=%d not %d!\n", mp->m_pcpname, mp->m_name, (int)mp->m_datalen, (int)xpect); return 0; } return mp->m_datalen; } /* * kernel memory reader setup */ struct nlist symbols[] = { { .n_name = "_ifnet" }, { .n_name = NULL } }; kvm_t *kvmp; static void kmemread_init(void) { int sts; int i; char errmsg[_POSIX2_LINE_MAX]; /* * If we're running as a daemon PMDA, assume we're setgid kmem, * so we can open /dev/kmem, and downgrade privileges after the * kvm_open(). * For a DSO PMDA, we have to assume pmcd has the required * privileges and don't dink with them. */ kvmp = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errmsg); if (!isDSO) setgid(getgid()); if (kvmp == NULL) { fprintf(stderr, "kmemread_init: kvm_openfiles failed: %s\n", errmsg); return; } sts = kvm_nlist(kvmp, symbols); if (sts < 0) { fprintf(stderr, "kmemread_init: kvm_nlist failed: %s\n", pmErrStr(-errno)); for (i = 0; i < sizeof(symbols)/sizeof(symbols[0])-1; i++) symbols[i].n_value = 0; return; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { for (i = 0; i < sizeof(symbols)/sizeof(symbols[0])-1; i++) { fprintf(stderr, "Info: kernel symbol %s found at 0x%08lx\n", symbols[i].n_name, symbols[i].n_value); } } #endif } /* * Callback provided to pmdaFetch ... come here once per metric-instance * pair in each pmFetch(). */ static int netbsd_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { int sts = PM_ERR_PMID; __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); mib_t *mp; mp = (mib_t *)mdesc->m_user; if (idp->cluster == CL_SYSCTL) { /* sysctl() simple cases */ switch (idp->item) { /* 32-bit integer values */ case 0: /* hinv.ncpu */ case 18: /* swap.pagesin */ case 19: /* swap.pagesout */ case 20: /* swap.in */ case 21: /* swap.out */ case 22: /* kernel.all.pswitch */ case 23: /* kernel.all.syscall */ case 24: /* kernel.all.intr */ sts = do_sysctl(mp, sizeof(atom->ul)); if (sts > 0) { atom->ul = *((__uint32_t *)mp->m_data); sts = 1; } break; /* 64-bit integer values */ case 1: /* hinv.physmem */ case 25: /* swap.length */ case 26: /* swap.used */ sts = do_sysctl(mp, sizeof(atom->ull)); if (sts > 0) { atom->ull = *((__uint64_t *)mp->m_data); sts = 1; } break; /* string values */ case 15: /* hinv.cpu.vendor */ case 16: /* hinv.cpu.model */ case 17: /* hinv.cpu.arch */ sts = do_sysctl(mp, (size_t)0); if (sts > 0) { atom->cp = (char *)mp->m_data; sts = 1; } break; /* structs and aggregates */ case 2: /* kernel.all.load */ sts = do_sysctl(mp, 3*sizeof(atom->d)); if (sts > 0) { int i; struct loadavg *lp = (struct loadavg *)mp->m_data; if (inst == 1) i = 0; else if (inst == 5) i = 1; else if (inst == 15) i = 2; else return PM_ERR_INST; atom->f = (float)((double)lp->ldavg[i] / lp->fscale); sts = 1; } break; case 3: /* kernel.all.cpu.user */ case 4: /* kernel.all.cpu.nice */ case 5: /* kernel.all.cpu.sys */ case 6: /* kernel.all.cpu.intr */ case 7: /* kernel.all.cpu.idle */ sts = do_sysctl(mp, CPUSTATES*sizeof(atom->ull)); if (sts > 0) { /* * PMID assignment is important in the "-3" below so * that metrics map to consecutive elements of the * returned value in the order defined for CPUSTATES, * i.e. CP_USER, CP_NICE, CP_SYS, CP_INTR and * CP_IDLE */ atom->ull = 1000*((__uint64_t *)mp->m_data)[idp->item-3]/cpuhz; sts = 1; } break; case 8: /* kernel.percpu.cpu.user */ case 9: /* kernel.percpu.cpu.nice */ case 10: /* kernel.percpu.cpu.sys */ case 11: /* kernel.percpu.cpu.intr */ case 12: /* kernel.percpu.cpu.idle */ sts = do_sysctl(mp, ncpu*CPUSTATES*sizeof(atom->ull)); if (sts > 0) { /* * PMID assignment is important in the "-8" below so * that metrics map to consecutive elements of the * returned value in the order defined for CPUSTATES, * i.e. CP_USER, CP_NICE, CP_SYS, CP_INTR and * CP_IDLE, and then there is one such set for each * CPU up to the maximum number of CPUs installed in * the system. */ atom->ull = 1000*((__uint64_t *)mp->m_data)[inst * CPUSTATES + idp->item-8]/cpuhz; sts = 1; } break; case 13: /* kernel.all.hz */ sts = do_sysctl(mp, sizeof(struct clockinfo)); if (sts > 0) { struct clockinfo *cp = (struct clockinfo *)mp->m_data; atom->ul = cp->hz; sts = 1; } break; } } else if (idp->cluster == CL_SPECIAL) { /* special cases */ switch (idp->item) { case 0: /* hinv.ndisk */ refresh_disk_metrics(); atom->ul = pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_SIZE_ACTIVE); sts = 1; break; case 1: /* swap.free */ /* first vm.swap_total */ sts = do_sysctl(mp, sizeof(atom->ull)); if (sts > 0) { atom->ull = *((__uint64_t *)mp->m_data); /* * now subtract vm.swap_reserved ... assumes consecutive * mib[] entries */ mp++; sts = do_sysctl(mp, sizeof(atom->ull)); if (sts > 0) { atom->ull -= *((__uint64_t *)mp->m_data); sts = 1; } } break; case 3: /* hinv.pagesize */ atom->ul = pagesize; sts = 1; break; case 4: /* mem.util.all */ case 6: /* mem.util.free */ case 8: /* mem.util.cached */ case 9: /* mem.util.wired */ case 10: /* mem.util.active */ case 11: /* mem.util.inactive */ sts = do_sysctl(mp, sizeof(atom->ul)); if (sts > 0) { atom->ul = *((__uint32_t *)mp->m_data) * (pagesize / 1024); sts = 1; } break; case 7: /* mem.util.bufmem */ sts = do_sysctl(mp, sizeof(atom->ul)); if (sts > 0) { atom->ul = *((__uint32_t *)mp->m_data) / 1024; sts = 1; } break; case 5: /* mem.util.used */ /* * mp-> v_page_count entry in mib[] * assuming consecutive mib[] entries, we want * v_page_count mp[0] - v_free_count mp[1] - * v_cache_count mp[2] - v_inactive_count mp[5] */ sts = do_sysctl(mp, sizeof(atom->ul)); if (sts > 0) { atom->ul = *((__uint32_t *)mp->m_data); sts = do_sysctl(&mp[1], sizeof(atom->ul)); if (sts > 0) { atom->ul -= *((__uint32_t *)mp[1].m_data); sts = do_sysctl(&mp[2], sizeof(atom->ul)); if (sts > 0) { atom->ul -= *((__uint32_t *)mp[2].m_data); sts = do_sysctl(&mp[5], sizeof(atom->ul)); if (sts > 0) { atom->ul -= *((__uint32_t *)mp[5].m_data); atom->ul *= (pagesize / 1024); sts = 1; } } } } break; case 12: /* mem.util.avail */ /* * mp-> v_page_count entry in mib[] * assuming consecutive mib[] entries, we want * v_free_count mp[1] + v_cache_count mp[2] + * v_inactive_count mp[5] */ sts = do_sysctl(&mp[1], sizeof(atom->ul)); if (sts > 0) { atom->ul = *((__uint32_t *)mp[1].m_data); sts = do_sysctl(&mp[2], sizeof(atom->ul)); if (sts > 0) { atom->ul += *((__uint32_t *)mp[2].m_data); sts = do_sysctl(&mp[5], sizeof(atom->ul)); if (sts > 0) { atom->ul += *((__uint32_t *)mp[5].m_data); atom->ul *= (pagesize / 1024); sts = 1; } } } break; } } else if (idp->cluster == CL_DISK) { /* disk metrics */ sts = do_disk_metrics(mdesc, inst, atom); } else if (idp->cluster == CL_NETIF) { /* network interface metrics */ sts = do_netif_metrics(mdesc, inst, atom); } return sts; } /* * wrapper for pmdaFetch ... force value caches to be reloaded if needed, * then do the fetch */ static int netbsd_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i; int done_disk = 0; int done_netif = 0; for (i = 0; i < maplen; i++) { map[i].m_fetched = 0; } /* * pre-fetch all metrics if needed, and update instance domains if * they have changed */ for (i = 0; !done_disk && !done_netif && i < numpmid; i++) { if (pmid_cluster(pmidlist[i]) == CL_DISK) { refresh_disk_metrics(); done_disk = 1; } else if (pmid_cluster(pmidlist[i]) == CL_NETIF) { refresh_netif_metrics(); done_netif = 1; } } return pmdaFetch(numpmid, pmidlist, resp, pmda); } /* * wrapper for pmdaInstance ... refresh required instance domain first */ static int netbsd_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) { /* * indomtab[] instance names and ids are not used for some indoms, * ensure pmdaCache is current */ if (indom == indomtab[DISK_INDOM].it_indom) refresh_disk_metrics(); if (indom == indomtab[NETIF_INDOM].it_indom) refresh_netif_metrics(); return pmdaInstance(indom, inst, name, result, pmda); } /* * PCP metric name matching for linking metrictab[] entries to mib[] * entries. * * Return 1 if prefix[] is equal to, or a prefix of name[] * * prefix[] of the form "a.bc" or "a.bc*" matches a name[] like "a.bc" * or "a.bcanything", to improve readability of the initializers in * mib[], and asterisk is a "match all" special case, so "a.b.*" matches * "a.b.anything" */ static int matchname(const char *prefix, const char *name) { while (*prefix != '\0' && *name != '\0' && *prefix == *name) { prefix++; name++; } if (*prefix == '\0' || *prefix == '*') return 1; else return 0; } /* * Initialise the agent (both daemon and DSO). * * Do mapping from sysclt(3) names to mibs. * Collect some global constants. * Build the system-specific, but not dynamic, instance domains, * e.g. CPU_INDOM. * Initialize the kernel memory reader. */ void netbsd_init(pmdaInterface *dp) { int i; int m; int sts; struct clockinfo clockrates; size_t sz; int mib[CTL_MAXNAME]; /* enough for longest mib key */ char iname[16]; /* enough for cpuNN.. */ if (isDSO) { char mypath[MAXPATHLEN]; int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "netbsd" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_5, "netbsd DSO", mypath); } else { __pmSetProcessIdentity(username); } if (dp->status != 0) return; dp->version.four.fetch = netbsd_fetch; dp->version.four.instance = netbsd_instance; pmdaSetFetchCallBack(dp, netbsd_fetchCallBack); pmdaInit(dp, indomtab, indomtablen, metrictab, metrictablen); /* * Link metrictab[] entries via m_user to map[] entries based on * matching sysctl(3) name * * also translate the sysctl(3) name to a mib */ for (m = 0; m < metrictablen; m++) { if (metrictab[m].m_user == NULL) { /* not using sysctl(3) */ continue; } for (i = 0; i < maplen; i++) { if (matchname(map[i].m_pcpname, (char *)metrictab[m].m_user)) { if (map[i].m_mib == NULL) { /* * multiple metrictab[] entries may point to the same * mib[] entry, but this is the first time for this * mib[] entry ... */ map[i].m_miblen = sizeof(mib); sts = sysctlnametomib(map[i].m_name, mib, &map[i].m_miblen); if (sts == 0) { map[i].m_mib = (int *)malloc(map[i].m_miblen*sizeof(map[i].m_mib[0])); if (map[i].m_mib == NULL) { fprintf(stderr, "Error: %s (%s): failed mib alloc for sysctl metric \"%s\"\n", map[i].m_pcpname, pmIDStr(metrictab[m].m_desc.pmid), map[i].m_name); __pmNoMem("netbsd_init: mib", map[i].m_miblen*sizeof(map[i].m_mib[0]), PM_FATAL_ERR); /*NOTREACHED*/ } memcpy(map[i].m_mib, mib, map[i].m_miblen*sizeof(map[i].m_mib[0])); } else { fprintf(stderr, "Error: %s (%s): failed sysctlnametomib(\"%s\", ...): %s\n", map[i].m_pcpname, pmIDStr(metrictab[m].m_desc.pmid), map[i].m_name, pmErrStr(-errno)); metrictab[m].m_user = (void *)&bad_mib; } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { int p; fprintf(stderr, "Info: %s (%s): sysctl metric \"%s\" -> ", (char *)metrictab[m].m_user, pmIDStr(metrictab[m].m_desc.pmid), map[i].m_name); for (p = 0; p < map[i].m_miblen; p++) { if (p > 0) fputc('.', stderr); fprintf(stderr, "%d", map[i].m_mib[p]); } fputc('\n', stderr); } #endif metrictab[m].m_user = (void *)&map[i]; break; } } if (i == maplen) { fprintf(stderr, "Error: %s (%s): cannot match name in sysctl map[]\n", (char *)metrictab[m].m_user, pmIDStr(metrictab[m].m_desc.pmid)); metrictab[m].m_user = (void *)&bad_mib; } } /* * Collect some global constants needed later ... */ sz = sizeof(clockrates); sts = sysctlbyname("kern.clockrate", &clockrates, &sz, NULL, 0); if (sts < 0) { fprintf(stderr, "Fatal Error: sysctlbyname(\"kern.clockrate\", ...) failed: %s\n", pmErrStr(-errno)); exit(1); } cpuhz = clockrates.stathz; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "Info: CPU time \"hz\" = %d\n", cpuhz); #endif mib[0] = CTL_HW; mib[1] = HW_NCPU; sz = sizeof(ncpu); sts = sysctl(mib, 2, &ncpu, &sz, NULL, 0); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "Info: ncpu = %d\n", ncpu); #endif sz = sizeof(pagesize); sts = sysctlbyname("hw.pagesize", &pagesize, &sz, NULL, 0); if (sts < 0) { fprintf(stderr, "Fatal Error: sysctlbyname(\"hw.pagesize\", ...) failed: %s\n", pmErrStr(-errno)); exit(1); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "Info: VM pagesize = %d\n", pagesize); #endif /* * Build some instance domains ... */ indomtab[CPU_INDOM].it_numinst = ncpu; indomtab[CPU_INDOM].it_set = (pmdaInstid *)malloc(ncpu * sizeof(pmdaInstid)); if (indomtab[CPU_INDOM].it_set == NULL) { __pmNoMem("netbsd_init: CPU_INDOM it_set", ncpu * sizeof(pmdaInstid), PM_FATAL_ERR); /*NOTREACHED*/ } for (i = 0; i < ncpu; i++) { indomtab[CPU_INDOM].it_set[i].i_inst = i; snprintf(iname, sizeof(iname), "cpu%d", i); indomtab[CPU_INDOM].it_set[i].i_name = strdup(iname); if (indomtab[CPU_INDOM].it_set[i].i_name == NULL) { __pmNoMem("netbsd_init: CPU_INDOM strdup iname", strlen(iname), PM_FATAL_ERR); /*NOTREACHED*/ } } kmemread_init(); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n" "\nExactly one of the following options may appear:\n" " -i port expect PMCD to connect on given inet port (number or name)\n" " -p expect PMCD to supply stdin/stdout (pipe)\n" " -u socket expect PMCD to connect on given unix domain socket\n" " -6 port expect PMCD to connect on given ipv6 port (number or name)\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int c, err = 0; int sep = __pmPathSeparator(); pmdaInterface dispatch; char mypath[MAXPATHLEN]; isDSO = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(mypath, sizeof(mypath), "%s%c" "netbsd" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_5, pmProgname, NETBSD, "netbsd.log", mypath); while ((c = pmdaGetOpt(argc, argv, "D:d:i:l:pu:U:6:?", &dispatch, &err)) != EOF) { switch(c) { case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&dispatch); netbsd_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/netbsd/root_netbsd0000664000000000000000000000540112272262501016221 0ustar /* * Metrics for NetBSD kernel PMDA * * Copyright (c) 2012 Ken McDonell All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * the domain for the NETBSD PMDA ... */ #ifndef NETBSD #define NETBSD 116 #endif root { hinv kernel disk mem network swap } hinv { ncpu NETBSD:0:0 ndisk NETBSD:1:0 physmem NETBSD:0:1 pagesize NETBSD:1:3 cpu } hinv.cpu { vendor NETBSD:0:15 model NETBSD:0:16 arch NETBSD:0:17 } kernel { all percpu } kernel.all { pswitch NETBSD:0:22 syscall NETBSD:0:23 intr NETBSD:0:24 hz NETBSD:0:13 load NETBSD:0:2 cpu } kernel.all.cpu { user NETBSD:0:3 nice NETBSD:0:4 sys NETBSD:0:5 intr NETBSD:0:6 idle NETBSD:0:7 } kernel.percpu { cpu } kernel.percpu.cpu { user NETBSD:0:8 nice NETBSD:0:9 sys NETBSD:0:10 intr NETBSD:0:11 idle NETBSD:0:12 } disk { dev all } disk.dev { read NETBSD:2:0 write NETBSD:2:1 total NETBSD:2:2 read_bytes NETBSD:2:3 write_bytes NETBSD:2:4 total_bytes NETBSD:2:5 blkread NETBSD:2:12 blkwrite NETBSD:2:13 blktotal NETBSD:2:14 } disk.all { read NETBSD:2:6 write NETBSD:2:7 total NETBSD:2:8 read_bytes NETBSD:2:9 write_bytes NETBSD:2:10 total_bytes NETBSD:2:11 blkread NETBSD:2:15 blkwrite NETBSD:2:16 blktotal NETBSD:2:17 } mem { util } mem.util { all NETBSD:1:4 used NETBSD:1:5 free NETBSD:1:6 bufmem NETBSD:1:7 cached NETBSD:1:8 wired NETBSD:1:9 active NETBSD:1:10 inactive NETBSD:1:11 avail NETBSD:1:12 } network { interface } network.interface { mtu NETBSD:3:0 up NETBSD:3:1 baudrate NETBSD:3:2 in out total } network.interface.in { bytes NETBSD:3:3 packets NETBSD:3:4 mcasts NETBSD:3:5 errors NETBSD:3:6 drops NETBSD:3:7 } network.interface.out { bytes NETBSD:3:8 packets NETBSD:3:9 mcasts NETBSD:3:10 errors NETBSD:3:11 collisions NETBSD:3:12 } network.interface.total { bytes NETBSD:3:13 packets NETBSD:3:14 mcasts NETBSD:3:15 errors NETBSD:3:16 } swap { pagesin NETBSD:0:18 pagesout NETBSD:0:19 in NETBSD:0:20 out NETBSD:0:21 length NETBSD:0:25 used NETBSD:0:26 free NETBSD:1:1 } #undef NETBSD pcp-3.8.12ubuntu1/src/pmdas/netbsd/disk.c0000664000000000000000000001356712272262501015066 0ustar /* * NetBSD Kernel PMDA - disk metrics * * Copyright (c) 2012,2013 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "netbsd.h" #if 0 #include struct devinfo devinfo = { 0 }; struct statinfo statinfo; #endif void refresh_disk_metrics(void) { #if 0 static int init_done = 0; int i; int sts; if (!init_done) { sts = devstat_checkversion(NULL); if (sts != 0) { fprintf(stderr, "refresh_disk_metrics: devstat_checkversion: failed! %s\n", devstat_errbuf); exit(1); } statinfo.dinfo = &devinfo; init_done = 1; } sts = devstat_getdevs(NULL, &statinfo); if (sts < 0) { fprintf(stderr, "refresh_disk_metrics: devstat_getdevs: %s\n", strerror(errno)); exit(1); } else if (sts == 1) { /* * First call, else devstat[] list has changed */ struct devstat *dsp; char iname[DEVSTAT_NAME_LEN+6]; pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_INACTIVE); for (i = 0; i < devinfo.numdevs; i++) { dsp = &devinfo.devices[i]; /* * Skip entries that are not interesting ... only include * "da" (direct access) disks at this stage */ if (strcmp(dsp->device_name, "da") != 0) continue; snprintf(iname, sizeof(iname), "%s%d", dsp->device_name, dsp->unit_number); sts = pmdaCacheLookupName(indomtab[DISK_INDOM].it_indom, iname, NULL, NULL); if (sts == PMDA_CACHE_ACTIVE) { int j; fprintf(stderr, "refresh_disk_metrics: Warning: duplicate name (%s) in disk indom\n", iname); for (j = 0; j < devinfo.numdevs; j++) { dsp = &devinfo.devices[j]; fprintf(stderr, " devinfo[%d]: %s%d\n", j, dsp->device_name, dsp->unit_number); } continue; } else { /* new entry or reactivate an existing one */ pmdaCacheStore(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_ADD, iname, (void *)dsp); } } } #endif } int do_disk_metrics(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { #if 0 struct devstat *dsp; int sts; if (inst != PM_IN_NULL) { /* * per-disk metrics */ sts = pmdaCacheLookup(indomtab[DISK_INDOM].it_indom, inst, NULL, (void **)&dsp); if (sts == PMDA_CACHE_ACTIVE) { sts = 1; /* cluster and domain already checked, just need item ... */ switch (pmid_item(mdesc->m_desc.pmid)) { case 0: /* disk.dev.read */ atom->ull = dsp->operations[DEVSTAT_READ]; break; case 1: /* disk.dev.write */ atom->ull = dsp->operations[DEVSTAT_WRITE]; break; case 2: /* disk.dev.total */ atom->ull = dsp->operations[DEVSTAT_READ] + dsp->operations[DEVSTAT_WRITE]; break; case 3: /* disk.dev.read_bytes */ atom->ull = dsp->bytes[DEVSTAT_READ]; break; case 4: /* disk.dev.write_bytes */ atom->ull = dsp->bytes[DEVSTAT_WRITE]; break; case 5: /* disk.dev.total_bytes */ atom->ull = dsp->bytes[DEVSTAT_READ] + dsp->bytes[DEVSTAT_WRITE]; break; case 12: /* disk.dev.blkread */ atom->ull = dsp->block_size == 0 ? 0 : dsp->bytes[DEVSTAT_READ] / dsp->block_size; break; case 13: /* disk.dev.blkwrite */ atom->ull = dsp->block_size == 0 ? 0 : dsp->bytes[DEVSTAT_WRITE] / dsp->block_size; break; case 14: /* disk.dev.blktotal */ atom->ull = dsp->block_size == 0 ? 0 : (dsp->bytes[DEVSTAT_READ] + dsp->bytes[DEVSTAT_WRITE]) / dsp->block_size; break; default: sts = PM_ERR_PMID; break; } } else sts = 0; } else { /* * all-disk summary metrics */ int i; atom->ull = 0; sts = 1; pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_WALK_REWIND); while (sts == 1 && (i = pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_WALK_NEXT)) >= 0) { int lsts; lsts = pmdaCacheLookup(indomtab[DISK_INDOM].it_indom, i, NULL, (void **)&dsp); if (lsts == PMDA_CACHE_ACTIVE) { /* cluster and domain already checked, just need item ... */ switch (pmid_item(mdesc->m_desc.pmid)) { case 6: /* disk.all.read */ atom->ull += dsp->operations[DEVSTAT_READ]; break; case 7: /* disk.all.write */ atom->ull += dsp->operations[DEVSTAT_WRITE]; break; case 8: /* disk.all.total */ atom->ull += dsp->operations[DEVSTAT_READ] + dsp->operations[DEVSTAT_WRITE]; break; case 9: /* disk.all.read_bytes */ atom->ull += dsp->bytes[DEVSTAT_READ]; break; case 10: /* disk.all.write_bytes */ atom->ull += dsp->bytes[DEVSTAT_WRITE]; break; case 11: /* disk.all.total_bytes */ atom->ull += dsp->bytes[DEVSTAT_READ] + dsp->bytes[DEVSTAT_WRITE]; break; case 15: /* disk.all.blkread */ atom->ull += dsp->block_size == 0 ? 0 : dsp->bytes[DEVSTAT_READ] / dsp->block_size; break; case 16: /* disk.all.blkwrite */ atom->ull += dsp->block_size == 0 ? 0 : dsp->bytes[DEVSTAT_WRITE] / dsp->block_size; break; case 17: /* disk.all.blktotal */ atom->ull += dsp->block_size == 0 ? 0 : (dsp->bytes[DEVSTAT_READ] + dsp->bytes[DEVSTAT_WRITE]) / dsp->block_size; break; default: sts = PM_ERR_PMID; break; } } } if (i < 0 && i != -1) /* not end of indom from cache walk, some other error */ sts = i; } return sts; #else return PM_ERR_PMID; #endif } pcp-3.8.12ubuntu1/src/pmdas/netbsd/help0000664000000000000000000001141412272262501014630 0ustar @ NETBSD.0 Instance domain for load average Universally 3 instances, "1 minute" (1), "5 minute" (5) and "15 minute" (15). @ NETBSD.1 CPU Instance domain for kernel.percpu metrics One instance for each physical CPU. @ NETBSD.2 DISK Instance domain for disk.dev metrics One instance for each physical "direct access" device. @ kernel.all.hz system hz rate Microseconds per "hz" tick. @ kernel.all.load 1, 5 and 15 minute load average @ kernel.all.pswitch count of context switches @ kernel.all.syscall count of system calls @ kernel.all.intr count of interrupts serviced @ kernel.all.cpu.user total user CPU time for all CPUs @ kernel.all.cpu.nice total nice user CPU time for all CPUs @ kernel.all.cpu.sys total sys CPU time for all CPUs @ kernel.all.cpu.intr total interrupt CPU time for all CPUs @ kernel.all.cpu.idle total idle CPU time for all CPUs @ kernel.percpu.cpu.user user CPU time for each CPU @ kernel.percpu.cpu.nice nice user CPU time for each CPU @ kernel.percpu.cpu.sys sys CPU time for each CPU @ kernel.percpu.cpu.intr interrupt CPU time for each CPU @ kernel.percpu.cpu.idle idle CPU time for each CPU @ hinv.ncpu number of CPUs in the system @ hinv.ndisk number of disks in the system @ hinv.physmem total system memory @ hinv.pagesize kernel page size @ hinv.cpu.vendor system's CPU vendor @ hinv.cpu.model system's CPU model @ hinv.cpu.arch system's machine dependent CPU architecture type @ swap.length total swap space size @ swap.used reserved (or allocated) swap space @ swap.free available swap space @ swap.pagesin pages read from external storage to service page faults @ swap.pagesout dirty pages written to swap devices When the rate of page writes is non-zero, this is the most useful indication severe demand for physical memory. @ swap.in number of swap in operations @ swap.out number of swap out operations @ disk.dev.read Count of read operations per disk @ disk.dev.write Count of write operations per disk @ disk.dev.total Count of read or write operations (IOPs) per disk @ disk.dev.read_bytes Count of bytes read from each disk @ disk.dev.write_bytes Count of bytes written to each disk @ disk.dev.total_bytes Count of bytes transferred to or from each disk @ disk.dev.blkread Count of blocks read from each disk @ disk.dev.blkwrite Count of blocks written to each disk @ disk.dev.blktotal Count of blocks transferred to or from each disk @ disk.all.read Count of read operations across all disks @ disk.all.write Count of write operations across all disks @ disk.all.total Count of read or write operations (IOPs) across all disks @ disk.all.read_bytes Count of bytes read from all disks @ disk.all.write_bytes Count of bytes written to all disks @ disk.all.total_bytes Count of bytes transferred to or from all disks @ disk.all.blkread Count of blocks read from all disks @ disk.all.blkwrite Count of blocks written to all disks @ disk.all.blktotal Count of blocks transferred to or from all disks @ mem.util.all Total memory managed by the system @ mem.util.used Memory that is actively in use Equals "all" minus "free" minus "inactive" minus "cached". @ mem.util.free Unallocated and free memory @ mem.util.bufmem Memory associated with active buffer I/O @ mem.util.cached Cached memory Unmodified (clean and cached) pages from files in filesystems. @ mem.util.wired Wired or pinned memory that cannot be paged out @ mem.util.active Recently accessed memory @ mem.util.inactive Memory that is in use, but has not be accessed recently @ mem.util.avail Available memory Free plus inactive plus cached. @ network.interface.mtu Maximum Transfer Unit for each network interface @ network.interface.up "UP" state for each network interface @ network.interface.baudrate Data baudrate for each network interface @ network.interface.in.bytes Bytes received on each network interface @ network.interface.in.packets Packets received on each network interface @ network.interface.in.mcasts Multicast packets received on each network interface @ network.interface.in.errors Input errors on each network interface @ network.interface.in.drops Dropped packets on each network interface @ network.interface.out.bytes Bytes transmitted on each network interface @ network.interface.out.packets Packets transmitted on each network interface @ network.interface.out.mcasts Multicast packets transmitted on each network interface @ network.interface.out.errors Output errors on each network interface @ network.interface.out.collisions Output collisions on each network interface @ network.interface.total.bytes Bytes received or transmitted on each network interface @ network.interface.total.packets Packets received or transmitted on each network interface @ network.interface.total.mcasts Multicast packets received or transmitted on each network interface @ network.interface.total.errors Input or output errors on each network interface pcp-3.8.12ubuntu1/src/pmdas/freebsd/0000775000000000000000000000000012272262620014111 5ustar pcp-3.8.12ubuntu1/src/pmdas/freebsd/freebsd.c0000664000000000000000000010150412272262501015666 0ustar /* * FreeBSD Kernel PMDA * * Copyright (c) 2012 Red Hat. * Copyright (c) 2012 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include #include #include #include #include #include #include #include "domain.h" #include "freebsd.h" /* static instances */ static pmdaInstid loadav_indom[] = { { 1, "1 minute" }, { 5, "5 minute" }, { 15, "15 minute" } }; /* instance domains */ pmdaIndom indomtab[] = { { LOADAV_INDOM, sizeof(loadav_indom)/sizeof(loadav_indom[0]), loadav_indom }, { CPU_INDOM, 0, NULL }, { DISK_INDOM, 0, NULL }, { NETIF_INDOM, 0, NULL }, }; static int indomtablen = sizeof(indomtab) / sizeof(indomtab[0]); #define CL_SYSCTL 0 #define CL_SPECIAL 1 #define CL_DISK 2 #define CL_NETIF 3 /* * All the PCP metrics. * * For sysctl metrics, m_user (the first field) is set the the PCP * name of the metric, and during initialization this is replaced by * a pointer to the corresponding entry in mib[] (based on matching, * or prefix matching (see matchname()) the PCP name here with * m_pcpname[] in the mib[] entries. * * cluster map * CL_SYSCTL simple sysctl() metrics, either one metric per mib, or * one struct per mib * CL_SPECIAL trickier sysctl() metrics involving synthesis or arithmetic * or other methods * CL_DISK disk metrics * CL_NETIF network interface metrics */ static pmdaMetric metrictab[] = { { (void *)"hinv.ncpu", { PMDA_PMID(CL_SYSCTL,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, { (void *)"hinv.physmem", { PMDA_PMID(CL_SYSCTL,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { (void *)"kernel.all.load", { PMDA_PMID(CL_SYSCTL,2), PM_TYPE_FLOAT, LOADAV_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, { (void *)"kernel.all.cpu.user", { PMDA_PMID(CL_SYSCTL,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.all.cpu.nice", { PMDA_PMID(CL_SYSCTL,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.all.cpu.sys", { PMDA_PMID(CL_SYSCTL,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.all.cpu.intr", { PMDA_PMID(CL_SYSCTL,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.all.cpu.idle", { PMDA_PMID(CL_SYSCTL,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.percpu.cpu.user", { PMDA_PMID(CL_SYSCTL,8), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.percpu.cpu.nice", { PMDA_PMID(CL_SYSCTL,9), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.percpu.cpu.sys", { PMDA_PMID(CL_SYSCTL,10), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.percpu.cpu.intr", { PMDA_PMID(CL_SYSCTL,11), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.percpu.cpu.idle", { PMDA_PMID(CL_SYSCTL,12), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, { (void *)"kernel.all.hz", { PMDA_PMID(CL_SYSCTL,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,1,0,0,PM_TIME_USEC,0) } }, { (void *)"hinv.cpu.vendor", { PMDA_PMID(CL_SYSCTL,15), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, { (void *)"hinv.cpu.model", { PMDA_PMID(CL_SYSCTL,16), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, { (void *)"hinv.cpu.arch", { PMDA_PMID(CL_SYSCTL,17), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, { (void *)"swap.pagesin", { PMDA_PMID(CL_SYSCTL,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"swap.pagesout", { PMDA_PMID(CL_SYSCTL,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"swap.in", { PMDA_PMID(CL_SYSCTL,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"swap.in", { PMDA_PMID(CL_SYSCTL,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"kernel.all.pswitch", { PMDA_PMID(CL_SYSCTL,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"kernel.all.syscall", { PMDA_PMID(CL_SYSCTL,23), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"kernel.all.intr", { PMDA_PMID(CL_SYSCTL,24), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { (void *)"swap.length", { PMDA_PMID(CL_SYSCTL,25), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { (void *)"swap.used", { PMDA_PMID(CL_SYSCTL,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* hinv.ndisk */ { PMDA_PMID(CL_SPECIAL,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* * swap.free is the difference between sysctl variables vm.swap_total * and vm.swap_reserved, so it is important they are kept together * in mib[] below */ { (void *)"swap.length", /* swap.free */ { PMDA_PMID(CL_SPECIAL,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* hinv.pagesize */ { PMDA_PMID(CL_SPECIAL,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { (void *)"mem.util.all", { PMDA_PMID(CL_SPECIAL,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* * mem.util.used is computed from several of the vm.stats.vm.v_*_count * sysctl metrics, so it is important they are kept together in mib[] * below */ { (void *)"mem.util.all", /* mem.util.used */ { PMDA_PMID(CL_SPECIAL,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { (void *)"mem.util.free", { PMDA_PMID(CL_SPECIAL,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { (void *)"mem.util.bufmem", { PMDA_PMID(CL_SPECIAL,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { (void *)"mem.util.cached", { PMDA_PMID(CL_SPECIAL,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { (void *)"mem.util.wired", { PMDA_PMID(CL_SPECIAL,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { (void *)"mem.util.active", { PMDA_PMID(CL_SPECIAL,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { (void *)"mem.util.inactive", { PMDA_PMID(CL_SPECIAL,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* * mem.util.avail is computed from several of the vm.stats.vm.v_*_count * sysctl metrics, so it is important they are kept together in mib[] * below */ { (void *)"mem.util.all", /* mem.util.avail */ { PMDA_PMID(CL_SPECIAL,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, { NULL, /* disk.dev.read */ { PMDA_PMID(CL_DISK,0), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.dev.write */ { PMDA_PMID(CL_DISK,1), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.dev.total */ { PMDA_PMID(CL_DISK,2), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.dev.read_bytes */ { PMDA_PMID(CL_DISK,3), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* disk.dev.write_bytes */ { PMDA_PMID(CL_DISK,4), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* disk.dev.total_bytes */ { PMDA_PMID(CL_DISK,5), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* disk.all.read */ { PMDA_PMID(CL_DISK,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.all.write */ { PMDA_PMID(CL_DISK,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.all.total */ { PMDA_PMID(CL_DISK,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.all.read_bytes */ { PMDA_PMID(CL_DISK,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* disk.all.write_bytes */ { PMDA_PMID(CL_DISK,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* disk.all.total_bytes */ { PMDA_PMID(CL_DISK,11), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* disk.dev.blkread */ { PMDA_PMID(CL_DISK,12), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.dev.blkwrite */ { PMDA_PMID(CL_DISK,13), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.dev.blktotal */ { PMDA_PMID(CL_DISK,14), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.all.blkread */ { PMDA_PMID(CL_DISK,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.all.blkwrite */ { PMDA_PMID(CL_DISK,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* disk.all.blktotal */ { PMDA_PMID(CL_DISK,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.mtu */ { PMDA_PMID(CL_NETIF,0), PM_TYPE_U32, NETIF_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, { NULL, /* network.interface.up */ { PMDA_PMID(CL_NETIF,1), PM_TYPE_U32, NETIF_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, { NULL, /* network.interface.baudrate */ { PMDA_PMID(CL_NETIF,2), PM_TYPE_U64, NETIF_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, { NULL, /* network.interface.in.bytes */ { PMDA_PMID(CL_NETIF,3), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* network.interface.in.packets */ { PMDA_PMID(CL_NETIF,4), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.in.mcasts */ { PMDA_PMID(CL_NETIF,5), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.in.errors */ { PMDA_PMID(CL_NETIF,6), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.in.drops */ { PMDA_PMID(CL_NETIF,7), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.out.bytes */ { PMDA_PMID(CL_NETIF,8), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* network.interface.out.packets */ { PMDA_PMID(CL_NETIF,9), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.out.mcasts */ { PMDA_PMID(CL_NETIF,10), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.out.errors */ { PMDA_PMID(CL_NETIF,11), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.out.collisions */ { PMDA_PMID(CL_NETIF,12), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.total.bytes */ { PMDA_PMID(CL_NETIF,13), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, { NULL, /* network.interface.total.packets */ { PMDA_PMID(CL_NETIF,14), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.total.mcasts */ { PMDA_PMID(CL_NETIF,15), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { NULL, /* network.interface.total.errors */ { PMDA_PMID(CL_NETIF,16), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, }; static int metrictablen = sizeof(metrictab) / sizeof(metrictab[0]); /* * mapping between PCP metrics and sysctl metrics * * initialization note ... all elments after m_pcpname and m_name are OK * to be 0 or NULL */ typedef struct { const char *m_pcpname; /* PCP metric name or prefix (see matchname() */ const char *m_name; /* sysctl metric name */ size_t m_miblen; /* number of elements in m_mib[] */ int *m_mib; int m_fetched; /* 1 if m_data is current and valid */ size_t m_datalen; /* number of bytes in m_data[] */ void *m_data; /* value from sysctl */ } mib_t; static mib_t map[] = { { "hinv.ncpu", "hw.ncpu" }, { "hinv.physmem", "hw.physmem" }, { "hinv.cpu.vendor", "hw.machine" }, { "hinv.cpu.model", "hw.model" }, { "hinv.cpu.arch", "hw.machine_arch" }, { "kernel.all.load", "vm.loadavg" }, { "kernel.all.hz", "kern.clockrate" }, { "kernel.all.cpu.*", "kern.cp_time" }, { "kernel.percpu.cpu.*", "kern.cp_times" }, { "swap.pagesin", "vm.stats.vm.v_swappgsin" }, { "swap.pagesout", "vm.stats.vm.v_swappgsout" }, { "swap.in", "vm.stats.vm.v_swapin" }, { "swap.out", "vm.stats.vm.v_swapout" }, { "kernel.all.pswitch", "vm.stats.sys.v_swtch" }, { "kernel.all.syscall", "vm.stats.sys.v_syscall" }, { "kernel.all.intr", "vm.stats.sys.v_intr" }, { "mem.util.bufmem", "vfs.bufspace" }, /* * DO NOT MOVE next 2 entries ... see note above for swap.free */ { "swap.length", "vm.swap_total" }, { "swap.used", "vm.swap_reserved" }, /* * DO NOT MOVE next 6 entries ... see note above for mem.util.avail * and mem.util.used */ { "mem.util.all", "vm.stats.vm.v_page_count" }, { "mem.util.free", "vm.stats.vm.v_free_count" }, { "mem.util.cached", "vm.stats.vm.v_cache_count" }, { "mem.util.wired", "vm.stats.vm.v_wire_count" }, { "mem.util.active", "vm.stats.vm.v_active_count" }, { "mem.util.inactive", "vm.stats.vm.v_inactive_count" }, }; static int maplen = sizeof(map) / sizeof(map[0]); static mib_t bad_mib = { "bad.mib", "bad.mib", 0, NULL, 0, 0, NULL }; static char *username; static int isDSO = 1; /* =0 I am a daemon */ static int cpuhz; /* frequency for CPU time metrics */ static int ncpu; /* number of cpus in kern.cp_times data */ static int pagesize; /* vm page size */ /* * Fetch values from sysctl() * * Expect the result to be xpect bytes to match the PCP data size or * anticipated structure size, unless xpect is ==0 in which case the * size test is skipped. */ static int do_sysctl(mib_t *mp, size_t xpect) { /* * Note zero trip if mp->m_data and mp->datalen are already valid * and current */ for ( ; mp->m_fetched == 0; ) { int sts; sts = sysctl(mp->m_mib, (u_int)mp->m_miblen, mp->m_data, &mp->m_datalen, NULL, 0); fprintf(stderr, "sysctl(%s%s) -> %d (datalen=%d)\n", mp->m_name, mp->m_data == NULL ? " firstcall" : "", sts, (int)mp->m_datalen); if (sts == 0 && mp->m_data != NULL) { mp->m_fetched = 1; break; } if ((sts == -1 && errno == ENOMEM) || (sts == 0 && mp->m_data == NULL)) { /* first call for this one, or data changed size */ mp->m_data = realloc(mp->m_data, mp->m_datalen); if (mp->m_data == NULL) { fprintf(stderr, "Error: %s: buffer alloc failed for sysctl metric \"%s\"\n", mp->m_pcpname, mp->m_name); __pmNoMem("do_sysctl", mp->m_datalen, PM_FATAL_ERR); /*NOTREACHED*/ } } else return -errno; } if (xpect > 0 && mp->m_datalen != xpect) { fprintf(stderr, "Error: %s: sysctl(%s) datalen=%d not %d!\n", mp->m_pcpname, mp->m_name, (int)mp->m_datalen, (int)xpect); return 0; } return mp->m_datalen; } /* * kernel memory reader setup */ struct nlist symbols[] = { { .n_name = "_ifnet" }, { .n_name = NULL } }; kvm_t *kvmp; static void kmemread_init(void) { int sts; int i; char errmsg[_POSIX2_LINE_MAX]; /* * If we're running as a daemon PMDA, assume we're setgid kmem, * so we can open /dev/kmem, and downgrade privileges after the * kvm_open(). * For a DSO PMDA, we have to assume pmcd has the required * privileges and don't dink with them. */ kvmp = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errmsg); if (!isDSO) setgid(getgid()); if (kvmp == NULL) { fprintf(stderr, "kmemread_init: kvm_openfiles failed: %s\n", errmsg); return; } sts = kvm_nlist(kvmp, symbols); if (sts < 0) { fprintf(stderr, "kmemread_init: kvm_nlist failed: %s\n", pmErrStr(-errno)); for (i = 0; i < sizeof(symbols)/sizeof(symbols[0])-1; i++) symbols[i].n_value = 0; return; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { for (i = 0; i < sizeof(symbols)/sizeof(symbols[0])-1; i++) { fprintf(stderr, "Info: kernel symbol %s found at 0x%08lx\n", symbols[i].n_name, symbols[i].n_value); } } #endif } /* * Callback provided to pmdaFetch ... come here once per metric-instance * pair in each pmFetch(). */ static int freebsd_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { int sts = PM_ERR_PMID; __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); mib_t *mp; mp = (mib_t *)mdesc->m_user; if (idp->cluster == CL_SYSCTL) { /* sysctl() simple cases */ switch (idp->item) { /* 32-bit integer values */ case 0: /* hinv.ncpu */ case 18: /* swap.pagesin */ case 19: /* swap.pagesout */ case 20: /* swap.in */ case 21: /* swap.out */ case 22: /* kernel.all.pswitch */ case 23: /* kernel.all.syscall */ case 24: /* kernel.all.intr */ sts = do_sysctl(mp, sizeof(atom->ul)); if (sts > 0) { atom->ul = *((__uint32_t *)mp->m_data); sts = 1; } break; /* 64-bit integer values */ case 1: /* hinv.physmem */ case 25: /* swap.length */ case 26: /* swap.used */ sts = do_sysctl(mp, sizeof(atom->ull)); if (sts > 0) { atom->ull = *((__uint64_t *)mp->m_data); sts = 1; } break; /* string values */ case 15: /* hinv.cpu.vendor */ case 16: /* hinv.cpu.model */ case 17: /* hinv.cpu.arch */ sts = do_sysctl(mp, (size_t)0); if (sts > 0) { atom->cp = (char *)mp->m_data; sts = 1; } break; /* structs and aggregates */ case 2: /* kernel.all.load */ sts = do_sysctl(mp, 3*sizeof(atom->d)); if (sts > 0) { int i; struct loadavg *lp = (struct loadavg *)mp->m_data; if (inst == 1) i = 0; else if (inst == 5) i = 1; else if (inst == 15) i = 2; else return PM_ERR_INST; atom->f = (float)((double)lp->ldavg[i] / lp->fscale); sts = 1; } break; case 3: /* kernel.all.cpu.user */ case 4: /* kernel.all.cpu.nice */ case 5: /* kernel.all.cpu.sys */ case 6: /* kernel.all.cpu.intr */ case 7: /* kernel.all.cpu.idle */ sts = do_sysctl(mp, CPUSTATES*sizeof(atom->ull)); if (sts > 0) { /* * PMID assignment is important in the "-3" below so * that metrics map to consecutive elements of the * returned value in the order defined for CPUSTATES, * i.e. CP_USER, CP_NICE, CP_SYS, CP_INTR and * CP_IDLE */ atom->ull = 1000*((__uint64_t *)mp->m_data)[idp->item-3]/cpuhz; sts = 1; } break; case 8: /* kernel.percpu.cpu.user */ case 9: /* kernel.percpu.cpu.nice */ case 10: /* kernel.percpu.cpu.sys */ case 11: /* kernel.percpu.cpu.intr */ case 12: /* kernel.percpu.cpu.idle */ sts = do_sysctl(mp, ncpu*CPUSTATES*sizeof(atom->ull)); if (sts > 0) { /* * PMID assignment is important in the "-8" below so * that metrics map to consecutive elements of the * returned value in the order defined for CPUSTATES, * i.e. CP_USER, CP_NICE, CP_SYS, CP_INTR and * CP_IDLE, and then there is one such set for each * CPU up to the maximum number of CPUs installed in * the system. */ atom->ull = 1000*((__uint64_t *)mp->m_data)[inst * CPUSTATES + idp->item-8]/cpuhz; sts = 1; } break; case 13: /* kernel.all.hz */ sts = do_sysctl(mp, sizeof(struct clockinfo)); if (sts > 0) { struct clockinfo *cp = (struct clockinfo *)mp->m_data; atom->ul = cp->hz; sts = 1; } break; } } else if (idp->cluster == CL_SPECIAL) { /* special cases */ switch (idp->item) { case 0: /* hinv.ndisk */ refresh_disk_metrics(); atom->ul = pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_SIZE_ACTIVE); sts = 1; break; case 1: /* swap.free */ /* first vm.swap_total */ sts = do_sysctl(mp, sizeof(atom->ull)); if (sts > 0) { atom->ull = *((__uint64_t *)mp->m_data); /* * now subtract vm.swap_reserved ... assumes consecutive * mib[] entries */ mp++; sts = do_sysctl(mp, sizeof(atom->ull)); if (sts > 0) { atom->ull -= *((__uint64_t *)mp->m_data); sts = 1; } } break; case 3: /* hinv.pagesize */ atom->ul = pagesize; sts = 1; break; case 4: /* mem.util.all */ case 6: /* mem.util.free */ case 8: /* mem.util.cached */ case 9: /* mem.util.wired */ case 10: /* mem.util.active */ case 11: /* mem.util.inactive */ sts = do_sysctl(mp, sizeof(atom->ul)); if (sts > 0) { atom->ul = *((__uint32_t *)mp->m_data) * (pagesize / 1024); sts = 1; } break; case 7: /* mem.util.bufmem */ sts = do_sysctl(mp, sizeof(atom->ul)); if (sts > 0) { atom->ul = *((__uint32_t *)mp->m_data) / 1024; sts = 1; } break; case 5: /* mem.util.used */ /* * mp-> v_page_count entry in mib[] * assuming consecutive mib[] entries, we want * v_page_count mp[0] - v_free_count mp[1] - * v_cache_count mp[2] - v_inactive_count mp[5] */ sts = do_sysctl(mp, sizeof(atom->ul)); if (sts > 0) { atom->ul = *((__uint32_t *)mp->m_data); sts = do_sysctl(&mp[1], sizeof(atom->ul)); if (sts > 0) { atom->ul -= *((__uint32_t *)mp[1].m_data); sts = do_sysctl(&mp[2], sizeof(atom->ul)); if (sts > 0) { atom->ul -= *((__uint32_t *)mp[2].m_data); sts = do_sysctl(&mp[5], sizeof(atom->ul)); if (sts > 0) { atom->ul -= *((__uint32_t *)mp[5].m_data); atom->ul *= (pagesize / 1024); sts = 1; } } } } break; case 12: /* mem.util.avail */ /* * mp-> v_page_count entry in mib[] * assuming consecutive mib[] entries, we want * v_free_count mp[1] + v_cache_count mp[2] + * v_inactive_count mp[5] */ sts = do_sysctl(&mp[1], sizeof(atom->ul)); if (sts > 0) { atom->ul = *((__uint32_t *)mp[1].m_data); sts = do_sysctl(&mp[2], sizeof(atom->ul)); if (sts > 0) { atom->ul += *((__uint32_t *)mp[2].m_data); sts = do_sysctl(&mp[5], sizeof(atom->ul)); if (sts > 0) { atom->ul += *((__uint32_t *)mp[5].m_data); atom->ul *= (pagesize / 1024); sts = 1; } } } break; } } else if (idp->cluster == CL_DISK) { /* disk metrics */ sts = do_disk_metrics(mdesc, inst, atom); } else if (idp->cluster == CL_NETIF) { /* network interface metrics */ sts = do_netif_metrics(mdesc, inst, atom); } return sts; } /* * wrapper for pmdaFetch ... force value caches to be reloaded if needed, * then do the fetch */ static int freebsd_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i; int done_disk = 0; int done_netif = 0; for (i = 0; i < maplen; i++) { map[i].m_fetched = 0; } /* * pre-fetch all metrics if needed, and update instance domains if * they have changed */ for (i = 0; !done_disk && !done_netif && i < numpmid; i++) { if (pmid_cluster(pmidlist[i]) == CL_DISK) { refresh_disk_metrics(); done_disk = 1; } else if (pmid_cluster(pmidlist[i]) == CL_NETIF) { refresh_netif_metrics(); done_netif = 1; } } return pmdaFetch(numpmid, pmidlist, resp, pmda); } /* * wrapper for pmdaInstance ... refresh required instance domain first */ static int freebsd_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) { /* * indomtab[] instance names and ids are not used for some indoms, * ensure pmdaCache is current */ if (indom == indomtab[DISK_INDOM].it_indom) refresh_disk_metrics(); if (indom == indomtab[NETIF_INDOM].it_indom) refresh_netif_metrics(); return pmdaInstance(indom, inst, name, result, pmda); } /* * PCP metric name matching for linking metrictab[] entries to mib[] * entries. * * Return 1 if prefix[] is equal to, or a prefix of name[] * * prefix[] of the form "a.bc" or "a.bc*" matches a name[] like "a.bc" * or "a.bcanything", to improve readability of the initializers in * mib[], and asterisk is a "match all" special case, so "a.b.*" matches * "a.b.anything" */ static int matchname(const char *prefix, const char *name) { while (*prefix != '\0' && *name != '\0' && *prefix == *name) { prefix++; name++; } if (*prefix == '\0' || *prefix == '*') return 1; else return 0; } /* * Initialise the agent (both daemon and DSO). * * Do mapping from sysclt(3) names to mibs. * Collect some global constants. * Build the system-specific, but not dynamic, instance domains, * e.g. CPU_INDOM. * Initialize the kernel memory reader. */ void freebsd_init(pmdaInterface *dp) { int i; int m; int sts; struct clockinfo clockrates; size_t sz; int mib[CTL_MAXNAME]; /* enough for longest mib key */ char iname[16]; /* enough for cpuNN.. */ if (isDSO) { char mypath[MAXPATHLEN]; int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "freebsd" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_5, "freebsd DSO", mypath); } else { __pmSetProcessIdentity(username); } if (dp->status != 0) return; dp->version.four.fetch = freebsd_fetch; dp->version.four.instance = freebsd_instance; pmdaSetFetchCallBack(dp, freebsd_fetchCallBack); pmdaInit(dp, indomtab, indomtablen, metrictab, metrictablen); /* * Link metrictab[] entries via m_user to map[] entries based on * matching sysctl(3) name * * also translate the sysctl(3) name to a mib */ for (m = 0; m < metrictablen; m++) { if (metrictab[m].m_user == NULL) { /* not using sysctl(3) */ continue; } for (i = 0; i < maplen; i++) { if (matchname(map[i].m_pcpname, (char *)metrictab[m].m_user)) { if (map[i].m_mib == NULL) { /* * multiple metrictab[] entries may point to the same * mib[] entry, but this is the first time for this * mib[] entry ... */ map[i].m_miblen = sizeof(mib); sts = sysctlnametomib(map[i].m_name, mib, &map[i].m_miblen); if (sts == 0) { map[i].m_mib = (int *)malloc(map[i].m_miblen*sizeof(map[i].m_mib[0])); if (map[i].m_mib == NULL) { fprintf(stderr, "Error: %s (%s): failed mib alloc for sysctl metric \"%s\"\n", map[i].m_pcpname, pmIDStr(metrictab[m].m_desc.pmid), map[i].m_name); __pmNoMem("freebsd_init: mib", map[i].m_miblen*sizeof(map[i].m_mib[0]), PM_FATAL_ERR); /*NOTREACHED*/ } memcpy(map[i].m_mib, mib, map[i].m_miblen*sizeof(map[i].m_mib[0])); } else { fprintf(stderr, "Error: %s (%s): failed sysctlnametomib(\"%s\", ...): %s\n", map[i].m_pcpname, pmIDStr(metrictab[m].m_desc.pmid), map[i].m_name, pmErrStr(-errno)); metrictab[m].m_user = (void *)&bad_mib; } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { int p; fprintf(stderr, "Info: %s (%s): sysctl metric \"%s\" -> ", (char *)metrictab[m].m_user, pmIDStr(metrictab[m].m_desc.pmid), map[i].m_name); for (p = 0; p < map[i].m_miblen; p++) { if (p > 0) fputc('.', stderr); fprintf(stderr, "%d", map[i].m_mib[p]); } fputc('\n', stderr); } #endif metrictab[m].m_user = (void *)&map[i]; break; } } if (i == maplen) { fprintf(stderr, "Error: %s (%s): cannot match name in sysctl map[]\n", (char *)metrictab[m].m_user, pmIDStr(metrictab[m].m_desc.pmid)); metrictab[m].m_user = (void *)&bad_mib; } } /* * Collect some global constants needed later ... */ sz = sizeof(clockrates); sts = sysctlbyname("kern.clockrate", &clockrates, &sz, NULL, 0); if (sts < 0) { fprintf(stderr, "Fatal Error: sysctlbyname(\"kern.clockrate\", ...) failed: %s\n", pmErrStr(-errno)); exit(1); } cpuhz = clockrates.stathz; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "Info: CPU time \"hz\" = %d\n", cpuhz); #endif sts = sysctlbyname("kern.cp_times", NULL, &sz, NULL, 0); if (sts < 0) { fprintf(stderr, "Fatal Error: sysctlbyname(\"kern.cp_times\", ...) failed: %s\n", pmErrStr(-errno)); exit(1); } /* * see note below when fetching kernel.percpu.cpu.* metrics to * explain this */ ncpu = sz / (CPUSTATES * sizeof(__uint64_t)); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "Info: ncpu = %d\n", ncpu); #endif sz = sizeof(pagesize); sts = sysctlbyname("hw.pagesize", &pagesize, &sz, NULL, 0); if (sts < 0) { fprintf(stderr, "Fatal Error: sysctlbyname(\"hw.pagesize\", ...) failed: %s\n", pmErrStr(-errno)); exit(1); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "Info: VM pagesize = %d\n", pagesize); #endif /* * Build some instance domains ... */ indomtab[CPU_INDOM].it_numinst = ncpu; indomtab[CPU_INDOM].it_set = (pmdaInstid *)malloc(ncpu * sizeof(pmdaInstid)); if (indomtab[CPU_INDOM].it_set == NULL) { __pmNoMem("freebsd_init: CPU_INDOM it_set", ncpu * sizeof(pmdaInstid), PM_FATAL_ERR); /*NOTREACHED*/ } for (i = 0; i < ncpu; i++) { indomtab[CPU_INDOM].it_set[i].i_inst = i; snprintf(iname, sizeof(iname), "cpu%d", i); indomtab[CPU_INDOM].it_set[i].i_name = strdup(iname); if (indomtab[CPU_INDOM].it_set[i].i_name == NULL) { __pmNoMem("freebsd_init: CPU_INDOM strdup iname", strlen(iname), PM_FATAL_ERR); /*NOTREACHED*/ } } kmemread_init(); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n" "\nExactly one of the following options may appear:\n" " -i port expect PMCD to connect on given inet port (number or name)\n" " -p expect PMCD to supply stdin/stdout (pipe)\n" " -u socket expect PMCD to connect on given unix domain socket\n" " -6 port expect PMCD to connect on given ipv6 port (number or name)\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int c, err = 0; int sep = __pmPathSeparator(); pmdaInterface dispatch; char mypath[MAXPATHLEN]; isDSO = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(mypath, sizeof(mypath), "%s%c" "freebsd" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_5, pmProgname, FREEBSD, "freebsd.log", mypath); while ((c = pmdaGetOpt(argc, argv, "D:d:i:l:pu:U:6:?", &dispatch, &err)) != EOF) { switch(c) { case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&dispatch); freebsd_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/freebsd/netif.c0000664000000000000000000001517012272262501015364 0ustar /* * FreeBSD Kernel PMDA - network interface metrics * * Copyright (c) 2012 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include #include #include #include #include #include "freebsd.h" #define WARN_INIT 1 #define WARN_READ_HEAD 2 void refresh_netif_metrics(void) { int i; int sts; unsigned long kaddr; struct ifnethead ifnethead; struct ifnet ifnet; struct ifnet *ifp; static int warn = 0; /* warn once control */ /* * Not sure that the order of chained netif structs is invariant, * especially if interfaces are added to the configuration after * initial system boot ... so mark all the instances as inactive * and re-match based on the interface name */ pmdaCacheOp(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_INACTIVE); kaddr = symbols[KERN_IFNET].n_value; if (kvmp == NULL || kaddr == 0) { /* no network interface metrics for us today ... */ if ((warn & WARN_INIT) == 0) { fprintf(stderr, "refresh_netif_metrics: Warning: cannot get any network interface metrics\n"); warn |= WARN_INIT; } return; } /* * Kernel data structures for the linked list of network interface * information. * * _ifnet -> struct ifnethead { * struct ifnet *tqh_first; * struct ifnet **tqh_last; * ... * } * * and within an ifnet struct (declared in ) we find * the linked list maintained in if_link, the external interface * name in if_xname[] and if_data which is a nested if_data stuct * (declared in ) that contains many of the goodies we're * after, e.g. u_char ifi_type, u_long ifi_mtu, u_long ifi_baudrate, * u_long ifi_ipackets, u_long ifi_opackets, u_long ifi_ibytes, * u_long ifi_obytes, etc. */ if (kvm_read(kvmp, kaddr, (char *)&ifnethead, sizeof(ifnethead)) != sizeof(ifnethead)) { if ((warn & WARN_READ_HEAD) == 0) { fprintf(stderr, "refresh_netif_metrics: Warning: kvm_read: ifnethead: %s\n", kvm_geterr(kvmp)); warn |= WARN_READ_HEAD; } return; } for (i = 0; ; i++) { if (i == 0) kaddr = (unsigned long)TAILQ_FIRST(&ifnethead); else kaddr = (unsigned long)TAILQ_NEXT(&ifnet, if_link); if (kaddr == 0) break; if (kvm_read(kvmp, kaddr, (char *)&ifnet, sizeof(ifnet)) != sizeof(ifnet)) { fprintf(stderr, "refresh_netif_metrics: Error: kvm_read: ifnet[%d]: %s\n", i, kvm_geterr(kvmp)); return; } /* skip network interfaces that are not interesting ... */ if (strcmp(ifnet.if_xname, "lo0") == 0) continue; sts = pmdaCacheLookupName(indomtab[NETIF_INDOM].it_indom, ifnet.if_xname, NULL, (void **)&ifp); if (sts == PMDA_CACHE_ACTIVE) { fprintf(stderr, "refresh_netif_metrics: Warning: duplicate name (%s) in network interface indom\n", ifnet.if_xname); continue; } else if (sts == PMDA_CACHE_INACTIVE) { /* reactivate an existing entry */ pmdaCacheStore(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_ADD, ifnet.if_xname, (void *)ifp); } else { /* new entry */ ifp = (struct ifnet *)malloc(sizeof(*ifp)); if (ifp == NULL) { fprintf(stderr, "Error: struct ifnet alloc failed for network interface \"%s\"\n", ifnet.if_xname); __pmNoMem("refresh_netif_metrics", sizeof(*ifp), PM_FATAL_ERR); /*NOTREACHED*/ } pmdaCacheStore(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_ADD, ifnet.if_xname, (void *)ifp); } memcpy((void *)ifp, (void *)&ifnet, sizeof(*ifp)); } } int do_netif_metrics(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { struct ifnet *ifp; int sts = 0; if (inst != PM_IN_NULL) { /* * per-network interface metrics */ sts = pmdaCacheLookup(indomtab[NETIF_INDOM].it_indom, inst, NULL, (void **)&ifp); if (sts == PMDA_CACHE_ACTIVE) { sts = 1; /* cluster and domain already checked, just need item ... */ switch (pmid_item(mdesc->m_desc.pmid)) { case 0: /* network.interface.mtu */ atom->ul = (__uint32_t)ifp->if_data.ifi_mtu; break; case 1: /* network.interface.up */ atom->ul = (ifp->if_flags & IFF_UP) == IFF_UP; break; case 2: /* network.interface.baudrate */ atom->ull = ifp->if_data.ifi_baudrate; break; case 3: /* network.interface.in.bytes */ atom->ull = ifp->if_data.ifi_ibytes; break; case 4: /* network.interface.in.packets */ atom->ull = ifp->if_data.ifi_ipackets; break; case 5: /* network.interface.in.mcasts */ atom->ull = ifp->if_data.ifi_imcasts; break; case 6: /* network.interface.in.errors */ atom->ull = ifp->if_data.ifi_ierrors; break; case 7: /* network.interface.in.drops */ atom->ull = ifp->if_data.ifi_iqdrops; break; case 8: /* network.interface.out.bytes */ atom->ull = ifp->if_data.ifi_obytes; break; case 9: /* network.interface.out.packets */ atom->ull = ifp->if_data.ifi_opackets; break; case 10: /* network.interface.out.mcasts */ atom->ull = ifp->if_data.ifi_omcasts; break; case 11: /* network.interface.out.errors */ atom->ull = ifp->if_data.ifi_oerrors; break; case 12: /* network.interface.out.collisions */ atom->ull = ifp->if_data.ifi_collisions; break; case 13: /* network.interface.total.bytes */ atom->ull = ifp->if_data.ifi_ibytes + ifp->if_data.ifi_obytes; break; case 14: /* network.interface.total.packets */ atom->ull = ifp->if_data.ifi_ipackets + ifp->if_data.ifi_opackets; break; case 15: /* network.interface.total.mcasts */ atom->ull = ifp->if_data.ifi_imcasts + ifp->if_data.ifi_omcasts; break; case 16: /* network.interface.total.errors */ atom->ull = ifp->if_data.ifi_ierrors + ifp->if_data.ifi_oerrors; break; default: sts = PM_ERR_PMID; break; } } else sts = 0; } return sts; } pcp-3.8.12ubuntu1/src/pmdas/freebsd/GNUmakefile0000664000000000000000000000375412272262501016172 0ustar # # Copyright (c) 2000,2003,2004,2008 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2007-2010 Aconex. All Rights Reserved. # Copyright (c) 2012 Ken McDonell. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = freebsd DOMAIN = FREEBSD CMDTARGET = pmdafreebsd LIBTARGET = pmda_freebsd.so PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) CONF_LINE = "freebsd 85 dso freebsd_init $(PMDADIR)/$(LIBTARGET)" CFILES = freebsd.c disk.c netif.c HFILES = freebsd.h LSRCFILES = help root_freebsd LDIRT = help.dir help.pag help.sed help.tmp domain.h $(IAM).log LLDLIBS = $(PCP_PMDALIB) -ldevstat default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "freebsd" build-me: domain.h $(LIBTARGET) $(CMDTARGET) help.dir help.pag @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 644 domain.h help help.dir help.pag $(PMDADIR) $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(PMDADIR) $(INSTALL) -m 644 root_freebsd $(PCP_VAR_DIR)/pmns/root_freebsd else build-me: install: endif help.dir help.pag : domain.h help $(SED) help.sed -n -e '/#define/s/#define[ ]*\([A-Z][A-Z]*\)[ ]*\([0-9][0-9]*\)/s@\1@\2@/p' $(SED) -f help.sed help.tmp $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_freebsd -v 2 -o help #include extern kvm_t *kvmp; #define KERN_IFNET 0 extern struct nlist symbols[]; pcp-3.8.12ubuntu1/src/pmdas/freebsd/disk.c0000664000000000000000000001345712272262501015217 0ustar /* * FreeBSD Kernel PMDA - disk metrics * * Copyright (c) 2012 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include #include "freebsd.h" struct devinfo devinfo = { 0 }; struct statinfo statinfo; void refresh_disk_metrics(void) { static int init_done = 0; int i; int sts; if (!init_done) { sts = devstat_checkversion(NULL); if (sts != 0) { fprintf(stderr, "refresh_disk_metrics: devstat_checkversion: failed! %s\n", devstat_errbuf); exit(1); } statinfo.dinfo = &devinfo; init_done = 1; } sts = devstat_getdevs(NULL, &statinfo); if (sts < 0) { fprintf(stderr, "refresh_disk_metrics: devstat_getdevs: %s\n", strerror(errno)); exit(1); } else if (sts == 1) { /* * First call, else devstat[] list has changed */ struct devstat *dsp; char iname[DEVSTAT_NAME_LEN+6]; pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_INACTIVE); for (i = 0; i < devinfo.numdevs; i++) { dsp = &devinfo.devices[i]; /* * Skip entries that are not interesting ... only include * "da" (direct access) disks at this stage */ if (strcmp(dsp->device_name, "da") != 0) continue; snprintf(iname, sizeof(iname), "%s%d", dsp->device_name, dsp->unit_number); sts = pmdaCacheLookupName(indomtab[DISK_INDOM].it_indom, iname, NULL, NULL); if (sts == PMDA_CACHE_ACTIVE) { int j; fprintf(stderr, "refresh_disk_metrics: Warning: duplicate name (%s) in disk indom\n", iname); for (j = 0; j < devinfo.numdevs; j++) { dsp = &devinfo.devices[j]; fprintf(stderr, " devinfo[%d]: %s%d\n", j, dsp->device_name, dsp->unit_number); } continue; } else { /* new entry or reactivate an existing one */ pmdaCacheStore(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_ADD, iname, (void *)dsp); } } } } int do_disk_metrics(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { struct devstat *dsp; int sts; if (inst != PM_IN_NULL) { /* * per-disk metrics */ sts = pmdaCacheLookup(indomtab[DISK_INDOM].it_indom, inst, NULL, (void **)&dsp); if (sts == PMDA_CACHE_ACTIVE) { sts = 1; /* cluster and domain already checked, just need item ... */ switch (pmid_item(mdesc->m_desc.pmid)) { case 0: /* disk.dev.read */ atom->ull = dsp->operations[DEVSTAT_READ]; break; case 1: /* disk.dev.write */ atom->ull = dsp->operations[DEVSTAT_WRITE]; break; case 2: /* disk.dev.total */ atom->ull = dsp->operations[DEVSTAT_READ] + dsp->operations[DEVSTAT_WRITE]; break; case 3: /* disk.dev.read_bytes */ atom->ull = dsp->bytes[DEVSTAT_READ]; break; case 4: /* disk.dev.write_bytes */ atom->ull = dsp->bytes[DEVSTAT_WRITE]; break; case 5: /* disk.dev.total_bytes */ atom->ull = dsp->bytes[DEVSTAT_READ] + dsp->bytes[DEVSTAT_WRITE]; break; case 12: /* disk.dev.blkread */ atom->ull = dsp->block_size == 0 ? 0 : dsp->bytes[DEVSTAT_READ] / dsp->block_size; break; case 13: /* disk.dev.blkwrite */ atom->ull = dsp->block_size == 0 ? 0 : dsp->bytes[DEVSTAT_WRITE] / dsp->block_size; break; case 14: /* disk.dev.blktotal */ atom->ull = dsp->block_size == 0 ? 0 : (dsp->bytes[DEVSTAT_READ] + dsp->bytes[DEVSTAT_WRITE]) / dsp->block_size; break; default: sts = PM_ERR_PMID; break; } } else sts = 0; } else { /* * all-disk summary metrics */ int i; atom->ull = 0; sts = 1; pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_WALK_REWIND); while (sts == 1 && (i = pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_WALK_NEXT)) >= 0) { int lsts; lsts = pmdaCacheLookup(indomtab[DISK_INDOM].it_indom, i, NULL, (void **)&dsp); if (lsts == PMDA_CACHE_ACTIVE) { /* cluster and domain already checked, just need item ... */ switch (pmid_item(mdesc->m_desc.pmid)) { case 6: /* disk.all.read */ atom->ull += dsp->operations[DEVSTAT_READ]; break; case 7: /* disk.all.write */ atom->ull += dsp->operations[DEVSTAT_WRITE]; break; case 8: /* disk.all.total */ atom->ull += dsp->operations[DEVSTAT_READ] + dsp->operations[DEVSTAT_WRITE]; break; case 9: /* disk.all.read_bytes */ atom->ull += dsp->bytes[DEVSTAT_READ]; break; case 10: /* disk.all.write_bytes */ atom->ull += dsp->bytes[DEVSTAT_WRITE]; break; case 11: /* disk.all.total_bytes */ atom->ull += dsp->bytes[DEVSTAT_READ] + dsp->bytes[DEVSTAT_WRITE]; break; case 15: /* disk.all.blkread */ atom->ull += dsp->block_size == 0 ? 0 : dsp->bytes[DEVSTAT_READ] / dsp->block_size; break; case 16: /* disk.all.blkwrite */ atom->ull += dsp->block_size == 0 ? 0 : dsp->bytes[DEVSTAT_WRITE] / dsp->block_size; break; case 17: /* disk.all.blktotal */ atom->ull += dsp->block_size == 0 ? 0 : (dsp->bytes[DEVSTAT_READ] + dsp->bytes[DEVSTAT_WRITE]) / dsp->block_size; break; default: sts = PM_ERR_PMID; break; } } } if (i < 0 && i != -1) /* not end of indom from cache walk, some other error */ sts = i; } return sts; } pcp-3.8.12ubuntu1/src/pmdas/freebsd/help0000664000000000000000000001141712272262501014766 0ustar @ FREEBSD.0 Instance domain for load average Universally 3 instances, "1 minute" (1), "5 minute" (5) and "15 minute" (15). @ FREEBSD.1 CPU Instance domain for kernel.percpu metrics One instance for each physical CPU. @ FREEBSD.2 DISK Instance domain for disk.dev metrics One instance for each physical "direct access" device. @ kernel.all.hz system hz rate Microseconds per "hz" tick. @ kernel.all.load 1, 5 and 15 minute load average @ kernel.all.pswitch count of context switches @ kernel.all.syscall count of system calls @ kernel.all.intr count of interrupts serviced @ kernel.all.cpu.user total user CPU time for all CPUs @ kernel.all.cpu.nice total nice user CPU time for all CPUs @ kernel.all.cpu.sys total sys CPU time for all CPUs @ kernel.all.cpu.intr total interrupt CPU time for all CPUs @ kernel.all.cpu.idle total idle CPU time for all CPUs @ kernel.percpu.cpu.user user CPU time for each CPU @ kernel.percpu.cpu.nice nice user CPU time for each CPU @ kernel.percpu.cpu.sys sys CPU time for each CPU @ kernel.percpu.cpu.intr interrupt CPU time for each CPU @ kernel.percpu.cpu.idle idle CPU time for each CPU @ hinv.ncpu number of CPUs in the system @ hinv.ndisk number of disks in the system @ hinv.physmem total system memory @ hinv.pagesize kernel page size @ hinv.cpu.vendor system's CPU vendor @ hinv.cpu.model system's CPU model @ hinv.cpu.arch system's machine dependent CPU architecture type @ swap.length total swap space size @ swap.used reserved (or allocated) swap space @ swap.free available swap space @ swap.pagesin pages read from external storage to service page faults @ swap.pagesout dirty pages written to swap devices When the rate of page writes is non-zero, this is the most useful indication severe demand for physical memory. @ swap.in number of swap in operations @ swap.out number of swap out operations @ disk.dev.read Count of read operations per disk @ disk.dev.write Count of write operations per disk @ disk.dev.total Count of read or write operations (IOPs) per disk @ disk.dev.read_bytes Count of bytes read from each disk @ disk.dev.write_bytes Count of bytes written to each disk @ disk.dev.total_bytes Count of bytes transferred to or from each disk @ disk.dev.blkread Count of blocks read from each disk @ disk.dev.blkwrite Count of blocks written to each disk @ disk.dev.blktotal Count of blocks transferred to or from each disk @ disk.all.read Count of read operations across all disks @ disk.all.write Count of write operations across all disks @ disk.all.total Count of read or write operations (IOPs) across all disks @ disk.all.read_bytes Count of bytes read from all disks @ disk.all.write_bytes Count of bytes written to all disks @ disk.all.total_bytes Count of bytes transferred to or from all disks @ disk.all.blkread Count of blocks read from all disks @ disk.all.blkwrite Count of blocks written to all disks @ disk.all.blktotal Count of blocks transferred to or from all disks @ mem.util.all Total memory managed by the system @ mem.util.used Memory that is actively in use Equals "all" minus "free" minus "inactive" minus "cached". @ mem.util.free Unallocated and free memory @ mem.util.bufmem Memory associated with active buffer I/O @ mem.util.cached Cached memory Unmodified (clean and cached) pages from files in filesystems. @ mem.util.wired Wired or pinned memory that cannot be paged out @ mem.util.active Recently accessed memory @ mem.util.inactive Memory that is in use, but has not be accessed recently @ mem.util.avail Available memory Free plus inactive plus cached. @ network.interface.mtu Maximum Transfer Unit for each network interface @ network.interface.up "UP" state for each network interface @ network.interface.baudrate Data baudrate for each network interface @ network.interface.in.bytes Bytes received on each network interface @ network.interface.in.packets Packets received on each network interface @ network.interface.in.mcasts Multicast packets received on each network interface @ network.interface.in.errors Input errors on each network interface @ network.interface.in.drops Dropped packets on each network interface @ network.interface.out.bytes Bytes transmitted on each network interface @ network.interface.out.packets Packets transmitted on each network interface @ network.interface.out.mcasts Multicast packets transmitted on each network interface @ network.interface.out.errors Output errors on each network interface @ network.interface.out.collisions Output collisions on each network interface @ network.interface.total.bytes Bytes received or transmitted on each network interface @ network.interface.total.packets Packets received or transmitted on each network interface @ network.interface.total.mcasts Multicast packets received or transmitted on each network interface @ network.interface.total.errors Input or output errors on each network interface pcp-3.8.12ubuntu1/src/pmdas/freebsd/root_freebsd0000664000000000000000000000551612272262501016516 0ustar /* * Metrics for FreeBSD kernel PMDA * * Copyright (c) 2012 Ken McDonell All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * the domain for the FreeBSD PMDA ... */ #ifndef FREEBSD #define FREEBSD 85 #endif root { hinv kernel disk mem network swap } hinv { ncpu FREEBSD:0:0 ndisk FREEBSD:1:0 physmem FREEBSD:0:1 pagesize FREEBSD:1:3 cpu } hinv.cpu { vendor FREEBSD:0:15 model FREEBSD:0:16 arch FREEBSD:0:17 } kernel { all percpu } kernel.all { pswitch FREEBSD:0:22 syscall FREEBSD:0:23 intr FREEBSD:0:24 hz FREEBSD:0:13 load FREEBSD:0:2 cpu } kernel.all.cpu { user FREEBSD:0:3 nice FREEBSD:0:4 sys FREEBSD:0:5 intr FREEBSD:0:6 idle FREEBSD:0:7 } kernel.percpu { cpu } kernel.percpu.cpu { user FREEBSD:0:8 nice FREEBSD:0:9 sys FREEBSD:0:10 intr FREEBSD:0:11 idle FREEBSD:0:12 } disk { dev all } disk.dev { read FREEBSD:2:0 write FREEBSD:2:1 total FREEBSD:2:2 read_bytes FREEBSD:2:3 write_bytes FREEBSD:2:4 total_bytes FREEBSD:2:5 blkread FREEBSD:2:12 blkwrite FREEBSD:2:13 blktotal FREEBSD:2:14 } disk.all { read FREEBSD:2:6 write FREEBSD:2:7 total FREEBSD:2:8 read_bytes FREEBSD:2:9 write_bytes FREEBSD:2:10 total_bytes FREEBSD:2:11 blkread FREEBSD:2:15 blkwrite FREEBSD:2:16 blktotal FREEBSD:2:17 } mem { util } mem.util { all FREEBSD:1:4 used FREEBSD:1:5 free FREEBSD:1:6 bufmem FREEBSD:1:7 cached FREEBSD:1:8 wired FREEBSD:1:9 active FREEBSD:1:10 inactive FREEBSD:1:11 avail FREEBSD:1:12 } network { interface } network.interface { mtu FREEBSD:3:0 up FREEBSD:3:1 baudrate FREEBSD:3:2 in out total } network.interface.in { bytes FREEBSD:3:3 packets FREEBSD:3:4 mcasts FREEBSD:3:5 errors FREEBSD:3:6 drops FREEBSD:3:7 } network.interface.out { bytes FREEBSD:3:8 packets FREEBSD:3:9 mcasts FREEBSD:3:10 errors FREEBSD:3:11 collisions FREEBSD:3:12 } network.interface.total { bytes FREEBSD:3:13 packets FREEBSD:3:14 mcasts FREEBSD:3:15 errors FREEBSD:3:16 } swap { pagesin FREEBSD:0:18 pagesout FREEBSD:0:19 in FREEBSD:0:20 out FREEBSD:0:21 length FREEBSD:0:25 used FREEBSD:0:26 free FREEBSD:1:1 } #undef FREEBSD pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/0000775000000000000000000000000012272262620014516 5ustar pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/filesys.c0000664000000000000000000001150412272262501016337 0ustar /* * XFS Filesystems Cluster * * Copyright (c) 2013 Red Hat. * Copyright (c) 2004,2007 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "filesys.h" static void refresh_filesys_projects(pmInDom qindom, filesys_t *fs) { char buffer[MAXPATHLEN]; project_t *qp; fs_quota_stat_t s; fs_disk_quota_t d; size_t idsz, devsz; FILE *projects; char *p, *idend; uint32_t prid; int qcmd, sts; qcmd = QCMD(Q_XGETQSTAT, XQM_PRJQUOTA); if (quotactl(qcmd, fs->device, 0, (void*)&s) < 0) return; if (s.qs_flags & XFS_QUOTA_PDQ_ENFD) fs->flags |= FSF_QUOT_PROJ_ENF; if (s.qs_flags & XFS_QUOTA_PDQ_ACCT) fs->flags |= FSF_QUOT_PROJ_ACC; else return; projects = fopen("/etc/projects", "r"); if (projects == NULL) return; qcmd = QCMD(Q_XQUOTASYNC, XQM_PRJQUOTA); quotactl(qcmd, fs->device, 0, NULL); while (fgets(buffer, sizeof(buffer), projects)) { if (buffer[0] == '#') continue; prid = strtol(buffer, &idend, 10); idsz = idend - buffer; qcmd = QCMD(Q_XGETQUOTA, XQM_PRJQUOTA); if (!idsz || quotactl(qcmd, fs->device, prid, (void *)&d) < 0) continue; devsz = strlen(fs->device); p = malloc(idsz+devsz+2); if (!p) continue; memcpy(p, buffer, idsz); p[idsz] = ':'; memcpy(&p[idsz+1], fs->device, devsz+1); qp = NULL; sts = pmdaCacheLookupName(qindom, p, NULL, (void **)&qp); if (sts == PMDA_CACHE_ACTIVE) /* repeated line in /etc/projects? */ goto next; if (sts != PMDA_CACHE_INACTIVE) { qp = (project_t *)malloc(sizeof(project_t)); if (!qp) goto next; if (pmDebug & DBG_TRACE_LIBPMDA) fprintf(stderr, "refresh_filesys_projects: add \"%s\"\n", p); } qp->space_hard = d.d_blk_hardlimit; qp->space_soft = d.d_blk_softlimit; qp->space_used = d.d_bcount; qp->space_time_left = d.d_btimer; qp->files_hard = d.d_ino_hardlimit; qp->files_soft = d.d_ino_softlimit; qp->files_used = d.d_icount; qp->files_time_left = d.d_itimer; pmdaCacheStore(qindom, PMDA_CACHE_ADD, p, (void *)qp); next: free(p); } fclose(projects); } char * scan_filesys_options(const char *options, const char *option) { static char buffer[128]; char *s; strncpy(buffer, options, sizeof(buffer)); buffer[sizeof(buffer)-1] = '\0'; s = strtok(buffer, ","); while (s) { if (strcmp(s, option) == 0) return s; s = strtok(NULL, ","); } return NULL; } int refresh_filesys(pmInDom filesys_indom, pmInDom quota_indom) { char buf[MAXPATHLEN]; char realdevice[MAXPATHLEN]; filesys_t *fs; pmInDom indom = filesys_indom; FILE *fp; char *path, *device, *type, *options; int sts; pmdaCacheOp(quota_indom, PMDA_CACHE_INACTIVE); pmdaCacheOp(filesys_indom, PMDA_CACHE_INACTIVE); if ((fp = fopen("/proc/mounts", "r")) == (FILE *)NULL) return -oserror(); while (fgets(buf, sizeof(buf), fp) != NULL) { if ((device = strtok(buf, " ")) == 0) continue; path = strtok(NULL, " "); type = strtok(NULL, " "); options = strtok(NULL, " "); if (strcmp(type, "xfs") != 0) continue; if (strncmp(device, "/dev", 4) != 0) continue; if (realpath(device, realdevice) != NULL) device = realdevice; sts = pmdaCacheLookupName(indom, device, NULL, (void **)&fs); if (sts == PMDA_CACHE_ACTIVE) /* repeated line in /proc/mounts? */ continue; if (sts == PMDA_CACHE_INACTIVE) { /* re-activate an old mount */ pmdaCacheStore(indom, PMDA_CACHE_ADD, device, fs); if (strcmp(path, fs->path) != 0) { /* old device, new path */ free(fs->path); fs->path = strdup(path); } if (strcmp(options, fs->options) != 0) { /* old device, new opts */ free(fs->options); fs->options = strdup(options); } } else { /* new mount */ if ((fs = malloc(sizeof(filesys_t))) == NULL) continue; fs->device = strdup(device); fs->path = strdup(path); fs->options = strdup(options); if (pmDebug & DBG_TRACE_LIBPMDA) fprintf(stderr, "refresh_filesys: add \"%s\" \"%s\"\n", fs->path, device); pmdaCacheStore(indom, PMDA_CACHE_ADD, device, fs); } fs->flags = 0; refresh_filesys_projects(quota_indom, fs); } /* * success * Note: we do not call statfs() here since only some instances * may be requested (rather, we do it in xfs_fetch, see pmda.c). */ fclose(fp); return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/root_xfs0000664000000000000000000001235612272262501016311 0ustar /* * Portions Copyright (c) 2013 Red Hat. * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef XFS #define XFS 11 #endif root { xfs quota } xfs { allocs alloc_btree block_map bmap_btree dir_ops transactions inode_ops log log_tail xstrat write XFS:16:51 write_bytes XFS:16:52 read XFS:16:53 read_bytes XFS:16:54 attr quota iflush_count XFS:16:67 icluster_flushcnt XFS:16:68 icluster_flushinode XFS:16:69 buffer vnodes control btree } xfs.allocs { alloc_extent XFS:16:0 alloc_block XFS:16:1 free_extent XFS:16:2 free_block XFS:16:3 } xfs.alloc_btree { lookup XFS:16:4 compare XFS:16:5 insrec XFS:16:6 delrec XFS:16:7 } xfs.block_map { read_ops XFS:16:8 write_ops XFS:16:9 unmap XFS:16:10 add_exlist XFS:16:11 del_exlist XFS:16:12 look_exlist XFS:16:13 cmp_exlist XFS:16:14 } xfs.bmap_btree { lookup XFS:16:15 compare XFS:16:16 insrec XFS:16:17 delrec XFS:16:18 } xfs.dir_ops { lookup XFS:16:19 create XFS:16:20 remove XFS:16:21 getdents XFS:16:22 } xfs.transactions { sync XFS:16:23 async XFS:16:24 empty XFS:16:25 } xfs.inode_ops { ig_attempts XFS:16:26 ig_found XFS:16:27 ig_frecycle XFS:16:28 ig_missed XFS:16:29 ig_dup XFS:16:30 ig_reclaims XFS:16:31 ig_attrchg XFS:16:32 } xfs.log { writes XFS:16:33 blocks XFS:16:34 write_ratio XFS:16:78 noiclogs XFS:16:35 force XFS:16:36 force_sleep XFS:16:37 } xfs.log_tail { try_logspace XFS:16:38 sleep_logspace XFS:16:39 push_ail } xfs.log_tail.push_ail { pushes XFS:16:40 success XFS:16:41 pushbuf XFS:16:42 pinned XFS:16:43 locked XFS:16:44 flushing XFS:16:45 restarts XFS:16:46 flush XFS:16:47 } xfs.xstrat { bytes XFS:16:48 quick XFS:16:49 split XFS:16:50 } xfs.attr { get XFS:16:55 set XFS:16:56 remove XFS:16:57 list XFS:16:58 } xfs.quota { reclaims XFS:16:59 reclaim_misses XFS:16:60 dquot_dups XFS:16:61 cachemisses XFS:16:62 cachehits XFS:16:63 wants XFS:16:64 shake_reclaims XFS:16:65 inact_reclaims XFS:16:66 } xfs.vnodes { active XFS:16:70 alloc XFS:16:71 get XFS:16:72 hold XFS:16:73 rele XFS:16:74 reclaim XFS:16:75 remove XFS:16:76 free XFS:16:77 } xfs.control { reset XFS:16:79 } xfs.buffer { get XFS:17:0 create XFS:17:1 get_locked XFS:17:2 get_locked_waited XFS:17:3 busy_locked XFS:17:4 miss_locked XFS:17:5 page_retries XFS:17:6 page_found XFS:17:7 get_read XFS:17:8 } xfs.btree { alloc_blocks alloc_contig block_map inode } xfs.btree.alloc_blocks { lookup XFS:16:80 compare XFS:16:81 insrec XFS:16:82 delrec XFS:16:83 newroot XFS:16:84 killroot XFS:16:85 increment XFS:16:86 decrement XFS:16:87 lshift XFS:16:88 rshift XFS:16:89 split XFS:16:90 join XFS:16:91 alloc XFS:16:92 free XFS:16:93 moves XFS:16:94 } xfs.btree.alloc_contig { lookup XFS:16:95 compare XFS:16:96 insrec XFS:16:97 delrec XFS:16:98 newroot XFS:16:99 killroot XFS:16:100 increment XFS:16:101 decrement XFS:16:102 lshift XFS:16:103 rshift XFS:16:104 split XFS:16:105 join XFS:16:106 alloc XFS:16:107 free XFS:16:108 moves XFS:16:109 } xfs.btree.block_map { lookup XFS:16:110 compare XFS:16:111 insrec XFS:16:112 delrec XFS:16:113 newroot XFS:16:114 killroot XFS:16:115 increment XFS:16:116 decrement XFS:16:117 lshift XFS:16:118 rshift XFS:16:119 split XFS:16:120 join XFS:16:121 alloc XFS:16:122 free XFS:16:123 moves XFS:16:124 } xfs.btree.inode { lookup XFS:16:125 compare XFS:16:126 insrec XFS:16:127 delrec XFS:16:128 newroot XFS:16:129 killroot XFS:16:130 increment XFS:16:131 decrement XFS:16:132 lshift XFS:16:133 rshift XFS:16:134 split XFS:16:135 join XFS:16:136 alloc XFS:16:137 free XFS:16:138 moves XFS:16:139 } quota { state project } quota.state { project } quota.state.project { accounting XFS:30:0 enforcement XFS:30:1 } quota.project { space files } quota.project.space { hard XFS:30:6 soft XFS:30:7 used XFS:30:8 time_left XFS:30:9 } quota.project.files { hard XFS:30:10 soft XFS:30:11 used XFS:30:12 time_left XFS:30:13 } #undef XFS pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/linux_xfs_migrate.conf0000664000000000000000000000113012272262501021105 0ustar # # Copyright 2013 Red Hat. # # pmlogrewrite configuration for migrating archives containing XFS metrics # that were captured prior to the XFS PMDA split-off from the Linux PMDA. # Basically, the PMID domain changed from 60 (linux) to 11 (xfs) but all # cluster and item numbers remain unchanged. # # # Migrate the domain field of the metric and indom identifiers # indom 60.16 { indom -> duplicate 11.16 } # need 11.16 and 60.16 metric 60.16.* { pmid -> 11.*.* } # CLUSTER_XFS metric 60.17.* { pmid -> 11.*.* } # CLUSTER_XFSBUF metric 60.30.* { pmid -> 11.*.* indom -> 11.16 } # CLUSTER_QUOTA pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/Remove0000775000000000000000000000123212272262501015675 0ustar #!/bin/sh # # Copyright (c) 2013 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the Linux XFS PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=xfs pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/Install0000775000000000000000000000135512272262501016054 0ustar #!/bin/sh # # Copyright (c) 2013 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the Linux XFS PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=xfs pmda_interface=3 daemon_opt=true pipe_opt=true pmns_source=root_xfs pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/GNUmakefile0000664000000000000000000000423112272262501016566 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2003,2004,2008 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = xfs DOMAIN = XFS CMDTARGET = pmda$(IAM) LIBTARGET = pmda_$(IAM).$(DSOSUFFIX) PMDAINIT = $(IAM)_init PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) CONF_LINE = "xfs 11 pipe binary $(PMDADIR)/$(CMDTARGET) -d 11" CFILES = proc_fs_xfs.c filesys.c pmda.c HFILES = proc_fs_xfs.h filesys.h clusters.h indom.h SCRIPTS = Install Remove VERSION_SCRIPT = exports HELPTARGETS = help.dir help.pag LSRCFILES = help root root_xfs linux_xfs_migrate.conf $(SCRIPTS) LDIRT = $(HELPTARGETS) domain.h $(VERSION_SCRIPT) LLDLIBS = $(PCP_PMDALIB) LCFLAGS = $(INVISIBILITY) default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "linux" build-me: domain.h $(LIBTARGET) $(CMDTARGET) $(HELPTARGETS) @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 644 domain.h help help.dir help.pag root root_xfs $(PMDADIR) $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(SCRIPTS) $(PMDADIR) $(INSTALL) -m 644 root_xfs $(PCP_VAR_DIR)/pmns/root_xfs $(INSTALL) -m 644 linux_xfs_migrate.conf $(PCP_VAR_DIR)/config/pmlogrewrite/linux_xfs_migrate.conf else build-me: install: endif default_pcp : default install_pcp : install $(HELPTARGETS) : help $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_xfs -v 2 -o help < help $(VERSION_SCRIPT): $(VERSION_SCRIPT_MAKERULE) domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pmda.o: domain.h pmda.o proc_fs_xfs.o: proc_fs_xfs.h filesys.o pmda.o: filesys.h pmda.o: $(VERSION_SCRIPT) pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/root0000664000000000000000000000014412272262501015421 0ustar /* * fake "root" for validating the local PMNS subtree */ #include #include "root_xfs" pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/filesys.h0000664000000000000000000001055312272262501016347 0ustar /* * XFS Filesystem Cluster * * Copyright (c) 2013 Red Hat. * Copyright (c) 2004,2007 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #define XQM_CMD(x) (('X'<<8)+(x)) /* note: forms first QCMD argument */ #define XQM_COMMAND(x) (((x) & (0xff<<8)) == ('X'<<8)) /* test if for XFS */ #define XQM_PRJQUOTA 2 #define Q_XGETQUOTA XQM_CMD(3) /* get disk limits and usage */ #define Q_XGETQSTAT XQM_CMD(5) /* get quota subsystem status */ #define Q_XQUOTASYNC XQM_CMD(7) /* delalloc flush, updates dquots */ #define XFS_QUOTA_PDQ_ACCT (1<<4) /* project quota accounting */ #define XFS_QUOTA_PDQ_ENFD (1<<5) /* project quota limits enforcement */ #define FS_QSTAT_VERSION 1 /* fs_quota_stat.qs_version */ /* * Some basic information about 'quota files'. */ typedef struct fs_qfilestat { uint64_t qfs_ino; /* inode number */ uint64_t qfs_nblks; /* number of BBs 512-byte-blks */ uint32_t qfs_nextents; /* number of extents */ } fs_qfilestat_t; typedef struct fs_quota_stat { char qs_version; /* version number for future changes */ uint16_t qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */ char qs_pad; /* unused */ fs_qfilestat_t qs_uquota; /* user quota storage information */ fs_qfilestat_t qs_gquota; /* group quota storage information */ uint32_t qs_incoredqs; /* number of dquots incore */ int32_t qs_btimelimit; /* limit for blks timer */ int32_t qs_itimelimit; /* limit for inodes timer */ int32_t qs_rtbtimelimit;/* limit for rt blks timer */ uint16_t qs_bwarnlimit; /* limit for num warnings */ uint16_t qs_iwarnlimit; /* limit for num warnings */ } fs_quota_stat_t; #define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */ typedef struct fs_disk_quota { char d_version; /* version of this structure */ char d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */ uint16_t d_fieldmask; /* field specifier */ uint32_t d_id; /* user, project, or group ID */ uint64_t d_blk_hardlimit;/* absolute limit on disk blks */ uint64_t d_blk_softlimit;/* preferred limit on disk blks */ uint64_t d_ino_hardlimit;/* maximum # allocated inodes */ uint64_t d_ino_softlimit;/* preferred inode limit */ uint64_t d_bcount; /* # disk blocks owned by the user */ uint64_t d_icount; /* # inodes owned by the user */ int32_t d_itimer; /* zero if within inode limits */ int32_t d_btimer; /* similar to above; for disk blocks */ uint16_t d_iwarns; /* # warnings issued wrt num inodes */ uint16_t d_bwarns; /* # warnings issued wrt disk blocks */ int32_t d_padding2; /* padding2 - for future use */ uint64_t d_rtb_hardlimit;/* absolute limit on realtime blks */ uint64_t d_rtb_softlimit;/* preferred limit on RT disk blks */ uint64_t d_rtbcount; /* # realtime blocks owned */ int32_t d_rtbtimer; /* similar to above; for RT disk blks */ uint16_t d_rtbwarns; /* # warnings issued wrt RT disk blks */ int16_t d_padding3; /* padding3 - for future use */ char d_padding4[8]; /* yet more padding */ } fs_disk_quota_t; typedef struct project { int32_t space_time_left; /* seconds */ int32_t files_time_left; /* seconds */ uint64_t space_hard; /* blocks */ uint64_t space_soft; /* blocks */ uint64_t space_used; /* blocks */ uint64_t files_hard; uint64_t files_soft; uint64_t files_used; } project_t; /* Values for flags in filesys_t */ #define FSF_FETCHED (1U << 0) #define FSF_QUOT_PROJ_ACC (1U << 1) #define FSF_QUOT_PROJ_ENF (1U << 2) typedef struct filesys { int id; unsigned int flags; char *device; char *path; char *options; struct statfs stats; } filesys_t; extern int refresh_filesys(pmInDom, pmInDom); extern char *scan_filesys_options(const char *, const char *); pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/indom.h0000664000000000000000000000223012272262501015770 0ustar /* * Copyright (c) 2013 Red Hat, Inc. All Rights Reserved. * Copyright (c) 2005,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _INDOM_H #define _INDOM_H /* * indom serial numbers ... to manage the indom migration after the * linux -> linux + xfs PMDAs split, these need to match the enum * assigned values for *_INDOM from the linux PMDA. Consequently, * the xfs indom table is sparse. */ #define FILESYS_INDOM 5 /* mounted filesystems */ #define QUOTA_PRJ_INDOM 16 /* project quota */ #define MIN_INDOM 5 /* first indom number we use here */ #define NUM_INDOMS 17 /* one more than highest indom number used */ #endif /* _INDOM_H */ pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/clusters.h0000664000000000000000000000222112272262501016526 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 2005,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _CLUSTERS_H #define _CLUSTERS_H /* * PMID cluster values ... to manage the PMID migration after the * linux -> linux + xfs PMDAs split, these need to match the enum * assigned values for CLUSTER_* from the original Linux PMDA. */ #define CLUSTER_XFS 16 /* /proc/fs/xfs/stat */ #define CLUSTER_XFSBUF 17 /* /proc/fs/pagebuf/stat */ #define CLUSTER_QUOTA 30 /* quotactl() */ #define MIN_CLUSTER 16 /* first cluster number we use here */ #define NUM_CLUSTERS 31 /* one more than highest cluster number used */ #endif /* _CLUSTERS_H */ pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/pmda.c0000664000000000000000000011230112272262501015577 0ustar /* * XFS PMDA * * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "indom.h" #include "domain.h" #include "clusters.h" #include "filesys.h" #include "proc_fs_xfs.h" static proc_fs_xfs_t proc_fs_xfs; /* * The XFS instance domain table is direct lookup and sparse. * It is initialized in xfs_init(), see below. */ static pmdaIndom xfs_indomtab[NUM_INDOMS]; #define INDOM(x) (xfs_indomtab[x].it_indom) static pmdaMetric xfs_metrictab[] = { /* xfs.allocs.alloc_extent */ { &proc_fs_xfs.xs_allocx, { PMDA_PMID(CLUSTER_XFS,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.allocs.alloc_block */ { &proc_fs_xfs.xs_allocb, { PMDA_PMID(CLUSTER_XFS,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.allocs.free_extent*/ { &proc_fs_xfs.xs_freex, { PMDA_PMID(CLUSTER_XFS,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.allocs.free_block */ { &proc_fs_xfs.xs_freeb, { PMDA_PMID(CLUSTER_XFS,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.alloc_btree.lookup */ { &proc_fs_xfs.xs_abt_lookup, { PMDA_PMID(CLUSTER_XFS,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.alloc_btree.compare */ { &proc_fs_xfs.xs_abt_compare, { PMDA_PMID(CLUSTER_XFS,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.alloc_btree.insrec */ { &proc_fs_xfs.xs_abt_insrec, { PMDA_PMID(CLUSTER_XFS,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.alloc_btree.delrec */ { &proc_fs_xfs.xs_abt_delrec, { PMDA_PMID(CLUSTER_XFS,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.block_map.read_ops */ { &proc_fs_xfs.xs_blk_mapr, { PMDA_PMID(CLUSTER_XFS,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.block_map.write_ops */ { &proc_fs_xfs.xs_blk_mapw, { PMDA_PMID(CLUSTER_XFS,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.block_map.unmap */ { &proc_fs_xfs.xs_blk_unmap, { PMDA_PMID(CLUSTER_XFS,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.block_map.add_exlist */ { &proc_fs_xfs.xs_add_exlist, { PMDA_PMID(CLUSTER_XFS,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.block_map.del_exlist */ { &proc_fs_xfs.xs_del_exlist, { PMDA_PMID(CLUSTER_XFS,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.block_map.look_exlist */ { &proc_fs_xfs.xs_look_exlist, { PMDA_PMID(CLUSTER_XFS,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.block_map.cmp_exlist */ { &proc_fs_xfs.xs_cmp_exlist, { PMDA_PMID(CLUSTER_XFS,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.bmap_btree.lookup */ { &proc_fs_xfs.xs_bmbt_lookup, { PMDA_PMID(CLUSTER_XFS,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.bmap_btree.compare */ { &proc_fs_xfs.xs_bmbt_compare, { PMDA_PMID(CLUSTER_XFS,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.bmap_btree.insrec */ { &proc_fs_xfs.xs_bmbt_insrec, { PMDA_PMID(CLUSTER_XFS,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.bmap_btree.delrec */ { &proc_fs_xfs.xs_bmbt_delrec, { PMDA_PMID(CLUSTER_XFS,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.dir_ops.lookup */ { &proc_fs_xfs.xs_dir_lookup, { PMDA_PMID(CLUSTER_XFS,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.dir_ops.create */ { &proc_fs_xfs.xs_dir_create, { PMDA_PMID(CLUSTER_XFS,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.dir_ops.remove */ { &proc_fs_xfs.xs_dir_remove, { PMDA_PMID(CLUSTER_XFS,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.dir_ops.getdents */ { &proc_fs_xfs.xs_dir_getdents, { PMDA_PMID(CLUSTER_XFS,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.transactions.sync */ { &proc_fs_xfs.xs_trans_sync, { PMDA_PMID(CLUSTER_XFS,23), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.transactions.async */ { &proc_fs_xfs.xs_trans_async, { PMDA_PMID(CLUSTER_XFS,24), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.transactions.empty */ { &proc_fs_xfs.xs_trans_empty, { PMDA_PMID(CLUSTER_XFS,25), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.inode_ops.ig_attempts */ { &proc_fs_xfs.xs_ig_attempts, { PMDA_PMID(CLUSTER_XFS,26), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.inode_ops.ig_found */ { &proc_fs_xfs.xs_ig_found, { PMDA_PMID(CLUSTER_XFS,27), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.inode_ops.ig_frecycle */ { &proc_fs_xfs.xs_ig_frecycle, { PMDA_PMID(CLUSTER_XFS,28), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.inode_ops.ig_missed */ { &proc_fs_xfs.xs_ig_missed, { PMDA_PMID(CLUSTER_XFS,29), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.inode_ops.ig_dup */ { &proc_fs_xfs.xs_ig_dup, { PMDA_PMID(CLUSTER_XFS,30), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.inode_ops.ig_reclaims */ { &proc_fs_xfs.xs_ig_reclaims, { PMDA_PMID(CLUSTER_XFS,31), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.inode_ops.ig_attrchg */ { &proc_fs_xfs.xs_ig_attrchg, { PMDA_PMID(CLUSTER_XFS,32), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log.writes */ { &proc_fs_xfs.xs_log_writes, { PMDA_PMID(CLUSTER_XFS,33), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log.blocks */ { &proc_fs_xfs.xs_log_blocks, { PMDA_PMID(CLUSTER_XFS,34), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* xfs.log.noiclogs */ { &proc_fs_xfs.xs_log_noiclogs, { PMDA_PMID(CLUSTER_XFS,35), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log.force */ { &proc_fs_xfs.xs_log_force, { PMDA_PMID(CLUSTER_XFS,36), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log.force_sleep */ { &proc_fs_xfs.xs_log_force_sleep, { PMDA_PMID(CLUSTER_XFS,37), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log_tail.try_logspace */ { &proc_fs_xfs.xs_try_logspace, { PMDA_PMID(CLUSTER_XFS,38), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log_tail.sleep_logspace */ { &proc_fs_xfs.xs_sleep_logspace, { PMDA_PMID(CLUSTER_XFS,39), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log_tail.push_ail.pushes */ { &proc_fs_xfs.xs_push_ail, { PMDA_PMID(CLUSTER_XFS,40), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log_tail.push_ail.success */ { &proc_fs_xfs.xs_push_ail_success, { PMDA_PMID(CLUSTER_XFS,41), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log_tail.push_ail.pushbuf */ { &proc_fs_xfs.xs_push_ail_pushbuf, { PMDA_PMID(CLUSTER_XFS,42), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log_tail.push_ail.pinned */ { &proc_fs_xfs.xs_push_ail_pinned, { PMDA_PMID(CLUSTER_XFS,43), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log_tail.push_ail.locked */ { &proc_fs_xfs.xs_push_ail_locked, { PMDA_PMID(CLUSTER_XFS,44), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log_tail.push_ail.flushing */ { &proc_fs_xfs.xs_push_ail_flushing, { PMDA_PMID(CLUSTER_XFS,45), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log_tail.push_ail.restarts */ { &proc_fs_xfs.xs_push_ail_restarts, { PMDA_PMID(CLUSTER_XFS,46), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log_tail.push_ail.flush */ { &proc_fs_xfs.xs_push_ail_flush, { PMDA_PMID(CLUSTER_XFS,47), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.xstrat.bytes */ { &proc_fs_xfs.xpc.xs_xstrat_bytes, { PMDA_PMID(CLUSTER_XFS,48), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* xfs.xstrat.quick */ { &proc_fs_xfs.xs_xstrat_quick, { PMDA_PMID(CLUSTER_XFS,49), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.xstrat.split */ { &proc_fs_xfs.xs_xstrat_split, { PMDA_PMID(CLUSTER_XFS,50), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.write */ { &proc_fs_xfs.xs_write_calls, { PMDA_PMID(CLUSTER_XFS,51), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.write_bytes */ { &proc_fs_xfs.xpc.xs_write_bytes, { PMDA_PMID(CLUSTER_XFS,52), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* xfs.read */ { &proc_fs_xfs.xs_read_calls, { PMDA_PMID(CLUSTER_XFS,53), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.read_bytes */ { &proc_fs_xfs.xpc.xs_read_bytes, { PMDA_PMID(CLUSTER_XFS,54), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* xfs.attr.get */ { &proc_fs_xfs.xs_attr_get, { PMDA_PMID(CLUSTER_XFS,55), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.attr.set */ { &proc_fs_xfs.xs_attr_set, { PMDA_PMID(CLUSTER_XFS,56), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.attr.remove */ { &proc_fs_xfs.xs_attr_remove, { PMDA_PMID(CLUSTER_XFS,57), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.attr.list */ { &proc_fs_xfs.xs_attr_list, { PMDA_PMID(CLUSTER_XFS,58), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.quota.reclaims */ { &proc_fs_xfs.xs_qm_dqreclaims, { PMDA_PMID(CLUSTER_XFS,59), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.quota.reclaim_misses */ { &proc_fs_xfs.xs_qm_dqreclaim_misses, { PMDA_PMID(CLUSTER_XFS,60), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.quota.dquot_dups */ { &proc_fs_xfs.xs_qm_dquot_dups, { PMDA_PMID(CLUSTER_XFS,61), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.quota.cachemisses */ { &proc_fs_xfs.xs_qm_dqcachemisses, { PMDA_PMID(CLUSTER_XFS,62), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.quota.cachehits */ { &proc_fs_xfs.xs_qm_dqcachehits, { PMDA_PMID(CLUSTER_XFS,63), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.quota.wants */ { &proc_fs_xfs.xs_qm_dqwants, { PMDA_PMID(CLUSTER_XFS,64), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.quota.shake_reclaims */ { &proc_fs_xfs.xs_qm_dqshake_reclaims, { PMDA_PMID(CLUSTER_XFS,65), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.quota.inact_reclaims */ { &proc_fs_xfs.xs_qm_dqinact_reclaims, { PMDA_PMID(CLUSTER_XFS,66), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.iflush_count */ { &proc_fs_xfs.xs_iflush_count, { PMDA_PMID(CLUSTER_XFS,67), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.icluster_flushcnt */ { &proc_fs_xfs.xs_icluster_flushcnt, { PMDA_PMID(CLUSTER_XFS,68), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.icluster_flushinode */ { &proc_fs_xfs.xs_icluster_flushinode, { PMDA_PMID(CLUSTER_XFS,69), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.buffer.get */ { &proc_fs_xfs.xs_buf_get, { PMDA_PMID(CLUSTER_XFSBUF,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.buffer.create */ { &proc_fs_xfs.xs_buf_create, { PMDA_PMID(CLUSTER_XFSBUF,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.buffer.get_locked */ { &proc_fs_xfs.xs_buf_get_locked, { PMDA_PMID(CLUSTER_XFSBUF,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.buffer.get_locked_waited */ { &proc_fs_xfs.xs_buf_get_locked_waited, { PMDA_PMID(CLUSTER_XFSBUF,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.buffer.busy_locked */ { &proc_fs_xfs.xs_buf_busy_locked, { PMDA_PMID(CLUSTER_XFSBUF,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.buffer.miss_locked */ { &proc_fs_xfs.xs_buf_miss_locked, { PMDA_PMID(CLUSTER_XFSBUF,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.buffer.page_retries */ { &proc_fs_xfs.xs_buf_page_retries, { PMDA_PMID(CLUSTER_XFSBUF,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.buffer.page_found */ { &proc_fs_xfs.xs_buf_page_found, { PMDA_PMID(CLUSTER_XFSBUF,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.buffer.get_read */ { &proc_fs_xfs.xs_buf_get_read, { PMDA_PMID(CLUSTER_XFSBUF,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.vnodes.active */ { &proc_fs_xfs.vnodes.vn_active, { PMDA_PMID(CLUSTER_XFS,70), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* xfs.vnodes.alloc */ { &proc_fs_xfs.vnodes.vn_alloc, { PMDA_PMID(CLUSTER_XFS,71), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.vnodes.get */ { &proc_fs_xfs.vnodes.vn_get, { PMDA_PMID(CLUSTER_XFS,72), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.vnodes.hold */ { &proc_fs_xfs.vnodes.vn_hold, { PMDA_PMID(CLUSTER_XFS,73), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.vnodes.rele */ { &proc_fs_xfs.vnodes.vn_rele, { PMDA_PMID(CLUSTER_XFS,74), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.vnodes.reclaim */ { &proc_fs_xfs.vnodes.vn_reclaim, { PMDA_PMID(CLUSTER_XFS,75), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.vnodes.remove */ { &proc_fs_xfs.vnodes.vn_remove, { PMDA_PMID(CLUSTER_XFS,76), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.vnodes.free */ { &proc_fs_xfs.vnodes.vn_free, { PMDA_PMID(CLUSTER_XFS,77), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.log.write_ratio */ { &proc_fs_xfs.xs_log_write_ratio, { PMDA_PMID(CLUSTER_XFS,78), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* xfs.control.reset */ { NULL, { PMDA_PMID(CLUSTER_XFS,79), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* xfs.btree.alloc_blocks.lookup */ { &proc_fs_xfs.xs_abtb_2_lookup, { PMDA_PMID(CLUSTER_XFS,80), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.compare */ { &proc_fs_xfs.xs_abtb_2_compare, { PMDA_PMID(CLUSTER_XFS,81), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.insrec */ { &proc_fs_xfs.xs_abtb_2_insrec, { PMDA_PMID(CLUSTER_XFS,82), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.delrec */ { &proc_fs_xfs.xs_abtb_2_delrec, { PMDA_PMID(CLUSTER_XFS,83), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.newroot */ { &proc_fs_xfs.xs_abtb_2_newroot, { PMDA_PMID(CLUSTER_XFS,84), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.killroot */ { &proc_fs_xfs.xs_abtb_2_killroot, { PMDA_PMID(CLUSTER_XFS,85), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.increment */ { &proc_fs_xfs.xs_abtb_2_increment, { PMDA_PMID(CLUSTER_XFS,86), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.decrement */ { &proc_fs_xfs.xs_abtb_2_decrement, { PMDA_PMID(CLUSTER_XFS,87), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.lshift */ { &proc_fs_xfs.xs_abtb_2_lshift, { PMDA_PMID(CLUSTER_XFS,88), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.rshift */ { &proc_fs_xfs.xs_abtb_2_rshift, { PMDA_PMID(CLUSTER_XFS,89), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.split */ { &proc_fs_xfs.xs_abtb_2_split, { PMDA_PMID(CLUSTER_XFS,90), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.join */ { &proc_fs_xfs.xs_abtb_2_join, { PMDA_PMID(CLUSTER_XFS,91), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.alloc */ { &proc_fs_xfs.xs_abtb_2_alloc, { PMDA_PMID(CLUSTER_XFS,92), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.free */ { &proc_fs_xfs.xs_abtb_2_free, { PMDA_PMID(CLUSTER_XFS,93), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_blocks.moves */ { &proc_fs_xfs.xs_abtb_2_moves, { PMDA_PMID(CLUSTER_XFS,94), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.lookup */ { &proc_fs_xfs.xs_abtc_2_lookup, { PMDA_PMID(CLUSTER_XFS,95), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.compare */ { &proc_fs_xfs.xs_abtc_2_compare, { PMDA_PMID(CLUSTER_XFS,96), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.insrec */ { &proc_fs_xfs.xs_abtc_2_insrec, { PMDA_PMID(CLUSTER_XFS,97), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.delrec */ { &proc_fs_xfs.xs_abtc_2_delrec, { PMDA_PMID(CLUSTER_XFS,98), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.newroot */ { &proc_fs_xfs.xs_abtc_2_newroot, { PMDA_PMID(CLUSTER_XFS,99), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.killroot */ { &proc_fs_xfs.xs_abtc_2_killroot, { PMDA_PMID(CLUSTER_XFS,100), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.increment */ { &proc_fs_xfs.xs_abtc_2_increment, { PMDA_PMID(CLUSTER_XFS,101), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.decrement */ { &proc_fs_xfs.xs_abtc_2_decrement, { PMDA_PMID(CLUSTER_XFS,102), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.lshift */ { &proc_fs_xfs.xs_abtc_2_lshift, { PMDA_PMID(CLUSTER_XFS,103), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.rshift */ { &proc_fs_xfs.xs_abtc_2_rshift, { PMDA_PMID(CLUSTER_XFS,104), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.split */ { &proc_fs_xfs.xs_abtc_2_split, { PMDA_PMID(CLUSTER_XFS,105), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.join */ { &proc_fs_xfs.xs_abtc_2_join, { PMDA_PMID(CLUSTER_XFS,106), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.alloc */ { &proc_fs_xfs.xs_abtc_2_alloc, { PMDA_PMID(CLUSTER_XFS,107), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.free */ { &proc_fs_xfs.xs_abtc_2_free, { PMDA_PMID(CLUSTER_XFS,108), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.alloc_contig.moves */ { &proc_fs_xfs.xs_abtc_2_moves, { PMDA_PMID(CLUSTER_XFS,109), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.lookup */ { &proc_fs_xfs.xs_bmbt_2_lookup, { PMDA_PMID(CLUSTER_XFS,110), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.compare */ { &proc_fs_xfs.xs_bmbt_2_compare, { PMDA_PMID(CLUSTER_XFS,111), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.insrec */ { &proc_fs_xfs.xs_bmbt_2_insrec, { PMDA_PMID(CLUSTER_XFS,112), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.delrec */ { &proc_fs_xfs.xs_bmbt_2_delrec, { PMDA_PMID(CLUSTER_XFS,113), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.newroot */ { &proc_fs_xfs.xs_bmbt_2_newroot, { PMDA_PMID(CLUSTER_XFS,114), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.killroot */ { &proc_fs_xfs.xs_bmbt_2_killroot, { PMDA_PMID(CLUSTER_XFS,115), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.increment */ { &proc_fs_xfs.xs_bmbt_2_increment, { PMDA_PMID(CLUSTER_XFS,116), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.decrement */ { &proc_fs_xfs.xs_bmbt_2_decrement, { PMDA_PMID(CLUSTER_XFS,117), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.lshift */ { &proc_fs_xfs.xs_bmbt_2_lshift, { PMDA_PMID(CLUSTER_XFS,118), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.rshift */ { &proc_fs_xfs.xs_bmbt_2_rshift, { PMDA_PMID(CLUSTER_XFS,119), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.split */ { &proc_fs_xfs.xs_bmbt_2_split, { PMDA_PMID(CLUSTER_XFS,120), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.join */ { &proc_fs_xfs.xs_bmbt_2_join, { PMDA_PMID(CLUSTER_XFS,121), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.alloc */ { &proc_fs_xfs.xs_bmbt_2_alloc, { PMDA_PMID(CLUSTER_XFS,122), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.free */ { &proc_fs_xfs.xs_bmbt_2_free, { PMDA_PMID(CLUSTER_XFS,123), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.block_map.moves */ { &proc_fs_xfs.xs_bmbt_2_moves, { PMDA_PMID(CLUSTER_XFS,124), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.lookup */ { &proc_fs_xfs.xs_ibt_2_compare, { PMDA_PMID(CLUSTER_XFS,125), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.compare */ { &proc_fs_xfs.xs_ibt_2_lookup, { PMDA_PMID(CLUSTER_XFS,126), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.insrec */ { &proc_fs_xfs.xs_ibt_2_insrec, { PMDA_PMID(CLUSTER_XFS,127), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.delrec */ { &proc_fs_xfs.xs_ibt_2_delrec, { PMDA_PMID(CLUSTER_XFS,128), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.newroot */ { &proc_fs_xfs.xs_ibt_2_newroot, { PMDA_PMID(CLUSTER_XFS,129), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.killroot */ { &proc_fs_xfs.xs_ibt_2_killroot, { PMDA_PMID(CLUSTER_XFS,130), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.increment */ { &proc_fs_xfs.xs_ibt_2_increment, { PMDA_PMID(CLUSTER_XFS,131), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.decrement */ { &proc_fs_xfs.xs_ibt_2_decrement, { PMDA_PMID(CLUSTER_XFS,132), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.lshift */ { &proc_fs_xfs.xs_ibt_2_lshift, { PMDA_PMID(CLUSTER_XFS,133), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.rshift */ { &proc_fs_xfs.xs_ibt_2_rshift, { PMDA_PMID(CLUSTER_XFS,134), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.split */ { &proc_fs_xfs.xs_ibt_2_split, { PMDA_PMID(CLUSTER_XFS,135), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.join */ { &proc_fs_xfs.xs_ibt_2_join, { PMDA_PMID(CLUSTER_XFS,136), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.alloc */ { &proc_fs_xfs.xs_ibt_2_alloc, { PMDA_PMID(CLUSTER_XFS,137), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.free */ { &proc_fs_xfs.xs_ibt_2_free, { PMDA_PMID(CLUSTER_XFS,138), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* xfs.btree.inode.moves */ { &proc_fs_xfs.xs_ibt_2_moves, { PMDA_PMID(CLUSTER_XFS,139), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* quota.state.project.accounting */ { NULL, { PMDA_PMID(CLUSTER_QUOTA,0), PM_TYPE_U32, FILESYS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* quota.state.project.enforcement */ { NULL, { PMDA_PMID(CLUSTER_QUOTA,1), PM_TYPE_U32, FILESYS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* quota.project.space.hard */ { NULL, { PMDA_PMID(CLUSTER_QUOTA,6), PM_TYPE_U64, QUOTA_PRJ_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* quota.project.space.soft */ { NULL, { PMDA_PMID(CLUSTER_QUOTA,7), PM_TYPE_U64, QUOTA_PRJ_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* quota.project.space.used */ { NULL, { PMDA_PMID(CLUSTER_QUOTA,8), PM_TYPE_U64, QUOTA_PRJ_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* quota.project.space.time_left */ { NULL, { PMDA_PMID(CLUSTER_QUOTA,9), PM_TYPE_32, QUOTA_PRJ_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, }, /* quota.project.files.hard */ { NULL, { PMDA_PMID(CLUSTER_QUOTA,10), PM_TYPE_U64, QUOTA_PRJ_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* quota.project.files.soft */ { NULL, { PMDA_PMID(CLUSTER_QUOTA,11), PM_TYPE_U64, QUOTA_PRJ_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* quota.project.files.used */ { NULL, { PMDA_PMID(CLUSTER_QUOTA,12), PM_TYPE_U64, QUOTA_PRJ_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* quota.project.files.time_left */ { NULL, { PMDA_PMID(CLUSTER_QUOTA,13), PM_TYPE_32, QUOTA_PRJ_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, }, }; static void xfs_refresh(pmdaExt *pmda, int *need_refresh) { if (need_refresh[CLUSTER_QUOTA]) refresh_filesys(INDOM(FILESYS_INDOM), INDOM(QUOTA_PRJ_INDOM)); if (need_refresh[CLUSTER_XFS] || need_refresh[CLUSTER_XFSBUF]) refresh_proc_fs_xfs(&proc_fs_xfs); } static int xfs_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) { __pmInDom_int *indomp = (__pmInDom_int *)&indom; int need_refresh[NUM_CLUSTERS] = { 0 }; if (indomp->serial == FILESYS_INDOM || indomp->serial == QUOTA_PRJ_INDOM) need_refresh[CLUSTER_QUOTA]++; xfs_refresh(pmda, need_refresh); return pmdaInstance(indom, inst, name, result, pmda); } static int xfs_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); struct filesys *fs; int sts; if (mdesc->m_user != NULL) { if ((idp->cluster == CLUSTER_XFS || idp->cluster == CLUSTER_XFSBUF) && proc_fs_xfs.errcode != 0) { /* no values available for XFS metrics */ return 0; } switch (mdesc->m_desc.type) { case PM_TYPE_32: atom->l = *(__int32_t *)mdesc->m_user; break; case PM_TYPE_U32: atom->ul = *(__uint32_t *)mdesc->m_user; break; case PM_TYPE_64: atom->ll = *(__int64_t *)mdesc->m_user; break; case PM_TYPE_U64: atom->ull = *(__uint64_t *)mdesc->m_user; break; case PM_TYPE_FLOAT: atom->f = *(float *)mdesc->m_user; break; case PM_TYPE_DOUBLE: atom->d = *(double *)mdesc->m_user; break; case PM_TYPE_STRING: atom->cp = (char *)mdesc->m_user; break; default: return 0; } } else switch (idp->cluster) { case CLUSTER_XFS: switch (idp->item) { case 79: /* xfs.control.reset */ atom->ul = 0; break; default: return PM_ERR_PMID; } break; case CLUSTER_QUOTA: if (idp->item <= 5) { sts = pmdaCacheLookup(INDOM(FILESYS_INDOM), inst, NULL, (void **)&fs); if (sts < 0) return sts; if (sts != PMDA_CACHE_ACTIVE) return PM_ERR_INST; switch (idp->item) { case 0: /* quota.state.project.accounting */ atom->ul = !!(fs->flags & FSF_QUOT_PROJ_ACC); break; case 1: /* quota.state.project.enforcement */ atom->ul = !!(fs->flags & FSF_QUOT_PROJ_ENF); break; default: return PM_ERR_PMID; } } else if (idp->item <= 13) { struct project *pp; sts = pmdaCacheLookup(INDOM(QUOTA_PRJ_INDOM), inst, NULL, (void **)&pp); if (sts < 0) return sts; if (sts != PMDA_CACHE_ACTIVE) return PM_ERR_INST; switch (idp->item) { case 6: /* quota.project.space.hard */ atom->ull = pp->space_hard >> 1; /* BBs to KB */ break; case 7: /* quota.project.space.soft */ atom->ull = pp->space_soft >> 1; /* BBs to KB */ break; case 8: /* quota.project.space.used */ atom->ull = pp->space_used >> 1; /* BBs to KB */ break; case 9: /* quota.project.space.time_left */ atom->l = pp->space_time_left; break; case 10: /* quota.project.files.hard */ atom->ull = pp->files_hard; break; case 11: /* quota.project.files.soft */ atom->ull = pp->files_soft; break; case 12: /* quota.project.files.used */ atom->ull = pp->files_used; break; case 13: /* quota.project.files.time_left */ atom->l = pp->files_time_left; break; default: return PM_ERR_PMID; } } else return PM_ERR_PMID; break; } return 1; } static int xfs_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i, need_refresh[NUM_CLUSTERS] = { 0 }; for (i = 0; i < numpmid; i++) { __pmID_int *idp = (__pmID_int *)&(pmidlist[i]); if (idp->cluster >= MIN_CLUSTER && idp->cluster < NUM_CLUSTERS) need_refresh[idp->cluster]++; } xfs_refresh(pmda, need_refresh); return pmdaFetch(numpmid, pmidlist, resp, pmda); } static int procfs_zero(const char *filename, pmValueSet *vsp) { FILE *fp; int value; int sts = 0; value = vsp->vlist[0].value.lval; if (value < 0) return PM_ERR_SIGN; fp = fopen(filename, "w"); if (!fp) { sts = PM_ERR_PERMISSION; } else { fprintf(fp, "%d\n", value); fclose(fp); } return sts; } static int xfs_store(pmResult *result, pmdaExt *pmda) { int i; int sts = 0; pmValueSet *vsp; __pmID_int *pmidp; for (i = 0; i < result->numpmid && !sts; i++) { vsp = result->vset[i]; pmidp = (__pmID_int *)&vsp->pmid; if (pmidp->cluster == CLUSTER_XFS && pmidp->item == 79) { if ((sts = procfs_zero("/proc/sys/fs/xfs/stats_clear", vsp)) < 0) break; } else { sts = PM_ERR_PERMISSION; break; } } return sts; } void __PMDA_INIT_CALL xfs_init(pmdaInterface *dp) { if (dp->status != 0) return; dp->version.any.fetch = xfs_fetch; dp->version.any.store = xfs_store; dp->version.any.instance = xfs_instance; pmdaSetFetchCallBack(dp, xfs_fetchCallBack); xfs_indomtab[FILESYS_INDOM].it_indom = FILESYS_INDOM; xfs_indomtab[QUOTA_PRJ_INDOM].it_indom = QUOTA_PRJ_INDOM; pmdaSetFlags(dp, PMDA_EXT_FLAG_HASHED); pmdaInit(dp, xfs_indomtab, sizeof(xfs_indomtab)/sizeof(xfs_indomtab[0]), xfs_metrictab, sizeof(xfs_metrictab)/sizeof(xfs_metrictab[0])); pmdaCacheOp(INDOM(FILESYS_INDOM), PMDA_CACHE_CULL); pmdaCacheOp(INDOM(QUOTA_PRJ_INDOM), PMDA_CACHE_CULL); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n", stderr); exit(1); } int main(int argc, char **argv) { int sep = __pmPathSeparator(); int err = 0; pmdaInterface dispatch; char helppath[MAXPATHLEN]; __pmSetProgname(argv[0]); snprintf(helppath, sizeof(helppath), "%s%c" "xfs" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_3, pmProgname, XFS, "xfs.log", helppath); while (pmdaGetOpt(argc, argv, "D:d:l:?", &dispatch, &err) != EOF) err++; if (err) usage(); pmdaOpenLog(&dispatch); xfs_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/proc_fs_xfs.c0000664000000000000000000002252112272262501017175 0ustar /* * Linux /proc/fs/xfs metrics cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2010 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "proc_fs_xfs.h" int refresh_proc_fs_xfs(proc_fs_xfs_t *proc_fs_xfs) { char buf[4096]; FILE *fp; memset(proc_fs_xfs, 0, sizeof(proc_fs_xfs_t)); if ((fp = fopen("/proc/fs/xfs/stat", "r")) == (FILE *)NULL) { proc_fs_xfs->errcode = -oserror(); } else { proc_fs_xfs->errcode = 0; while (fgets(buf, sizeof(buf), fp) != NULL) { if (strncmp(buf, "extent_alloc ", 13) == 0) sscanf(buf, "extent_alloc %u %u %u %u", &proc_fs_xfs->xs_allocx, &proc_fs_xfs->xs_allocb, &proc_fs_xfs->xs_freex, &proc_fs_xfs->xs_freeb); else if (strncmp(buf, "abt ", 4) == 0) sscanf(buf, "abt %u %u %u %u", &proc_fs_xfs->xs_abt_lookup, &proc_fs_xfs->xs_abt_compare, &proc_fs_xfs->xs_abt_insrec, &proc_fs_xfs->xs_abt_delrec); else if (strncmp(buf, "blk_map ", 8) == 0) sscanf(buf, "blk_map %u %u %u %u %u %u %u", &proc_fs_xfs->xs_blk_mapr, &proc_fs_xfs->xs_blk_mapw, &proc_fs_xfs->xs_blk_unmap, &proc_fs_xfs->xs_add_exlist, &proc_fs_xfs->xs_del_exlist, &proc_fs_xfs->xs_look_exlist, &proc_fs_xfs->xs_cmp_exlist); else if (strncmp(buf, "bmbt ", 5) == 0) sscanf(buf, "bmbt %u %u %u %u", &proc_fs_xfs->xs_bmbt_lookup, &proc_fs_xfs->xs_bmbt_compare, &proc_fs_xfs->xs_bmbt_insrec, &proc_fs_xfs->xs_bmbt_delrec); else if (strncmp(buf, "dir ", 4) == 0) sscanf(buf, "dir %u %u %u %u", &proc_fs_xfs->xs_dir_lookup, &proc_fs_xfs->xs_dir_create, &proc_fs_xfs->xs_dir_remove, &proc_fs_xfs->xs_dir_getdents); else if (strncmp(buf, "trans ", 6) == 0) sscanf(buf, "trans %u %u %u", &proc_fs_xfs->xs_trans_sync, &proc_fs_xfs->xs_trans_async, &proc_fs_xfs->xs_trans_empty); else if (strncmp(buf, "ig ", 3) == 0) sscanf(buf, "ig %u %u %u %u %u %u %u", &proc_fs_xfs->xs_ig_attempts, &proc_fs_xfs->xs_ig_found, &proc_fs_xfs->xs_ig_frecycle, &proc_fs_xfs->xs_ig_missed, &proc_fs_xfs->xs_ig_dup, &proc_fs_xfs->xs_ig_reclaims, &proc_fs_xfs->xs_ig_attrchg); else if (strncmp(buf, "log ", 4) == 0) { sscanf(buf, "log %u %u %u %u %u", &proc_fs_xfs->xs_log_writes, &proc_fs_xfs->xs_log_blocks, &proc_fs_xfs->xs_log_noiclogs, &proc_fs_xfs->xs_log_force, &proc_fs_xfs->xs_log_force_sleep); } else if (strncmp(buf, "push_ail ", 9) == 0) sscanf(buf, "push_ail %u %u %u %u %u %u %u %u %u %u", &proc_fs_xfs->xs_try_logspace, &proc_fs_xfs->xs_sleep_logspace, &proc_fs_xfs->xs_push_ail, &proc_fs_xfs->xs_push_ail_success, &proc_fs_xfs->xs_push_ail_pushbuf, &proc_fs_xfs->xs_push_ail_pinned, &proc_fs_xfs->xs_push_ail_locked, &proc_fs_xfs->xs_push_ail_flushing, &proc_fs_xfs->xs_push_ail_restarts, &proc_fs_xfs->xs_push_ail_flush); else if (strncmp(buf, "xstrat ", 7) == 0) sscanf(buf, "xstrat %u %u", &proc_fs_xfs->xs_xstrat_quick, &proc_fs_xfs->xs_xstrat_split); else if (strncmp(buf, "rw ", 3) == 0) sscanf(buf, "rw %u %u", &proc_fs_xfs->xs_write_calls, &proc_fs_xfs->xs_read_calls); else if (strncmp(buf, "attr ", 5) == 0) sscanf(buf, "attr %u %u %u %u", &proc_fs_xfs->xs_attr_get, &proc_fs_xfs->xs_attr_set, &proc_fs_xfs->xs_attr_remove, &proc_fs_xfs->xs_attr_list); else if (strncmp(buf, "qm ", 3) == 0) sscanf(buf, "qm %u %u %u %u %u %u %u %u", &proc_fs_xfs->xs_qm_dqreclaims, &proc_fs_xfs->xs_qm_dqreclaim_misses, &proc_fs_xfs->xs_qm_dquot_dups, &proc_fs_xfs->xs_qm_dqcachemisses, &proc_fs_xfs->xs_qm_dqcachehits, &proc_fs_xfs->xs_qm_dqwants, &proc_fs_xfs->xs_qm_dqshake_reclaims, &proc_fs_xfs->xs_qm_dqinact_reclaims); else if (strncmp(buf, "icluster ", 9) == 0) sscanf(buf, "icluster %u %u %u", &proc_fs_xfs->xs_iflush_count, &proc_fs_xfs->xs_icluster_flushcnt, &proc_fs_xfs->xs_icluster_flushinode); else if (strncmp(buf, "buf ", 4) == 0) { sscanf(buf, "buf %u %u %u %u %u %u %u %u %u", &proc_fs_xfs->xs_buf_get, &proc_fs_xfs->xs_buf_create, &proc_fs_xfs->xs_buf_get_locked, &proc_fs_xfs->xs_buf_get_locked_waited, &proc_fs_xfs->xs_buf_busy_locked, &proc_fs_xfs->xs_buf_miss_locked, &proc_fs_xfs->xs_buf_page_retries, &proc_fs_xfs->xs_buf_page_found, &proc_fs_xfs->xs_buf_get_read); } else if (strncmp(buf, "vnodes ", 7) == 0) { sscanf(buf, "vnodes %u %u %u %u %u %u %u %u", &proc_fs_xfs->vnodes.vn_active, &proc_fs_xfs->vnodes.vn_alloc, &proc_fs_xfs->vnodes.vn_get, &proc_fs_xfs->vnodes.vn_hold, &proc_fs_xfs->vnodes.vn_rele, &proc_fs_xfs->vnodes.vn_reclaim, &proc_fs_xfs->vnodes.vn_remove, &proc_fs_xfs->vnodes.vn_free); } else if (strncmp(buf, "abtb2 ", 6) == 0) { sscanf(buf, "abtb2 %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", &proc_fs_xfs->xs_abtb_2_lookup, &proc_fs_xfs->xs_abtb_2_compare, &proc_fs_xfs->xs_abtb_2_insrec, &proc_fs_xfs->xs_abtb_2_delrec, &proc_fs_xfs->xs_abtb_2_newroot, &proc_fs_xfs->xs_abtb_2_killroot, &proc_fs_xfs->xs_abtb_2_increment, &proc_fs_xfs->xs_abtb_2_decrement, &proc_fs_xfs->xs_abtb_2_lshift, &proc_fs_xfs->xs_abtb_2_rshift, &proc_fs_xfs->xs_abtb_2_split, &proc_fs_xfs->xs_abtb_2_join, &proc_fs_xfs->xs_abtb_2_alloc, &proc_fs_xfs->xs_abtb_2_free, &proc_fs_xfs->xs_abtb_2_moves); } else if (strncmp(buf, "abtc2 ", 6) == 0) { sscanf(buf, "abtc2 %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", &proc_fs_xfs->xs_abtc_2_lookup, &proc_fs_xfs->xs_abtc_2_compare, &proc_fs_xfs->xs_abtc_2_insrec, &proc_fs_xfs->xs_abtc_2_delrec, &proc_fs_xfs->xs_abtc_2_newroot, &proc_fs_xfs->xs_abtc_2_killroot, &proc_fs_xfs->xs_abtc_2_increment, &proc_fs_xfs->xs_abtc_2_decrement, &proc_fs_xfs->xs_abtc_2_lshift, &proc_fs_xfs->xs_abtc_2_rshift, &proc_fs_xfs->xs_abtc_2_split, &proc_fs_xfs->xs_abtc_2_join, &proc_fs_xfs->xs_abtc_2_alloc, &proc_fs_xfs->xs_abtc_2_free, &proc_fs_xfs->xs_abtc_2_moves); } else if (strncmp(buf, "bmbt2 ", 6) == 0) { sscanf(buf, "bmbt2 %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", &proc_fs_xfs->xs_bmbt_2_lookup, &proc_fs_xfs->xs_bmbt_2_compare, &proc_fs_xfs->xs_bmbt_2_insrec, &proc_fs_xfs->xs_bmbt_2_delrec, &proc_fs_xfs->xs_bmbt_2_newroot, &proc_fs_xfs->xs_bmbt_2_killroot, &proc_fs_xfs->xs_bmbt_2_increment, &proc_fs_xfs->xs_bmbt_2_decrement, &proc_fs_xfs->xs_bmbt_2_lshift, &proc_fs_xfs->xs_bmbt_2_rshift, &proc_fs_xfs->xs_bmbt_2_split, &proc_fs_xfs->xs_bmbt_2_join, &proc_fs_xfs->xs_bmbt_2_alloc, &proc_fs_xfs->xs_bmbt_2_free, &proc_fs_xfs->xs_bmbt_2_moves); } else if (strncmp(buf, "ibt2 ", 5) == 0) { sscanf(buf, "ibt2 %u %u %u %u %u %u %u %u %u %u %u %u %u %u %u", &proc_fs_xfs->xs_ibt_2_lookup, &proc_fs_xfs->xs_ibt_2_compare, &proc_fs_xfs->xs_ibt_2_insrec, &proc_fs_xfs->xs_ibt_2_delrec, &proc_fs_xfs->xs_ibt_2_newroot, &proc_fs_xfs->xs_ibt_2_killroot, &proc_fs_xfs->xs_ibt_2_increment, &proc_fs_xfs->xs_ibt_2_decrement, &proc_fs_xfs->xs_ibt_2_lshift, &proc_fs_xfs->xs_ibt_2_rshift, &proc_fs_xfs->xs_ibt_2_split, &proc_fs_xfs->xs_ibt_2_join, &proc_fs_xfs->xs_ibt_2_alloc, &proc_fs_xfs->xs_ibt_2_free, &proc_fs_xfs->xs_ibt_2_moves); } else if (strncmp(buf, "xpc", 3) == 0) sscanf(buf, "xpc %llu %llu %llu", (unsigned long long *)&proc_fs_xfs->xpc.xs_xstrat_bytes, (unsigned long long *)&proc_fs_xfs->xpc.xs_write_bytes, (unsigned long long *)&proc_fs_xfs->xpc.xs_read_bytes); } fclose(fp); if (proc_fs_xfs->xs_log_writes) proc_fs_xfs->xs_log_write_ratio = proc_fs_xfs->xs_log_blocks / proc_fs_xfs->xs_log_writes; /* * Bug #824382. xs_log_blocks is counted in units * of 512 bytes/block, but PCP exports it as Kbytes. */ proc_fs_xfs->xs_log_blocks >>= 1; fp = fopen("/proc/fs/xfs/xqmstat", "r"); if (fp != (FILE *)NULL) { if (fgets(buf, sizeof(buf), fp) != NULL) { if (strncmp(buf, "qm", 2) == 0) sscanf(buf, "qm %u %u %u %u %u %u %u %u", &proc_fs_xfs->xs_qm_dqreclaims, &proc_fs_xfs->xs_qm_dqreclaim_misses, &proc_fs_xfs->xs_qm_dquot_dups, &proc_fs_xfs->xs_qm_dqcachemisses, &proc_fs_xfs->xs_qm_dqcachehits, &proc_fs_xfs->xs_qm_dqwants, &proc_fs_xfs->xs_qm_dqshake_reclaims, &proc_fs_xfs->xs_qm_dqinact_reclaims); } fclose(fp); } } if (proc_fs_xfs->errcode == 0) return 0; return -1; } pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/help0000664000000000000000000005603612272262501015401 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2004-2008 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Linux XFS PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ xfs.allocs.alloc_extent XFS extents allocated Number of file system extents allocated over all XFS filesystems @ xfs.allocs.alloc_block XFS blocks allocated Number of file system blocks allocated over all XFS filesystems @ xfs.allocs.free_extent XFS extents freed Number of file system extents freed over all XFS filesystems @ xfs.allocs.free_block XFS blocks freed Number of file system blocks freed over all XFS filesystems @ xfs.alloc_btree.lookup lookups in XFS alloc btrees Number of lookup operations in XFS filesystem allocation btrees @ xfs.alloc_btree.compare compares in XFS alloc btrees Number of compares in XFS filesystem allocation btree lookups @ xfs.alloc_btree.insrec insertions in XFS alloc btrees Number of extent records inserted into XFS filesystem allocation btrees @ xfs.alloc_btree.delrec deletions in XFS alloc btrees Number of extent records deleted from XFS filesystem allocation btrees @ xfs.block_map.read_ops block map read ops in XFS Number of block map for read operations performed on XFS files @ xfs.block_map.write_ops block map write ops in XFS Number of block map for write operations performed on XFS files @ xfs.block_map.unmap block unmap ops in XFS Number of block unmap (delete) operations performed on XFS files @ xfs.block_map.add_exlist extent list add ops in XFS Number of extent list insertion operations for XFS files @ xfs.block_map.del_exlist extent list delete ops in XFS Number of extent list deletion operations for XFS files @ xfs.block_map.look_exlist extent list lookup ops in XFS Number of extent list lookup operations for XFS files @ xfs.block_map.cmp_exlist extent list compare ops in XFS Number of extent list comparisons in XFS extent list lookups @ xfs.bmap_btree.lookup block map btree lookup ops in XFS Number of block map btree lookup operations on XFS files @ xfs.bmap_btree.compare block map btree compare ops in XFS Number of block map btree compare operations in XFS block map lookups @ xfs.bmap_btree.insrec block map btree insert ops in XFS Number of block map btree records inserted for XFS files @ xfs.bmap_btree.delrec block map btree delete ops in XFS Number of block map btree records deleted for XFS files @ xfs.dir_ops.lookup number of file name directory lookups This is a count of the number of file name directory lookups in XFS filesystems. It counts only those lookups which miss in the operating system's directory name lookup cache and must search the real directory structure for the name in question. The count is incremented once for each level of a pathname search that results in a directory lookup. @ xfs.dir_ops.create number of directory entry creation operations This is the number of times a new directory entry was created in XFS filesystems. Each time that a new file, directory, link, symbolic link, or special file is created in the directory hierarchy the count is incremented. @ xfs.dir_ops.remove number of directory entry remove operations This is the number of times an existing directory entry was removed in XFS filesystems. Each time that a file, directory, link, symbolic link, or special file is removed from the directory hierarchy the count is incremented. @ xfs.dir_ops.getdents number of times the getdents operation is performed This is the number of times the XFS directory getdents operation was performed. The getdents operation is used by programs to read the contents of directories in a file system independent fashion. This count corresponds exactly to the number of times the getdents(2) system call was successfully used on an XFS directory. @ xfs.transactions.sync number of synchronous meta-data transactions performed This is the number of meta-data transactions which waited to be committed to the on-disk log before allowing the process performing the transaction to continue. These transactions are slower and more expensive than asynchronous transactions, because they force the in memory log buffers to be forced to disk more often and they wait for the completion of the log buffer writes. @ xfs.transactions.async number of asynchronous meta-data transactions performed This is the number of meta-data transactions which did not wait to be committed to the on-disk log before allowing the process performing the transaction to continue. These transactions are faster and more efficient than synchronous transactions, because they commit their data to the in memory log buffers without forcing those buffers to be written to disk. This allows multiple asynchronous transactions to be committed to disk in a single log buffer write. Most transactions used in XFS file systems are asynchronous. @ xfs.transactions.empty number of meta-data transactions which committed without changing anything This is the number of meta-data transactions which did not actually change anything. These are transactions which were started for some purpose, but in the end it turned out that no change was necessary. @ xfs.inode_ops.ig_attempts number of in memory inode lookup operations This is the number of times the operating system looked for an XFS inode in the inode cache. Whether the inode was found in the cache or needed to be read in from the disk is not indicated here, but this can be computed from the ig_found and ig_missed counts. @ xfs.inode_ops.ig_found number of successful in memory inode lookup operations This is the number of times the operating system looked for an XFS inode in the inode cache and found it. The closer this count is to the ig_attempts count the better the inode cache is performing. @ xfs.inode_ops.ig_frecycle number of just missed in memory inode lookup operations This is the number of times the operating system looked for an XFS inode in the inode cache and saw that it was there but was unable to use the in memory inode because it was being recycled by another process. @ xfs.inode_ops.ig_missed number of failed in memory inode lookup operations This is the number of times the operating system looked for an XFS inode in the inode cache and the inode was not there. The further this count is from the ig_attempts count the better. @ xfs.inode_ops.ig_dup number of inode cache insertions that fail because the inode is there This is the number of times the operating system looked for an XFS inode in the inode cache and found that it was not there but upon attempting to add the inode to the cache found that another process had already inserted it. @ xfs.inode_ops.ig_reclaims number of in memory inode recycle operations This is the number of times the operating system recycled an XFS inode from the inode cache in order to use the memory for that inode for another purpose. Inodes are recycled in order to keep the inode cache from growing without bound. If the reclaim rate is high it may be beneficial to raise the vnode_free_ratio kernel tunable variable to increase the size of inode cache. @ xfs.inode_ops.ig_attrchg number of inode attribute change operations This is the number of times the operating system explicitly changed the attributes of an XFS inode. For example, this could be to change the inode's owner, the inode's size, or the inode's timestamps. @ xfs.log.writes number of buffer writes going to the disk from the log This variable counts the number of log buffer writes going to the physical log partitions of all XFS filesystems. Log data traffic is proportional to the level of meta-data updating. Log buffer writes get generated when they fill up or external syncs occur. @ xfs.log.blocks write throughput to the physical XFS log This variable counts the number of Kbytes of information being written to the physical log partitions of all XFS filesystems. Log data traffic is proportional to the level of meta-data updating. The rate with which log data gets written depends on the size of internal log buffers and disk write speed. Therefore, filesystems with very high meta-data updating may need to stripe the log partition or put the log partition on a separate drive. @ xfs.log.write_ratio ratio of count of XFS log blocks written to log writes The ratio of log blocks written to log writes. If block count isn't a "reasonable" multiple of writes, then many small log writes are being performed - this is suboptimal. Perfection is 64. Fine-grain control can be obtained when this metric is used in conjuntion with pmstore(1) and the xfs.control.reset metric. @ xfs.log.noiclogs count of failures for immediate get of buffered/internal This variable keeps track of times when a logged transaction can not get any log buffer space. When this occurs, all of the internal log buffers are busy flushing their data to the physical on-disk log. @ xfs.log.force value from xs_log_force field of struct xfsstats The number of times the in-core log is forced to disk. It is equivalent to the number of successful calls to the function xfs_log_force(). @ xfs.log.force_sleep value from xs_log_force_sleep field of struct xfsstats This metric is exported from the xs_log_force_sleep field of struct xfsstats @ xfs.log_tail.try_logspace value from xs_try_logspace field of struct xfsstats This metric is exported from the xs_try_logspace field of struct xfsstats @ xfs.log_tail.sleep_logspace value from xs_sleep_logspace field of struct xfsstats This metric is exported from the xs_sleep_logspace field of struct xfsstats @ xfs.log_tail.push_ail.pushes number of times the AIL tail is moved forward The number of times the tail of the AIL is moved forward. It is equivalent to the number of successful calls to the function xfs_trans_push_ail(). @ xfs.log_tail.push_ail.success value from xs_push_ail_success field of struct xfsstats @ xfs.log_tail.push_ail.pushbuf value from xs_push_ail_pushbuf field of struct xfsstats @ xfs.log_tail.push_ail.pinned value from xs_push_ail_pinned field of struct xfsstats @ xfs.log_tail.push_ail.locked value from xs_push_ail_locked field of struct xfsstats @ xfs.log_tail.push_ail.flushing value from xs_push_ail_flushing field of struct xfsstats @ xfs.log_tail.push_ail.restarts value from xs_push_ail_restarts field of struct xfsstats @ xfs.log_tail.push_ail.flush value from xs_push_ail_flush field of struct xfsstats @ xfs.xstrat.bytes number of bytes of data processed by the XFS daemons This is the number of bytes of file data flushed out by the XFS flushing daemons. @ xfs.xstrat.quick number of buffers processed by the XFS daemons written to contiguous space on disk This is the number of buffers flushed out by the XFS flushing daemons which are written to contiguous space on disk. The buffers handled by the XFS daemons are delayed allocation buffers, so this count gives an indication of the success of the XFS daemons in allocating contiguous disk space for the data being flushed to disk. @ xfs.xstrat.split number of buffers processed by the XFS daemons written to non-contiguous space on disk This is the number of buffers flushed out by the XFS flushing daemons which are written to non-contiguous space on disk. The buffers handled by the XFS daemons are delayed allocation buffers, so this count gives an indication of the failure of the XFS daemons in allocating contiguous disk space for the data being flushed to disk. Large values in this counter indicate that the file system has become fragmented. @ xfs.write number of XFS file system write operations This is the number of write(2) system calls made to files in XFS file systems. @ xfs.write_bytes number of bytes written in XFS file system write operations This is the number of bytes written via write(2) system calls to files in XFS file systems. It can be used in conjunction with the write_calls count to calculate the average size of the write operations to files in XFS file systems. @ xfs.read number of XFS file system read operations This is the number of read(2) system calls made to files in XFS file systems. @ xfs.read_bytes number of bytes read in XFS file system read operations This is the number of bytes read via read(2) system calls to files in XFS file systems. It can be used in conjunction with the read_calls count to calculate the average size of the read operations to files in XFS file systems. @ xfs.attr.get number of "get" operations on XFS extended file attributes The number of "get" operations performed on extended file attributes within XFS filesystems. The "get" operation retrieves the value of an extended attribute. @ xfs.attr.set number of "set" operations on XFS extended file attributes The number of "set" operations performed on extended file attributes within XFS filesystems. The "set" operation creates and sets the value of an extended attribute. @ xfs.attr.remove number of "remove" operations on XFS extended file attributes The number of "remove" operations performed on extended file attributes within XFS filesystems. The "remove" operation deletes an extended attribute. @ xfs.attr.list number of "list" operations on XFS extended file attributes The number of "list" operations performed on extended file attributes within XFS filesystems. The "list" operation retrieves the set of extended attributes associated with a file. @ xfs.quota.reclaims value from xs_qm_dqreclaims field of struct xfsstats @ xfs.quota.reclaim_misses value from xs_qm_dqreclaim_misses field of struct xfsstats @ xfs.quota.dquot_dups value from xs_qm_dquot_dups field of struct xfsstats @ xfs.quota.cachemisses value from xs_qm_dqcachemisses field of struct xfsstats @ xfs.quota.cachehits value from xs_qm_dqcachehits field of struct xfsstats @ xfs.quota.wants value from xs_qm_dqwants field of struct xfsstats @ xfs.quota.shake_reclaims value from xs_qm_dqshake_reclaims field of struct xfsstats @ xfs.quota.inact_reclaims value from xs_qm_dqinact_reclaims field of struct xfsstats @ xfs.iflush_count the number of calls to xfs_iflush This is the number of calls to xfs_iflush which gets called when an inode is being flushed (such as by bdflush or tail pushing). xfs_iflush searches for other inodes in the same cluster which are dirty and flushable. @ xfs.icluster_flushcnt value from xs_icluster_flushcnt field of struct xfsstats @ xfs.icluster_flushinode number of flushes of only one inode in cluster This is the number of times that the inode clustering was not able to flush anything but the one inode it was called with. @ xfs.buffer.get number of request buffer calls @ xfs.buffer.create number of buffers created @ xfs.buffer.get_locked number of requests for a locked buffer which succeeded @ xfs.buffer.get_locked_waited number of requests for a locked buffer which waited @ xfs.buffer.miss_locked number of requests for a locked buffer which failed due to no buffer @ xfs.buffer.busy_locked number of non-blocking requests for a locked buffer which failed @ xfs.buffer.page_retries number of retry attempts when allocating a page for insertion in a buffer @ xfs.buffer.page_found number of hits in the page cache when looking for a page @ xfs.buffer.get_read number of buffer get calls requiring immediate device reads @ xfs.vnodes.active number of vnodes not on free lists @ xfs.vnodes.alloc number of times vn_alloc called @ xfs.vnodes.get number of times vn_get called @ xfs.vnodes.hold number of times vn_hold called @ xfs.vnodes.rele number of times vn_rele called @ xfs.vnodes.reclaim number of times vn_reclaim called @ xfs.vnodes.remove number of times vn_remove called @ xfs.vnodes.free number of times vn_free called @ xfs.control.reset reset the values of all XFS metrics to zero @ quota.state.project.accounting 1 indicates quota accounting enabled, else 0 @ quota.state.project.enforcement 1 indicates quotas enforced, else 0 @ quota.project.space.hard hard limit for this project and filesys in Kbytes @ quota.project.space.soft soft limit for this project and filesys in Kbytes @ quota.project.space.used space used for this project and filesys in Kbytes @ quota.project.space.time_left when soft limit is exceeded, seconds until it is enacted @ quota.project.files.hard file count hard limit for this project and filesys @ quota.project.files.soft file count soft limit for this project and filesys @ quota.project.files.used file count for this project and filesys @ quota.project.files.time_left when soft limit is exceeded, seconds until it is enacted @ xfs.btree.alloc_blocks.lookup Number of free-space-by-block-number btree record lookups @ xfs.btree.alloc_blocks.compare Number of free-space-by-block-number btree record compares @ xfs.btree.alloc_blocks.insrec Number of free-space-by-block-number btree insert record operations executed @ xfs.btree.alloc_blocks.delrec Number of free-space-by-block-number btree delete record operations executed @ xfs.btree.alloc_blocks.newroot Number of times a new level is added to a free-space-by-block-number btree @ xfs.btree.alloc_blocks.killroot Number of times a level is removed from a free-space-by-block-number btree @ xfs.btree.alloc_blocks.increment Number of times a cursor has been moved forward one free-space-by-block-number btree record @ xfs.btree.alloc_blocks.decrement Number of times a cursor has been moved backward one free-space-by-block-number btree record @ xfs.btree.alloc_blocks.lshift Left shift block operations to make space for a new free-space-by-block-number btree record @ xfs.btree.alloc_blocks.rshift Right shift block operations to make space for a new free-space-by-block-number btree record @ xfs.btree.alloc_blocks.split Split block operations to make space for a new free-space-by-block-number btree record @ xfs.btree.alloc_blocks.join Merge block operations when deleting free-space-by-block-number btree records @ xfs.btree.alloc_blocks.alloc Btree block allocations during free-space-by-block-number btree operations @ xfs.btree.alloc_blocks.free Btree blocks freed during free-space-by-block-number btree operations @ xfs.btree.alloc_blocks.moves Records moved inside blocks during free-space-by-block-number btree operations @ xfs.btree.alloc_contig.lookup Number of free-space-by-size btree record lookups @ xfs.btree.alloc_contig.compare Number of free-space-by-size btree btree record compares @ xfs.btree.alloc_contig.insrec Number of free-space-by-size btree insert record operations executed @ xfs.btree.alloc_contig.delrec Number of free-space-by-size btree delete record operations executed @ xfs.btree.alloc_contig.newroot Number of times a new level is added to a free-space-by-size btree tree @ xfs.btree.alloc_contig.killroot Number of times a level is removed from a free-space-by-size btree tree @ xfs.btree.alloc_contig.increment Number of times a free-space-by-size btree cursor has been moved forward one record @ xfs.btree.alloc_contig.decrement Number of times a free-space-by-size btree cursor has been moved backward one record @ xfs.btree.alloc_contig.lshift Left shift block operations to make space for a new free-space-by-size btree record @ xfs.btree.alloc_contig.rshift Right shift block operations to make space for a new free-space-by-size btree record @ xfs.btree.alloc_contig.split Split block operations to make space for a new free-space-by-size btree record @ xfs.btree.alloc_contig.join Merge block operations when deleting free-space-by-size btree records @ xfs.btree.alloc_contig.alloc Btree block allocations during free-space-by-size btree operations @ xfs.btree.alloc_contig.free Btree blocks freed during free-space-by-size btree operations @ xfs.btree.alloc_contig.moves Records moved inside blocks during free-space-by-size btree operations @ xfs.btree.block_map.lookup Number of inode-block-map/extent btree record lookups @ xfs.btree.block_map.compare Number of inode-block-map/extent btree record compares @ xfs.btree.block_map.insrec Number of inode-block-map/extent btree insert record operations executed @ xfs.btree.block_map.delrec Number of inode-block-map/extent btree delete record operations executed @ xfs.btree.block_map.newroot Number of times a new level is added to an inode-block-map/extent btree @ xfs.btree.block_map.killroot Number of times a level is removed from an inode-block-map/extent btree @ xfs.btree.block_map.increment Number of times an inode-block-map/extent btree cursor has been moved forward one record @ xfs.btree.block_map.decrement Number of times an inode-block-map/extent btree cursor has been moved backward one record @ xfs.btree.block_map.lshift Left shift block operations to make space for a new inode-block-map/extent btree record @ xfs.btree.block_map.rshift Right shift block operations to make space for a new inode-block-map/extent btree record @ xfs.btree.block_map.split Split block operations to make space for a new inode-block-map/extent btree record @ xfs.btree.block_map.join Merge block operations when deleting inode-block-map/extent btree records @ xfs.btree.block_map.alloc Btree block allocations during inode-block-map/extent btree operations @ xfs.btree.block_map.free Btree blocks freed during inode-block-map/extent btree operations @ xfs.btree.block_map.moves Records moved inside blocks during inode-block-map/extent btree operations @ xfs.btree.inode.lookup Number of inode-allocation btree record lookups @ xfs.btree.inode.compare Number of inode-allocation btree record compares @ xfs.btree.inode.insrec Number of inode-allocation btree insert record operations executed @ xfs.btree.inode.delrec Number of inode-allocation btree delete record operations executed @ xfs.btree.inode.newroot Number of times a new level is added to an inode-allocation btree @ xfs.btree.inode.killroot Number of times a level is removed from an inode-allocation btree @ xfs.btree.inode.increment Number of times a cursor has been moved forward one inode-allocation btree record @ xfs.btree.inode.decrement Number of times a cursor has been moved backward one inode-allocation btree record @ xfs.btree.inode.lshift Left shift block operations to make space for a new inode-allocation btree record @ xfs.btree.inode.rshift Right shift block operations to make space for a new inode-allocation btree record @ xfs.btree.inode.split Split block operations to make space for a new inode-allocation btree record @ xfs.btree.inode.join Merge block operations when deleting inode-allocation btree records @ xfs.btree.inode.alloc Btree block allocations during inode-allocation btree operations @ xfs.btree.inode.free Btree blocks freed during inode-allocation btree operations @ xfs.btree.inode.moves Records moved inside blocks during inode-allocation btree operations pcp-3.8.12ubuntu1/src/pmdas/linux_xfs/proc_fs_xfs.h0000664000000000000000000002303412272262501017202 0ustar /* * Linux /proc/fs/xfs metrics cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2010 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ typedef struct { int errcode; /* error from previous refresh */ unsigned int xs_allocx; /* allocs.alloc_extent */ unsigned int xs_allocb; /* allocs.alloc_block */ unsigned int xs_freex; /* allocs.free_extent */ unsigned int xs_freeb; /* allocs.free_block */ unsigned int xs_abt_lookup; /* alloc_btree.lookup */ unsigned int xs_abt_compare; /* alloc_btree.compare */ unsigned int xs_abt_insrec; /* alloc_btree.insrec */ unsigned int xs_abt_delrec; /* alloc_btree.delrec */ unsigned int xs_blk_mapr; /* block_map.read_ops */ unsigned int xs_blk_mapw; /* block_map.write_ops */ unsigned int xs_blk_unmap; /* block_map.unmap */ unsigned int xs_add_exlist; /* block_map.add_exlist */ unsigned int xs_del_exlist; /* block_map.del_exlist */ unsigned int xs_look_exlist; /* block_map.look_exlist */ unsigned int xs_cmp_exlist; /* block_map.cmp_exlist */ unsigned int xs_bmbt_lookup; /* bmap_btree.lookup */ unsigned int xs_bmbt_compare; /* bmap_btree.compare */ unsigned int xs_bmbt_insrec; /* bmap_btree.insrec */ unsigned int xs_bmbt_delrec; /* bmap_btree.delrec */ unsigned int xs_dir_lookup; /* dir_ops.lookup */ unsigned int xs_dir_create; /* dir_ops.create */ unsigned int xs_dir_remove; /* dir_ops.remove */ unsigned int xs_dir_getdents; /* dir_ops.getdents */ unsigned int xs_trans_sync; /* transactions.sync */ unsigned int xs_trans_async; /* transactions.async */ unsigned int xs_trans_empty; /* transactions.empty */ unsigned int xs_ig_attempts; /* inode_ops.ig_attempts */ unsigned int xs_ig_found; /* inode_ops.ig_found */ unsigned int xs_ig_frecycle; /* inode_ops.ig_frecycle */ unsigned int xs_ig_missed; /* inode_ops.ig_missed */ unsigned int xs_ig_dup; /* inode_ops.ig_dup */ unsigned int xs_ig_reclaims; /* inode_ops.ig_reclaims */ unsigned int xs_ig_attrchg; /* inode_ops.ig_attrchg */ unsigned int xs_log_writes; /* log.writes */ unsigned int xs_log_blocks; /* log.blocks */ float xs_log_write_ratio; /* log.write_ratio */ unsigned int xs_log_noiclogs; /* log.noiclogs */ unsigned int xs_xstrat_quick; /* xstrat.quick */ unsigned int xs_xstrat_split; /* xstrat.split */ unsigned int xs_write_calls; /* write */ unsigned int xs_read_calls; /* read */ unsigned int xs_attr_get; /* attr.get */ unsigned int xs_attr_set; /* attr.set */ unsigned int xs_attr_remove; /* attr.remove */ unsigned int xs_attr_list; /* attr.list */ unsigned int xs_log_force; /* log.force */ unsigned int xs_log_force_sleep; /* log.force_sleep */ unsigned int xs_try_logspace; /* log_tail.try_logspace */ unsigned int xs_sleep_logspace; /* log_tail.sleep_logspace */ unsigned int xs_push_ail; /* log_tail.push_ail.pushes */ unsigned int xs_push_ail_success; /* log_tail.push_ail.success */ unsigned int xs_push_ail_pushbuf; /* log_tail.push_ail.pushbuf */ unsigned int xs_push_ail_pinned; /* log_tail.push_ail.pinned */ unsigned int xs_push_ail_locked; /* log_tail.push_ail.locked */ unsigned int xs_push_ail_flushing; /* log_tail.push_ail.flushing */ unsigned int xs_push_ail_restarts; /* log_tail.push_ail.restarts */ unsigned int xs_push_ail_flush; /* log_tail.push_ail.flush */ unsigned int xs_qm_dqreclaims; /* quota.reclaims */ unsigned int xs_qm_dqreclaim_misses; /* quota.reclaim_misses */ unsigned int xs_qm_dquot_dups; /* quota.dquot_dups */ unsigned int xs_qm_dqcachemisses; /* quota.cachemisses */ unsigned int xs_qm_dqcachehits; /* quota.cachehits */ unsigned int xs_qm_dqwants; /* quota.wants */ unsigned int xs_qm_dqshake_reclaims; /* quota.shake_reclaims */ unsigned int xs_qm_dqinact_reclaims; /* quota.inact_reclaims */ unsigned int xs_iflush_count; /* iflush_count */ unsigned int xs_icluster_flushcnt; /* icluster_flushcnt */ unsigned int xs_icluster_flushinode; /* icluster_flushinode */ unsigned int xs_buf_get; /* buffer.get */ unsigned int xs_buf_create; /* buffer.create */ unsigned int xs_buf_get_locked; /* buffer.get_locked */ unsigned int xs_buf_get_locked_waited; /* buffer.get_locked_waited */ unsigned int xs_buf_busy_locked; /* buffer.busy_locked */ unsigned int xs_buf_miss_locked; /* buffer.miss_locked */ unsigned int xs_buf_page_retries; /* buffer.page_retries */ unsigned int xs_buf_page_found; /* buffer.page_found */ unsigned int xs_buf_get_read; /* buffer.get_read */ unsigned int xs_abtb_2_lookup; /* btree.alloc_blocks.lookup */ unsigned int xs_abtb_2_compare; /* btree.alloc_blocks.compare */ unsigned int xs_abtb_2_insrec; /* btree.alloc_blocks.insrec */ unsigned int xs_abtb_2_delrec; /* btree.alloc_blocks.delrec */ unsigned int xs_abtb_2_newroot; /* btree.alloc_blocks.newroot */ unsigned int xs_abtb_2_killroot; /* btree.alloc_blocks.killroot */ unsigned int xs_abtb_2_increment; /* btree.alloc_blocks.increment */ unsigned int xs_abtb_2_decrement; /* btree.alloc_blocks.decrement */ unsigned int xs_abtb_2_lshift; /* btree.alloc_blocks.lshift */ unsigned int xs_abtb_2_rshift; /* btree.alloc_blocks.rshift */ unsigned int xs_abtb_2_split; /* btree.alloc_blocks.split */ unsigned int xs_abtb_2_join; /* btree.alloc_blocks.join */ unsigned int xs_abtb_2_alloc; /* btree.alloc_blocks.alloc */ unsigned int xs_abtb_2_free; /* btree.alloc_blocks.free */ unsigned int xs_abtb_2_moves; /* btree.alloc_blocks.moves */ unsigned int xs_abtc_2_lookup; /* btree.alloc_contig.lookup */ unsigned int xs_abtc_2_compare; /* btree.alloc_contig.compare */ unsigned int xs_abtc_2_insrec; /* btree.alloc_contig.insrec */ unsigned int xs_abtc_2_delrec; /* btree.alloc_contig.delrec */ unsigned int xs_abtc_2_newroot; /* btree.alloc_contig.newroot */ unsigned int xs_abtc_2_killroot; /* btree.alloc_contig.killroot */ unsigned int xs_abtc_2_increment; /* btree.alloc_contig.increment */ unsigned int xs_abtc_2_decrement; /* btree.alloc_contig.decrement */ unsigned int xs_abtc_2_lshift; /* btree.alloc_contig.lshift */ unsigned int xs_abtc_2_rshift; /* btree.alloc_contig.rshift */ unsigned int xs_abtc_2_split; /* btree.alloc_contig.split */ unsigned int xs_abtc_2_join; /* btree.alloc_contig.join */ unsigned int xs_abtc_2_alloc; /* btree.alloc_contig.alloc */ unsigned int xs_abtc_2_free; /* btree.alloc_contig.free */ unsigned int xs_abtc_2_moves; /* btree.alloc_contig.moves */ unsigned int xs_bmbt_2_lookup; /* btree.block_map.lookup */ unsigned int xs_bmbt_2_compare; /* btree.block_map.compare */ unsigned int xs_bmbt_2_insrec; /* btree.block_map.insrec */ unsigned int xs_bmbt_2_delrec; /* btree.block_map.delrec */ unsigned int xs_bmbt_2_newroot; /* btree.block_map.newroot */ unsigned int xs_bmbt_2_killroot; /* btree.block_map.killroot */ unsigned int xs_bmbt_2_increment; /* btree.block_map.increment */ unsigned int xs_bmbt_2_decrement; /* btree.block_map.decrement */ unsigned int xs_bmbt_2_lshift; /* btree.block_map.lshift */ unsigned int xs_bmbt_2_rshift; /* btree.block_map.rshift */ unsigned int xs_bmbt_2_split; /* btree.block_map.split */ unsigned int xs_bmbt_2_join; /* btree.block_map.join */ unsigned int xs_bmbt_2_alloc; /* btree.block_map.alloc */ unsigned int xs_bmbt_2_free; /* btree.block_map.free */ unsigned int xs_bmbt_2_moves; /* btree.block_map.moves */ unsigned int xs_ibt_2_lookup; /* btree.inode.lookup */ unsigned int xs_ibt_2_compare; /* btree.inode.compare */ unsigned int xs_ibt_2_insrec; /* btree.inode.insrec */ unsigned int xs_ibt_2_delrec; /* btree.inode.delrec */ unsigned int xs_ibt_2_newroot; /* btree.inode.newroot */ unsigned int xs_ibt_2_killroot; /* btree.inode.killroot */ unsigned int xs_ibt_2_increment; /* btree.inode.increment */ unsigned int xs_ibt_2_decrement; /* btree.inode.decrement */ unsigned int xs_ibt_2_lshift; /* btree.inode.lshift */ unsigned int xs_ibt_2_rshift; /* btree.inode.rshift */ unsigned int xs_ibt_2_split; /* btree.inode.split */ unsigned int xs_ibt_2_join; /* btree.inode.join */ unsigned int xs_ibt_2_alloc; /* btree.inode.alloc */ unsigned int xs_ibt_2_free; /* btree.inode.free */ unsigned int xs_ibt_2_moves; /* btree.inode.moves */ struct vnodes { unsigned int vn_active; /* vnodes.active */ unsigned int vn_alloc; /* vnodes.alloc */ unsigned int vn_get; /* vnodes.get */ unsigned int vn_hold; /* vnodes.hold */ unsigned int vn_rele; /* vnodes.rele */ unsigned int vn_reclaim; /* vnodes.reclaim */ unsigned int vn_remove; /* vnodes.remove */ unsigned int vn_free; /* vnodes.free */ } vnodes; struct xpc { __uint64_t xs_write_bytes; /* write_bytes */ __uint64_t xs_read_bytes; /* read_bytes */ __uint64_t xs_xstrat_bytes; /* xstrat_bytes */ } xpc; } proc_fs_xfs_t; extern int refresh_proc_fs_xfs(proc_fs_xfs_t *); pcp-3.8.12ubuntu1/src/pmdas/elasticsearch/0000775000000000000000000000000012272262620015311 5ustar pcp-3.8.12ubuntu1/src/pmdas/elasticsearch/Remove0000775000000000000000000000130312272262501016467 0ustar #! /bin/sh # # Copyright (c) 2011-2012 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the ElasticSearch PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=elasticsearch pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/elasticsearch/Install0000775000000000000000000000165312272262501016650 0ustar #!/bin/sh # # Copyright (c) 2011-2012 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the ElasticSearch PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=elasticsearch perl_opt=true daemon_opt=false forced_restart=false for module in JSON LWP::UserAgent do perl -e "use $module" 2>/dev/null if test $? -ne 0 then echo "$module perl module is not installed" exit 1 fi done pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/elasticsearch/GNUmakefile0000664000000000000000000000273212272262501017365 0ustar #!gmake # # Copyright (c) 2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = elasticsearch DOMAIN = ELASTICSEARCH PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif LDIRT = domain.h root pmns *.log $(MAN_PAGES) default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/elasticsearch/pmdaelasticsearch.pl0000775000000000000000000010552512272262501021333 0ustar # # Copyright (c) 2011-2013 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use JSON; use PCP::PMDA; use LWP::UserAgent; my $es_port = 9200; my $es_instance = 'localhost'; use vars qw($pmda $http $es_cluster $es_nodes $es_nodestats $es_root $es_searchstats $es_cluster_state); my $nodes_indom = 0; my @nodes_instances; my @nodes_instance_ids; my $search_indom = 1; my @search_instances; my @search_instance_ids; my $index_indom = 2; my @index_instances; my @index_instance_ids; my @cluster_cache; # time of last refresh for each cluster my $cache_interval = 2; # min secs between refreshes for clusters my $http_timeout = 1; # max secs for a request (*must* be small). # Configuration files for overriding the above settings for my $file (pmda_config('PCP_PMDAS_DIR') . '/elasticsearch/es.conf', 'es.conf') { eval `cat $file` unless ! -f $file; } my $baseurl = "http://$es_instance:$es_port/"; my $http = LWP::UserAgent->new; $http->agent('pmdaelasticsearch'); $http->timeout($http_timeout); # if elasticsearch not timely, no soup for you # http GET of elasticsearch json from a given url sub es_agent_get { my $response = $http->get(shift); return undef unless $response->is_success; return $response->decoded_content; } # crack json data structure, extract only data-node names sub es_data_node_instances { my $nodeIDs = shift; my $i = 0; @nodes_instances = (); @nodes_instance_ids = (); foreach my $node (keys %$nodeIDs) { my $attributes = $nodeIDs->{$node}->{'attributes'}; unless (defined($attributes) && $attributes->{'data'} == 'false') { my $name = $nodeIDs->{$node}->{'name'}; $nodes_instances[$i*2] = $i; $nodes_instances[($i*2)+1] = $name; $nodes_instance_ids[$i*2] = $i; $nodes_instance_ids[($i*2)+1] = $node; $i++; # $pmda->log("es_instances added node: $name ($node)"); } } $pmda->replace_indom($nodes_indom, \@nodes_instances); } sub es_data_index_instances { my $indexIDs = shift; my $i = 0; @index_instances = (); @index_instance_ids = (); foreach my $index (keys %$indexIDs){ $index_instances[$i*2] = $i; $index_instances[($i*2)+1] = $index; $index_instance_ids[$i*2] = $i; $index_instance_ids[($i*2)+1] = $index; $i++; } $pmda->replace_indom($index_indom, \@index_instances); } # crack json data structure, extract index names sub es_search_instances { my $searchIDs = shift; my $i = 0; @search_instances = (); @search_instance_ids = (); foreach my $search (keys %$searchIDs) { $search_instances[$i*2] = $i; $search_instances[($i*2)+1] = $search; $search_instance_ids[$i*2] = $i; $search_instance_ids[($i*2)+1] = $search; $i++; # $pmda->log("es_search_instances added index: $search"); } $pmda->replace_indom($search_indom, \@search_instances); } sub es_refresh_cluster_health { my $content = es_agent_get($baseurl . "_cluster/health"); $es_cluster = defined($content) ? decode_json($content) : undef; } # Update the JSON hash of ES indices so we can later map the metric names # much more easily back to the PMID (during the fetch callback routine). # sub es_rewrite_cluster_state { my $indices = $es_cluster_state->{'metadata'}->{'indices'}; foreach my $index_key (keys %$indices) { # Go over each setting key and transpose what the key name is called my $settings = $indices->{$index_key}->{'settings'}; foreach my $settings_key (keys %$settings) { # Convert keys like "index.version.created" to "version_created" my $transformed_key = $settings_key; $transformed_key =~ s/index\.//; $transformed_key =~ s/\./_/g; $settings->{$transformed_key} = $settings->{$settings_key}; } } } sub es_refresh_cluster_state { my $content = es_agent_get($baseurl . "_cluster/state"); if (defined($content)) { $es_cluster_state = decode_json($content); es_rewrite_cluster_state(); es_data_index_instances($es_cluster_state->{'metadata'}->{'indices'}); } else { $es_cluster_state = undef; } } sub es_refresh_cluster_nodes_stats_all { my $content = es_agent_get($baseurl . "_cluster/nodes/stats?all"); if (defined($content)) { $es_nodestats = decode_json($content); es_data_node_instances($es_nodestats->{'nodes'}); } else { $es_nodestats = undef; } } sub es_refresh_cluster_nodes_all { my $content = es_agent_get($baseurl . "_cluster/nodes?all"); if (defined($content)) { $es_nodes = decode_json($content); es_data_node_instances($es_nodes->{'nodes'}); } else { $es_nodes = undef; } } sub es_refresh_root { my $content = es_agent_get($baseurl); $es_root = defined($content) ? decode_json($content) : undef; } sub es_refresh_stats_search { my $content = es_agent_get($baseurl . "_stats/search"); if (defined($content)) { $es_searchstats = decode_json($content); es_search_instances($es_searchstats->{'_all'}->{'indices'}); } else { $es_searchstats = undef; } } sub es_refresh { my ($cluster) = @_; my $now = time; if (defined($cluster_cache[$cluster]) && $now - $cluster_cache[$cluster] <= $cache_interval) { return; } if ($cluster == 0) { # Update the cluster metrics es_refresh_cluster_health(); } elsif ($cluster == 1) { # Update the node metrics es_refresh_cluster_nodes_stats_all(); } elsif ($cluster == 2) { # Update the other node metrics es_refresh_cluster_nodes_all(); } elsif ($cluster == 3) { # Update the root metrics es_refresh_root(); } elsif ($cluster == 4 || # Update the search metrics $cluster == 5) { es_refresh_stats_search(); # avoid 2nd refresh call on metrics in other cluster $cluster_cache[4] = $cluster_cache[5] = $now; } elsif ($cluster == 6 || $cluster == 7) { # Update the cluster state es_refresh_cluster_state(); } $cluster_cache[$cluster] = $now; } sub es_lookup_node { my ($json, $inst) = @_; my $nodeID = $nodes_instance_ids[($inst*2)+1]; return $json->{'nodes'}->{$nodeID}; } sub es_lookup_search { my ($json, $inst) = @_; my $searchID = $search_instance_ids[($inst*2)+1]; return $json->{'_all'}->{'indices'}->{$searchID}; } sub es_lookup_index { my ($json, $inst) = @_; my $indexID = $index_instance_ids[($inst*2)+1]; return $json->{'metadata'}->{'indices'}->{$indexID}; } # iterate over metric-name components, performing hash lookups as we go. sub es_value { my ( $values, $names ) = @_; my ( $value, $name ); foreach $name (@$names) { $value = $values->{$name}; return (PM_ERR_APPVERSION, 0) unless (defined($value)); $values = $value; } return (PM_ERR_APPVERSION, 0) unless (defined($value)); return ($value, 1); } # translate status string into a numeric code for pmie and friends sub es_status { my ($value) = @_; if (!defined($value)) { return (PM_ERR_AGAIN, 0); } elsif ($value eq "green" || $value eq "false") { return (0, 1); } elsif ($value eq "yellow" || $value eq "true") { return (1, 1); } elsif ($value eq "red") { return (2, 1); } return (-1, 1); # unknown } sub es_fetch_callback { my ($cluster, $item, $inst) = @_; my $metric_name = pmda_pmid_name($cluster, $item); my @metric_subnames = split(/\./, $metric_name); my ($node, $json, $search); # $pmda->log("es_fetch_callback: $metric_name $cluster.$item ($inst)"); if ($cluster == 0) { if (!defined($es_cluster)) { return (PM_ERR_AGAIN, 0); } if ($inst != PM_IN_NULL) { return (PM_ERR_INST, 0); } # remove first couple (i.e. elasticsearch.cluster.) splice(@metric_subnames, 0, 2); # cluster.timed_out and cluster.status (numeric codes) if ($item == 1) { my $value = $es_cluster->{'status'}; return (PM_ERR_APPVERSION, 0) unless (defined($value)); return ($value, 1); } elsif ($item == 2 || $item == 10) { return es_status($es_cluster->{$metric_subnames[0]}); } return es_value($es_cluster, \@metric_subnames); } elsif ($cluster == 1) { if ($inst == PM_IN_NULL) { return (PM_ERR_INST, 0); } if ($inst > @nodes_instances) { return (PM_ERR_INST, 0); } $node = es_lookup_node($es_nodestats, $inst); if (!defined($node)) { return (PM_ERR_AGAIN, 0); } # remove first couple (i.e. elasticsearch.node.) splice(@metric_subnames, 0, 2); return es_value($node, \@metric_subnames); } elsif ($cluster == 2) { if ($inst == PM_IN_NULL) { return (PM_ERR_INST, 0); } if ($inst > @nodes_instances) { return (PM_ERR_INST, 0); } $node = es_lookup_node($es_nodes, $inst); if (!defined($node)) { return (PM_ERR_AGAIN, 0); } # remove first couple (i.e. elasticsearch.node.) splice(@metric_subnames, 0, 2); return es_value($node, \@metric_subnames); } elsif ($cluster == 3) { if (!defined($es_root)) { return (PM_ERR_AGAIN, 0); } if ($inst != PM_IN_NULL) { return (PM_ERR_INST, 0); } # remove first one (i.e. elasticsearch.) splice(@metric_subnames, 0, 1); return es_value($es_root, \@metric_subnames); } elsif ($cluster == 4) { if (!defined($es_searchstats)) { return (PM_ERR_AGAIN, 0); } if ($inst != PM_IN_NULL) { return (PM_ERR_INST, 0); } # remove first couple (i.e. elasticsearch.search.) splice(@metric_subnames, 0, 2); # regex fixes up _all and _shard for us (invalid names) $metric_subnames[0] =~ s/^(all|shards)$/_$1/; return es_value($es_searchstats, \@metric_subnames); } elsif ($cluster == 5) { if ($inst == PM_IN_NULL) { return (PM_ERR_INST, 0); } if ($inst > @search_instances) { return (PM_ERR_INST, 0); } # remove first three (i.e. elasticsearch.search.perindex.) splice(@metric_subnames, 0, 3); $search = es_lookup_search($es_searchstats, $inst); if (!defined($search)) { return (PM_ERR_AGAIN, 0); } return es_value($search, \@metric_subnames); } elsif ($cluster == 6) { if (!defined($es_cluster_state)){ return (PM_ERR_AGAIN, 0); } if ($inst != PM_IN_NULL) { return (PM_ERR_INST, 0); } # remove first couple (i.e. elasticsearch.cluster.) splice(@metric_subnames, 0, 2); return es_value($es_cluster_state, \@metric_subnames); } elsif ($cluster == 7) { # Remove elasticsearch.index splice(@metric_subnames, 0, 2); if (!defined($es_cluster_state)){ return (PM_ERR_AGAIN, 0); } if ($inst == PM_IN_NULL) { return (PM_ERR_INST, 0); } $search = es_lookup_index($es_cluster_state, $inst); if (!defined($search)) { return (PM_ERR_AGAIN, 0); } return es_value($search, \@metric_subnames); } return (PM_ERR_PMID, 0); } $pmda = PCP::PMDA->new('elasticsearch', 108); # cluster stats $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.cluster.cluster_name', 'Name of the elasticsearch cluster', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.cluster.status.colour', 'Status (green,yellow,red) of the elasticsearch cluster', ''); $pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.cluster.timed_out', 'Timed out status (0:false,1:true) of the elasticsearch cluster', 'Maps the cluster timed-out status to a numeric value for alarming'); $pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.cluster.number_of_nodes', 'Number of nodes in the elasticsearch cluster', ''); $pmda->add_metric(pmda_pmid(0,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.cluster.number_of_data_nodes', 'Number of data nodes in the elasticsearch cluster', ''); $pmda->add_metric(pmda_pmid(0,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.cluster.active_primary_shards', 'Number of active primary shards in the elasticsearch cluster', ''); $pmda->add_metric(pmda_pmid(0,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.cluster.active_shards', 'Number of primary shards in the elasticsearch cluster', ''); $pmda->add_metric(pmda_pmid(0,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.cluster.relocating_shards', 'Number of relocating shards in the elasticsearch cluster', ''); $pmda->add_metric(pmda_pmid(0,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.cluster.initializing_shards', 'Number of initializing shards in the elasticsearch cluster', ''); $pmda->add_metric(pmda_pmid(0,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.cluster.unassigned_shards', 'Number of unassigned shards in the elasticsearch cluster', ''); $pmda->add_metric(pmda_pmid(0,10), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.cluster.status.code', 'Status code (0:green,1:yellow,2:red) of the elasticsearch cluster', 'Maps the cluster status colour to a numeric value for alarming'); # node stats $pmda->add_metric(pmda_pmid(1,0), PM_TYPE_U64, $nodes_indom, # deprecated PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.indices.size_in_bytes', '', ''); $pmda->add_metric(pmda_pmid(1,1), PM_TYPE_U64, $nodes_indom, # deprecated PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.docs.count', '', ''); $pmda->add_metric(pmda_pmid(1,2), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.docs.num_docs', 'Raw number of documents indexed by elasticsearch', ''); $pmda->add_metric(pmda_pmid(1,3), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.cache.field_evictions', '', ''); $pmda->add_metric(pmda_pmid(1,4), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.indices.cache.field_size_in_bytes', '', ''); $pmda->add_metric(pmda_pmid(1,5), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.cache.filter_count', '', ''); $pmda->add_metric(pmda_pmid(1,6), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.cache.filter_evictions', '', ''); $pmda->add_metric(pmda_pmid(1,7), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.indices.cache.filter_size_in_bytes', '', ''); $pmda->add_metric(pmda_pmid(1,8), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.merges.current', '', ''); $pmda->add_metric(pmda_pmid(1,9), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.merges.total', '', ''); $pmda->add_metric(pmda_pmid(1,10), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.indices.merges.total_time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,11), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.jvm.uptime_in_millis', 'Number of milliseconds each elasticsearch node has been running', ''); $pmda->add_metric(pmda_pmid(1,12), PM_TYPE_STRING, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.jvm.uptime', 'Time (as a string) that each elasticsearch node has been up', ''); $pmda->add_metric(pmda_pmid(1,13), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.jvm.mem.heap_used_in_bytes', 'Actual amount of memory in use for the Java heap', ''); $pmda->add_metric(pmda_pmid(1,14), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.jvm.mem.heap_committed_in_bytes', 'Virtual memory size', ''); $pmda->add_metric(pmda_pmid(1,15), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.jvm.mem.non_heap_used_in_bytes', 'Actual memory in use by Java excluding heap space', ''); $pmda->add_metric(pmda_pmid(1,16), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.jvm.mem.non_heap_committed_in_bytes', 'Virtual memory size excluding heap', ''); $pmda->add_metric(pmda_pmid(1,17), PM_TYPE_U32, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.jvm.threads.count', 'Number of Java threads currently in use on each node', ''); $pmda->add_metric(pmda_pmid(1,18), PM_TYPE_U32, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.jvm.threads.peak_count', 'Maximum observed Java threads in use on each node', ''); $pmda->add_metric(pmda_pmid(1,19), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.jvm.gc.collection_count', 'Count of Java garbage collections', ''); $pmda->add_metric(pmda_pmid(1,20), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.jvm.gc.collection_time_in_millis', 'Time spent performing garbage collections in Java', ''); $pmda->add_metric(pmda_pmid(1,21), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.jvm.gc.collectors.Copy.collection_count', '', ''); $pmda->add_metric(pmda_pmid(1,22), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.jvm.gc.collectors.Copy.collection_time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,23), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.jvm.gc.collectors.ParNew.collection_count', '', ''); $pmda->add_metric(pmda_pmid(1,24), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.jvm.gc.collectors.ParNew.collection_time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,25), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.jvm.gc.collectors.ConcurrentMarkSweep.collection_count', '', ''); $pmda->add_metric(pmda_pmid(1,26), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.jvm.gc.collectors.ConcurrentMarkSweep.collection_time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,27), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.docs.deleted', '', ''); $pmda->add_metric(pmda_pmid(1,28), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.indexing.index_total', '', ''); $pmda->add_metric(pmda_pmid(1,29), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.indices.indexing.index_time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,30), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.indexing.delete_total', '', ''); $pmda->add_metric(pmda_pmid(1,31), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.indices.indexing.delete_time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,32), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.merges.current_docs', '', ''); $pmda->add_metric(pmda_pmid(1,33), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.indices.merges.current_size_in_bytes', '', ''); $pmda->add_metric(pmda_pmid(1,34), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.merges.total_docs', '', ''); $pmda->add_metric(pmda_pmid(1,35), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.indices.merges.total_size_in_bytes', '', ''); $pmda->add_metric(pmda_pmid(1,36), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.refresh.total', '', ''); $pmda->add_metric(pmda_pmid(1,37), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.indices.refresh.total_time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,38), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.flush.total', '', ''); $pmda->add_metric(pmda_pmid(1,39), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.indices.flush.total_time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,40), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.process.timestamp', '', ''); $pmda->add_metric(pmda_pmid(1,41), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.process.open_file_descriptors', '', ''); $pmda->add_metric(pmda_pmid(1,42), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.process.cpu.percent', '', ''); $pmda->add_metric(pmda_pmid(1,43), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.process.cpu.sys_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,44), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.process.cpu.user_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,45), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.process.mem.resident_in_bytes', '', ''); $pmda->add_metric(pmda_pmid(1,46), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.process.mem.total_virtual_in_bytes', '', ''); $pmda->add_metric(pmda_pmid(1,47), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.indices.store.size_in_bytes', 'Size of indices store on each elasticsearch node', ''); $pmda->add_metric(pmda_pmid(1,48), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.get.total', '', ''); $pmda->add_metric(pmda_pmid(1,49), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.indices.get.time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,50), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.get.exists_total', '', ''); $pmda->add_metric(pmda_pmid(1,51), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.indices.get.exists_time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,52), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.get.missing_total', '', ''); $pmda->add_metric(pmda_pmid(1,53), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.indices.get.missing_time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,54), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.search.query_total', '', ''); $pmda->add_metric(pmda_pmid(1,55), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.indices.search.query_time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,56), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.indices.search.fetch_total', '', ''); $pmda->add_metric(pmda_pmid(1,57), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.nodes.indices.search.fetch_time_in_millis', '', ''); $pmda->add_metric(pmda_pmid(1,58), PM_TYPE_U32, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.transport.server_open', 'Count of open server connections', ''); $pmda->add_metric(pmda_pmid(1,59), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.transport.rx_count', 'Receive transaction count', ''); $pmda->add_metric(pmda_pmid(1,60), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.transport.rx_size_in_bytes', 'Receive transaction size', ''); $pmda->add_metric(pmda_pmid(1,61), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.transport.tx_count', 'Transmit transaction count', ''); $pmda->add_metric(pmda_pmid(1,62), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.transport.tx_size_in_bytes', 'Transmit transaction size', ''); $pmda->add_metric(pmda_pmid(1,63), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.http.current_open', 'Number of currently open http connections', ''); $pmda->add_metric(pmda_pmid(1,64), PM_TYPE_U64, $nodes_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.nodes.http.total_opened', 'Count of http connections opened since starting', ''); # node info stats $pmda->add_metric(pmda_pmid(2,0), PM_TYPE_U32, $nodes_indom, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.jvm.pid', 'Process identifier for elasticsearch on each node', ''); $pmda->add_metric(pmda_pmid(2,1), PM_TYPE_STRING, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.jvm.version', 'Java Runtime environment version', ''); $pmda->add_metric(pmda_pmid(2,2), PM_TYPE_STRING, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.jvm.vm_name', 'Name of the Java Virtual Machine running on each node', ''); $pmda->add_metric(pmda_pmid(2,3), PM_TYPE_STRING, $nodes_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.jvm.vm_version', 'Java Virtual Machine version on each node', ''); $pmda->add_metric(pmda_pmid(2,4), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.jvm.mem.heap_init_in_bytes', 'Initial Java heap memory configuration size', ''); $pmda->add_metric(pmda_pmid(2,5), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.jvm.mem.heap_max_in_bytes', 'Maximum Java memory size', ''); $pmda->add_metric(pmda_pmid(2,6), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.jvm.mem.non_heap_init_in_bytes', 'Initial Java memory configuration size excluding heap space', ''); $pmda->add_metric(pmda_pmid(2,7), PM_TYPE_U64, $nodes_indom, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'elasticsearch.nodes.jvm.mem.non_heap_max_in_bytes', 'Maximum Java memory size excluding heap space', ''); $pmda->add_metric(pmda_pmid(2,8), PM_TYPE_U64, $nodes_indom, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'elasticsearch.nodes.process.max_file_descriptors', '', ''); $pmda->add_metric(pmda_pmid(3,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'elasticsearch.version.number', 'Version number of elasticsearch', ''); $pmda->add_metric(pmda_pmid(4,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.search.shards.total', 'Number of shards in the elasticsearch cluster', ''); $pmda->add_metric(pmda_pmid(4,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.search.shards.successful', 'Number of successful shards in the elasticsearch cluster', ''); $pmda->add_metric(pmda_pmid(4,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.search.shards.failed', 'Number of failed shards in the elasticsearch cluster', ''); $pmda->add_metric(pmda_pmid(4,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.search.all.primaries.search.query_total', 'Number of search queries to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(4,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.search.all.primaries.search.query_time_in_millis', 'Time spent in search queries to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(4,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.search.all.primaries.search.fetch_total', 'Number of search fetches to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(4,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.search.all.primaries.search.fetch_time_in_millis', 'Time spent in search fetches to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(4,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.search.all.total.search.query_total', 'Number of search queries to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(4,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.search.all.total.search.query_time_in_millis', 'Time spent in search queries to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(4,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.search.all.total.search.fetch_total', 'Number of search fetches to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(4,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.search.all.total.search.fetch_time_in_millis', 'Time spent in search fetches to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(5,0), PM_TYPE_U64, $search_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.search.perindex.primaries.search.query_total', 'Number of search queries to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(5,1), PM_TYPE_U64, $search_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.search.perindex.primaries.search.query_time_in_millis', 'Time spent in search queries to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(5,2), PM_TYPE_U64, $search_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.search.perindex.primaries.search.fetch_total', 'Number of search fetches to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(5,3), PM_TYPE_U64, $search_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.search.perindex.primaries.search.fetch_time_in_millis', 'Time spent in search fetches to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(5,4), PM_TYPE_U64, $search_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.search.perindex.total.search.query_total', 'Number of search queries to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(5,5), PM_TYPE_U64, $search_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.search.perindex.total.search.query_time_in_millis', 'Time spent in search queries to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(5,6), PM_TYPE_U64, $search_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'elasticsearch.search.perindex.total.search.fetch_total', 'Number of search fetches to all elasticsearch primaries', ''); $pmda->add_metric(pmda_pmid(5,7), PM_TYPE_U64, $search_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.search.perindex.total.search.fetch_time_in_millis', 'Time spent in search fetches to all elasticsearch primaries', ''); # cluster state $pmda->add_metric(pmda_pmid(6,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.cluster.master_node', 'Internal identifier of the master node of the cluster', ''); # index state $pmda->add_metric(pmda_pmid(7,0), PM_TYPE_64, $index_indom, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'elasticsearch.index.settings.gateway_snapshot_interval', 'Interval between gateway snapshots', ''); $pmda->add_metric(pmda_pmid(7,1), PM_TYPE_U64, $index_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.index.settings.number_of_replicas', 'Number of replicas of shards index setting', ''); $pmda->add_metric(pmda_pmid(7,2), PM_TYPE_U64, $index_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.index.settings.number_of_shards', 'Number of shards index setting', ''); $pmda->add_metric(pmda_pmid(7,3), PM_TYPE_U64, $index_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'elasticsearch.index.settings.version_created', 'The version of elasticsearch the index was created with', ''); $pmda->add_indom($nodes_indom, \@nodes_instances, 'Instance domain exporting each elasticsearch node', ''); $pmda->add_indom($search_indom, \@search_instances, 'Instance domain exporting each elasticsearch index', ''); $pmda->add_indom($index_indom, \@index_instances, 'Instance domain exporting each elasticsearch index metadata', ''); $pmda->set_fetch_callback(\&es_fetch_callback); $pmda->set_refresh(\&es_refresh); $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdaelasticsearch - elasticsearch performance metrics domain agent (PMDA) =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from elasticsearch. =head1 INSTALLATION This PMDA requires that elasticsearch is running on the local host and is accepting queries on TCP port 9200 Install the elasticsearch PMDA by using the B script as root: # cd $PCP_PMDAS_DIR/elasticsearch # ./Install To uninstall, do the following as root: # cd $PCP_PMDAS_DIR/elasticsearch # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/elasticsearch/es.conf optional configuration file for B elasticsearch PMDA for PCP =item $PCP_PMDAS_DIR/elasticsearch/Install installation script for the B agent =item $PCP_PMDAS_DIR/elasticsearch/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/elasticsearch.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1). pcp-3.8.12ubuntu1/src/pmdas/snmp/0000775000000000000000000000000012272262620013454 5ustar pcp-3.8.12ubuntu1/src/pmdas/snmp/Remove0000775000000000000000000000157312272262501014643 0ustar #!/bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Remove the SNMP PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=snmp pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/snmp/Install0000775000000000000000000000135112272262501015006 0ustar #!/bin/sh # # Copyright (c) 2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the SNMP gateway PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=snmp perl_opt=true daemon_opt=false forced_restart=false pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/snmp/GNUmakefile0000664000000000000000000000276112272262501015532 0ustar #!gmake # # Copyright (c) 2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = snmp PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl snmp.conf LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl $(INSTALL) -m 644 snmp.conf $(PMDADIR)/snmp.conf @$(INSTALL_MAN) default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/snmp/pmdasnmp.pl0000775000000000000000000002574012272262501015641 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2011-2012 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use FileHandle; use PCP::PMDA; use Net::SNMP qw(:asn1); use Data::Dumper; $Data::Dumper::Indent = 1; $Data::Dumper::Sortkeys = 1; $Data::Dumper::Quotekeys = 0; $Data::Dumper::Useqq = 1; # PMDA log doesnt like binary :-( our $VERSION='0.3'; my $db = {}; my $option = { max_row => 100, # default maximum number of rows for a table pmid_per_host => 100, # default number of pmid's for each host }; # SNMP string type name to numeric type number # my $snmptype2val = { INTEGER => INTEGER32, INTEGER32 => INTEGER32, OCTET_STRING => OCTET_STRING, STRING => OCTET_STRING, OBJECT_IDENTIFIER => OBJECT_IDENTIFIER, IPADDRESS => IPADDRESS, COUNTER => COUNTER32, COUNTER32 => COUNTER32, GAUGE => GAUGE32, GAUGE32 => GAUGE32, UNSIGNED32 => UNSIGNED32, TIMETICKS => TIMETICKS, OPAQUE => OPAQUE, COUNTER64 => COUNTER64, }; # SNMP numeric type number to PCP type number # my $snmptype2pcp = { 0x02 => { type=> PM_TYPE_32, sem=> PM_SEM_INSTANT }, # INTEGER32 0x04 => { type=> PM_TYPE_STRING, sem=> PM_SEM_DISCRETE }, # OCTET_STRING 0x06 => { type=> PM_TYPE_STRING, sem=> PM_SEM_DISCRETE }, # OBJECT_IDENTIFIER 0x40 => { type=> PM_TYPE_STRING, sem=> PM_SEM_DISCRETE }, # IPADDRESS 0x41 => { type=> PM_TYPE_U32, sem=> PM_SEM_COUNTER }, # COUNTER32 0x42 => { type=> PM_TYPE_32, sem=> PM_SEM_INSTANT }, # GAUGE32 0x42 => { type=> PM_TYPE_U32, sem=> PM_SEM_INSTANT }, # UNSIGNED32 0x43 => { type=> PM_TYPE_64, sem=> PM_SEM_COUNTER }, # TIMETICKS 0x44 => { type=> PM_TYPE_STRING, sem=> PM_SEM_DISCRETE }, # OPAQUE 0x46 => { type=> PM_TYPE_64, sem=> PM_SEM_COUNTER }, # COUNTER64 }; my $dom_rows = 0; # this indom nr used for generic row numbers my $pmda = PCP::PMDA->new('snmp', 56); # Read in the config file(s) # sub load_config { my $db = shift; if (!defined $db->{hosts}) { $db->{hosts} = {}; } if (!defined $db->{map}) { $db->{map} = {}; $db->{map}{hosts} = []; $db->{map}{oids} = []; } for my $filename (@_) { my $fh = FileHandle->new($filename); if (!defined $fh) { warn "opening $filename $!"; next; } while(<$fh>) { chomp; s/\r//g; # strip whitespace at the beginning and end of the line s/^\s+//; s/\s+$//; # strip comments s/^#.*//; # line starts with a comment char s/[^\\]#.*//; # non quoted comment char if (m/^$/) { # empty lines, or lines that were all comment next; } if (m/^set\s+(\w+)\s+(.*)$/) { # set an option my $key = $1; my $val = $2; $option->{$key}=$val; } elsif (m/^host\s+(\S+)\s+(.*)$/) { my $e = {}; $e->{hostname}=$1; $e->{community}=$2; # The reversed dotted hostname is used in the metric name $e->{revname} = join('.',reverse(split('\.',$1))); # TODO - lazy create snmp sessions on first use my ($session,$error) = Net::SNMP->session( -hostname =>$e->{hostname}, -community=>$e->{community}, ); if (!$session) { warn("SNMP session to $e->{hostname}: $error"); $e->{error}=$error; } else { $e->{snmp}=$session; $e->{snmp}->translate([-timeticks=>0]); } $db->{hosts}{$1} = $e; my $id = scalar @{$db->{map}{hosts}}; # TODO - allow this pmid 'index base' to be set $e->{id} = $id; @{$db->{map}{hosts}}[$id]=$e; } elsif (m/^map\s+(single|column)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.*)$/) { my $snmptype = $snmptype2val->{$3}; if (!defined $snmptype) { warn("Invalid SNMP type '$3' on oid '$2'\n"); next; } my $e = {}; my $id = $4; if ($id eq '+') { # select the next available number $id = scalar @{$db->{map}{oids}}; } if ($id > $option->{pmid_per_host}) { warn("More metrics than allowed by pmid_per_host"); next; } $e->{type}=$1; $e->{oid}=$2; $e->{snmptype}=$snmptype; $e->{id}=$id; $e->{text}=$5; @{$db->{map}{oids}}[$id]=$e; } else { warn("Unrecognised config line: $_\n"); } # TODO - add map tree, mib load } } $db->{max}{hosts} = scalar keys %{$db->{hosts}}; $db->{max}{oids} = scalar @{$db->{map}{oids}}; $db->{max}{static} = $db->{max}{hosts} * $option->{pmid_per_host}; # any PMID above max static is available for dynamicly created mappings return $db; } # Create the fake generic rows indom # TODO - demand create the rows indoms sub db_create_indom { my ($db) = @_; my @dom; for my $row (0..$option->{max_row}) { # first is id, second is string description # for now, both are the same # TODO - populate the indom with rational names from an SNMP column push @dom,$row,$row; } $pmda->add_indom($dom_rows,\@dom,'SNMP rows',''); } # Using the mappings, define all the metrics # sub db_add_metrics { my ($db) = @_; # TODO - nuke the PMDA.xs current list of metrics here # (there is a clear_metrics() in the xs that might be adapted to work) # add our version $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), "snmp.version", '', ''); for my $host (@{$db->{map}{hosts}}) { # calculate the pmid for the first metric for this host my $hostbase = $host->{id} * $option->{pmid_per_host}; # skip hosts that did not setup their snmp session next if (!$host->{snmp}); for my $e (@{$db->{map}{oids}}) { # for each predefined static mapping, register a metric if (!defined $e) { next; } my $id = $hostbase + $e->{id}; # hack around the too transparent opaque datatype my $cluster = int($id /1024); my $item = $id %1024; my $type = $snmptype2pcp->{$e->{snmptype}}; if (!defined $type) { warn("Unknown type=$type for id=$e->{id}\n"); next; } my $indom; if ($e->{type} eq 'single') { $indom = PM_INDOM_NULL; } elsif ($e->{type} eq 'column') { # TODO - use metric specific indom, for now, just use generic $indom = $dom_rows; $e->{indom} = $indom; } else { warn("Unknown map type = $e->{type}\n"); next; } $pmda->add_metric(pmda_pmid($cluster,$item), $type->{type}, $indom, $type->{sem}, pmda_units(0,0,0,0,0,0), 'snmp.host.'.$host->{revname}.'.'.$e->{oid}, $e->{text}, '' ); } } } # debug when fetch is called # fetch_func is called with no params during a "fetch", after refreshing the # PMNS before calling refresh_func # sub fetch { if ($option->{debug}) { $pmda->log("fetch"); } } # debug when instance is called # instance_func is called with "indom" param during a "instance", after # refreshing the PMNS before calling pmdaInstance # sub instance { my ($indom) = @_; if ($option->{debug}) { $pmda->log("instance $indom"); } } sub fetch_callback { my ($cluster, $item, $inst) = @_; my $id = $cluster*1024 + $item; if ($option->{debug}) { my $metric_name = pmda_pmid_name($cluster, $item); $pmda->log("fetch_callback $metric_name $cluster:$item ($inst)"); } if ($id == 0) { return ($VERSION,1); } my $hostnr = int($id / $option->{pmid_per_host}); my $host = @{$db->{map}{hosts}}[$hostnr]; if (!defined $host) { return (PM_ERR_NOTHOST, 0); } my $map = @{$db->{map}{oids}}[$id % $option->{pmid_per_host}]; if (!defined $map) { return (PM_ERR_PMID, 0); } my $oid = $map->{oid}; if (defined $map->{indom}) { # only metrics with rows have an indom $oid.='.'.$inst; } # TODO - maybe check if a map single has been called with an inst other # than PM_INDOM_NULL if ($option->{debug}) { $pmda->log("fetch_callback hostnr=$hostnr rownr=$inst"); } if (!defined $host->{snmp}) { # We have no snmp object for this host # FIXME - a better errno? return (PM_ERR_EOF, 0); } my $snmp = $host->{snmp}; my $result = $snmp->get_request( -varbindlist=>[ $oid, ] ); if (!$result) { # We didnt get a valid snmp response return (PM_ERR_PMID, 0); } my $types = $snmp->var_bind_types(); if ($map->{snmptype} != $types->{$oid}) { return (PM_ERR_CONV, 0); } return ($result->{$oid},1); } load_config($db, pmda_config('PCP_PMDAS_DIR').'/snmp/snmp.conf', # 'snmp.conf' ); db_create_indom($db); db_add_metrics($db); $pmda->set_fetch(\&fetch); $pmda->set_instance(\&instance); $pmda->set_fetch_callback(\&fetch_callback); if ($option->{debug}) { $pmda->log("db=".Dumper($db)."\n"); $pmda->log("option=".Dumper($option)."\n"); } $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdasnmp - Gateway from SNMP to PCP (PMDA) =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which provides a generic gateway from PCP queries from a PCP client to SNMP queries to one or more SNMP agents. =head1 INSTALLATION If you want access to the SNMP gateway performance metrics, do the following as root: # cd $PCP_PMDAS_DIR/snmp # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/snmp # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 CONFIGURATION TODO: define config file format here - map/set/host/... etc =head1 FILES =over =item $PCP_PMDAS_DIR/snmp/snmp.conf optional configuration file for B =item $PCP_PMDAS_DIR/snmp/Install installation script for the B agent =item $PCP_PMDAS_DIR/snmp/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/snmp.log default log file for error and warn() messages from B =back =head1 SEE ALSO pmcd(1) and SNMP pcp-3.8.12ubuntu1/src/pmdas/snmp/snmp.conf0000664000000000000000000000263512272262501015304 0ustar # Simple, first pass at a config file. I expect to need a more expressive # file format in the future # hashes begin comments # comments can begin in the # middle of a line # define a host #host $hostname $community # TODO - allow the pmid 'index base' to be set for each host # currently only community based auth is supported host localhost public # load a mib (future) - gives name to number oid mappings #mib $mibfilename # static mapping # single maps a single oid # column maps a simple table column where the last octet in the oid is the row # id's start at 1 and redefininitions result in the last define winning # the snmptype is used to calculate the pcp metric type to use # the text is used as the metric short help text #map (single|column) $oid $snmptype $id $text map single 1.3.6.1.2.1.1.3.0 TIMETICKS 1 sysUpTime map single 1.3.6.1.2.1.1.5.0 STRING 2 sysName map column 1.3.6.1.2.1.2.2.1.2 STRING 10 ifDescr map column 1.3.6.1.2.1.2.2.1.5 GAUGE32 + ifSpeed map column 1.3.6.1.2.1.2.2.1.10 COUNTER32 + ifInOctets # TODO - work out some kind of static walk define #map tree $oid $id_start $id_max $text_prefix # For the moment, table oids are limited to this max number set max_row 50 # Set the maximum number of metrics per host. This is used to create the # metric ID and thus if changed will affect merging data with older archives. set pmid_per_host 1000 # set an option #set key val set debug 1 pcp-3.8.12ubuntu1/src/pmdas/zimbra/0000775000000000000000000000000012272262620013763 5ustar pcp-3.8.12ubuntu1/src/pmdas/zimbra/Remove0000775000000000000000000000125712272262501015151 0ustar #!/bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the Zimbra PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=zimbra pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/zimbra/Install0000775000000000000000000000164212272262501015320 0ustar #!/bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the Zimbra PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=zimbra perl_opt=true daemon_opt=false forced_restart=false if ! test -d /opt/zimbra/zmstat ; then echo "Zimbra does not appear to be installed (no /opt/zimbra/zmstat)" echo "Pushing on regardless, but no metric values exist initially." fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/zimbra/GNUmakefile0000664000000000000000000000270612272262501016040 0ustar #!gmake # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = zimbra PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl zimbraprobe.sh pmlogconf.all LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 755 zimbraprobe.sh $(PMDADIR)/zimbraprobe $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) $(INSTALL) -m 755 -d $(PCP_VAR_DIR)/config/pmlogconf/$(IAM) $(INSTALL) -m 644 pmlogconf.all $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)/all default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/zimbra/zimbraprobe.sh0000775000000000000000000000141112272262501016631 0ustar #!/bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # delay=${1:-10} # First one produces any errors to PMDA logfile su -c 'zmcontrol status' - zimbra while true do date +'%d/%m/%Y %H:%M:%S' sleep $delay su -c 'zmcontrol status' - zimbra 2>/dev/null done pcp-3.8.12ubuntu1/src/pmdas/zimbra/pmlogconf.all0000664000000000000000000000012012272262501016430 0ustar #pmlogconf-setup 2.0 ident All Zimbra information probe zimbra.fd_count zimbra pcp-3.8.12ubuntu1/src/pmdas/zimbra/pmdazimbra.pl0000664000000000000000000012531212272262501016450 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; my $pmda = PCP::PMDA->new('zimbra', 98); my $probe = pmda_config('PCP_PMDAS_DIR') . '/zimbra/zimbraprobe'; my $stats = '/opt/zimbra/zmstat/'; # Zimbra instrumentation is exported through a series of CSV files. # Several of these are system-level files that we already have PMDAs # for, extracted more accurately and efficiently, so we ignore those # (cpu,vm,mysql). # For the rest, we use the PMDA.pm file "tail" mechanism to monitor # appends to each of the CSV files. For all data received, we parse # the line and extract values. These we store in fixed-size arrays, # one per metric cluster, then the fetch callback just passes out the # most recently seen value. my ( $imap_domain, $soap_domain ) = ( 0, 1 ); my @imap_indom = ( 0 => 'CAPABILITY', 1 => 'UID', 2 => 'STATUS', 3 => 'SUBSCRIBE', 4 => 'LIST', 5 => 'SELECT', 6 => 'LOGIN', 7 => 'NAMESPACE', 8 => 'APPEND', 9 => 'OTHER' ); my @soap_indom = ( 0 => 'AuthRequest', 1 => 'DelegateAuthRequest', 2 => 'GetAccountInfoRequest', 3 => 'GetAllServersRequest', 4 => 'GetDomainRequest', 5 => 'GetDomainInfoRequest', 6 => 'GetCosRequest', 7 => 'GetServiceStatusRequest', 8 => 'GetVersionInfoRequest', 9 => 'GetAccountMembershipRequest', 10 => 'GetLDAPEntriesRequest', 11 => 'GetAdminSavedSearchesRequest', 12 => 'GetAdminExtensionZimletsRequest', 13 => 'GetAllConfigRequest', 14 => 'GetLicenseRequest', 15 => 'SearchDirectoryRequest', 16 => 'Other' ); sub zimbra_array_lookup { my ( $indomref, $name ) = @_; my @indom = @$indomref; my $index; for ($index = 1; $index < $#indom; $index += 2) { return (($index-1) / 2) unless ($indom[$index] ne $name); } return (($#indom-1) / 2); # return the "other" bucket } use vars qw( @fd_values @imap_time_values @imap_count_values @soap_time_values @soap_count_values @mailbox_values @mtaqueue_values @proc_values @threads_values @probe_values ); use vars qw( $fd_timestamp $imap_timestamp $soap_timestamp $mailbox_timestamp $mtaqueue_timestamp $proc_timestamp $threads_timestamp $probe_timestamp ); $fd_timestamp = $imap_timestamp = $soap_timestamp = $mailbox_timestamp = $mtaqueue_timestamp = $proc_timestamp = $threads_timestamp = $probe_timestamp = 0; sub zimbra_fd_parser { ( undef, $_ ) = @_; # $pmda->log("zimbra_fd_parser got line: $_"); if (s|^(\d\d/\d\d/\d\d\d\d \d\d:\d\d:\d\d), ||) { chomp; $fd_timestamp = $1; @fd_values = split /,/; } } sub zimbra_imap_parser { ( undef, $_ ) = @_; # $pmda->log("zimbra_imap_parser got line: $_"); if (s|^(\d\d/\d\d/\d\d\d\d \d\d:\d\d:\d\d),||) { chomp; my $timestamp = $1; my @values = split /,/; if ($timestamp ne $imap_timestamp) { $imap_timestamp = $timestamp; @imap_count_values = (); $imap_count_values[($#imap_indom-1)/2] = 0; @imap_time_values = (); $imap_time_values[($#imap_indom-1)/2] = 0; } my $index = zimbra_array_lookup(\@imap_indom, $values[0]); $imap_count_values[$index] = $values[1]; $imap_time_values[$index] = $values[2]; } } sub zimbra_soap_parser { ( undef, $_ ) = @_; # $pmda->log("zimbra_soap_parser got line: $_"); if (s|^(\d\d/\d\d/\d\d\d\d \d\d:\d\d:\d\d),||) { chomp; my $timestamp = $1; my @values = split /,/; if ($timestamp ne $soap_timestamp) { $soap_timestamp = $timestamp; @soap_count_values = (); $soap_count_values[($#soap_indom-1)/2] = 0; @soap_time_values = (); $soap_time_values[($#soap_indom-1)/2] = 0; } my $index = zimbra_array_lookup(\@soap_indom, $values[0]); $soap_count_values[$index] = $values[1]; $soap_time_values[$index] = $values[2]; } } sub zimbra_mailbox_parser { ( undef, $_ ) = @_; # $pmda->log("zimbra_mailbox_parser got line: $_"); if (s|^(\d\d/\d\d/\d\d\d\d \d\d:\d\d:\d\d),||) { chomp; $mailbox_timestamp = $1; @mailbox_values = split /,/; } } sub zimbra_mtaqueue_parser { ( undef, $_ ) = @_; # $pmda->log("zimbra_mtaqueue_parser got line: $_"); if (s|^(\d\d/\d\d/\d\d\d\d \d\d:\d\d:\d\d), ||) { chomp; $mtaqueue_timestamp = $1; @mtaqueue_values = split /,/; } } sub zimbra_proc_parser { ( undef, $_ ) = @_; # $pmda->log("zimbra_proc_parser got line: $_"); if (s|^(\d\d/\d\d/\d\d\d\d \d\d:\d\d:\d\d), ||) { chomp; $proc_timestamp = $1; @proc_values = (); my @values = split /,/; splice(@values, 0, 5); # ditch "system" values # 7 values for mailbox,mysql,convertd,ldap,postfix,amavis,clam # seems sometimes not all are installed/available/whatever, so # take care to handle that case. while ($#values >= 7) { my $offset = 0; my @chunk = splice(@values, 0, 8); if (defined($chunk[0])) { $chunk[0] =~ s/\s//g; } if (!defined($chunk[0])) { $pmda->log("zimbra_proc_parser unexpected input: $_"); } elsif ($chunk[0] eq 'mailbox') { $offset = 0; } elsif ($chunk[0] eq 'mysql') { $offset = 7; } elsif ($chunk[0] eq 'convertd') { $offset = 14; } elsif ($chunk[0] eq 'ldap') { $offset = 21; } elsif ($chunk[0] eq 'postfix') { $offset = 28; } elsif ($chunk[0] eq 'amavis') { $offset = 35; } elsif ($chunk[0] eq 'clam') { $offset = 42; } else { $pmda->log("zimbra_proc_parser unexpected data: $chunk[0]"); } shift @chunk; # remove the chunk name - then add values splice(@proc_values, $offset, 7, @chunk); # to correct spot } } else { # This includes the initial header line, so just debug: # $pmda->log("zimbra_proc_parser could not parse line: $_"); } } sub zimbra_threads_parser { ( undef, $_ ) = @_; # $pmda->log("zimbra_threads_parser got line: $_"); if (s|^(\d\d/\d\d/\d\d\d\d \d\d:\d\d:\d\d),||) { chomp; $threads_timestamp = $1; @threads_values = split /,/; } } sub zimbra_probe_callback { ( undef, $_ ) = @_; # $pmda->log("zimbra_probe_callback got line: $_"); if (s|^(\d\d/\d\d/\d\d\d\d \d\d:\d\d:\d\d)$||) { $probe_timestamp = $1; } else { my ($service, $status) = split; return unless defined($status); $status = ($status eq 'Running') ? 1 : 0; $probe_values[ 0] = $status unless ($service ne 'antivirus'); $probe_values[ 1] = $status unless ($service ne 'antispam'); $probe_values[ 2] = $status unless ($service ne 'archiving'); $probe_values[ 3] = $status unless ($service ne 'convertd'); $probe_values[ 4] = $status unless ($service ne 'mta'); $probe_values[ 5] = $status unless ($service ne 'mailbox'); $probe_values[ 6] = $status unless ($service ne 'logger'); $probe_values[ 7] = $status unless ($service ne 'snmp'); $probe_values[ 8] = $status unless ($service ne 'ldap'); $probe_values[ 9] = $status unless ($service ne 'spell'); $probe_values[10] = $status unless ($service ne 'imapproxy'); $probe_values[11] = $status unless ($service ne 'stats'); } } sub zimbra_fetch_callback { my ($cluster, $item, $inst) = @_; #$pmda->log("zimbra_fetch_callback for PMID: $cluster.$item ($inst)"); if ($inst != PM_IN_NULL && $cluster != 1 && $cluster != 2) { return (PM_ERR_INST, 0); } if ($cluster == 0) { # fd.csv if ($item >= 0 && $item <= 0) { return (PM_ERR_AGAIN, 0) unless defined($fd_values[$item]); return ($fd_values[$item], 1); } } elsif ($cluster == 1 && $item == 0) { # imap.csv if ($inst >= 0 && $inst <= $#imap_indom) { return (PM_ERR_AGAIN, 0) unless defined($imap_count_values[$inst]); return ($imap_count_values[$inst], 1); } } elsif ($cluster == 1 && $item == 1) { # imap.csv if ($inst >= 0 && $inst < $#imap_indom) { return (PM_ERR_AGAIN, 0) unless defined($imap_time_values[$inst]); return ($imap_time_values[$inst], 1); } } elsif ($cluster == 2 && $item == 0) { # soap.csv if ($inst >= 0 && $inst < $#soap_indom) { return (PM_ERR_AGAIN, 0) unless defined($soap_count_values[$inst]); return ($soap_count_values[$inst], 1); } } elsif ($cluster == 2 && $item == 1) { # soap.csv if ($inst >= 0 && $inst < $#soap_indom) { return (PM_ERR_AGAIN, 0) unless defined($soap_time_values[$inst]); return ($soap_time_values[$inst], 1); } } elsif ($cluster == 3) { # mailboxd.csv if ($item >= 0 && $item <= 60) { return (PM_ERR_AGAIN, 0) unless defined($mailbox_values[$item]); if ($mailbox_values[$item] eq '') { $mailbox_values[$item] = 0; } return ($mailbox_values[$item], 1); } } elsif ($cluster == 4) { # mtaqueue.csv if ($item >= 0 && $item <= 1) { return (PM_ERR_AGAIN, 0) unless defined($mtaqueue_values[$item]); return ($mtaqueue_values[$item], 1); } } elsif ($cluster == 5) { # proc.csv if ($item >= 0 && $item <= 48) { return (PM_ERR_AGAIN, 0) unless defined($proc_values[$item]); return ($proc_values[$item], 1); } } elsif ($cluster == 6) { # threads.csv if ($item >= 0 && $item <= 13) { return (PM_ERR_AGAIN, 0) unless defined($threads_values[$item]); return ($threads_values[$item], 1); } } elsif ($cluster == 7) { # timestamps return ($fd_timestamp, 1) unless ($item != 0); return ($imap_timestamp, 1) unless ($item != 1); return ($soap_timestamp, 1) unless ($item != 2); return ($mailbox_timestamp, 1) unless ($item != 3); return ($mtaqueue_timestamp, 1) unless ($item != 4); return ($proc_timestamp, 1) unless ($item != 5); return ($threads_timestamp, 1) unless ($item != 6); return ($probe_timestamp, 1) unless ($item != 7); } elsif ($cluster == 8) { # status probe if ($item >= 0 && $item <= 11) { return (PM_ERR_APPVERSION, 0) unless defined($probe_values[$item]); return ($probe_values[$item], 1); } } return (PM_ERR_PMID, 0); } $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.fd_count', '/opt/zimbra/zmstat/fd.csv', 'Open file descriptors'); $pmda->add_metric(pmda_pmid(1,0), PM_TYPE_U32, $imap_domain, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.imap.count', '/opt/zimbra/zmstat/imap.csv', 'Count of Internet Message Access Protocol commands'); $pmda->add_metric(pmda_pmid(1,1), PM_TYPE_U32, $imap_domain, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'zimbra.imap.avgtime', '/opt/zimbra/zmstat/imap.csv', 'Time spent executing Internet Message Access Protocol commands'); $pmda->add_metric(pmda_pmid(2,0), PM_TYPE_U32, $soap_domain, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.soap.count', '/opt/zimbra/zmstat/soap.csv', 'Count of Simple Object Access Protocol commands'); $pmda->add_metric(pmda_pmid(2,1), PM_TYPE_U32, $soap_domain, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'zimbra.soap.avgtime', '/opt/zimbra/zmstat/soap.csv', 'Time spent executing Simple Object Access Protocol commands'); $pmda->add_metric(pmda_pmid(3,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.lmtp.rcvd_msgs', '/opt/zimbra/zmstat/mailboxd.csv', 'Received mail messages'); $pmda->add_metric(pmda_pmid(3,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.lmtp.rcvd_bytes', '/opt/zimbra/zmstat/mailboxd.csv', 'Received bytes'); $pmda->add_metric(pmda_pmid(3,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.lmtp.rcvd_rcpt', '/opt/zimbra/zmstat/mailboxd.csv', 'Received receipts'); $pmda->add_metric(pmda_pmid(3,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.lmtp.dlvd_msgs', '/opt/zimbra/zmstat/mailboxd.csv', 'Delivered messages'); $pmda->add_metric(pmda_pmid(3,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.lmtp.dlvd_bytes', '/opt/zimbra/zmstat/mailboxd.csv', 'Delivered bytes'); $pmda->add_metric(pmda_pmid(3,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.db_conn.count', '/opt/zimbra/zmstat/mailboxd.csv', 'Database connection count'); $pmda->add_metric(pmda_pmid(3,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'zimbra.mailboxd.db_conn.time', '/opt/zimbra/zmstat/mailboxd.csv', 'Database connection time'); $pmda->add_metric(pmda_pmid(3,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.ldap.dc_count', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'zimbra.mailboxd.ldap.dc_time', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.mbox.add_msg_count', '/opt/zimbra/zmstat/mailboxd.csv', 'Mailbox message add count'); $pmda->add_metric(pmda_pmid(3,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'zimbra.mailboxd.mbox.add_msg_time', '/opt/zimbra/zmstat/mailboxd.csv', 'Mailbox message add average time'); $pmda->add_metric(pmda_pmid(3,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.mbox.get_count', '/opt/zimbra/zmstat/mailboxd.csv', 'Mailbox get count'); $pmda->add_metric(pmda_pmid(3,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'zimbra.mailboxd.mbox.get_time', '/opt/zimbra/zmstat/mailboxd.csv', 'Mailbox average get time'); $pmda->add_metric(pmda_pmid(3,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.mailboxd.mbox_cache', '/opt/zimbra/zmstat/mailboxd.csv', 'Mailbox cache'); $pmda->add_metric(pmda_pmid(3,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.mailboxd.mbox_msg_cache', '/opt/zimbra/zmstat/mailboxd.csv', 'Mailbox message cache'); $pmda->add_metric(pmda_pmid(3,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.mailboxd.mbox_item_cache', '/opt/zimbra/zmstat/mailboxd.csv', 'Mailbox item cache'); $pmda->add_metric(pmda_pmid(3,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.soap.count', '/opt/zimbra/zmstat/mailboxd.csv', 'Simple Object Access Protocol count'); $pmda->add_metric(pmda_pmid(3,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'zimbra.mailboxd.soap.time', '/opt/zimbra/zmstat/mailboxd.csv', 'Simple Object Access Protocol time'); $pmda->add_metric(pmda_pmid(3,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.imap.count', '/opt/zimbra/zmstat/mailboxd.csv', 'Internet Message Access Protocol count'); $pmda->add_metric(pmda_pmid(3,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'zimbra.mailboxd.imap.time', '/opt/zimbra/zmstat/mailboxd.csv', 'Internet Message Access Protocol time'); $pmda->add_metric(pmda_pmid(3,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.pop.count', '/opt/zimbra/zmstat/mailboxd.csv', 'Post Office Protocol count'); $pmda->add_metric(pmda_pmid(3,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'zimbra.mailboxd.pop.time', '/opt/zimbra/zmstat/mailboxd.csv', 'Post Office Protocol time'); $pmda->add_metric(pmda_pmid(3,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.mailboxd.idx.wrt_avg', '/opt/zimbra/zmstat/mailboxd.csv', 'Lucene Index Writer count'); $pmda->add_metric(pmda_pmid(3,23), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.mailboxd.idx.wrt_opened', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,24), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.idx.wrt_opened_cache_hit', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,25), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.calcache.hit', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,26), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.calcache.mem_hit', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,27), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.calcache.lru_size', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,28), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.idx.bytes_written', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,29), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.idx.bytes_written_avg', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,30), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.idx.bytes_read', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,31), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.idx.bytes_read_avg', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,32), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.bis.read', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,33), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.mailboxd.bis.seek_rate', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,34), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.mailboxd.db_pool_size', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,35), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.innodb_bp_hit_rate', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,36), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.pop.conn', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,37), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.pop.ssl_conn', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,38), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.imap.conn', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,39), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.imap.ssl_conn', '/opt/zimbra/zmstat/mailboxd.csv', ''); $pmda->add_metric(pmda_pmid(3,40), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.soap.sessions', '/opt/zimbra/zmstat/mailboxd.csv', 'Simple Object Access Protocol session count'); # Zimbra duplicates four metrics here, so skip four for direct indexing $pmda->add_metric(pmda_pmid(3,45), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.gc.minor_count', '/opt/zimbra/zmstat/mailboxd.csv', 'Java minor garbage collection count'); $pmda->add_metric(pmda_pmid(3,46), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'zimbra.mailboxd.gc.minor_time', '/opt/zimbra/zmstat/mailboxd.csv', 'Java minor garbage collection time'); $pmda->add_metric(pmda_pmid(3,47), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.mailboxd.gc.major_count', '/opt/zimbra/zmstat/mailboxd.csv', 'Java major garbage collection count'); $pmda->add_metric(pmda_pmid(3,48), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'zimbra.mailboxd.gc.major_time', '/opt/zimbra/zmstat/mailboxd.csv', 'Java major garbage collection time'); $pmda->add_metric(pmda_pmid(3,49), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.mempool.code_cache_used', '/opt/zimbra/zmstat/mailboxd.csv', 'Java code cache space used'); $pmda->add_metric(pmda_pmid(3,50), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.mempool.code_cache_free', '/opt/zimbra/zmstat/mailboxd.csv', 'Java code cache space free'); $pmda->add_metric(pmda_pmid(3,51), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.mempool.eden_space_used', '/opt/zimbra/zmstat/mailboxd.csv', 'Java Eden area space used'); $pmda->add_metric(pmda_pmid(3,52), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.mempool.eden_space_free', '/opt/zimbra/zmstat/mailboxd.csv', 'Java Eden area space free'); $pmda->add_metric(pmda_pmid(3,53), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.mempool.survivor_space_used', '/opt/zimbra/zmstat/mailboxd.csv', 'Java survivor area space used'); $pmda->add_metric(pmda_pmid(3,54), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.mempool.survivor_space_free', '/opt/zimbra/zmstat/mailboxd.csv', 'Java survivor area space free'); $pmda->add_metric(pmda_pmid(3,55), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.mempool.old_gen_space_used', '/opt/zimbra/zmstat/mailboxd.csv', 'Java old generation space used'); $pmda->add_metric(pmda_pmid(3,56), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.mempool.old_gen_space_free', '/opt/zimbra/zmstat/mailboxd.csv', 'Java old generation space free'); $pmda->add_metric(pmda_pmid(3,57), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.mempool.perm_gen_space_used', '/opt/zimbra/zmstat/mailboxd.csv', 'Java permanent generation space used'); $pmda->add_metric(pmda_pmid(3,58), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.mempool.perm_gen_space_free', '/opt/zimbra/zmstat/mailboxd.csv', 'Java permanent generation space free'); $pmda->add_metric(pmda_pmid(3,59), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.heap.used', '/opt/zimbra/zmstat/mailboxd.csv', 'Java heap space used'); $pmda->add_metric(pmda_pmid(3,60), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'zimbra.mailboxd.heap.free', '/opt/zimbra/zmstat/mailboxd.csv', 'Java heap space free'); $pmda->add_metric(pmda_pmid(4,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'zimbra.mtaqueue.size', '/opt/zimbra/zmstat/mtaqueue.csv', 'Number of kilobytes queued to the Mail Transfer Agent'); $pmda->add_metric(pmda_pmid(4,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'zimbra.mtaqueue.requests', '/opt/zimbra/zmstat/mtaqueue.csv', 'Number of requests queued to the Mail Transfer Agent'); $pmda->add_metric(pmda_pmid(5,0), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.mailbox.cputime', '/opt/zimbra/zmstat/proc.csv', 'Total time as a percentage spent executing the mailbox process'); $pmda->add_metric(pmda_pmid(5,1), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.mailbox.utime', '/opt/zimbra/zmstat/proc.csv', 'Total user time as a percentage spent executing the mailbox process'); $pmda->add_metric(pmda_pmid(5,2), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.mailbox.stime', '/opt/zimbra/zmstat/proc.csv', 'Total systime as a percentage spent executing the mailbox process'); $pmda->add_metric(pmda_pmid(5,3), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.mailbox.total', '/opt/zimbra/zmstat/proc.csv', 'Total virtual memory footprint of the mailbox processes'); $pmda->add_metric(pmda_pmid(5,4), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.mailbox.rss', '/opt/zimbra/zmstat/proc.csv', 'Resident set size of the mailbox processes'); $pmda->add_metric(pmda_pmid(5,5), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.mailbox.shared', '/opt/zimbra/zmstat/proc.csv', 'Shared memory space used by the mailbox processes'); $pmda->add_metric(pmda_pmid(5,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.proc.mailbox.count', '/opt/zimbra/zmstat/proc.csv', 'Total number of mailbox processes'); $pmda->add_metric(pmda_pmid(5,7), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.mysql.cputime', '/opt/zimbra/zmstat/proc.csv', 'Total time as a percentage spent executing the MySQL process'); $pmda->add_metric(pmda_pmid(5,8), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.mysql.utime', '/opt/zimbra/zmstat/proc.csv', 'Total user time as a percentage spent executing the MySQL process'); $pmda->add_metric(pmda_pmid(5,9), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.mysql.stime', '/opt/zimbra/zmstat/proc.csv', 'Total systime as a percentage spent executing the MySQL process'); $pmda->add_metric(pmda_pmid(5,10), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.mysql.total', '/opt/zimbra/zmstat/proc.csv', 'Total virtual memory footprint of the MySQL processes'); $pmda->add_metric(pmda_pmid(5,11), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.mysql.rss', '/opt/zimbra/zmstat/proc.csv', 'Resident set size of the MySQL processes'); $pmda->add_metric(pmda_pmid(5,12), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.mysql.shared', '/opt/zimbra/zmstat/proc.csv', 'Shared memory space used by the MySQL processes'); $pmda->add_metric(pmda_pmid(5,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.proc.mysql.count', '/opt/zimbra/zmstat/proc.csv', 'Total number of MySQL processes'); $pmda->add_metric(pmda_pmid(5,14), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.convertd.cputime', '/opt/zimbra/zmstat/proc.csv', 'Total time as a percentage spent executing the convertd process'); $pmda->add_metric(pmda_pmid(5,15), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.convertd.utime', '/opt/zimbra/zmstat/proc.csv', 'Total user time as a percentage spent executing the convertd process'); $pmda->add_metric(pmda_pmid(5,16), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.convertd.stime', '/opt/zimbra/zmstat/proc.csv', 'Total systime as a percentage spent executing the convertd process'); $pmda->add_metric(pmda_pmid(5,17), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.convertd.total', '/opt/zimbra/zmstat/proc.csv', 'Total virtual memory footprint of the convertd processes'); $pmda->add_metric(pmda_pmid(5,18), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.convertd.rss', '/opt/zimbra/zmstat/proc.csv', 'Resident set size of the convertd processes'); $pmda->add_metric(pmda_pmid(5,19), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.convertd.shared', '/opt/zimbra/zmstat/proc.csv', 'Shared memory space used by the convertd processes'); $pmda->add_metric(pmda_pmid(5,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.proc.convertd.count', '/opt/zimbra/zmstat/proc.csv', 'Total number of convertd processes'); $pmda->add_metric(pmda_pmid(5,21), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.ldap.cputime', '/opt/zimbra/zmstat/proc.csv', 'Total time as a percentage spent executing the LDAP process'); $pmda->add_metric(pmda_pmid(5,22), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.ldap.utime', '/opt/zimbra/zmstat/proc.csv', 'Total user time as a percentage spent executing the LDAP process'); $pmda->add_metric(pmda_pmid(5,23), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.ldap.stime', '/opt/zimbra/zmstat/proc.csv', 'Total systime as a percentage spent executing the LDAP process'); $pmda->add_metric(pmda_pmid(5,24), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.ldap.total', '/opt/zimbra/zmstat/proc.csv', 'Total virtual memory footprint of the LDAP processes'); $pmda->add_metric(pmda_pmid(5,25), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.ldap.rss', '/opt/zimbra/zmstat/proc.csv', 'Resident set size of the LDAP processes'); $pmda->add_metric(pmda_pmid(5,26), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.ldap.shared', '/opt/zimbra/zmstat/proc.csv', 'Shared memory space used by the LDAP processes'); $pmda->add_metric(pmda_pmid(5,27), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.proc.ldap.count', '/opt/zimbra/zmstat/proc.csv', 'Total number of LDAP processes'); $pmda->add_metric(pmda_pmid(5,28), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.postfix.cputime', '/opt/zimbra/zmstat/proc.csv', 'Total time as a percentage spent executing the postfix process'); $pmda->add_metric(pmda_pmid(5,29), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.postfix.utime', '/opt/zimbra/zmstat/proc.csv', 'Total user time as a percentage spent executing the postfix process'); $pmda->add_metric(pmda_pmid(5,30), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.postfix.stime', '/opt/zimbra/zmstat/proc.csv', 'Total systime as a percentage spent executing the postfix process'); $pmda->add_metric(pmda_pmid(5,31), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.postfix.total', '/opt/zimbra/zmstat/proc.csv', 'Total virtual memory footprint of the postfix processes'); $pmda->add_metric(pmda_pmid(5,32), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.postfix.rss', '/opt/zimbra/zmstat/proc.csv', 'Resident set size of the postfix processes'); $pmda->add_metric(pmda_pmid(5,33), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.postfix.shared', '/opt/zimbra/zmstat/proc.csv', 'Shared memory space used by the postfix processes'); $pmda->add_metric(pmda_pmid(5,34), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.proc.postfix.count', '/opt/zimbra/zmstat/proc.csv', 'Total number of postfix processes'); $pmda->add_metric(pmda_pmid(5,35), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.amavis.cputime', '/opt/zimbra/zmstat/proc.csv', 'Total time as a percentage spent executing the virus scanner'); $pmda->add_metric(pmda_pmid(5,36), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.amavis.utime', '/opt/zimbra/zmstat/proc.csv', 'Total user time as a percentage spent executing the virus scanner'); $pmda->add_metric(pmda_pmid(5,37), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.amavis.stime', '/opt/zimbra/zmstat/proc.csv', 'Total systime as a percentage spent executing the virus scanner'); $pmda->add_metric(pmda_pmid(5,38), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.amavis.total', '/opt/zimbra/zmstat/proc.csv', 'Total virtual memory footprint of the virus scanner process'); $pmda->add_metric(pmda_pmid(5,39), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.amavis.rss', '/opt/zimbra/zmstat/proc.csv', 'Resident set size of the virus scanner process'); $pmda->add_metric(pmda_pmid(5,40), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.amavis.shared', '/opt/zimbra/zmstat/proc.csv', 'Shared memory space used by the virus scanner processes'); $pmda->add_metric(pmda_pmid(5,41), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.proc.amavis.count', '/opt/zimbra/zmstat/proc.csv', 'Total number of virus scanner processes'); $pmda->add_metric(pmda_pmid(5,42), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.clam.cputime', '/opt/zimbra/zmstat/proc.csv', 'Total time as a percentage spent executing the anti-virus process'); $pmda->add_metric(pmda_pmid(5,43), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.clam.utime', '/opt/zimbra/zmstat/proc.csv', 'Total user time as a percentage spent executing the anti-virus process'); $pmda->add_metric(pmda_pmid(5,44), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.proc.clam.stime', '/opt/zimbra/zmstat/proc.csv', 'Total systime as a percentage spent executing the anti-virus process'); $pmda->add_metric(pmda_pmid(5,45), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.clam.total', '/opt/zimbra/zmstat/proc.csv', 'Total virtual memory footprint of the anti-virus processes'); $pmda->add_metric(pmda_pmid(5,46), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.clam.rss', '/opt/zimbra/zmstat/proc.csv', 'Resident set size of the clam processes'); $pmda->add_metric(pmda_pmid(5,47), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'zimbra.proc.clam.shared', '/opt/zimbra/zmstat/proc.csv', 'Shared memory space used by the anti-virus processes'); $pmda->add_metric(pmda_pmid(5,48), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.proc.clam.count', '/opt/zimbra/zmstat/proc.csv', 'Total number of anti-virus processes'); $pmda->add_metric(pmda_pmid(6,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.btpool', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.pool', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.lmtp', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.imap', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.pop3', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.scheduled_tasks', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.timer', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.anonymous_io', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.flap_processor', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.gc', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.socket_acceptor', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.thread', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.other', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(6,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'zimbra.threads.total', '/opt/zimbra/zmstat/threads.csv', ''); $pmda->add_metric(pmda_pmid(7,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.control.fd.timestamp', 'Timestamp for completion of last fd value fetch', ''); $pmda->add_metric(pmda_pmid(7,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.control.imap.timestamp', 'Timestamp for completion of last imap value fetch', ''); $pmda->add_metric(pmda_pmid(7,2), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.control.soap.timestamp', 'Timestamp for completion of last soap value fetch', ''); $pmda->add_metric(pmda_pmid(7,3), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.control.mailbox.timestamp', 'Timestamp for completion of last mailbox value fetch', ''); $pmda->add_metric(pmda_pmid(7,4), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.control.mtaqueue.timestamp', 'Timestamp for completion of last mtaqueue value fetch', ''); $pmda->add_metric(pmda_pmid(7,5), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.control.proc.timestamp', 'Timestamp for completion of last process value fetch', ''); $pmda->add_metric(pmda_pmid(7,6), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.control.threads.timestamp', 'Timestamp for completion of last threads value fetch', ''); $pmda->add_metric(pmda_pmid(7,7), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.control.status.timestamp', 'Timestamp for completion of last status probe', ''); $pmda->add_metric(pmda_pmid(8,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.status.antivirus', 'Status for Zimbra antivirus service - 0=stopped, 1=running', ''); $pmda->add_metric(pmda_pmid(8,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.status.antispam', 'Status for Zimbra antispam service - 0=stopped, 1=running', ''); $pmda->add_metric(pmda_pmid(8,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.status.archiving', 'Status for Zimbra archiving service - 0=stopped, 1=running', ''); $pmda->add_metric(pmda_pmid(8,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.status.convertd', 'Status for Zimbra convertd service - 0=stopped, 1=running', ''); $pmda->add_metric(pmda_pmid(8,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.status.mta', 'Status for Zimbra MTA service - 0=stopped, 1=running', ''); $pmda->add_metric(pmda_pmid(8,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.status.mailbox', 'Status for Zimbra mailbox service - 0=stopped, 1=running', ''); $pmda->add_metric(pmda_pmid(8,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.status.logger', 'Status for Zimbra logger service - 0=stopped, 1=running', ''); $pmda->add_metric(pmda_pmid(8,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.status.snmp', 'Status for Zimbra SNMP service - 0=stopped, 1=running', ''); $pmda->add_metric(pmda_pmid(8,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.status.ldap', 'Status for Zimbra LDAP service - 0=stopped, 1=running', ''); $pmda->add_metric(pmda_pmid(8,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.status.spell', 'Status for Zimbra spell service - 0=stopped, 1=running', ''); $pmda->add_metric(pmda_pmid(8,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.status.imapproxy', 'Status for Zimbra imapproxy service - 0=stopped, 1=running', ''); $pmda->add_metric(pmda_pmid(8,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'zimbra.status.stats', 'Status for Zimbra stats service - 0=stopped, 1=running', ''); $pmda->add_indom($imap_domain, \@imap_indom, 'IMAP operations', 'Internet Message Access Protocol operations'); $pmda->add_indom($soap_domain, \@soap_indom, 'SOAP operation', 'Simple Object Access Protocol operations'); $pmda->add_tail($stats . 'fd.csv', \&zimbra_fd_parser, 0); $pmda->add_tail($stats . 'imap.csv', \&zimbra_imap_parser, 0); $pmda->add_tail($stats . 'mailboxd.csv', \&zimbra_mailbox_parser, 0); $pmda->add_tail($stats . 'mtaqueue.csv', \&zimbra_mtaqueue_parser, 0); $pmda->add_tail($stats . 'proc.csv', \&zimbra_proc_parser, 0); $pmda->add_tail($stats . 'soap.csv', \&zimbra_soap_parser, 0); $pmda->add_tail($stats . 'threads.csv', \&zimbra_threads_parser, 0); $pmda->add_pipe($probe, \&zimbra_probe_callback, 0); $pmda->set_fetch_callback(\&zimbra_fetch_callback); $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdazimbra - Zimbra Collaboration Suite (ZCS) PMDA =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from several subsystems of the Zimbra Suite. Further details on Zimbra can be found at http://www.zimbra.com/. =head1 INSTALLATION If you want access to the names and values for the zimbra performance metrics, do the following as root: # cd $PCP_PMDAS_DIR/zimbra # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/zimbra # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item /opt/zimbra/zmstat/* comma-separated value files containing Zimbra performance data =item $PCP_PMDAS_DIR/zimbra/Install installation script for the B agent =item $PCP_PMDAS_DIR/zimbra/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/zimbra.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1). pcp-3.8.12ubuntu1/src/pmdas/kvm/0000775000000000000000000000000012272262620013274 5ustar pcp-3.8.12ubuntu1/src/pmdas/kvm/Remove0000775000000000000000000000125212272262501014455 0ustar #! /bin/sh # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the KVM PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=kvm pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/kvm/Install0000775000000000000000000000200612272262501014624 0ustar #! /bin/sh # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the KVM PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=kvm perl_opt=true daemon_opt=false forced_restart=true if ! test -d /sys/kernel/debug; then echo "DEBUGFS not enabled in your kernel" exit 1 fi if ! test -d /sys/kernel/debug/kvm; then echo "KVM statistics unavailable (load kvm module and mount debugfs)" exit 1 fi if ! test -r /sys/kernel/debug/kvm; then forced_restart=true fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/kvm/GNUmakefile0000664000000000000000000000275012272262501015350 0ustar #!gmake # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = kvm PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) ifeq "$(TARGET_OS)" "linux" install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) else install: endif default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/kvm/pmdakvm.pl0000664000000000000000000000641112272262501015270 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; use vars qw( $pmda ); my $kvm_path = '/sys/kernel/debug/kvm'; sub kvm_fetch_callback { my ($cluster, $item, $inst) = @_; my $metric_name = pmda_pmid_name($cluster, $item); my ($path, $value, $fh); # $pmda->log("kvm_fetch_callback $metric_name $cluster:$item ($inst)\n"); if ($inst != PM_IN_NULL) { return (PM_ERR_INST, 0); } if (!defined($metric_name)) { return (PM_ERR_PMID, 0); } $path = $metric_name; $path =~ s/^kvm\./$kvm_path\//; open($fh, $path) || return (PM_ERR_APPVERSION, 0); $value = <$fh>; close $fh; if (!defined($value)) { return (PM_ERR_APPVERSION, 0); } return ($value, 1); } $pmda = PCP::PMDA->new('kvm', 95); # May need to be root to read the directory $kvm_path (/sys/kernel/debug/kvm) # and so # (a) do not use $pmda->set_user('pcp') below, and # (b) need forced_restart=true in the Install script so pmcd is restarted # and we're running as root at this point (SIGHUP pmcd once it has # changed to user "pcp" is not going to work for PMDA installation) # my $pmid = 0; opendir(DIR, $kvm_path) || $pmda->err("pmdakvm failed to open $kvm_path: $!"); my @metrics = grep { unless (/^\./) { $pmda->add_metric(pmda_pmid(0,$pmid++), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "kvm.$_", '', ''); # $pmda->log("pmdakvm added metric kvm.$_\n"); } } readdir(DIR); closedir DIR; $pmda->set_fetch_callback(\&kvm_fetch_callback); # Careful with permissions - may need to be root to read /sys/kernel/debug/kvm # see note above. #$pmda->set_user('pcp') if -r $kvm_path; $pmda->run; =pod =head1 NAME pmdakvm - Linux virtualisation performance metrics domain agent (PMDA) =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from the Linux KVM virtualisation subsystem. Unlike many PMDAs it dynamically enumerates its metric hierarchy, based entirely on the contents of /sys/kernel/debug/kvm. =head1 INSTALLATION If you want access to the names and values for the kvm performance metrics, do the following as root: # cd $PCP_PMDAS_DIR/kvm # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/kvm # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/kvm/Install installation script for the B agent =item $PCP_PMDAS_DIR/kvm/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/kvm.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1) and kvm(1). pcp-3.8.12ubuntu1/src/pmdas/systemtap/0000775000000000000000000000000012272262620014530 5ustar pcp-3.8.12ubuntu1/src/pmdas/systemtap/Remove0000775000000000000000000000161212272262501015711 0ustar #! /bin/sh # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the SystemTap PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=systemtap pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/systemtap/Install0000775000000000000000000000151612272262501016065 0ustar #!/bin/sh # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the SystemTap PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=systemtap perl_opt=true daemon_opt=false forced_restart=false if ! test -x /usr/bin/stap; then echo "SystemTap \"stap\" tool is not installed" && exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/systemtap/GNUmakefile0000664000000000000000000000277412272262501016612 0ustar #!gmake # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = systemtap DOMAIN = SYSTEMTAP PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl probes.stp ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif LDIRT = domain.h root pmns *.log $(MAN_PAGES) default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default ifeq "$(TARGET_OS)" "linux" $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 probes.stp pmda$(IAM).pl $(PMDADIR) @$(INSTALL_MAN) endif default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/systemtap/probes.stp0000664000000000000000000000026212272262501016550 0ustar probe kernel.function("vfs_readdir") { printf ("readdir: (%d) %s\n", pid(), execname()) } probe kernel.function("sys_sync") { printf ("sync: (%d) %s\n", pid(), execname()) } pcp-3.8.12ubuntu1/src/pmdas/systemtap/pmdasystemtap.pl0000664000000000000000000001114512272262501017760 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; use vars qw( $pmda $id ); my $probe_indom = 0; my $probe_script = pmda_config('PCP_PMDAS_DIR') . '/systemtap/probes.stp'; my $probe_command = "/usr/bin/stap -m pmdasystemtap $probe_script"; my @probe_instances = ( 0 => 'sync', 1 => 'readdir' ); my ( $sync_count, $sync_pid, $sync_cmd ) = ( 0, 0, "(none)" ); my ( $readdir_count, $readdir_pid, $readdir_cmd ) = ( 0, 0, "(none)" ); sub systemtap_input_callback { ( $id, $_ ) = @_; # $pmda->log($_); if (/^readdir: \((\d+)\) (.*)$/) { ( $readdir_pid, $readdir_cmd ) = ( $1, $2 ); $readdir_count++; } elsif (/^sync: \((\d+)\) (.*)$/) { ( $sync_pid, $sync_cmd ) = ( $1, $2 ); $sync_count++; } } sub systemtap_fetch_callback { my ($cluster, $item, $inst) = @_; if ($inst < 0 || $inst > 1) { return (PM_ERR_INST, 0); } if ($cluster == 0) { if ($item == 0) { if ($inst == 0) { return ($sync_count, 1); } else { return ($readdir_count, 1); } } elsif ($item == 1) { if ($inst == 0) { return ($sync_pid, 1); } else { return ($readdir_pid, 1); } } elsif ($item == 2) { if ($inst == 0) { return ($sync_cmd, 1); } else { return ($readdir_cmd, 1); } } } return (PM_ERR_PMID, 0); } $pmda = PCP::PMDA->new('systemtap', 88); $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U32, $probe_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'systemtap.probes.count', 'Number of times the probe has been observed', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_32, $probe_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'systemtap.probes.pid', 'The PID of the last process to pass the probe point', ''); $pmda->add_metric(pmda_pmid(0,2), PM_TYPE_STRING, $probe_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'systemtap.probes.cmd', 'The name of the last process to pass the probe point', ''); $pmda->add_indom($probe_indom, \@probe_instances, 'Instance domain exporting each SystemTap probe', ''); $pmda->set_fetch_callback(\&systemtap_fetch_callback); $pmda->add_pipe($probe_command, \&systemtap_input_callback, 0); $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdasystemtap - Systemtap performance metrics domain agent (PMDA) =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from the Linux Systemtap dynamic tracing toolkit. This implementation uses the stap(1) tool, which is a front-end to the Systemtap toolkit. =head1 INSTALLATION In order to access performance data exported by Systemtap from with PCP, it is necessary to perform two configuration steps: =over =item 1. Configure Systemtap probes, and verify them with stap(1). These should be produced in a format that is easily parsed, and then stored in the $PCP_PMDAS_DIR/systemtap/probes.stp file. =item 2. Configure B to extract the values from the text produced by stap. Two example probes are implemented in the default systemtap PMDA script - readdir and sync traces (see $PCP_PMDAS_DIR/systemtap/pmdasystemtap.pl for details). =back # cd $PCP_PMDAS_DIR/systemtap # [ edit probes.stp, test /usr/bin/stap probes.stp ] # [ edit pmdasystemtap.pl ] Once this is setup, you can access the names and values for the systemtap performance metrics by doing the following as root: # cd $PCP_PMDAS_DIR/systemtap # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/systemtap # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/systemtap/probes.stp probe configuration file for stap(1), run by B =item $PCP_PMDAS_DIR/systemtap/Install installation script for the B agent =item $PCP_PMDAS_DIR/systemtap/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/systemtap.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1) and stap(1). pcp-3.8.12ubuntu1/src/pmdas/logger/0000775000000000000000000000000012272262620013756 5ustar pcp-3.8.12ubuntu1/src/pmdas/logger/util.c0000664000000000000000000001104012272262501015071 0ustar /* * Utility functions for the logger PMDA. * * Copyright (c) 2011 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "util.h" void rstrip(char *str) { char *ptr; /* Remove all trailing whitespace. Set ptr to last char of * string. */ ptr = str + strlen(str) - 1; /* While trailing whitespace, move back. */ while (ptr >= str && isspace((int)*ptr)) { --ptr; } *(ptr+1) = '\0'; /* Now set '\0' as terminal byte. */ } char * lstrip(char *str) { /* While leading whitespace, move forward. */ char *ptr = str; while (*ptr != '\0' && isspace((int)*ptr)) { ptr++; } return ptr; } int start_cmd(const char *cmd, pid_t *ppid) { pid_t child_pid; int rc; int pipe_fds[2]; #define PARENT_END 0 /* parent end of the pipe */ #define CHILD_END 1 /* child end of the pipe */ #define STDOUT_FD 1 /* stdout fd */ /* FIXME items: * (1) Should we be looking to handle shell metachars * differently? Perhaps we should just allow isalnum()||isspace() * chars only. * (2) Do we need to clean up the environment in the child before * the exec()? Remove things like IFS, CDPATH, ENV, and BASH_ENV. */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_INFO, "%s: Trying to run command: %s", __FUNCTION__, cmd); #endif /* Create the pipes. */ #if defined(HAVE_PIPE2) rc = pipe2(pipe_fds, O_CLOEXEC|O_NONBLOCK); if (rc < 0) { __pmNotifyErr(LOG_ERR, "%s: pipe2() returned %s", __FUNCTION__, strerror(-rc)); return rc; } #else rc = pipe(pipe_fds); if (rc < 0) { __pmNotifyErr(LOG_ERR, "%s: pipe() returned %s", __FUNCTION__, strerror(-rc)); return rc; } /* Set the right flags on the pipes. */ if (fcntl(pipe_fds[PARENT_END], F_SETFL, O_NDELAY) < 0 || fcntl(pipe_fds[CHILD_END], F_SETFL, O_NDELAY) < 0) { __pmNotifyErr(LOG_ERR, "%s: fcntl() returned %s", __FUNCTION__, strerror(-rc)); return rc; } if (fcntl(pipe_fds[PARENT_END], F_SETFD, O_CLOEXEC) < 0 || fcntl(pipe_fds[CHILD_END], F_SETFD, O_CLOEXEC) < 0) { __pmNotifyErr(LOG_ERR, "%s: fcntl() returned %s", __FUNCTION__, strerror(-rc)); return rc; } #endif /* Create the new process. */ child_pid = fork(); if (child_pid == 0) { /* child process */ int i; /* Duplicate our pipe fd onto stdout of the child. Note that * this clears O_CLOEXEC, so the new stdout should stay open * when we call exec(). */ if (pipe_fds[CHILD_END] != STDOUT_FD) { if (dup2(pipe_fds[CHILD_END], STDOUT_FD) < 0) { __pmNotifyErr(LOG_ERR, "%s: dup2() returned %s", __FUNCTION__, strerror(errno)); _exit(127); } } /* Close all other fds. */ for (i = 0; i <= pipe_fds[CHILD_END]; i++) { if (i != STDOUT_FD) { close(i); } } /* Actually run the command. */ execl ("/bin/sh", "sh", "-c", cmd, (char *)NULL); _exit (127); } else if (child_pid > 0) { /* parent process */ close (pipe_fds[CHILD_END]); if (ppid != NULL) { *ppid = child_pid; } } else if (child_pid < 0) { /* fork error */ int errno_save = errno; __pmNotifyErr(LOG_ERR, "%s: fork() returned %s", __FUNCTION__, strerror(errno_save)); close (pipe_fds[PARENT_END]); close (pipe_fds[CHILD_END]); return -errno_save; } return pipe_fds[PARENT_END]; } int stop_cmd(pid_t pid) { int rc; pid_t wait_pid; int wstatus; __pmNotifyErr(LOG_INFO, "%s: killing pid %" FMT_PID, __FUNCTION__, pid); /* Send the TERM signal. */ rc = kill(pid, SIGTERM); __pmNotifyErr(LOG_INFO, "%s: kill returned %d", __FUNCTION__, rc); /* Wait for the process to go away. */ do { wait_pid = waitpid (pid, &wstatus, 0); __pmNotifyErr(LOG_INFO, "%s: waitpid returned %d", __FUNCTION__, (int)wait_pid); } while (wait_pid == -1 && errno == EINTR); /* Return process exit status. */ return wstatus; } pcp-3.8.12ubuntu1/src/pmdas/logger/README0000664000000000000000000000241312272262501014634 0ustar Logger PMDA =========== This PMDA exports information about the event status of log files specified in a config file. The default configuration file is $PCP_VAR_DIR/config/logger/logger.conf, which should contain one line for each file you wish to monitor. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT logger Installation ============ + # cd $PCP_PMDAS_DIR/logger + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options -- everything else is automated. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/logger # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/logger.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/logger/Remove0000664000000000000000000000133712272262501015140 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2011 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the logger PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=logger pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/logger/Install0000664000000000000000000001004112272262501015301 0ustar #! /bin/sh # # Copyright (c) 2011-2012 Red Hat. # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the logger PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=logger pmda_interface=5 forced_restart=false pmdaSetup # be careful that mortals cannot write any configuration files, as # these would present a security problem # umask 022 # PMDA variables # configfile="" _parsedefaults() { echo "Extracting options from current installation ..." while getopts D:d:l c do case $c in \?) echo "Warning: Unrecognized option in $PCP_PMCDCONF_PATH" echo " Remove line for the $iam PMDA in $PCP_PMCDCONF_PATH and re-run ./Install" exit 2;; * ) ;; esac done eval configfile='$'$OPTIND } # Get logfile(s) to monitor if $do_pmda then # set options from $PCP_PMCDCONF_PATH, if possible # ans=`$PCP_AWK_PROG <$PCP_PMCDCONF_PATH ' $1 == "'$iam'" { printf "%s",$6 for (i=7;i<=NF;i++) printf " %s",$i print "" }'` if [ ! -z "$ans" ] then _parsedefaults $ans fi # go figure out which configuration file to use ... # #default_configfile=./sample.conf default_configfile='' pmdaChooseConfigFile if [ ! -f "$configfile" ] then $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to enter logfile names and paths manually? [y] ""$PCP_ECHO_C" read ans if [ "X$ans" = "Xy" -o "X$ans" = "XY" -o -z "$ans" ] then configfile="$configdir/$iam.conf" if [ -f "$configfile" ] then echo "Removing old configuration file \"$configfile\"" rm -f "$configfile" if [ -f "$configfile" ] then echo "Cannot remove \"$configfile\"" exit 1 fi fi echo echo \ 'Enter the PMNS name and logfile path. If the path ends in "|", the filename is interpreted as a command which will output data. An empty line terminates the logfile selection process and there must be at least one logfile specified. ' args="" touch "$configfile" if [ ! -f "$configfile" ] then echo "Installation aborted." exit 1 fi while [ ! -s "$configfile" ] do while true do $PCP_ECHO_PROG $PCP_ECHO_N "Logfile PMNS name: ""$PCP_ECHO_C" read name [ -z "$name" ] && break # Check name for invalid chars. if ! echo $name | grep "^[A-Za-z][_A-Za-z0-9]*$" > /dev/null then echo \ "Invalid characters in PMNS name: \"$name\". Names must start with an alphabetic character ([a-zA-Z]). The rest of the characters in the name must be alphanumeric ([a-zA-Z0-9]) or an underscore ('_')." continue fi # Make sure name isn't already in the logfile. if grep "^${name}[ \t]" "$configfile" >/dev/null then echo "Sorry, logfile PMNS name \"$name\" already specified. Please try again." continue fi $PCP_ECHO_PROG $PCP_ECHO_N "Logfile pathname: ""$PCP_ECHO_C" read pathname [ -z "$pathname" ] && break if grep "[ \t]${pathname}$" "$configfile" >/dev/null then echo "Sorry, pathname \"$pathname\" already specified. Please try again." continue fi $PCP_ECHO_PROG $PCP_ECHO_N "Restricted access [n]: ""$PCP_ECHO_C" read restrict if [ "$restrict" = "y" -o "$restrict" = "yes" ]; then restrict="y" else restrict="n" fi echo "$name $restrict $pathname" >>"$configfile" done done else echo "" echo "Error: Abandoning installation as no configuration file was specified." exit 1 fi fi args="$configfile" fi pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/logger/GNUmakefile0000664000000000000000000000302412272262501016025 0ustar # # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2011 Nathan Scott. All Rights Reversed. # Copyright (c) 2011-2012 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs CMDTARGET = pmdalogger$(EXECSUFFIX) DFILES = README CFILES = event.c util.c logger.c HFILES = event.h util.h LLDLIBS = $(PCP_PMDALIB) LSRCFILES = Install Remove pmns help $(DFILES) root IAM = logger DOMAIN = LOGGER PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LDIRT = domain.h *.o $(IAM).log $(CMDTARGET) default: domain.h $(CMDTARGET) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 $(DFILES) root help pmns $(PMDADIR) $(INSTALL) -m 644 domain.h $(PMDADIR)/domain.h $(INSTALL) -m 755 $(CMDTARGET) $(PMDADIR)/$(CMDTARGET) logger.o: domain.h event.o logger.o: event.h util.o event.o logger.o: util.h .NOTPARALLEL: .ORDER: domain.h $(OBJECTS) default_pcp : default install_pcp : install domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/logger/root0000664000000000000000000000016312272262501014662 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { logger } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/logger/logger.c0000664000000000000000000003772412272262501015414 0ustar /* * Logger, a configurable log file monitoring PMDA * * Copyright (c) 2011-2012 Red Hat. * Copyright (c) 2011 Nathan Scott. All Rights Reserved. * Copyright (c) 1995,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Debug options * APPL0 configfile processing and PMNS setup * APPL1 loading event data from the log files * APPL2 interaction with PMCD */ #include "domain.h" #include "event.h" #include "util.h" #include "pmda.h" /* * Logger PMDA * * Metrics * logger.numclients - number of attached clients * logger.numlogfiles - number of monitored logfiles * logger.param_string - string event data * logger.perfile.{LOGFILE}.count - observed event count * logger.perfile.{LOGFILE}.bytes - observed events size * logger.perfile.{LOGFILE}.size - logfile size * logger.perfile.{LOGFILE}.path - logfile path * logger.perfile.{LOGFILE}.numclients - number of attached * clients/logfile * logger.perfile.{LOGFILE}.records - event records/logfile */ #define DEFAULT_MAXMEM (2 * 1024 * 1024) /* 2 megabytes */ long maxmem; int maxfd; fd_set fds; static int interval_expired; static struct timeval interval = { 2, 0 }; static char *username; static int nummetrics; static __pmnsTree *pmns; typedef struct dynamic_metric_info { int handle; int pmid_index; const char *help_text; } dynamic_metric_info_t; static dynamic_metric_info_t *dynamic_metric_infotab; static pmdaMetric dynamic_metrictab[] = { /* perfile.{LOGFILE}.count */ { NULL, /* m_user gets filled in later */ { 0 /* pmid gets filled in later */, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* perfile.{LOGFILE}.bytes */ { NULL, /* m_user gets filled in later */ { 0 /* pmid gets filled in later */, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* perfile.{LOGFILE}.size */ { NULL, /* m_user gets filled in later */ { 0 /* pmid gets filled in later */, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* perfile.{LOGFILE}.path */ { NULL, /* m_user gets filled in later */ { 0 /* pmid gets filled in later */, PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* perfile.{LOGFILE}.numclients */ { NULL, /* m_user gets filled in later */ { 0 /* pmid gets filled in later */, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* perfile.{LOGFILE}.records */ { NULL, /* m_user gets filled in later */ { 0 /* pmid gets filled in later */, PM_TYPE_EVENT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* perfile.{LOGFILE}.queuemem */ { NULL, /* m_user gets filled in later */ { 0 /* pmid gets filled in later */, PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, }; static char *dynamic_nametab[] = { /* perfile.{LOGFILE}.count */ "count", /* perfile.{LOGFILE}.bytes */ "bytes", /* perfile.{LOGFILE}.size */ "size", /* perfile.{LOGFILE}.path */ "path", /* perfile.{LOGFILE}.numclients */ "numclients", /* perfile.{LOGFILE}.records */ "records", /* perfile.{LOGFILE}.queuemem */ "queuemem", }; static const char *dynamic_helptab[] = { /* perfile.{LOGFILE}.count */ "The cumulative number of events seen for this logfile.", /* perfile.{LOGFILE}.bytes */ "Cumulative number of bytes in events seen for this logfile.", /* perfile.{LOGFILE}.size */ "The current size of this logfile.", /* perfile.{LOGFILE}.path */ "The path for this logfile.", /* perfile.{LOGFILE}.numclients */ "The number of attached clients for this logfile.", /* perfile.{LOGFILE}.records */ "Event records for this logfile.", /* perfile.{LOGFILE}.queuemem */ "Amount of memory used for event data.", }; static pmdaMetric static_metrictab[] = { /* numclients */ { NULL, { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* numlogfiles */ { NULL, { PMDA_PMID(0,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* param_string */ { NULL, { PMDA_PMID(0,2), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* perfile.maxmem */ { NULL, /* m_user gets filled in later */ { PMDA_PMID(0,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, }; static pmdaMetric *metrictab; static int logger_profile(__pmProfile *prof, pmdaExt *pmda) { pmdaEventNewClient(pmda->e_context); return 0; } static int logger_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { pmdaEventNewClient(pmda->e_context); return pmdaFetch(numpmid, pmidlist, resp, pmda); } static int valid_pmid(unsigned int cluster, unsigned int item) { if (cluster != 0 || item > nummetrics) return PM_ERR_PMID; return 0; } static int logger_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); int sts; if ((sts = valid_pmid(idp->cluster, idp->item)) < 0) return sts; sts = PMDA_FETCH_STATIC; if (idp->item < 4) { switch (idp->item) { case 0: /* logger.numclients */ sts = pmdaEventClients(atom); break; case 1: /* logger.numlogfiles */ atom->ul = event_logcount(); break; case 2: /* logger.param_string */ sts = PMDA_FETCH_NOVALUES; break; case 3: /* logger.maxmem */ atom->ull = (unsigned long long)maxmem; break; default: return PM_ERR_PMID; } } else { dynamic_metric_info_t *pinfo; int queue; if ((pinfo = ((mdesc != NULL) ? mdesc->m_user : NULL)) == NULL) return PM_ERR_PMID; queue = event_queueid(pinfo->handle); switch (pinfo->pmid_index) { case 0: /* perfile.{LOGFILE}.count */ sts = pmdaEventQueueCounter(queue, atom); break; case 1: /* perfile.{LOGFILE}.bytes */ sts = pmdaEventQueueBytes(queue, atom); break; case 2: /* perfile.{LOGFILE}.size */ atom->ull = event_pathsize(pinfo->handle); break; case 3: /* perfile.{LOGFILE}.path */ atom->cp = (char *)event_pathname(pinfo->handle); break; case 4: /* perfile.{LOGFILE}.numclients */ sts = pmdaEventQueueClients(queue, atom); break; case 5: /* perfile.{LOGFILE}.records */ sts = pmdaEventQueueRecords(queue, atom, pmdaGetContext(), event_decoder, &pinfo->handle); break; case 6: /* perfile.{LOGFILE}.queuemem */ sts = pmdaEventQueueMemory(queue, atom); break; default: return PM_ERR_PMID; } } return sts; } static int logger_store(pmResult *result, pmdaExt *pmda) { int i, j, sts; pmdaEventNewClient(pmda->e_context); for (i = 0; i < result->numpmid; i++) { pmValueSet *vsp = result->vset[i]; __pmID_int *idp = (__pmID_int *)&vsp->pmid; dynamic_metric_info_t *pinfo = NULL; void *filter; int queueid; if ((sts = valid_pmid(idp->cluster, idp->item)) < 0) return sts; for (j = 0; j < pmda->e_nmetrics; j++) { if (vsp->pmid == pmda->e_metrics[j].m_desc.pmid) { pinfo = pmda->e_metrics[j].m_user; break; } } if (pinfo == NULL) return PM_ERR_PMID; if (pinfo->pmid_index != 5) return PM_ERR_PERMISSION; queueid = event_queueid(pinfo->handle); if (vsp->numval != 1 || vsp->valfmt != PM_VAL_SPTR) return PM_ERR_CONV; sts = event_regex_alloc(vsp->vlist[0].value.pval->vbuf, &filter); if (sts < 0) return sts; sts = pmdaEventSetFilter(pmda->e_context, queueid, filter, event_regex_apply, event_regex_release); if (sts < 0 ) return sts; } return 0; } static void logger_end_contextCallBack(int context) { pmdaEventEndClient(context); } static int logger_pmid(const char *name, pmID *pmid, pmdaExt *pmda) { pmdaEventNewClient(pmda->e_context); return pmdaTreePMID(pmns, name, pmid); } static int logger_name(pmID pmid, char ***nameset, pmdaExt *pmda) { pmdaEventNewClient(pmda->e_context); return pmdaTreeName(pmns, pmid, nameset); } static int logger_children(const char *name, int traverse, char ***kids, int **sts, pmdaExt *pmda) { pmdaEventNewClient(pmda->e_context); return pmdaTreeChildren(pmns, name, traverse, kids, sts); } static int logger_text(int ident, int type, char **buffer, pmdaExt *pmda) { int numstatics = sizeof(static_metrictab)/sizeof(static_metrictab[0]); pmdaEventNewClient(pmda->e_context); if ((type & PM_TEXT_PMID) == PM_TEXT_PMID) { /* Lookup pmid in the metric table. */ int item = pmid_item(ident); /* If the PMID item was for a dynamic metric... */ if (item >= numstatics && item < nummetrics /* and the PMID matches... */ && metrictab[item].m_desc.pmid == (pmID)ident /* and we've got user data... */ && metrictab[item].m_user != NULL) { dynamic_metric_info_t *pinfo = metrictab[item].m_user; /* Return the correct help text. */ *buffer = (char *)pinfo->help_text; return 0; } } return pmdaText(ident, type, buffer, pmda); } void logger_init(pmdaInterface *dp, const char *configfile) { size_t size; int i, j, sts, item, numloggers; int numstatics = sizeof(static_metrictab)/sizeof(static_metrictab[0]); int numdynamics = sizeof(dynamic_metrictab)/sizeof(dynamic_metrictab[0]); pmdaMetric *pmetric; char name[MAXPATHLEN * 2]; dynamic_metric_info_t *pinfo; __pmSetProcessIdentity(username); /* Read and parse config file. */ if ((numloggers = event_config(configfile)) < 0) return; /* Create the dynamic metric info table based on the logfile table */ size = sizeof(struct dynamic_metric_info) * numdynamics * numloggers; if ((dynamic_metric_infotab = malloc(size)) == NULL) { __pmNoMem("logger_init(dynamic)", size, PM_FATAL_ERR); return; } pinfo = dynamic_metric_infotab; for (i = 0; i < numloggers; i++) { for (j = 0; j < numdynamics; j++) { pinfo->handle = i; pinfo->pmid_index = j; pinfo->help_text = dynamic_helptab[j]; pinfo++; } } /* Create the metric table based on the static and dynamic metric tables */ nummetrics = numstatics + (numloggers * numdynamics); size = sizeof(pmdaMetric) * nummetrics; if ((metrictab = malloc(size)) == NULL) { free(dynamic_metric_infotab); __pmNoMem("logger_init(static)", size, PM_FATAL_ERR); return; } memcpy(metrictab, static_metrictab, sizeof(static_metrictab)); pmetric = &metrictab[numstatics]; pinfo = dynamic_metric_infotab; item = numstatics; for (i = 0; i < numloggers; i++) { memcpy(pmetric, dynamic_metrictab, sizeof(dynamic_metrictab)); for (j = 0; j < numdynamics; j++) { pmetric[j].m_desc.pmid = PMDA_PMID(0, item++); pmetric[j].m_user = pinfo++; } pmetric += numdynamics; } if (dp->status != 0) return; dp->version.four.fetch = logger_fetch; dp->version.four.store = logger_store; dp->version.four.profile = logger_profile; dp->version.four.pmid = logger_pmid; dp->version.four.name = logger_name; dp->version.four.children = logger_children; dp->version.four.text = logger_text; pmdaSetFetchCallBack(dp, logger_fetchCallBack); pmdaSetEndContextCallBack(dp, logger_end_contextCallBack); pmdaInit(dp, NULL, 0, metrictab, nummetrics); /* Create the dynamic PMNS tree and populate it. */ if ((sts = __pmNewPMNS(&pmns)) < 0) { __pmNotifyErr(LOG_ERR, "%s: failed to create new pmns: %s\n", pmProgname, pmErrStr(sts)); pmns = NULL; return; } pmetric = &metrictab[numstatics]; for (i = 0; i < numloggers; i++) { const char *id = event_pmnsname(i); for (j = 0; j < numdynamics; j++) { snprintf(name, sizeof(name), "logger.perfile.%s.%s", id, dynamic_nametab[j]); __pmAddPMNSNode(pmns, pmetric[j].m_desc.pmid, name); } pmetric += numdynamics; } /* for reverse (pmid->name) lookups */ pmdaTreeRebuildHash(pmns, (numloggers * numdynamics)); /* initialise the event and client tracking code */ event_init(metrictab[2].m_desc.pmid); } static void logger_timer(int sig, void *ptr) { interval_expired = 1; } void loggerMain(pmdaInterface *dispatch) { fd_set readyfds; int nready, pmcdfd; pmcdfd = __pmdaInFd(dispatch); if (pmcdfd > maxfd) maxfd = pmcdfd; FD_ZERO(&fds); FD_SET(pmcdfd, &fds); /* arm interval timer */ if (__pmAFregister(&interval, NULL, logger_timer) < 0) { __pmNotifyErr(LOG_ERR, "registering event interval handler"); exit(1); } for (;;) { memcpy(&readyfds, &fds, sizeof(readyfds)); nready = select(maxfd+1, &readyfds, NULL, NULL, NULL); if (pmDebug & DBG_TRACE_APPL2) __pmNotifyErr(LOG_DEBUG, "select: nready=%d interval=%d", nready, interval_expired); if (nready < 0) { if (neterror() != EINTR) { __pmNotifyErr(LOG_ERR, "select failure: %s", netstrerror()); exit(1); } else if (!interval_expired) { continue; } } __pmAFblock(); if (nready > 0 && FD_ISSET(pmcdfd, &readyfds)) { if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "processing pmcd PDU [fd=%d]", pmcdfd); if (__pmdaMainPDU(dispatch) < 0) { __pmAFunblock(); exit(1); /* fatal if we lose pmcd */ } if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "completed pmcd PDU [fd=%d]", pmcdfd); } if (interval_expired) { interval_expired = 0; event_refresh(); } __pmAFunblock(); } } static void convertUnits(char **endnum, long *maxmem) { switch ((int) **endnum) { case 'b': case 'B': break; case 'k': case 'K': *maxmem *= 1024; break; case 'm': case 'M': *maxmem *= 1024 * 1024; break; case 'g': case 'G': *maxmem *= 1024 * 1024 * 1024; break; } (*endnum)++; } static void usage(void) { fprintf(stderr, "Usage: %s [options] configfile\n\n" "Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than the default\n" " -m memory maximum memory used per logfile (default %ld bytes)\n" " -s interval default delay between iterations (default %d sec)\n" " -U username user account to run under (default \"pcp\")\n", pmProgname, maxmem, (int)interval.tv_sec); exit(1); } int main(int argc, char **argv) { static char helppath[MAXPATHLEN]; char *endnum; pmdaInterface desc; long minmem; int c, err = 0, sep = __pmPathSeparator(); __pmSetProgname(argv[0]); __pmGetUsername(&username); minmem = getpagesize(); maxmem = (minmem > DEFAULT_MAXMEM) ? minmem : DEFAULT_MAXMEM; snprintf(helppath, sizeof(helppath), "%s%c" "logger" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&desc, PMDA_INTERFACE_5, pmProgname, LOGGER, "logger.log", helppath); while ((c = pmdaGetOpt(argc, argv, "D:d:l:m:s:U:?", &desc, &err)) != EOF) { switch (c) { case 'm': maxmem = strtol(optarg, &endnum, 10); if (*endnum != '\0') convertUnits(&endnum, &maxmem); if (*endnum != '\0' || maxmem < minmem) { fprintf(stderr, "%s: invalid max memory '%s' (min=%ld)\n", pmProgname, optarg, minmem); err++; } break; case 's': if (pmParseInterval(optarg, &interval, &endnum) < 0) { fprintf(stderr, "%s: -s requires a time interval: %s\n", pmProgname, endnum); free(endnum); err++; } break; case 'U': username = optarg; break; default: err++; break; } } if (err || optind != argc -1) usage(); pmdaOpenLog(&desc); logger_init(&desc, argv[optind]); pmdaConnect(&desc); loggerMain(&desc); event_shutdown(); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/logger/pmns0000664000000000000000000000132012272262501014650 0ustar /* * Metrics for logger PMDA * * Copyright (c) 2011 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ logger { numclients LOGGER:0:0 numlogfiles LOGGER:0:1 param_string LOGGER:0:2 maxmem LOGGER:0:3 perfile LOGGER:*:* } pcp-3.8.12ubuntu1/src/pmdas/logger/util.h0000664000000000000000000000140712272262501015104 0ustar /* * Utility routines. * * Copyright (c) 2011 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _UTIL_H #define _UTIL_H extern char *lstrip(char *str); extern void rstrip(char *str); extern int start_cmd(const char *cmd, pid_t *ppid); extern int stop_cmd(pid_t pid); #endif /* _UTIL_H */ pcp-3.8.12ubuntu1/src/pmdas/logger/event.c0000664000000000000000000003055412272262501015250 0ustar /* * Event support for the Logger PMDA * * Copyright (c) 2011-2012 Red Hat. * Copyright (c) 2011 Nathan Scott. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "event.h" #include "pmda.h" #include "util.h" #include #ifdef HAVE_REGEX_H #include #endif static int numlogfiles; static event_logfile_t *logfiles; void event_init(pmID pmid) { char cmd[MAXPATHLEN]; int i, fd; for (i = 0; i < numlogfiles; i++) { size_t pathlen = strlen(logfiles[i].pathname); /* * We support 2 kinds of PATHNAMEs: * (1) Regular paths. These paths are opened normally. * (2) Pipes. If the path ends in '|', the filename is * interpreted as a command which pipes input to us. */ if (logfiles[i].pathname[pathlen - 1] != '|') { fd = open(logfiles[i].pathname, O_RDONLY|O_NONBLOCK); if (fd < 0) { if (logfiles[i].fd >= 0) /* log once only */ __pmNotifyErr(LOG_ERR, "open: %s - %s", logfiles[i].pathname, strerror(errno)); } else { if (fstat(fd, &logfiles[i].pathstat) < 0) if (logfiles[i].fd >= 0) /* log once only */ __pmNotifyErr(LOG_ERR, "fstat: %s - %s", logfiles[i].pathname, strerror(errno)); lseek(fd, 0, SEEK_END); } } else { strncpy(cmd, logfiles[i].pathname, sizeof(cmd)); cmd[pathlen - 1] = '\0'; /* get rid of the '|' */ rstrip(cmd); /* Remove all trailing whitespace. */ fd = start_cmd(cmd, &logfiles[i].pid); if (fd < 0) { if (logfiles[i].fd >= 0) /* log once only */ __pmNotifyErr(LOG_ERR, "pipe: %s - %s", logfiles[i].pathname, strerror(errno)); } else { if (fd > maxfd) maxfd = fd; FD_SET(fd, &fds); } } logfiles[i].fd = fd; /* keep file descriptor (or error) */ logfiles[i].pmid = pmid; /* string param metric identifier */ logfiles[i].queueid = pmdaEventNewQueue(logfiles[i].pmnsname, maxmem); } } void event_shutdown(void) { int i; __pmNotifyErr(LOG_INFO, "%s: Shutting down...", __FUNCTION__); for (i = 0; i < numlogfiles; i++) { if (logfiles[i].pid != 0) { stop_cmd(logfiles[i].pid); logfiles[i].pid = 0; } if (logfiles[i].fd > 0) { close(logfiles[i].fd); logfiles[i].fd = 0; } } } /* * Ensure given name (identifier) can be used as a namespace entry. */ static int valid_pmns_name(char *name) { if (!isalpha((int)name[0])) return 0; for (; *name != '\0'; name++) if (!isalnum((int)*name) && *name != '_') return 0; return 1; } /* * Parse the configuration file and do initial data structure setup. */ int event_config(const char *fname) { FILE *configFile; event_logfile_t *logfile; int sts = 0; size_t len; char line[MAXPATHLEN * 2]; char *ptr, *name, *noaccess; configFile = fopen(fname, "r"); if (configFile == NULL) { __pmNotifyErr(LOG_ERR, "event_config: %s: %s", fname, strerror(errno)); return -1; } while (!feof(configFile)) { if (fgets(line, sizeof(line), configFile) == NULL) { if (feof(configFile)) break; __pmNotifyErr(LOG_ERR, "event_config: fgets: %s", strerror(errno)); sts = -1; break; } /* * fgets() puts the '\n' at the end of the buffer. Remove * it. If it isn't there, that must mean that the line is * longer than our buffer. */ len = strlen(line); if (len == 0) /* Ignore empty strings. */ continue; if (line[len - 1] != '\n') { /* String must be too long */ __pmNotifyErr(LOG_ERR, "event_config: config line too long: '%s'", line); sts = -1; break; } line[len - 1] = '\0'; /* Remove the '\n'. */ /* Strip all trailing whitespace. */ rstrip(line); /* If the string is now empty or a comment, just ignore the line. */ len = strlen(line); if (len == 0) continue; if (line[0] == '#') continue; /* Skip past all leading whitespace to find the start of * NAME. */ ptr = name = lstrip(line); /* Now we need to split the line into 3 parts: NAME, ACCESS * and PATHNAME. NAME can't have whitespace in it, so look * for the first non-whitespace. */ while (*ptr != '\0' && ! isspace((int)*ptr)) { ptr++; } /* If we're at the end, we didn't find any whitespace, so * we've only got a NAME, with no ACCESS/PATHNAME. */ if (*ptr == '\0') { __pmNotifyErr(LOG_ERR, "event_config: badly formatted " " configuration file line: '%s'", line); sts = -1; break; } /* Terminate NAME at the 1st whitespace. */ *ptr++ = '\0'; /* Make sure NAME isn't too long. */ if (strlen(name) > MAXPATHLEN) { __pmNotifyErr(LOG_ERR, "event_config: name too long: '%s'", name); sts = -1; break; } /* Make sure NAME is valid. */ if (valid_pmns_name(name) == 0) { __pmNotifyErr(LOG_ERR, "event_config: invalid name: '%s'", name); sts = -1; break; } /* Skip past any extra whitespace between NAME and ACCESS */ ptr = noaccess = lstrip(ptr); /* Look for the next whitespace, and that terminate ACCESS */ while (*ptr != '\0' && ! isspace((int)*ptr)) { ptr++; } /* If we're at the end, we didn't find any whitespace, so * we've only got NAME and ACCESS with no/PATHNAME. */ if (*ptr == '\0') { __pmNotifyErr(LOG_ERR, "event_config: badly formatted " " configuration file line: '%s'", line); sts = -1; break; } /* Terminate ACCESS at the 1st whitespace. */ *ptr++ = '\0'; /* Skip past any extra whitespace between ACCESS and PATHNAME */ ptr = lstrip(ptr); /* Make sure PATHNAME (the rest of the line) isn't too long. */ if (strlen(ptr) > MAXPATHLEN) { __pmNotifyErr(LOG_ERR, "event_config: path is too long: '%s'", ptr); sts = -1; break; } /* Now we've got a reasonable NAME/ACCESS/PATHNAME. Save them. */ len = (numlogfiles + 1) * sizeof(event_logfile_t); logfiles = realloc(logfiles, len); if (logfiles == NULL) { __pmNoMem("event_config", len, PM_FATAL_ERR); sts = -1; break; } logfile = &logfiles[numlogfiles]; memset(logfile, 0, sizeof(*logfile)); logfile->noaccess = (noaccess[0] == 'y' || noaccess[0] == 'Y'); strncpy(logfile->pmnsname, name, sizeof(logfile->pmnsname)); logfile->pmnsname[sizeof(logfile->pmnsname)-1] = '\0'; strncpy(logfile->pathname, ptr, sizeof(logfile->pathname)); logfile->pathname[sizeof(logfile->pathname)-1] = '\0'; /* remaining fields filled in after pmdaInit() is called. */ numlogfiles++; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_INFO, "event_config: new logfile %s (%s)", logfile->pathname, logfile->pmnsname); } fclose(configFile); if (sts < 0) { free(logfiles); return sts; } if (numlogfiles == 0) { __pmNotifyErr(LOG_ERR, "event_config: no valid log files found"); return -1; } return numlogfiles; } static int event_create(event_logfile_t *logfile) { int j; char *s, *p; size_t offset; ssize_t bytes; struct timeval timestamp; static char *buffer; static int bufsize; /* * Using a static (global) event buffer to hold initial read. * The aim is to reduce memory allocation until we know we'll * need to keep something. */ if (!buffer) { int sts = 0; bufsize = 16 * getpagesize(); #ifdef HAVE_POSIX_MEMALIGN sts = posix_memalign((void **)&buffer, getpagesize(), bufsize); #else #ifdef HAVE_MEMALIGN buffer = (char *)memalign(getpagesize(), bufsize); if (buffer == NULL) sts = -1; #else buffer = (char *)malloc(bufsize); if (buffer == NULL) sts = -1; #endif #endif if (sts != 0) { __pmNotifyErr(LOG_ERR, "event buffer allocation failure"); return -1; } } offset = 0; multiread: if (logfile->fd < 0) return 0; bytes = read(logfile->fd, buffer + offset, bufsize - 1 - offset); /* * Ignore the error if: * - we've got EOF (0 bytes read) * - EBADF (fd isn't valid - most likely a closed pipe) * - EAGAIN/EWOULDBLOCK (fd is marked nonblocking and read would block) * - EINVAL/EISDIR (fd is a directory - config file botch) */ if (bytes == 0) return 0; if (bytes < 0 && (errno == EBADF || errno == EISDIR || errno == EINVAL)) return 0; if (bytes < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) return 0; if (bytes > maxmem) return 0; if (bytes < 0) { __pmNotifyErr(LOG_ERR, "read failure on %s: %s", logfile->pathname, strerror(errno)); return -1; } gettimeofday(×tamp, NULL); buffer[bufsize-1] = '\0'; for (s = p = buffer, j = 0; *s != '\0' && j < bufsize-1; s++, j++) { if (*s != '\n') continue; *s = '\0'; bytes = (s+1) - p; pmdaEventQueueAppend(logfile->queueid, p, bytes, ×tamp); p = s + 1; } /* did we just do a full buffer read? */ if (p == buffer) { char msg[64]; __pmNotifyErr(LOG_ERR, "Ignoring long (%d bytes) line: \"%s\"", (int) bytes, __pmdaEventPrint(p, bytes, msg, sizeof(msg))); } else if (j == bufsize - 1) { offset = bufsize-1 - (p - buffer); memmove(buffer, p, offset); goto multiread; /* read rest of line */ } return 1; } void event_refresh(void) { struct event_logfile *logfile; struct stat pathstat; int i, fd, sts; for (i = 0; i < numlogfiles; i++) { logfile = &logfiles[i]; if (logfile->pid > 0) /* process pipe */ goto events; if (stat(logfile->pathname, &pathstat) < 0) { if (logfile->fd >= 0) { close(logfile->fd); logfile->fd = -1; } memset(&logfile->pathstat, 0, sizeof(logfile->pathstat)); } else { /* reopen if no descriptor before, or log rotated (new file) */ if (logfile->fd < 0 || logfile->pathstat.st_ino != pathstat.st_ino || logfile->pathstat.st_dev != pathstat.st_dev) { if (logfile->fd >= 0) close(logfile->fd); fd = open(logfile->pathname, O_RDONLY|O_NONBLOCK); if (fd < 0 && logfile->fd >= 0) /* log once */ __pmNotifyErr(LOG_ERR, "open: %s - %s", logfile->pathname, strerror(errno)); logfile->fd = fd; } else { if ((S_ISREG(pathstat.st_mode)) && (memcmp(&logfile->pathstat.st_mtime, &pathstat.st_mtime, sizeof(pathstat.st_mtime))) == 0) continue; } logfile->pathstat = pathstat; events: do { sts = event_create(logfile); } while (sts != 0); } } } int event_logcount(void) { return numlogfiles; } int event_queueid(int handle) { if (handle < 0 || handle >= numlogfiles) return 0; /* if logfile unrestricted, allow this client access to this queue */ if (logfiles[handle].noaccess == 0) pmdaEventSetAccess(pmdaGetContext(), logfiles[handle].queueid, 1); return logfiles[handle].queueid; } __uint64_t event_pathsize(int handle) { if (handle < 0 || handle >= numlogfiles) return 0; return logfiles[handle].pathstat.st_size; } const char * event_pathname(int handle) { if (handle < 0 || handle >= numlogfiles) return NULL; return logfiles[handle].pathname; } const char * event_pmnsname(int handle) { if (handle < 0 || handle >= numlogfiles) return NULL; return logfiles[handle].pmnsname; } pmID event_pmid(int handle) { if (handle < 0 || handle >= numlogfiles) return 0; return logfiles[handle].pmid; } int event_decoder(int eventarray, void *buffer, size_t size, struct timeval *timestamp, void *data) { int sts, handle = *(int *)data; pmID pmid = event_pmid(handle); pmAtomValue atom; sts = pmdaEventAddRecord(eventarray, timestamp, PM_EVENT_FLAG_POINT); if (sts < 0) return sts; atom.cp = buffer; sts = pmdaEventAddParam(eventarray, pmid, PM_TYPE_STRING, &atom); if (sts < 0) return sts; return 1; /* simple decoder, added just one event array */ } int event_regex_apply(void *rp, void *data, size_t size) { regex_t *regex = (regex_t *)rp; return regexec(regex, data, 0, NULL, 0) == REG_NOMATCH; } void event_regex_release(void *rp) { regex_t *regex = (regex_t *)rp; regfree(regex); } int event_regex_alloc(const char *string, void **filter) { regex_t *regex = malloc(sizeof(regex_t)); if (regex == NULL) return -ENOMEM; if (regcomp(regex, string, REG_EXTENDED|REG_NOSUB) != 0) { free(regex); return PM_ERR_CONV; } *filter = (void *)regex; return 0; } pcp-3.8.12ubuntu1/src/pmdas/logger/help0000664000000000000000000000260212272262501014627 0ustar # # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # logger PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ logger.numclients The number of attached clients The number of attached clients. @ logger.numlogfiles The number of monitored logfiles The number of monitored logfiles. @ logger.param_string String event data String event data. @ logger.maxmem Maximum number of queued event bytes Maximum number of queued event bytes for each log file. pcp-3.8.12ubuntu1/src/pmdas/logger/event.h0000664000000000000000000000330212272262501015244 0ustar /* * Event support for the Logger PMDA * * Copyright (c) 2011 Red Hat Inc. * Copyright (c) 2011 Nathan Scott. All rights reversed. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _EVENT_H #define _EVENT_H #include "pmapi.h" #include "impl.h" #include typedef struct event_logfile { pmID pmid; int fd; pid_t pid; int queueid; int noaccess; struct stat pathstat; char pmnsname[MAXPATHLEN]; char pathname[MAXPATHLEN]; } event_logfile_t; extern int maxfd; extern fd_set fds; extern long maxmem; extern void event_init(pmID pmid); extern void event_shutdown(void); extern void event_refresh(void); extern int event_config(const char *filename); extern int event_logcount(void); extern pmID event_pmid(int handle); extern int event_queueid(int handle); extern __uint64_t event_pathsize(int handle); extern const char *event_pathname(int handle); extern const char *event_pmnsname(int handle); extern int event_decoder(int arrayid, void *buffer, size_t size, struct timeval *timestamp, void *data); extern int event_regex_alloc(const char *s, void **filter); extern int event_regex_apply(void *rp, void *data, size_t size); extern void event_regex_release(void *rp); #endif /* _EVENT_H */ pcp-3.8.12ubuntu1/src/pmdas/gfs2/0000775000000000000000000000000012272262620013340 5ustar pcp-3.8.12ubuntu1/src/pmdas/gfs2/ftrace.c0000664000000000000000000005454112272262501014757 0ustar /* * GFS2 ftrace based trace-point metrics. * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "pmdagfs2.h" #include "ftrace.h" #include "worst_glock.h" #include #include #include #include #include static char *TRACE_PIPE = "/sys/kernel/debug/tracing/trace_pipe"; static int max_glock_throughput = INITIAL_GLOBAL_MAX_GLOCK_THROUGHPUT; static struct ftrace_data *ftrace_data; static int capacity, num_accepted_entries; /* * Fetches the value for the given metric item and then assigns to pmAtomValue. * We check to see if item is in valid range for the metric. */ int gfs2_ftrace_fetch(int item, struct ftrace *ftrace, pmAtomValue *atom) { /* Ensure that metric value wanted is valid */ if ((item < 0 || item >= NUM_TRACEPOINT_STATS)) return PM_ERR_PMID; atom->ull = ftrace->values[item]; return 1; } /* * External function to allow the increment of the num_accepted_locks * variable from pmStore. */ void ftrace_increase_num_accepted_entries(){ num_accepted_entries++; } /* * Sets the value of max_glock_throughput using pmstore, value should * must be positive. */ int ftrace_set_threshold(pmValueSet *vsp) { int value = vsp->vlist[0].value.lval; if (value < 0) /* Ensure positive value */ return PM_ERR_SIGN; max_glock_throughput = value; return 0; } /* * Returns the max number of glocks we allow per run through the trace_pipe, * Used by the fetch for the control metrics. */ int ftrace_get_threshold() { return max_glock_throughput; } /* * We open the ftrace trace file in write mode and straight after * close it. This acts as a way to completely clear the trace ring- * buffer when needed. */ static int ftrace_clear_buffer() { char *TRACE = "/sys/kernel/debug/tracing/trace"; FILE *fp; /* Open in write mode and then straight close will purge buffer contents */ if (( fp = fopen(TRACE, "w")) == NULL ) return -oserror(); fclose(fp); return 0; } /* * We take tracedata from the trace pipe and store only the data which is * from GFS2 metrics. We collect all the data in one array to be worked * through later, this is because all trace data comes through the * trace pipe mixed. */ static int gfs2_extract_trace_values(char *buffer) { struct ftrace_data temp; int major, minor; char *data; /* Allocate memory for our data */ if (ftrace_data == NULL) { ftrace_data = malloc(capacity * sizeof(struct ftrace_data)); if (ftrace_data == NULL) { return -oserror(); } } /* Interpret data, we work out what tracepoint it belongs to first */ if ((data = strstr(buffer, "gfs2_glock_state_change: "))) { temp.tracepoint = GLOCK_STATE_CHANGE; sscanf(data, "gfs2_glock_state_change: %"SCNu32",%"SCNu32"", &major, &minor); } else if ((data = strstr(buffer, "gfs2_glock_put: "))) { temp.tracepoint = GLOCK_PUT; sscanf(data, "gfs2_glock_put: %"SCNu32",%"SCNu32"", &major, &minor); } else if ((data = strstr(buffer, "gfs2_demote_rq: "))) { temp.tracepoint = DEMOTE_RQ; sscanf(data, "gfs2_demote_rq: %"SCNu32",%"SCNu32"", &major, &minor); } else if ((data = strstr(buffer, "gfs2_promote: "))) { temp.tracepoint = PROMOTE; sscanf(data, "gfs2_promote: %"SCNu32",%"SCNu32"", &major, &minor); } else if ((data = strstr(buffer, "gfs2_glock_queue: "))) { temp.tracepoint = GLOCK_QUEUE; sscanf(data, "gfs2_glock_queue: %"SCNu32",%"SCNu32"", &major, &minor); } else if ((data = strstr(buffer, "gfs2_glock_lock_time: "))) { temp.tracepoint = GLOCK_LOCK_TIME; sscanf(data, "gfs2_glock_lock_time: %"SCNu32",%"SCNu32"", &major, &minor); /* * Pass tracepoint data over for worst_glock metrics for processing, * only if the metrics are enabled. */ if (worst_glock_get_state() == 1) gfs2_extract_worst_glock(data); } else if ((data = strstr(buffer, "gfs2_pin: "))) { temp.tracepoint = PIN; sscanf(data, "gfs2_pin: %"SCNu32",%"SCNu32"", &major, &minor); } else if ((data = strstr(buffer, "gfs2_log_flush: "))) { temp.tracepoint = LOG_FLUSH; sscanf(data, "gfs2_log_flush: %"SCNu32",%"SCNu32"", &major, &minor); } else if ((data = strstr(buffer, "gfs2_log_blocks: "))) { temp.tracepoint = LOG_BLOCKS; sscanf(data, "gfs2_log_blocks: %"SCNu32",%"SCNu32"", &major, &minor); } else if ((data = strstr(buffer, "gfs2_ail_flush: "))) { temp.tracepoint = AIL_FLUSH; sscanf(data, "gfs2_ail_flush: %"SCNu32",%"SCNu32"", &major, &minor); } else if ((data = strstr(buffer, "gfs2_block_alloc: "))) { temp.tracepoint = BLOCK_ALLOC; sscanf(data, "gfs2_block_alloc: %"SCNu32",%"SCNu32" %s", &major, &minor, data); } else if ((data = strstr(buffer, "gfs2_bmap: "))) { temp.tracepoint = BMAP; sscanf(data, "gfs2_bmap: %"SCNu32",%"SCNu32"", &major, &minor); } else if ((data = strstr(buffer, "gfs2_rs: "))) { temp.tracepoint = RS; sscanf(data, "gfs2_rs: %"SCNu32",%"SCNu32" %s", &major, &minor, data); } else { return 0; /* If we do not have matching data, return and continue */ } temp.dev_id = makedev(major, minor); strncpy(temp.data, data, sizeof(temp.data)-1); /* Re-allocate and extend array if we are near capacity */ if (num_accepted_entries == capacity) { struct ftrace_data *ftrace_data_realloc = realloc(ftrace_data, (capacity + FTRACE_ARRAY_CAPACITY) * sizeof(struct ftrace_data) ); if (ftrace_data_realloc == NULL) { free(ftrace_data); ftrace_data = NULL; return -oserror(); } else { ftrace_data = ftrace_data_realloc; ftrace_data_realloc = NULL; capacity += FTRACE_ARRAY_CAPACITY; } } /* Assign data in the array and update counters */ ftrace_data[num_accepted_entries] = temp; num_accepted_entries++; return 0; } /* * We work though each mounted filesystem and update the metric data based * off what tracepoint information we have collected from the trace pipe. * Data is consumed and the ftrace_data array is deallocated on each refresh * cycle. */ static void gfs2_assign_ftrace(pmInDom gfs2_fs_indom) { int i, j, k, sts; struct gfs2_fs *fs; /* We walk through for each filesystem */ for (pmdaCacheOp(gfs2_fs_indom, PMDA_CACHE_WALK_REWIND);;) { if ((i = pmdaCacheOp(gfs2_fs_indom, PMDA_CACHE_WALK_NEXT)) < 0) break; sts = pmdaCacheLookup(gfs2_fs_indom, i, NULL, (void **)&fs); if (sts != PMDA_CACHE_ACTIVE) continue; for (j = 0; j < NUM_TRACEPOINT_STATS; j++) { /* Reset old metric data for all tracepoints */ fs->ftrace.values[j] = 0; } for (k = 0; k < num_accepted_entries; k++) { if (fs->dev_id != ftrace_data[k].dev_id) continue; /* Work through the data, increasing metric counters */ if (ftrace_data[k].tracepoint == GLOCK_STATE_CHANGE) { char state[3], target[3]; sscanf(ftrace_data[k].data, "gfs2_glock_state_change: %*d,%*d glock %*d:%*d state %*s to %s tgt:%s dmt:%*s flags:%*s", state, target ); if (strncmp(state, "NL", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKSTATE_NULLLOCK]++; } else if (strncmp(state, "CR", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKSTATE_CONCURRENTREAD]++; } else if (strncmp(state, "CW", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKSTATE_CONCURRENTWRITE]++; } else if (strncmp(state, "PR", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKSTATE_PROTECTEDREAD]++; } else if (strncmp(state, "PW", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKSTATE_PROTECTEDWRITE]++; } else if (strncmp(state, "EX", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKSTATE_EXCLUSIVE]++; } fs->ftrace.values[FTRACE_GLOCKSTATE_TOTAL]++; if (strncmp(state, target, 2) == 0) { fs->ftrace.values[FTRACE_GLOCKSTATE_GLOCK_CHANGEDTARGET]++; } else { fs->ftrace.values[FTRACE_GLOCKSTATE_GLOCK_MISSEDTARGET]++; } } else if (ftrace_data[k].tracepoint == GLOCK_PUT) { char state[3]; sscanf(ftrace_data[k].data, "gfs2_glock_put: %*d,%*d glock %*d:%*d state %*s => %s flags:%*s", state ); if (strncmp(state, "NL", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKPUT_NULLLOCK]++; } else if (strncmp(state, "CR", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKPUT_CONCURRENTREAD]++; } else if (strncmp(state, "CW", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKPUT_CONCURRENTWRITE]++; } else if (strncmp(state, "PR", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKPUT_PROTECTEDREAD]++; } else if (strncmp(state, "PW", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKPUT_PROTECTEDWRITE]++; } else if (strncmp(state, "EX", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKPUT_EXCLUSIVE]++; } fs->ftrace.values[FTRACE_GLOCKPUT_TOTAL]++; } else if (ftrace_data[k].tracepoint == DEMOTE_RQ) { char state[3], remote[7]; sscanf(ftrace_data[k].data, "gfs2_demote_rq: %*d,%*d glock %*d:%*d demote %*s to %s flags:%*s %s", state, remote ); if (strncmp(state, "NL", 2) == 0) { fs->ftrace.values[FTRACE_DEMOTERQ_NULLLOCK]++; } else if (strncmp(state, "CR", 2) == 0) { fs->ftrace.values[FTRACE_DEMOTERQ_CONCURRENTREAD]++; } else if (strncmp(state, "CW", 2) == 0) { fs->ftrace.values[FTRACE_DEMOTERQ_CONCURRENTWRITE]++; } else if (strncmp(state, "PR", 2) == 0) { fs->ftrace.values[FTRACE_DEMOTERQ_PROTECTEDREAD]++; } else if (strncmp(state, "PW", 2) == 0) { fs->ftrace.values[FTRACE_DEMOTERQ_PROTECTEDWRITE]++; } else if (strncmp(state, "EX", 2) == 0) { fs->ftrace.values[FTRACE_DEMOTERQ_EXCLUSIVE]++; } fs->ftrace.values[FTRACE_DEMOTERQ_TOTAL]++; if (strncmp(remote, "remote", 6) == 0) { fs->ftrace.values[FTRACE_DEMOTERQ_REQUESTED_REMOTE]++; } else if (strncmp(remote, "local", 6) == 0) { fs->ftrace.values[FTRACE_DEMOTERQ_REQUESTED_LOCAL]++; } } else if (ftrace_data[k].tracepoint == PROMOTE) { char state[3], first[6]; sscanf(ftrace_data[k].data, "gfs2_promote: %*d,%*d glock %*d:%*d promote %s %s", first, state ); if (strncmp(first, "first", 5) == 0) { if (strncmp(state, "NL", 2) == 0) { fs->ftrace.values[FTRACE_PROMOTE_FIRST_NULLLOCK]++; } else if (strncmp(state, "CR", 2) == 0) { fs->ftrace.values[FTRACE_PROMOTE_FIRST_CONCURRENTREAD]++; } else if (strncmp(state, "CW", 2) == 0) { fs->ftrace.values[FTRACE_PROMOTE_FIRST_CONCURRENTWRITE]++; } else if (strncmp(state, "PR", 2) == 0) { fs->ftrace.values[FTRACE_PROMOTE_FIRST_PROTECTEDREAD]++; } else if (strncmp(state, "PW", 2) == 0) { fs->ftrace.values[FTRACE_PROMOTE_FIRST_PROTECTEDWRITE]++; } else if (strncmp(state, "EX", 2) == 0) { fs->ftrace.values[FTRACE_PROMOTE_FIRST_EXCLUSIVE]++; } } else if (strncmp(first, "other", 5) == 0) { if (strncmp(state, "NL", 2) == 0) { fs->ftrace.values[FTRACE_PROMOTE_OTHER_NULLLOCK]++; } else if (strncmp(state, "CR", 2) == 0) { fs->ftrace.values[FTRACE_PROMOTE_OTHER_CONCURRENTREAD]++; } else if (strncmp(state, "CW", 2) == 0) { fs->ftrace.values[FTRACE_PROMOTE_OTHER_CONCURRENTWRITE]++; } else if (strncmp(state, "PR", 2) == 0) { fs->ftrace.values[FTRACE_PROMOTE_OTHER_PROTECTEDREAD]++; } else if (strncmp(state, "PW", 2) == 0) { fs->ftrace.values[FTRACE_PROMOTE_OTHER_PROTECTEDWRITE]++; } else if (strncmp(state, "EX", 2) == 0) { fs->ftrace.values[FTRACE_PROMOTE_OTHER_EXCLUSIVE]++; } } fs->ftrace.values[FTRACE_PROMOTE_TOTAL]++; } else if (ftrace_data[k].tracepoint == GLOCK_QUEUE) { char state[3], queue[3]; sscanf(ftrace_data[k].data, "gfs2_glock_queue: %*d,%*d glock %*d:%*d %squeue %s", queue, state ); if (strncmp(queue, "", 2) == 0) { if (strncmp(state, "NL", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKQUEUE_QUEUE_NULLLOCK]++; } else if (strncmp(state, "CR", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKQUEUE_QUEUE_CONCURRENTREAD]++; } else if (strncmp(state, "CW", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKQUEUE_QUEUE_CONCURRENTWRITE]++; } else if (strncmp(state, "PR", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKQUEUE_QUEUE_PROTECTEDREAD]++; } else if (strncmp(state, "PW", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKQUEUE_QUEUE_PROTECTEDWRITE]++; } else if (strncmp(state, "EX", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKQUEUE_QUEUE_EXCLUSIVE]++; } fs->ftrace.values[FTRACE_GLOCKQUEUE_QUEUE_TOTAL]++; } else if (strncmp(queue, "de", 2) == 0) { if (strncmp(state, "NL", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKQUEUE_DEQUEUE_NULLLOCK]++; } else if (strncmp(state, "CR", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKQUEUE_DEQUEUE_CONCURRENTREAD]++; } else if (strncmp(state, "CW", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKQUEUE_DEQUEUE_CONCURRENTWRITE]++; } else if (strncmp(state, "PR", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKQUEUE_DEQUEUE_PROTECTEDREAD]++; } else if (strncmp(state, "PW", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKQUEUE_DEQUEUE_PROTECTEDWRITE]++; } else if (strncmp(state, "EX", 2) == 0) { fs->ftrace.values[FTRACE_GLOCKQUEUE_DEQUEUE_EXCLUSIVE]++; } fs->ftrace.values[FTRACE_GLOCKQUEUE_DEQUEUE_TOTAL]++; } fs->ftrace.values[FTRACE_PROMOTE_TOTAL]++; } else if (ftrace_data[k].tracepoint == GLOCK_LOCK_TIME) { uint32_t lock_type; sscanf(ftrace_data[k].data, "gfs2_glock_lock_time: %*d,%*d glock %"SCNu32":%*d status:%*d flags:%*x tdiff:%*d srtt:%*d/%*d srttb:%*d/%*d sirt:%*d/%*d dcnt:%*d qcnt:%*d", &lock_type ); if (lock_type == 1) { fs->ftrace.values[FTRACE_GLOCKLOCKTIME_TRANS]++; } else if (lock_type == 2) { fs->ftrace.values[FTRACE_GLOCKLOCKTIME_INDOE]++; } else if (lock_type == 3) { fs->ftrace.values[FTRACE_GLOCKLOCKTIME_RGRP]++; } else if (lock_type == 4) { fs->ftrace.values[FTRACE_GLOCKLOCKTIME_META]++; } else if (lock_type == 5) { fs->ftrace.values[FTRACE_GLOCKLOCKTIME_IOPEN]++; } else if (lock_type == 6) { fs->ftrace.values[FTRACE_GLOCKLOCKTIME_FLOCK]++; } else if (lock_type == 8) { fs->ftrace.values[FTRACE_GLOCKLOCKTIME_QUOTA]++; } else if (lock_type == 9) { fs->ftrace.values[FTRACE_GLOCKLOCKTIME_JOURNAL]++; } fs->ftrace.values[FTRACE_GLOCKLOCKTIME_TOTAL]++; } else if (ftrace_data[k].tracepoint == PIN) { char pinned[6]; uint32_t length; sscanf(ftrace_data[k].data, "gfs2_pin: %*d,%*d log %s %*d/%"SCNu32" inode: %*d", pinned, &length ); if (strncmp(pinned, "pin", 5) == 0) { fs->ftrace.values[FTRACE_PIN_PINTOTAL]++; } else if (strncmp(pinned, "unpin", 5) == 0) { fs->ftrace.values[FTRACE_PIN_UNPINTOTAL]++; } fs->ftrace.values[FTRACE_PIN_TOTAL]++; if(fs->ftrace.values[FTRACE_PIN_LONGESTPINNED] < length) fs->ftrace.values[FTRACE_PIN_LONGESTPINNED] = length; } else if (ftrace_data[k].tracepoint == LOG_FLUSH) { fs->ftrace.values[FTRACE_LOGFLUSH_TOTAL]++; } else if (ftrace_data[k].tracepoint == LOG_BLOCKS) { fs->ftrace.values[FTRACE_LOGBLOCKS_TOTAL]++; } else if (ftrace_data[k].tracepoint == AIL_FLUSH) { fs->ftrace.values[FTRACE_AILFLUSH_TOTAL]++; } else if (ftrace_data[k].tracepoint == BLOCK_ALLOC) { char type[8]; sscanf(ftrace_data[k].data, "gfs2_block_alloc: %*d,%*d bmap %*u alloc %*u/%*u %s rg:%*u rf:%*u rr:%*u", type ); if (strncmp(type, "free", 8) == 0) { fs->ftrace.values[FTRACE_BLOCKALLOC_FREE]++; } else if (strncmp(type, "used", 8) == 0) { fs->ftrace.values[FTRACE_BLOCKALLOC_USED]++; } else if (strncmp(type, "dinode", 8) == 0) { fs->ftrace.values[FTRACE_BLOCKALLOC_DINODE]++; } else if (strncmp(type, "unlinked", 8) == 0) { fs->ftrace.values[FTRACE_BLOCKALLOC_UNLINKED]++; } fs->ftrace.values[FTRACE_BLOCKALLOC_TOTAL]++; } else if (ftrace_data[k].tracepoint == BMAP) { char type[8]; sscanf(ftrace_data[k].data, "gfs2_bmap: %*d,%*d bmap %*u map %*u/%*u to %*u flags:%*x %s %*d", type ); if (strncmp(type, "create", 8) == 0) { fs->ftrace.values[FTRACE_BMAP_CREATE]++; } else if (strncmp(type, "nocreate", 8) == 0) { fs->ftrace.values[FTRACE_BMAP_NOCREATE]++; } fs->ftrace.values[FTRACE_BMAP_TOTAL]++; } else if (ftrace_data[k].tracepoint == RS) { char type[8]; sscanf(ftrace_data[k].data, "gfs2_rs: %*d,%*d bmap %*u resrv %*u rg:%*u rf:%*u rr:%*u %s f:%*u", type ); if (strncmp(type, "del", 4) == 0) { fs->ftrace.values[FTRACE_RS_DEL]++; } else if (strncmp(type, "tdel", 4) == 0) { fs->ftrace.values[FTRACE_RS_TDEL]++; } else if (strncmp(type, "ins", 4) == 0) { fs->ftrace.values[FTRACE_RS_INS]++; } else if (strncmp(type, "clm", 4) == 0) { fs->ftrace.values[FTRACE_RS_CLM]++; } fs->ftrace.values[FTRACE_RS_TOTAL]++; } } /* LOGFLUSH & AILFLUSH have start/end operations so we divide the total values */ fs ->ftrace.values[FTRACE_LOGFLUSH_TOTAL] /= 2; fs ->ftrace.values[FTRACE_AILFLUSH_TOTAL] /= 2; } /* Free memory */ free(ftrace_data); ftrace_data = NULL; } /* * We take all required data from the trace_pipe. Whilst keeping track of * the number of locks we have seen so far. After locks have been collected * we assign values and return. */ int gfs2_refresh_ftrace_stats(pmInDom gfs_fs_indom) { FILE *fp; int fd, flags; char buffer[8196]; /* Reset the metric types we have found */ num_accepted_entries = 0; capacity = FTRACE_ARRAY_CAPACITY; /* We open the pipe in both read-only and non-blocking mode */ if ((fp = fopen(TRACE_PIPE, "r")) == NULL) return -oserror(); /* Set flags of fp as non-blocking */ fd = fileno(fp); flags = fcntl(fd, F_GETFL); if (fcntl(fd, F_SETFL, flags | O_RDONLY | O_NONBLOCK) < 0) { fclose(fp); return -oserror(); } /* Extract data from the trace_pipe */ while (fgets(buffer, sizeof(buffer), fp) != NULL) { if (num_accepted_entries >= max_glock_throughput) break; /* In the event of an allocation error */ if (gfs2_extract_trace_values(buffer) != 0) break; } fclose(fp); /* Clear the rest of the ring buffer after passing max_glock_throughput */ ftrace_clear_buffer(); /* Processing here */ if (ftrace_data != NULL) gfs2_assign_ftrace(gfs_fs_indom); /* Assign worst_glock entries */ if (worst_glock_get_state() == 1) worst_glock_assign_glocks(gfs_fs_indom); return 0; } pcp-3.8.12ubuntu1/src/pmdas/gfs2/control.c0000664000000000000000000000741112272262501015165 0ustar /* * GFS2 trace-point metrics control. * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "control.h" #include "ftrace.h" #include "worst_glock.h" /* Locations of the enable files for the gfs2 tracepoints */ const char *control_locations[] = { [CONTROL_ALL] = "/sys/kernel/debug/tracing/events/gfs2/enable", [CONTROL_GLOCK_STATE_CHANGE] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_glock_state_change/enable", [CONTROL_GLOCK_PUT] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_glock_put/enable", [CONTROL_DEMOTE_RQ] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_demote_rq/enable", [CONTROL_PROMOTE] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_promote/enable", [CONTROL_GLOCK_QUEUE] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_glock_queue/enable", [CONTROL_GLOCK_LOCK_TIME] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_glock_lock_time/enable", [CONTROL_PIN] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_pin/enable", [CONTROL_LOG_FLUSH] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_log_flush/enable", [CONTROL_LOG_BLOCKS] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_log_blocks/enable", [CONTROL_AIL_FLUSH] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_ail_flush/enable", [CONTROL_BLOCK_ALLOC] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_block_alloc/enable", [CONTROL_BMAP] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_bmap/enable", [CONTROL_RS] = "/sys/kernel/debug/tracing/events/gfs2/gfs2_rs/enable", [CONTROL_GLOBAL_TRACING] = "/sys/kernel/debug/tracing/tracing_on" }; /* * Refresh callback for the control metrics; For traceppoints that have file * based enabling we use gfs2_control_check_value(), for other metrics we * call their corresponding "get" value. */ int gfs2_control_fetch(int item, pmAtomValue *atom) { if (item >= CONTROL_ALL && item <= CONTROL_GLOBAL_TRACING) { atom->ul = gfs2_control_check_value(control_locations[item]); } else if (item == CONTROL_WORSTGLOCK) { atom->ul = worst_glock_get_state(); } else if (item == CONTROL_FTRACE_GLOCK_THRESHOLD) { atom->ul = ftrace_get_threshold(); } else { return PM_ERR_PMID; } return 1; } /* * Attempt open the enable file for the given filename and set the value * contained in pmValueSet. The enable file for the tracepoint only accept * 0 for disabled or 1 for enabled. */ int gfs2_control_set_value(const char *filename, pmValueSet *vsp) { FILE *fp; int sts = 0; int value = vsp->vlist[0].value.lval; if (value < 0 || value > 1) return -oserror(); fp = fopen(filename, "w"); if (!fp) { sts = -oserror(); /* EACCESS, File not found (stats not supported) */; } else { fprintf(fp, "%d\n", value); fclose(fp); } return sts; } /* * We check the tracepoint enable file given by filename and return the value * contained. This should either be 0 for disabled or 1 for enabled. In the * event of permissions or file not found we will return error. */ int gfs2_control_check_value(const char *filename) { FILE *fp; char buffer[2]; int value = 0; fp = fopen(filename, "r"); if (fp) { while (fgets(buffer, sizeof(buffer), fp) != NULL) sscanf(buffer, "%d", &value); fclose(fp); } return value; } pcp-3.8.12ubuntu1/src/pmdas/gfs2/ftrace.h0000664000000000000000000001014012272262501014747 0ustar /* * GFS2 ftrace based trace-point metrics. * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef FTRACE_H #define FTRACE_H #define FTRACE_ARRAY_CAPACITY 2048 #define INITIAL_GLOBAL_MAX_GLOCK_THROUGHPUT 750000 enum { GLOCK_STATE_CHANGE = 0, GLOCK_PUT, DEMOTE_RQ, PROMOTE, GLOCK_QUEUE, GLOCK_LOCK_TIME, PIN, LOG_FLUSH, LOG_BLOCKS, AIL_FLUSH, BLOCK_ALLOC, BMAP, RS, NUM_FTRACE_TRACEPOINTS }; enum { FTRACE_GLOCKSTATE_TOTAL = 0, FTRACE_GLOCKSTATE_NULLLOCK, FTRACE_GLOCKSTATE_CONCURRENTREAD, FTRACE_GLOCKSTATE_CONCURRENTWRITE, FTRACE_GLOCKSTATE_PROTECTEDREAD, FTRACE_GLOCKSTATE_PROTECTEDWRITE, FTRACE_GLOCKSTATE_EXCLUSIVE, FTRACE_GLOCKSTATE_GLOCK_CHANGEDTARGET, FTRACE_GLOCKSTATE_GLOCK_MISSEDTARGET, FTRACE_GLOCKPUT_TOTAL, FTRACE_GLOCKPUT_NULLLOCK, FTRACE_GLOCKPUT_CONCURRENTREAD, FTRACE_GLOCKPUT_CONCURRENTWRITE, FTRACE_GLOCKPUT_PROTECTEDREAD, FTRACE_GLOCKPUT_PROTECTEDWRITE, FTRACE_GLOCKPUT_EXCLUSIVE, FTRACE_DEMOTERQ_TOTAL, FTRACE_DEMOTERQ_NULLLOCK, FTRACE_DEMOTERQ_CONCURRENTREAD, FTRACE_DEMOTERQ_CONCURRENTWRITE, FTRACE_DEMOTERQ_PROTECTEDREAD, FTRACE_DEMOTERQ_PROTECTEDWRITE, FTRACE_DEMOTERQ_EXCLUSIVE, FTRACE_DEMOTERQ_REQUESTED_REMOTE, FTRACE_DEMOTERQ_REQUESTED_LOCAL, FTRACE_PROMOTE_TOTAL, FTRACE_PROMOTE_FIRST_NULLLOCK, FTRACE_PROMOTE_FIRST_CONCURRENTREAD, FTRACE_PROMOTE_FIRST_CONCURRENTWRITE, FTRACE_PROMOTE_FIRST_PROTECTEDREAD, FTRACE_PROMOTE_FIRST_PROTECTEDWRITE, FTRACE_PROMOTE_FIRST_EXCLUSIVE, FTRACE_PROMOTE_OTHER_NULLLOCK, FTRACE_PROMOTE_OTHER_CONCURRENTREAD, FTRACE_PROMOTE_OTHER_CONCURRENTWRITE, FTRACE_PROMOTE_OTHER_PROTECTEDREAD, FTRACE_PROMOTE_OTHER_PROTECTEDWRITE, FTRACE_PROMOTE_OTHER_EXCLUSIVE, FTRACE_GLOCKQUEUE_TOTAL, FTRACE_GLOCKQUEUE_QUEUE_TOTAL, FTRACE_GLOCKQUEUE_QUEUE_NULLLOCK, FTRACE_GLOCKQUEUE_QUEUE_CONCURRENTREAD, FTRACE_GLOCKQUEUE_QUEUE_CONCURRENTWRITE, FTRACE_GLOCKQUEUE_QUEUE_PROTECTEDREAD, FTRACE_GLOCKQUEUE_QUEUE_PROTECTEDWRITE, FTRACE_GLOCKQUEUE_QUEUE_EXCLUSIVE, FTRACE_GLOCKQUEUE_DEQUEUE_TOTAL, FTRACE_GLOCKQUEUE_DEQUEUE_NULLLOCK, FTRACE_GLOCKQUEUE_DEQUEUE_CONCURRENTREAD, FTRACE_GLOCKQUEUE_DEQUEUE_CONCURRENTWRITE, FTRACE_GLOCKQUEUE_DEQUEUE_PROTECTEDREAD, FTRACE_GLOCKQUEUE_DEQUEUE_PROTECTEDWRITE, FTRACE_GLOCKQUEUE_DEQUEUE_EXCLUSIVE, FTRACE_GLOCKLOCKTIME_TOTAL, FTRACE_GLOCKLOCKTIME_TRANS, FTRACE_GLOCKLOCKTIME_INDOE, FTRACE_GLOCKLOCKTIME_RGRP, FTRACE_GLOCKLOCKTIME_META, FTRACE_GLOCKLOCKTIME_IOPEN, FTRACE_GLOCKLOCKTIME_FLOCK, FTRACE_GLOCKLOCKTIME_QUOTA, FTRACE_GLOCKLOCKTIME_JOURNAL, FTRACE_PIN_TOTAL, FTRACE_PIN_PINTOTAL, FTRACE_PIN_UNPINTOTAL, FTRACE_PIN_LONGESTPINNED, FTRACE_LOGFLUSH_TOTAL, FTRACE_LOGBLOCKS_TOTAL, FTRACE_AILFLUSH_TOTAL, FTRACE_BLOCKALLOC_TOTAL, FTRACE_BLOCKALLOC_FREE, FTRACE_BLOCKALLOC_USED, FTRACE_BLOCKALLOC_DINODE, FTRACE_BLOCKALLOC_UNLINKED, FTRACE_BMAP_TOTAL, FTRACE_BMAP_CREATE, FTRACE_BMAP_NOCREATE, FTRACE_RS_TOTAL, FTRACE_RS_DEL, FTRACE_RS_TDEL, FTRACE_RS_INS, FTRACE_RS_CLM, NUM_TRACEPOINT_STATS }; struct ftrace { uint64_t values[NUM_TRACEPOINT_STATS]; }; struct ftrace_data { dev_t dev_id; int tracepoint; char data[512]; }; extern void ftrace_increase_num_accepted_entries(); extern int gfs2_ftrace_fetch(int, struct ftrace *, pmAtomValue *); extern int gfs2_refresh_ftrace_stats(pmInDom); extern int ftrace_get_threshold(); extern int ftrace_set_threshold(pmValueSet *vsp); #endif /*FTRACE_H*/ pcp-3.8.12ubuntu1/src/pmdas/gfs2/README0000664000000000000000000000757712272262501014236 0ustar Performance Co-Pilot PMDA for Monitoring GFS2 Filesystems ========================================================= This PMDA is capable of collecting glock statistics from GFS2 filesystems mounted on the system in both local and clustered configurations. The PMDA collects its data from the trace-point output given by GFS2 as the filesystem is working, this information is provided in userland through debugfs. In order for pmdagfs2 to be able to provide any metric data the user must have debugfs mounted and at least on GFS2 filesystem mounted on the system to be monitored. As mentioned above the PMDA can be used both situations where GFS2 filesystems are mounted as local filesystems and in cluster configurations where GFS2 is used as a shared disk filesystem. When the PMDA is being used in conjunction with a locally mounted filesystem (no clustering) only a base number of metrics will be available to provide metric information back to PMCD, these metrics can be recognised by their lack of corresponding “control†metrics. For configurations where GFS2 is used in a clustered environment the additional “cluster only†metrics are able to collect data through the cache control mechanism of the cluster. This data being passed between cluster nodes regarding the state of glocks is unavailable in local filesystem configurations leading the requirement for a cluster configuration for these metrics. For more information on GFS2 or cluster setups please visit www.redhat.com Metrics ======= The file ./help contains descriptions for all of the metrics which are exposed by this PMDA. Once the PMDA has been installed, the following command will list all of the available metrics and their explanatory “help†text: + # $ pminfo -fT gfs2 Installation ============ + # cd $PCP_PMDAS_DIR/gfs2 + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDA's currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number (This should only be an issue on installations with third party PMDA's installed as the domain number given has been reserved for the GFS2 PMDA with base PCP installations). + Then simply use # ./Install and choose both the “collector†and “monitor†installation configuration options. Configuration ============= Some of the metrics provided by the PMDA can be configured to whether they are turned on or off with regards to collecting metric data. These metrics are distinguished by having a corresponding “control†metric. Identification of these metrics which have this control can be found by issuing the following command. + $ pminfo -fT gfs2.control The metrics given as output through pminfo in this way can be controlled by setting their metric value to either 0 (Off: no collection of metric data) or 1 (On: collection of metric data) using the provided command pmstore whilst specifying the metric to set the value for and a valid value. + $ pmstore gfs2.control.tracepoints.all 1 Any metrics without a corresponding control metric cannot have their functionality toggled in this way. De-Installation =============== + Simply use # cd $PCP_PMDAS_DIR/gfs2 #./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/PMCD/gfs2.log) should be checked for any warnings or errors. + In an event where no values are being returned for most of the metrics check ensure that both debugfs is mounted, metrics with control options are enabled and your distribution supports the full range of GFS2 trace-points. $ mount -t debugfs none /sys/kernel/debug $ pminfo -f gfs2.control $ pmstore gfs2.control.tracepoints.all 1 pcp-3.8.12ubuntu1/src/pmdas/gfs2/glstats.c0000664000000000000000000000726312272262501015173 0ustar /* * GFS2 glstats file statistics. * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "glstats.h" /* * GFS2 glock type identification; note that the glock type 7 is currently not * used and is reserved to be on the safe side. * * Type Lock type Use * 1 Trans Transaction lock * 2 Inode Inode metadata and data * 3 Rgrp Resource group metadata * 4 Meta The superblock * 5 Iopen Inode last closer detection * 6 Flock flock(2) syscall * 8 Quota Quota operations * 9 Journal Journal mutex * */ int gfs2_glstats_fetch(int item, struct glstats *glstats, pmAtomValue *atom) { /* Handle the case for our reserved but not used glock type 7 */ if ((item < 0 || item >= NUM_GLSTATS_STATS) && item != 7) return PM_ERR_PMID; /* Check for no values recorded */ if(glstats->values[item] == UINT64_MAX) return 0; atom->ull = glstats->values[item]; return 1; } int gfs2_refresh_glstats(const char *sysfs, const char *name, struct glstats *glstats){ char buffer[4096]; FILE *fp; /* Reset all counter for this fs */ memset(glstats, 0, sizeof(*glstats)); snprintf(buffer, sizeof(buffer), "%s/%s/glstats", sysfs, name); buffer[sizeof(buffer) - 1] = '\0'; if ((fp = fopen(buffer, "r")) == NULL){ /* * We set the values to UINT64_MAX to signify we have no * current values (no metric support or debugfs not mounted) * */ memset(glstats, -1, sizeof(*glstats)); return -oserror(); } /* * We read through the glstats file, finding out what glock types we are * coming across and tally up the number of each type of glock we find. * This file however contains the total number of locks at this time, * on a large, heavy utilized filesystem there could be millions of entries * so needs to be quick and efficient. * */ while(fgets(buffer, sizeof(buffer), fp) != NULL){ char *p = buffer; /* We pick out the various glock types by the identifying number */ if (strncmp(p, "G: n:1", 6) == 0){ glstats->values[GLSTATS_TRANS]++; } else if (strncmp(p, "G: n:2 ", 6) == 0){ glstats->values[GLSTATS_INODE]++; } else if (strncmp(p, "G: n:3 ", 6) == 0){ glstats->values[GLSTATS_RGRP]++; } else if (strncmp(p, "G: n:4 ", 6) == 0){ glstats->values[GLSTATS_META]++; } else if (strncmp(p, "G: n:5 ", 6) == 0){ glstats->values[GLSTATS_IOPEN]++; } else if (strncmp(p, "G: n:6 ", 6) == 0){ glstats->values[GLSTATS_FLOCK]++; } else if (strncmp(p, "G: n:8 ", 6) == 0){ glstats->values[GLSTATS_QUOTA]++; } else if (strncmp(p, "G: n:9 ", 6) == 0){ glstats->values[GLSTATS_JOURNAL]++; } glstats->values[GLSTATS_TOTAL]++; /* * We advance the cursor for after we read what type of lock we have * for (p += 6; isspace((int)*p); p++) {;} * * [ We can extract any other future fields from here on] * */ } fclose(fp); return 0; } pcp-3.8.12ubuntu1/src/pmdas/gfs2/sbstats.c0000664000000000000000000001657412272262501015202 0ustar /* * GFS2 sbstats sysfs file statistics. * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "pmdagfs2.h" #include static const char *stattype[] = { [LOCKSTAT_SRTT] = "srtt", [LOCKSTAT_SRTTVAR] = "srttvar", [LOCKSTAT_SRTTB] = "srttb", [LOCKSTAT_SRTTVARB] = "srttvarb", [LOCKSTAT_SIRT] = "sirt", [LOCKSTAT_SIRTVAR] = "sirtvar", [LOCKSTAT_DCOUNT] = "dlm", [LOCKSTAT_QCOUNT] = "queue", }; static const char *stattext[] = { [LOCKSTAT_SRTT] = "Non-blocking smoothed round trip time", [LOCKSTAT_SRTTVAR] = "Non-blocking smoothed variance", [LOCKSTAT_SRTTB] = "Blocking smoothed round trip time", [LOCKSTAT_SRTTVARB] = "Blocking smoothed variance", [LOCKSTAT_SIRT] = "Smoothed inter-request time", [LOCKSTAT_SIRTVAR] = "Smoothed inter-request variance", [LOCKSTAT_DCOUNT] = "Count of Distributed Lock Manager requests", [LOCKSTAT_QCOUNT] = "Count of gfs2_holder queues", }; static const char *locktype[] = { [LOCKTYPE_RESERVED] = "reserved", [LOCKTYPE_NONDISK] = "nondisk", [LOCKTYPE_INODE] = "inode", [LOCKTYPE_RGRB] = "rgrp", [LOCKTYPE_META] = "meta", [LOCKTYPE_IOPEN] = "iopen", [LOCKTYPE_FLOCK] = "flock", [LOCKTYPE_PLOCK] = "plock", [LOCKTYPE_QUOTA] = "quota", [LOCKTYPE_JOURNAL] = "journal", }; int gfs2_sbstats_fetch(int item, struct sbstats *fs, pmAtomValue *atom) { /* Check for valid metric count */ if (item < 0 || item >= SBSTATS_COUNT) return PM_ERR_PMID; /* Check for no values recorded */ if(fs->values[item] == UINT64_MAX) return 0; atom->ull = fs->values[item]; return 1; } int gfs2_refresh_sbstats(const char *sysfs, const char *name, struct sbstats *sb) { unsigned int id = 0; char buffer[4096]; FILE *fp; /* Reset all counter for this fs */ memset(sb, 0, sizeof(*sb)); snprintf(buffer, sizeof(buffer), "%s/%s/sbstats", sysfs, name); buffer[sizeof(buffer)-1] = '\0'; if ((fp = fopen(buffer, "r")) == NULL){ /* * We set the values to UINT64_MAX to signify we have no * current values (no metric support or debugfs not mounted) * */ memset(sb, -1, sizeof(*sb)); return -oserror(); } /* * Read through sbstats file one line at a time. This is called on each * and every fetch request, so should be as quick as we can make it. * * Once we've skipped over the heading, the format is fixed so to make this * faster (we expect the kernel has a fixed set of types/stats) we go right * ahead and index directly into the stats structure for each line. We do * check validity too - if there's a mismatch, we throw our toys. * * Also, we aggregate the per-CPU data for each statistic - we could go for * separate per-CPU metrics as well, but for now just keep it simple until * there's a real need for that extra complexity. * */ while (fgets(buffer, sizeof(buffer), fp) != NULL) { char *typestr, *statstr, *end; char *p = buffer; if (strncmp(p, "type", 4) == 0) continue; if (id > SBSTATS_COUNT) break; typestr = p; for (typestr = p; !isspace((int)*p); p++) { } /* skip lock type */ for (; isspace((int)*p); p++) { *p = '\0'; } /* eat whitespace */ for (statstr = p; *p != ':'; p++) { } /* skip stat type */ *p = '\0'; /* verify that the id we are up to matches what we see in the file */ unsigned int type = id / NUM_LOCKSTATS; unsigned int stat = id % NUM_LOCKSTATS; if (strcmp(typestr, locktype[type]) != 0) { __pmNotifyErr(LOG_ERR, "unexpected sbstat type \"%s\" (want %s at line %u)", typestr, locktype[type], id); break; /* eh? */ } if (strcmp(statstr, stattype[stat]) != 0) { __pmNotifyErr(LOG_ERR, "unexpected sbstat stat \"%s\" (want %s at line %u)", statstr, stattype[stat], id); break; /* wha? */ } /* decode all of the (per-CPU) values until the end of line */ for (p++; *p != '\0'; p++) { __uint64_t value; value = strtoull(p, &end, 10); if (end == p) break; sb->values[id] += value; p = end; } if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_INFO, "got expected sbstat type \"%s\", stat \"%s\" at line %u", typestr, statstr, id); /* now we can move on to the next metric (on the next line) */ id++; } fclose(fp); return (id == SBSTATS_COUNT) ? 0 : -EINVAL; } static void add_pmns_node(__pmnsTree *tree, int domain, int cluster, int lock, int stat) { char entry[64]; pmID pmid = pmid_build(domain, cluster, (lock * NUM_LOCKSTATS) + stat); snprintf(entry, sizeof(entry), "gfs2.sbstats.%s.%s", locktype[lock], stattype[stat]); __pmAddPMNSNode(tree, pmid, entry); if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "GFS2 sbstats added %s (%s)", entry, pmIDStr(pmid)); } static int refresh_sbstats(pmdaExt *pmda, __pmnsTree **tree) { int t, s, sts; static __pmnsTree *sbstats_tree; if (sbstats_tree) { *tree = sbstats_tree; } else if ((sts = __pmNewPMNS(&sbstats_tree)) < 0) { __pmNotifyErr(LOG_ERR, "%s: failed to create sbstats names: %s\n", pmProgname, pmErrStr(sts)); *tree = NULL; } else { for (t = 0; t < NUM_LOCKTYPES; t++) for (s = 0; s < NUM_LOCKSTATS; s++) add_pmns_node(sbstats_tree, pmda->e_domain, CLUSTER_SBSTATS, t, s); *tree = sbstats_tree; return 1; } return 0; } /* * Create a new metric table entry based on an existing one. * */ static void refresh_metrictable(pmdaMetric *source, pmdaMetric *dest, int lock) { int item = pmid_item(source->m_desc.pmid); int domain = pmid_domain(source->m_desc.pmid); int cluster = pmid_cluster(source->m_desc.pmid); memcpy(dest, source, sizeof(pmdaMetric)); item += lock * NUM_LOCKSTATS; dest->m_desc.pmid = pmid_build(domain, cluster, item); if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "GFS2 sbstats refresh_metrictable: (%p -> %p) " "metric ID dup: %d.%d.%d -> %d.%d.%d\n", source, dest, domain, cluster, pmid_item(source->m_desc.pmid), domain, cluster, item); } /* * Used to answer the question: how much extra space needs to be * allocated in the metric table for (dynamic) sbstats metrics? * */ static void size_metrictable(int *total, int *trees) { *total = NUM_LOCKSTATS; *trees = NUM_LOCKTYPES; } static int sbstats_text(pmdaExt *pmda, pmID pmid, int type, char **buf) { int item = pmid_item(pmid); static char text[128]; if (pmid_cluster(pmid) != CLUSTER_SBSTATS) return PM_ERR_PMID; if (item < 0 || item >= SBSTATS_COUNT) return PM_ERR_PMID; snprintf(text, sizeof(text), "%s for %s glocks", stattext[item % NUM_LOCKSTATS], locktype[item / NUM_LOCKSTATS]); *buf = text; return 0; } void gfs2_sbstats_init(pmdaMetric *metrics, int nmetrics) { int set[] = { CLUSTER_SBSTATS }; pmdaDynamicPMNS("gfs2.sbstats", set, sizeof(set)/sizeof(int), refresh_sbstats, sbstats_text, refresh_metrictable, size_metrictable, metrics, nmetrics); } pcp-3.8.12ubuntu1/src/pmdas/gfs2/Remove0000664000000000000000000000122612272262501014517 0ustar #! /bin/sh # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the GFS2 PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=gfs2 pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/gfs2/glocks.h0000664000000000000000000000172012272262501014771 0ustar /* * GFS2 glock file statistics. * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef GLOCKS_H #define GLOCKS_H enum { GLOCKS_TOTAL = 0, GLOCKS_SHARED = 1, GLOCKS_UNLOCKED = 2, GLOCKS_DEFERRED = 3, GLOCKS_EXCLUSIVE = 4, NUM_GLOCKS_STATS }; struct glocks { __uint64_t values[NUM_GLOCKS_STATS]; }; extern int gfs2_glocks_fetch(int, struct glocks *, pmAtomValue *); extern int gfs2_refresh_glocks(const char *, const char *, struct glocks *); #endif /*GLOCKS_H*/ pcp-3.8.12ubuntu1/src/pmdas/gfs2/sbstats.h0000664000000000000000000000313112272262501015170 0ustar /* * GFS2 sbstats sysfs file statistics. * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef SBSTATS_H #define SBSTATS_H enum { LOCKSTAT_SRTT = 0, /* Non-blocking smoothed round trip time */ LOCKSTAT_SRTTVAR, /* Non-blocking smoothed variance */ LOCKSTAT_SRTTB, /* Blocking smoothed round trip time */ LOCKSTAT_SRTTVARB, /* Blocking smoothed variance */ LOCKSTAT_SIRT, /* Smoothed inter-request time */ LOCKSTAT_SIRTVAR, /* Smoothed inter-request variance */ LOCKSTAT_DCOUNT, /* Count of DLM requests */ LOCKSTAT_QCOUNT, /* Count of gfs2_holder queues */ NUM_LOCKSTATS }; enum { LOCKTYPE_RESERVED = 0, LOCKTYPE_NONDISK, LOCKTYPE_INODE, LOCKTYPE_RGRB, LOCKTYPE_META, LOCKTYPE_IOPEN, LOCKTYPE_FLOCK, LOCKTYPE_PLOCK, LOCKTYPE_QUOTA, LOCKTYPE_JOURNAL, NUM_LOCKTYPES }; #define SBSTATS_COUNT (NUM_LOCKSTATS*NUM_LOCKTYPES) struct sbstats { __uint64_t values[SBSTATS_COUNT]; }; extern void gfs2_sbstats_init(pmdaMetric *, int); extern int gfs2_sbstats_fetch(int, struct sbstats *, pmAtomValue *); extern int gfs2_refresh_sbstats(const char *, const char *, struct sbstats *); #endif /* SBSTATS_H */ pcp-3.8.12ubuntu1/src/pmdas/gfs2/Install0000664000000000000000000000127612272262501014675 0ustar #! /bin/sh # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the GFS2 PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=gfs2 forced_restart=true pmda_interface=4 pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/gfs2/control.h0000664000000000000000000000241512272262501015171 0ustar /* * GFS2 trace-point enable controls. * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef CONTROL_H #define CONTROL_H enum { CONTROL_ALL = 0, CONTROL_GLOCK_STATE_CHANGE, CONTROL_GLOCK_PUT, CONTROL_DEMOTE_RQ, CONTROL_PROMOTE, CONTROL_GLOCK_QUEUE, CONTROL_GLOCK_LOCK_TIME, CONTROL_PIN, CONTROL_LOG_FLUSH, CONTROL_LOG_BLOCKS, CONTROL_AIL_FLUSH, CONTROL_BLOCK_ALLOC, CONTROL_BMAP, CONTROL_RS, CONTROL_GLOBAL_TRACING, CONTROL_WORSTGLOCK, CONTROL_FTRACE_GLOCK_THRESHOLD, NUM_CONTROL_STATS }; extern const char *control_locations[]; extern int gfs2_control_fetch(int, pmAtomValue *); extern int gfs2_control_set_value(const char *, pmValueSet *); extern int gfs2_control_check_value(const char *); #endif /* CONTROL_H */ pcp-3.8.12ubuntu1/src/pmdas/gfs2/GNUmakefile0000664000000000000000000000277512272262501015423 0ustar # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs CFILES = control.c glstats.c worst_glock.c glocks.c sbstats.c ftrace.c pmda.c HFILES = control.h glstats.h worst_glock.h glocks.h sbstats.h ftrace.h pmdagfs2.h CMDTARGET = pmdagfs2 LLDLIBS = $(PCP_PMDALIB) LSRCFILES = Install Remove pmns root help README IAM = gfs2 DOMAIN = GFS2 PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LDIRT = domain.h $(IAM).log default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "linux" build-me: domain.h $(CMDTARGET) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(CMDTARGET) $(PMDADIR) $(INSTALL) -m 644 root pmns domain.h help $(PMDADIR) else build-me: install: endif default_pcp : default install_pcp : install domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pmda.o glocks.o: glocks.h pmda.o sbstats.o: sbstats.h pmda.o: pmdagfs2.h pmda.o glstats.o: glstats.h pmda.o worst_glock.o: worst_glock.h pmda.o ftrace.o: ftrace.h pmda.o control.o: control.h pcp-3.8.12ubuntu1/src/pmdas/gfs2/root0000664000000000000000000000024112272262501014241 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { gfs2 } #ifndef GFS2 #define GFS2 115 #endif #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/gfs2/pmns0000664000000000000000000001126112272262501014237 0ustar /* * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * Changed GFS2:*:* to root number 115 to remove ASCII parse errors during * install of PMDA whilst testing. */ gfs2 { glocks sbstats GFS2:*:* glstats tracepoints worst_glock control } gfs2.glocks { total GFS2:0:0 shared GFS2:0:1 unlocked GFS2:0:2 deferred GFS2:0:3 exclusive GFS2:0:4 } gfs2.glstats { total GFS2:2:0 trans GFS2:2:1 inode GFS2:2:2 rgrp GFS2:2:3 meta GFS2:2:4 iopen GFS2:2:5 flock GFS2:2:6 quota GFS2:2:8 journal GFS2:2:9 } gfs2.tracepoints { glock_state_change glock_put demote_rq promote glock_queue glock_lock_time pin log_flush log_block ail_flush block_alloc bmap rs } gfs2.tracepoints.glock_state_change { total GFS2:3:0 null_lock GFS2:3:1 concurrent_read GFS2:3:2 concurrent_write GFS2:3:3 protected_read GFS2:3:4 protected_write GFS2:3:5 exclusive GFS2:3:6 glocks } gfs2.tracepoints.glock_state_change.glocks { changed_target GFS2:3:7 missed_target GFS2:3:8 } gfs2.tracepoints.glock_put { total GFS2:3:9 null_lock GFS2:3:10 concurrent_read GFS2:3:11 concurrent_write GFS2:3:12 protected_read GFS2:3:13 protected_write GFS2:3:14 exclusive GFS2:3:15 } gfs2.tracepoints.demote_rq { total GFS2:3:16 null_lock GFS2:3:17 concurrent_read GFS2:3:18 concurrent_write GFS2:3:19 protected_read GFS2:3:20 protected_write GFS2:3:21 exclusive GFS2:3:22 requested } gfs2.tracepoints.demote_rq.requested { remote GFS2:3:23 local GFS2:3:24 } gfs2.tracepoints.promote { total GFS2:3:25 first other } gfs2.tracepoints.promote.first { null_lock GFS2:3:26 concurrent_read GFS2:3:27 concurrent_write GFS2:3:28 protected_read GFS2:3:29 protected_write GFS2:3:30 exclusive GFS2:3:31 } gfs2.tracepoints.promote.other { null_lock GFS2:3:32 concurrent_read GFS2:3:33 concurrent_write GFS2:3:34 protected_read GFS2:3:35 protected_write GFS2:3:36 exclusive GFS2:3:37 } gfs2.tracepoints.glock_queue { total GFS2:3:38 queue dequeue } gfs2.tracepoints.glock_queue.queue { total GFS2:3:39 null_lock GFS2:3:40 concurrent_read GFS2:3:41 concurrent_write GFS2:3:42 protected_read GFS2:3:43 protected_write GFS2:3:44 exclusive GFS2:3:45 } gfs2.tracepoints.glock_queue.dequeue { total GFS2:3:46 null_lock GFS2:3:47 concurrent_read GFS2:3:48 concurrent_write GFS2:3:49 protected_read GFS2:3:50 protected_write GFS2:3:51 exclusive GFS2:3:52 } gfs2.tracepoints.glock_lock_time { total GFS2:3:53 trans GFS2:3:54 inode GFS2:3:55 rgrp GFS2:3:56 meta GFS2:3:57 iopen GFS2:3:58 flock GFS2:3:59 quota GFS2:3:60 journal GFS2:3:61 } gfs2.tracepoints.pin { total GFS2:3:62 pin_total GFS2:3:63 unpin_total GFS2:3:64 longest_pinned GFS2:3:65 } gfs2.tracepoints.log_flush { total GFS2:3:66 } gfs2.tracepoints.log_block { total GFS2:3:67 } gfs2.tracepoints.ail_flush { total GFS2:3:68 } gfs2.tracepoints.block_alloc { total GFS2:3:69 free GFS2:3:70 used GFS2:3:71 dinode GFS2:3:72 unlinked GFS2:3:73 } gfs2.tracepoints.bmap { total GFS2:3:74 create GFS2:3:75 nocreate GFS2:3:76 } gfs2.tracepoints.rs { total GFS2:3:77 del GFS2:3:78 tdel GFS2:3:79 ins GFS2:3:80 clm GFS2:3:81 } gfs2.worst_glock { lock_type GFS2:4:0 number GFS2:4:1 srtt GFS2:4:2 srttvar GFS2:4:3 srttb GFS2:4:4 srttvarb GFS2:4:5 sirt GFS2:4:6 sirtvar GFS2:4:7 dlm GFS2:4:8 queue GFS2:4:9 } gfs2.control { tracepoints global_tracing GFS2:5:14 worst_glock GFS2:5:15 glock_threshold GFS2:5:16 } gfs2.control.tracepoints { all GFS2:5:0 glock_state_change GFS2:5:1 glock_put GFS2:5:2 demote_rq GFS2:5:3 promote GFS2:5:4 glock_queue GFS2:5:5 glock_lock_time GFS2:5:6 pin GFS2:5:7 log_flush GFS2:5:8 log_blocks GFS2:5:9 ail_flush GFS2:5:10 block_alloc GFS2:5:11 bmap GFS2:5:12 rs GFS2:5:13 } pcp-3.8.12ubuntu1/src/pmdas/gfs2/worst_glock.h0000664000000000000000000000411212272262501016042 0ustar /* * GFS2 gfs2_glock_lock_time trace-point metrics. * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef LOCK_TIME_H #define LOCK_TIME_H #define COUNT_THRESHOLD 350 #define DEFAULT_WORST_GLOCK_STATE 1 enum { WORSTGLOCK_LOCK_TYPE = 0, WORSTGLOCK_NUMBER, WORSTGLOCK_SRTT, WORSTGLOCK_SRTTVAR, WORSTGLOCK_SRTTB, WORSTGLOCK_SRTTVARB, WORSTGLOCK_SIRT, WORSTGLOCK_SIRTVAR, WORSTGLOCK_DLM, WORSTGLOCK_QUEUE }; enum { LOCKTIME_TRANS = 1, LOCKTIME_INODE = 2, LOCKTIME_RGRP = 3, LOCKTIME_META = 4, LOCKTIME_IOPEN = 5, LOCKTIME_FLOCK = 6, LOCKTIME_RESERVED = 7, LOCKTIME_QUOTA = 8, LOCKTIME_JOURNAL = 9 }; struct worst_glock { dev_t dev_id; uint32_t lock_type; /* Glock type number */ uint64_t number; /* Inode or resource group number */ int64_t srtt; /* Non blocking smoothed round trip time */ int64_t srttvar; /* Non blocking smoothed variance */ int64_t srttb; /* Blocking smoothed round trip time */ int64_t srttvarb; /* Blocking smoothed variance */ int64_t sirt; /* Smoothed Inter-request time */ int64_t sirtvar; /* Smoothed Inter-request variance */ int64_t dlm; /* Count of dlm requests */ int64_t queue; /* Count of gfs2_holder queues */ }; extern int gfs2_worst_glock_fetch(int, struct worst_glock *, pmAtomValue *); extern int gfs2_extract_worst_glock(char *); extern void worst_glock_assign_glocks(pmInDom); extern int worst_glock_get_state(); extern int worst_glock_set_state(pmValueSet *vsp); #endif /* LOCK_TIME_H */ pcp-3.8.12ubuntu1/src/pmdas/gfs2/glocks.c0000664000000000000000000000473212272262501014772 0ustar /* * GFS2 glocks sysfs file statistics. * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "glocks.h" #include int gfs2_glocks_fetch(int item, struct glocks *glocks, pmAtomValue *atom) { /* Check for valid metric count */ if (item < 0 || item >= NUM_GLOCKS_STATS) return PM_ERR_PMID; /* Check for no values recorded */ if(glocks->values[item] == UINT64_MAX) return 0; atom->ull = glocks->values[item]; return 1; } int gfs2_refresh_glocks(const char *sysfs, const char *name, struct glocks *glocks) { char buffer[4096]; FILE *fp; /* Reset all counter for this fs */ memset(glocks, 0, sizeof(*glocks)); snprintf(buffer, sizeof(buffer), "%s/%s/glocks", sysfs, name); buffer[sizeof(buffer)-1] = '\0'; if ((fp = fopen(buffer, "r")) == NULL) { /* * We set the values to UINT64_MAX to signify we have no * current values (no metric support or debugfs not mounted) * */ memset(glocks, -1, sizeof(*glocks)); return -oserror(); } /* * Read through glocks file accumulating statistics as we go; * as an early starting point, we're simply binning aggregate * glock state counts. * */ while (fgets(buffer, sizeof(buffer), fp) != NULL) { char *p = buffer; /* interested in glock lines only for now */ if (strncmp(p, "G:", 2) != 0) continue; for (p += 2; isspace((int)*p); p++) {;} /* pick out the various state fields next */ if (strncmp(p, "s:SH", 4) == 0) glocks->values[GLOCKS_SHARED]++; else if (strncmp(p, "s:UN ", 4) == 0) glocks->values[GLOCKS_UNLOCKED]++; else if (strncmp(p, "s:DF ", 4) == 0) glocks->values[GLOCKS_DEFERRED]++; else if (strncmp(p, "s:EX", 4) == 0) glocks->values[GLOCKS_EXCLUSIVE]++; glocks->values[GLOCKS_TOTAL]++; for (p += 4; isspace((int)*p); p++) {;} /* [ extract any other field stats here ] */ } fclose(fp); return 0; } pcp-3.8.12ubuntu1/src/pmdas/gfs2/pmda.c0000664000000000000000000010161712272262501014431 0ustar /* * Global Filesystem v2 (GFS2) PMDA * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include "pmdagfs2.h" #include #include static char *gfs2_sysfsdir = "/sys/kernel/debug/gfs2"; static char *gfs2_sysdir = "/sys/fs/gfs2"; pmdaIndom indomtable[] = { { .it_indom = GFS_FS_INDOM }, }; #define INDOM(x) (indomtable[x].it_indom) /* * all metrics supported in this PMDA - one table entry for each * */ pmdaMetric metrictable[] = { /* GLOCK */ { .m_desc = { PMDA_PMID(CLUSTER_GLOCKS, GLOCKS_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { .m_desc = { PMDA_PMID(CLUSTER_GLOCKS, GLOCKS_SHARED), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { .m_desc = { PMDA_PMID(CLUSTER_GLOCKS, GLOCKS_UNLOCKED), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { .m_desc = { PMDA_PMID(CLUSTER_GLOCKS, GLOCKS_DEFERRED), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, { .m_desc = { PMDA_PMID(CLUSTER_GLOCKS, GLOCKS_EXCLUSIVE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* SBSTATS */ { .m_desc = { PMDA_PMID(CLUSTER_SBSTATS, LOCKSTAT_SRTT), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,PM_TIME_NSEC,0,0,1,0) } }, { .m_desc = { PMDA_PMID(CLUSTER_SBSTATS, LOCKSTAT_SRTTVAR), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,PM_TIME_NSEC,0,0,1,0) } }, { .m_desc = { PMDA_PMID(CLUSTER_SBSTATS, LOCKSTAT_SRTTB), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,PM_TIME_NSEC,0,0,1,0) }, }, { .m_desc = { PMDA_PMID(CLUSTER_SBSTATS, LOCKSTAT_SRTTVARB), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,PM_TIME_NSEC,0,0,1,0) }, }, { .m_desc = { PMDA_PMID(CLUSTER_SBSTATS, LOCKSTAT_SIRT), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,PM_TIME_NSEC,0,0,1,0) }, }, { .m_desc = { PMDA_PMID(CLUSTER_SBSTATS, LOCKSTAT_SIRTVAR), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,PM_TIME_NSEC,0,0,1,0) }, }, { .m_desc = { PMDA_PMID(CLUSTER_SBSTATS, LOCKSTAT_DCOUNT), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_SBSTATS, LOCKSTAT_QCOUNT), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* GLSTATS */ { .m_desc = { PMDA_PMID(CLUSTER_GLSTATS, GLSTATS_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_GLSTATS, GLSTATS_TRANS), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_GLSTATS, GLSTATS_INODE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_GLSTATS, GLSTATS_RGRP), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_GLSTATS, GLSTATS_META), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_GLSTATS, GLSTATS_IOPEN), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_GLSTATS, GLSTATS_FLOCK), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_GLSTATS, GLSTATS_QUOTA), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_GLSTATS, GLSTATS_JOURNAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* TRACEPOINTS */ { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKSTATE_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKSTATE_NULLLOCK), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKSTATE_CONCURRENTREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKSTATE_CONCURRENTWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKSTATE_PROTECTEDREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKSTATE_PROTECTEDWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKSTATE_EXCLUSIVE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKSTATE_GLOCK_CHANGEDTARGET), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKSTATE_GLOCK_MISSEDTARGET), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKPUT_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKPUT_NULLLOCK), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKPUT_CONCURRENTREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKPUT_CONCURRENTWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKPUT_PROTECTEDREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKPUT_PROTECTEDWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKPUT_EXCLUSIVE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_DEMOTERQ_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_DEMOTERQ_NULLLOCK), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_DEMOTERQ_CONCURRENTREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_DEMOTERQ_CONCURRENTWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_DEMOTERQ_PROTECTEDREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_DEMOTERQ_PROTECTEDWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_DEMOTERQ_EXCLUSIVE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_DEMOTERQ_REQUESTED_REMOTE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_DEMOTERQ_REQUESTED_LOCAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_FIRST_NULLLOCK), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_FIRST_CONCURRENTREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_FIRST_CONCURRENTWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_FIRST_PROTECTEDREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_FIRST_PROTECTEDWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_FIRST_EXCLUSIVE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_OTHER_NULLLOCK), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_OTHER_CONCURRENTREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_OTHER_CONCURRENTWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_OTHER_PROTECTEDREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_OTHER_PROTECTEDWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PROMOTE_OTHER_EXCLUSIVE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_QUEUE_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_QUEUE_NULLLOCK), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_QUEUE_CONCURRENTREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_QUEUE_CONCURRENTWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_QUEUE_PROTECTEDREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_QUEUE_PROTECTEDWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_QUEUE_EXCLUSIVE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_DEQUEUE_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_DEQUEUE_NULLLOCK), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_DEQUEUE_CONCURRENTREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_DEQUEUE_CONCURRENTWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_DEQUEUE_PROTECTEDREAD), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_DEQUEUE_PROTECTEDWRITE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKQUEUE_DEQUEUE_EXCLUSIVE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKLOCKTIME_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKLOCKTIME_TRANS), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKLOCKTIME_INDOE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKLOCKTIME_RGRP), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKLOCKTIME_META), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKLOCKTIME_IOPEN), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKLOCKTIME_FLOCK), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKLOCKTIME_QUOTA), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_GLOCKLOCKTIME_JOURNAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PIN_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PIN_PINTOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PIN_UNPINTOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_PIN_LONGESTPINNED), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_LOGFLUSH_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_LOGBLOCKS_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_AILFLUSH_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_BLOCKALLOC_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_BLOCKALLOC_FREE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_BLOCKALLOC_USED), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_BLOCKALLOC_DINODE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_BLOCKALLOC_UNLINKED), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_BMAP_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_BMAP_CREATE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_BMAP_NOCREATE), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_RS_TOTAL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_RS_DEL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_RS_TDEL), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_RS_INS), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_TRACEPOINTS, FTRACE_RS_CLM), PM_TYPE_U64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* WORST_GLOCKS */ { .m_desc = { PMDA_PMID(CLUSTER_WORSTGLOCK, WORSTGLOCK_LOCK_TYPE), PM_TYPE_U32, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_WORSTGLOCK, WORSTGLOCK_NUMBER), PM_TYPE_U32, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_WORSTGLOCK, WORSTGLOCK_SRTT), PM_TYPE_64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_WORSTGLOCK, WORSTGLOCK_SRTTVAR), PM_TYPE_64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_WORSTGLOCK, WORSTGLOCK_SRTTB), PM_TYPE_64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_WORSTGLOCK, WORSTGLOCK_SRTTVARB), PM_TYPE_64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_WORSTGLOCK, WORSTGLOCK_SIRT), PM_TYPE_64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_WORSTGLOCK, WORSTGLOCK_SIRTVAR), PM_TYPE_64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_WORSTGLOCK, WORSTGLOCK_DLM), PM_TYPE_64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, { .m_desc = { PMDA_PMID(CLUSTER_WORSTGLOCK, WORSTGLOCK_QUEUE), PM_TYPE_64, GFS_FS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* GFS2.CONTROL */ { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_ALL), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_GLOCK_STATE_CHANGE), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_GLOCK_PUT), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_DEMOTE_RQ), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_PROMOTE), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_GLOCK_QUEUE), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_GLOCK_LOCK_TIME), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_PIN), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_LOG_FLUSH), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_LOG_BLOCKS), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_AIL_FLUSH), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_BLOCK_ALLOC), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_BMAP), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_RS), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_GLOBAL_TRACING), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_WORSTGLOCK), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { NULL, { PMDA_PMID(CLUSTER_CONTROL, CONTROL_FTRACE_GLOCK_THRESHOLD), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, }; int metrictable_size(void) { return sizeof(metrictable)/sizeof(metrictable[0]); } static dev_t gfs2_device_identifier(const char *name) { char buffer[4096]; int major, minor; dev_t dev_id; FILE *fp; dev_id = makedev(0, 0); /* Error case */ /* gfs2_glock_lock_time requires block device id for each filesystem * in order to match to the lock data, this info can be found in * /sys/fs/gfs2/NAME/id, we extract the data and store it in gfs2_fs->dev * */ snprintf(buffer, sizeof(buffer), "%s/%s/id", gfs2_sysdir, name); buffer[sizeof(buffer)-1] = '\0'; if ((fp = fopen(buffer, "r")) == NULL) return oserror(); while (fgets(buffer, sizeof(buffer), fp) != NULL) { sscanf(buffer, "%d:%d", &major, &minor); dev_id = makedev(major, minor); } fclose(fp); return dev_id; } /* * Update the GFS2 filesystems instance domain. This will change * as filesystems are mounted and unmounted (and re-mounted, etc). * Using the pmdaCache interfaces simplifies things and provides us * with guarantees around consistent instance numbering in all of * those interesting corner cases. */ static int gfs2_instance_refresh(void) { int i, sts, count, gfs2_status; struct dirent **files; pmInDom indom = INDOM(GFS_FS_INDOM); pmdaCacheOp(indom, PMDA_CACHE_INACTIVE); /* update indom cache based on scan of /sys/fs/gfs2 */ count = scandir(gfs2_sysdir, &files, NULL, NULL); if (count < 0) { /* give some feedback as to GFS2 kernel state */ if (oserror() == EPERM) gfs2_status = PM_ERR_PERMISSION; else if (oserror() == ENOENT) gfs2_status = PM_ERR_AGAIN; /* we might see a mount later */ else gfs2_status = PM_ERR_APPVERSION; } else { gfs2_status = 0; /* we possibly have stats available */ } for (i = 0; i < count; i++) { struct gfs2_fs *fs; const char *name = files[i]->d_name; if (name[0] == '.') continue; sts = pmdaCacheLookupName(indom, name, NULL, (void **)&fs); if (sts == PM_ERR_INST || (sts >= 0 && fs == NULL)){ fs = calloc(1, sizeof(struct gfs2_fs)); if (fs == NULL) return PM_ERR_AGAIN; fs->dev_id = gfs2_device_identifier(name); if ((major(fs->dev_id) == 0) && (minor(fs->dev_id) == 0)) { free(fs); return PM_ERR_AGAIN; } } else if (sts < 0) continue; /* (re)activate this entry for the current query */ pmdaCacheStore(indom, PMDA_CACHE_ADD, name, (void *)fs); } for (i = 0; i < count; i++) free(files[i]); if (count > 0) free(files); return gfs2_status; } static int gfs2_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) { gfs2_instance_refresh(); return pmdaInstance(indom, inst, name, result, pmda); } static int gfs2_fetch_refresh(pmdaExt *pmda, int *need_refresh) { pmInDom indom = INDOM(GFS_FS_INDOM); struct gfs2_fs *fs; char *name; int i, sts; if ((sts = gfs2_instance_refresh()) < 0) return sts; for (pmdaCacheOp(indom, PMDA_CACHE_WALK_REWIND);;) { if ((i = pmdaCacheOp(indom, PMDA_CACHE_WALK_NEXT)) < 0) break; if (!pmdaCacheLookup(indom, i, &name, (void **)&fs) || !fs) continue; if (need_refresh[CLUSTER_GLOCKS]) gfs2_refresh_glocks(gfs2_sysfsdir, name, &fs->glocks); if (need_refresh[CLUSTER_SBSTATS]) gfs2_refresh_sbstats(gfs2_sysfsdir, name, &fs->sbstats); if (need_refresh[CLUSTER_GLSTATS]) gfs2_refresh_glstats(gfs2_sysfsdir, name, &fs->glstats); } if (need_refresh[CLUSTER_TRACEPOINTS] || need_refresh[CLUSTER_WORSTGLOCK]) gfs2_refresh_ftrace_stats(indom); return sts; } static int gfs2_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i, sts, need_refresh[NUM_CLUSTERS] = { 0 }; for (i = 0; i < numpmid; i++) { __pmID_int *idp = (__pmID_int *)&(pmidlist[i]); if (idp->cluster < NUM_CLUSTERS) need_refresh[idp->cluster]++; } if ((sts = gfs2_fetch_refresh(pmda, need_refresh)) < 0) return sts; return pmdaFetch(numpmid, pmidlist, resp, pmda); } /* * callback provided to pmdaFetch */ static int gfs2_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); struct gfs2_fs *fs; int sts; switch (idp->cluster) { case CLUSTER_GLOCKS: sts = pmdaCacheLookup(INDOM(GFS_FS_INDOM), inst, NULL, (void **)&fs); if (sts < 0) return sts; return gfs2_glocks_fetch(idp->item, &fs->glocks, atom); case CLUSTER_SBSTATS: sts = pmdaCacheLookup(INDOM(GFS_FS_INDOM), inst, NULL, (void **)&fs); if (sts < 0) return sts; return gfs2_sbstats_fetch(idp->item, &fs->sbstats, atom); case CLUSTER_GLSTATS: sts = pmdaCacheLookup(INDOM(GFS_FS_INDOM), inst, NULL, (void **)&fs); if (sts < 0) return sts; return gfs2_glstats_fetch(idp->item, &fs->glstats, atom); case CLUSTER_TRACEPOINTS: sts = pmdaCacheLookup(INDOM(GFS_FS_INDOM), inst, NULL, (void **)&fs); if (sts < 0) return sts; return gfs2_ftrace_fetch(idp->item, &fs->ftrace, atom); case CLUSTER_WORSTGLOCK: sts = pmdaCacheLookup(INDOM(GFS_FS_INDOM), inst, NULL, (void**)&fs); if (sts < 0) return sts; return gfs2_worst_glock_fetch(idp->item, &fs->worst_glock, atom); case CLUSTER_CONTROL: return gfs2_control_fetch(idp->item, atom); default: /* unknown cluster */ return PM_ERR_PMID; } return 1; } static int gfs2_store(pmResult *result, pmdaExt *pmda) { int i; int sts = 0; pmValueSet *vsp; __pmID_int *pmidp; for (i = 0; i < result->numpmid && !sts; i++) { vsp = result->vset[i]; pmidp = (__pmID_int *)&vsp->pmid; if (pmidp->cluster == CLUSTER_CONTROL && pmidp->item <= CONTROL_RS) { sts = gfs2_control_set_value(control_locations[pmidp->item], vsp); } if (pmidp->cluster == CLUSTER_CONTROL && pmidp->item == CONTROL_WORSTGLOCK) { sts = worst_glock_set_state(vsp); } if (pmidp->cluster == CLUSTER_CONTROL && pmidp->item == CONTROL_FTRACE_GLOCK_THRESHOLD) { sts = ftrace_set_threshold(vsp); } } return sts; } static int gfs2_text(int ident, int type, char **buf, pmdaExt *pmda) { if ((type & PM_TEXT_PMID) == PM_TEXT_PMID) { int sts = pmdaDynamicLookupText(ident, type, buf, pmda); if (sts != -ENOENT) return sts; } return pmdaText(ident, type, buf, pmda); } static int gfs2_pmid(const char *name, pmID *pmid, pmdaExt *pmda) { __pmnsTree *tree = pmdaDynamicLookupName(pmda, name); return pmdaTreePMID(tree, name, pmid); } static int gfs2_name(pmID pmid, char ***nameset, pmdaExt *pmda) { __pmnsTree *tree = pmdaDynamicLookupPMID(pmda, pmid); return pmdaTreeName(tree, pmid, nameset); } static int gfs2_children(const char *name, int flag, char ***kids, int **sts, pmdaExt *pmda) { __pmnsTree *tree = pmdaDynamicLookupName(pmda, name); return pmdaTreeChildren(tree, name, flag, kids, sts); } /* * Initialise the agent (both daemon and DSO). */ void gfs2_init(pmdaInterface *dp) { int nindoms = sizeof(indomtable)/sizeof(indomtable[0]); int nmetrics = sizeof(metrictable)/sizeof(metrictable[0]); if (dp->status != 0) return; dp->version.four.instance = gfs2_instance; dp->version.four.store = gfs2_store; dp->version.four.fetch = gfs2_fetch; dp->version.four.text = gfs2_text; dp->version.four.pmid = gfs2_pmid; dp->version.four.name = gfs2_name; dp->version.four.children = gfs2_children; pmdaSetFetchCallBack(dp, gfs2_fetchCallBack); gfs2_sbstats_init(metrictable, nmetrics); pmdaSetFlags(dp, PMDA_EXT_FLAG_HASHED); pmdaInit(dp, indomtable, nindoms, metrictable, nmetrics); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int sep = __pmPathSeparator(); int err = 0; pmdaInterface dispatch; char helppath[MAXPATHLEN]; __pmSetProgname(argv[0]); snprintf(helppath, sizeof(helppath), "%s%c" "gfs2" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_4, pmProgname, GFS2, "gfs2.log", helppath); if (pmdaGetOpt(argc, argv, "D:d:l:?", &dispatch, &err) != EOF) err++; if (err) usage(); pmdaOpenLog(&dispatch); gfs2_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/gfs2/worst_glock.c0000664000000000000000000001772512272262501016053 0ustar /* * GFS2 gfs2_glock_lock_time trace-point metrics. * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "pmdagfs2.h" #include "ftrace.h" #include "worst_glock.h" #include #include #include #include static struct worst_glock *glock_data; static int capacity, num_accepted_entries; static int worst_glock_state = DEFAULT_WORST_GLOCK_STATE; /* * Sets the value of max_glock_state using pmstore, value * must be 0 or 1. */ int worst_glock_set_state(pmValueSet *vsp) { int value = vsp->vlist[0].value.lval; if (value == 0 || value == 1) { worst_glock_state = value; return 0; } else { return PM_ERR_SIGN; } } /* * Used to see whether the worst_glock metrics are enabled or disabled. Should * only return either 0 or 1. */ int worst_glock_get_state() { return worst_glock_state; } /* * Refreshing of the metrics for gfs2.lock_time, some of metrics are of * a different typing. */ int gfs2_worst_glock_fetch(int item, struct worst_glock *worst_glock, pmAtomValue *atom) { /* Check if tracepoint is enabled */ if (worst_glock_get_state() == 0) return 0; /* Check to see if we have values to assign */ if (worst_glock->lock_type == LOCKTIME_INODE || worst_glock->lock_type == LOCKTIME_RGRP){ switch(item){ case WORSTGLOCK_LOCK_TYPE: atom->ul = worst_glock->lock_type; /* Glock type number */ break; case WORSTGLOCK_NUMBER: atom->ull = worst_glock->number; /* Inode or resource group number */ break; case WORSTGLOCK_SRTT: atom->ll = worst_glock->srtt; /* Non blocking smoothed round trip time */ break; case WORSTGLOCK_SRTTVAR: atom->ll = worst_glock->srttvar; /* Non blocking smoothed variance */ break; case WORSTGLOCK_SRTTB: atom->ll = worst_glock->srttb; /* Blocking smoothed round trip time */ break; case WORSTGLOCK_SRTTVARB: atom->ll = worst_glock->srttvarb; /* Blocking smoothed variance */ break; case WORSTGLOCK_SIRT: atom->ll = worst_glock->sirt; /* Smoothed Inter-request time */ break; case WORSTGLOCK_SIRTVAR: atom->ll = worst_glock->sirtvar; /* Smoothed Inter-request variance */ break; case WORSTGLOCK_DLM: atom->ll = worst_glock->dlm; /* Count of dlm requests */ break; case WORSTGLOCK_QUEUE: atom->ll = worst_glock->queue; /* Count of gfs2_holder queues */ break; default: return PM_ERR_PMID; } return 1; /* Return we have had values */ } else { return 0; /* If we have no valid values */ } } /* * We work out the individual metric values from our buffer input and store * them for processing after all of the values have been extracted from the * trace pipe. */ int gfs2_extract_worst_glock(char *buffer) { struct worst_glock glock; unsigned int major, minor; fprintf(stderr, "VALUES TO HAVE A LOOK AT NAE = %d, CAP = %d \n", num_accepted_entries, capacity); /* If we havent already set the array, have a go */ if (glock_data == NULL) { num_accepted_entries = 0; capacity = FTRACE_ARRAY_CAPACITY; fprintf(stderr, "HERE WE APPEAR TO BE PEOPLE \n"); glock_data = malloc(capacity * sizeof(struct worst_glock)); if (glock_data == NULL) { /* If we fail, return */ return -oserror(); } } /* Assign data */ sscanf(buffer, "gfs2_glock_lock_time: %"SCNu32",%"SCNu32" glock %"SCNu32":%"SCNu64" status:%*d flags:%*x tdiff:%*d srtt:%"SCNd64"/%"SCNd64" srttb:%"SCNd64"/%"SCNd64" sirt:%"SCNd64"/%"SCNd64" dcnt:%"SCNd64" qcnt:%"SCNd64, &major, &minor, &glock.lock_type, &glock.number, &glock.srtt, &glock.srttvar, &glock.srttb, &glock.srttvarb, &glock.sirt, &glock.sirtvar, &glock.dlm, &glock.queue ); glock.dev_id = makedev(major, minor); /* Filter on required lock types */ if ((glock.lock_type == LOCKTIME_INODE || glock.lock_type == LOCKTIME_RGRP) && (glock.dlm > COUNT_THRESHOLD || glock.queue > COUNT_THRESHOLD)) { /* Re-allocate and extend array if we are near capacity */ if (num_accepted_entries == capacity) { struct worst_glock *glock_data_realloc = realloc(glock_data, (capacity + FTRACE_ARRAY_CAPACITY) * sizeof(struct worst_glock)); if (glock_data_realloc == NULL) { free(glock_data); glock_data = NULL; return -oserror(); } else { glock_data = glock_data_realloc; glock_data_realloc = NULL; capacity += FTRACE_ARRAY_CAPACITY; } } /* Assign and increase counters */ glock_data[num_accepted_entries] = glock; num_accepted_entries++; ftrace_increase_num_accepted_entries(); /* Increase the global counter aswell */ } return 0; } /* * Comparison function we compare the values; we return the lock which * is deemed to be the worst. */ static int lock_comparison(const void *a, const void *b) { struct worst_glock *aa = (struct worst_glock *)a; struct worst_glock *bb = (struct worst_glock *)b; int true_count = 0; /* (A sirt (LESS THAN) B sirt = A worse) */ if (aa->sirtvar < bb->sirtvar) true_count++; /* A srtt (MORE THAN) B srtt = A worse */ if (aa->srttvarb > bb->srttvarb) true_count++; /* A srttb (MORE THAN) B srttb = A worse */ if (aa->srttvar > bb->srttvar) true_count++; /* If there are more counts where A is worse than B? */ if ( true_count > 1 ) { return 1; /* a is worse than b */ } else if ( true_count == 1 ){ /* Tie break condition */ if ( aa->dlm > bb->queue ) return 1; /* a is worse than b */ } return -1; /* b is worse than a */ } /* * We loop through each of our available file-sytems, find the locks that corr- * esspond to the filesystem. With these locks we find the worst and assign it * to the filesystem before returning the metric values. */ void worst_glock_assign_glocks(pmInDom gfs2_fs_indom) { int i, j, sts; struct gfs2_fs *fs; /* Sort our values with our comparator */ qsort(glock_data, num_accepted_entries, sizeof(struct worst_glock), lock_comparison); /* We walk through for each filesystem */ for (pmdaCacheOp(gfs2_fs_indom, PMDA_CACHE_WALK_REWIND);;) { if ((i = pmdaCacheOp(gfs2_fs_indom, PMDA_CACHE_WALK_NEXT)) < 0) break; sts = pmdaCacheLookup(gfs2_fs_indom, i, NULL, (void **)&fs); if (sts != PMDA_CACHE_ACTIVE) continue; /* Reset old metric data */ memset(&fs->worst_glock, 0, sizeof(struct worst_glock)); /* Assign our worst glock */ for (j = 0; j < num_accepted_entries; j++) { if (fs->dev_id != glock_data[j].dev_id) continue; fs->worst_glock = glock_data[j]; break; } } /* Free memory */ free(glock_data); glock_data = NULL; capacity = FTRACE_ARRAY_CAPACITY; num_accepted_entries = 0; } pcp-3.8.12ubuntu1/src/pmdas/gfs2/pmdagfs2.h0000664000000000000000000000316612272262501015220 0ustar /* * Global Filesystem v2 (GFS2) PMDA * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef PMDAGFS2_H #define PMDAGFS2_H #include "glocks.h" #include "sbstats.h" #include "glstats.h" #include "worst_glock.h" #include "ftrace.h" #include "control.h" enum { CLUSTER_GLOCKS = 0, /* 0 - /sys/kernel/debug/gfs2//glocks */ CLUSTER_SBSTATS, /* 1 - /sys/kernel/debug/gfs2//sbstats */ CLUSTER_GLSTATS, /* 2 - /sys/kernel/debug/gfs2//glstats */ CLUSTER_TRACEPOINTS, /* 3 - /sys/kernel/debug/tracing/events/gfs2/ */ CLUSTER_WORSTGLOCK, /* 4 - Custom metric for worst glock */ CLUSTER_CONTROL, /* 5 - Control for specific tracepoint enabling (for installs without all of the GFS2 tracepoints) */ NUM_CLUSTERS }; enum { GFS_FS_INDOM = 0, /* 0 -- mounted gfs filesystem names */ NUM_INDOMS }; struct gfs2_fs { dev_t dev_id; struct glocks glocks; struct sbstats sbstats; struct glstats glstats; struct ftrace ftrace; struct worst_glock worst_glock; }; extern pmdaMetric metrictable[]; extern int metrictable_size(); #endif /*PMDAGFS2_H*/ pcp-3.8.12ubuntu1/src/pmdas/gfs2/glstats.h0000664000000000000000000000310212272262501015164 0ustar /* * GFS2 glstats file statistics. * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef GLSTATS_H #define GLSTATS_H /* * GFS2 glock type identification; note that the glock type 7 is currently not * used and is reserved to be on the safe side. * * Type Lock type Use * 1 Trans Transaction lock * 2 Inode Inode metadata and data * 3 Rgrp Resource group metadata * 4 Meta The superblock * 5 Iopen Inode last closer detection * 6 Flock flock(2) syscall * 8 Quota Quota operations * 9 Journal Journal mutex * */ enum { GLSTATS_TOTAL = 0, GLSTATS_TRANS = 1, GLSTATS_INODE = 2, GLSTATS_RGRP = 3, GLSTATS_META = 4, GLSTATS_IOPEN = 5, GLSTATS_FLOCK = 6, GLSTATS_RESERVED_NOT_USED = 7, GLSTATS_QUOTA = 8, GLSTATS_JOURNAL = 9, NUM_GLSTATS_STATS }; struct glstats { __uint64_t values[NUM_GLSTATS_STATS]; }; extern int gfs2_glstats_fetch(int, struct glstats *, pmAtomValue *); extern int gfs2_refresh_glstats(const char *, const char *, struct glstats *); #endif /* GLSTATS_H */ pcp-3.8.12ubuntu1/src/pmdas/gfs2/help0000664000000000000000000005660112272262501014221 0ustar # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # GFS2 PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ GFS2.0 Instance domain for mounted GFS2 filesystems @ gfs2.glocks.total Count of total observed incore GFS2 global locks Count of total incore GFS2 glock data structures based on parsing the contents of the /sys/kernel/debug/gfs2//glocks files. @ gfs2.glocks.shared GFS2 global locks in shared state Count of incore GFS2 glock data structures in shared state, based on parsing /sys/kernel/debug/gfs2//glocks entries with state field (s:) value "SH". @ gfs2.glocks.unlocked GFS2 global locks in unlocked state Count of incore GFS2 glock data structures in unlocked state, based on parsing /sys/kernel/debug/gfs2//glocks entries with state field (s:) value "UN". @ gfs2.glocks.deferred GFS2 global locks in deferred state Count of incore GFS2 glock data structures in deferred state, based on parsing /sys/kernel/debug/gfs2//glocks entries with state field (s:) value "DF". @ gfs2.glocks.exclusive GFS2 global locks in exclusive state Count of incore GFS2 glock data structures in exclusive state, based on parsing /sys/kernel/debug/gfs2//glocks entries with state field (s:) value "EX". # help text for gfs2.sbstats.*.* is generated dynamically @ gfs2.glstats.total The total number of current glocks Total count of the number of glocks which currently reside for filesystem on the given node. Data is based from /sys/kernel/debug/gfs2//glstats counting the total number of glock entries. @ gfs2.glstats.trans The number of transaction glocks The count of the current number of transaction type glocks that currently exist for the given filesystem. The data is recorded and counted from /sys/kernel/ debug/gfs2/glstats file entries for this type of glock. @ gfs2.glstats.inode The number of inode (metadata and data) glocks The count of the current number of inode metadata and data type glocks that currently exist for the given filesystem. The data is recorded and counted from /sys/kernel/debug/gfs2/glstats file entries for this type of glock. @ gfs2.glstats.rgrp The number of resource group metadata glocks The count of the current number of resource group metadata type glocks that currently exist for the given filesystem. The data is recorded and counted from /sys/kernel/debug/gfs2/glstats file entries for this type of glock. @ gfs2.glstats.meta The number of superblock glocks The count of the current number of superblock type glocks that currently exist for the given filesystem. The data is recorded and counted from /sys/kernel/ debug/gfs2/glstats file entries for this type of glock. @ gfs2.glstats.iopen The number of inode last closer detection glocks The count of the current number of inode last closer detection type glocks that currently exist for the given filesystem. The data is recorded and counted from /sys/kernel/debug/gfs2/glstats file entries for this type of glock. @ gfs2.glstats.flock The number of flock(2) syscall glocks The count of the current number of flock(2) syscall type glocks that currently exist for the given filesystem. The data is recorded and counted from /sys/ kernel/debug/gfs2/glstats file entries for this type of glock. @ gfs2.glstats.quota The number of quota operations glocks The count of the current number of quota operations type glocks that currently exist for the given filesystem. The data is recorded and counted from /sys/ kernel/debug/gfs2/glstats file entries for this type of glock. @ gfs2.glstats.journal The number of journal mutex glocks The count of the current number of journal mutex type glocks that currently exist for the given filesystem. The data is recorded and counted from /sys/ kernel/debug/gfs2/glstats file entries for this type of glock. @ gfs2.tracepoints.glock_state_change.total Total number of glock state changes. The total number of counted glock state changes. @ gfs2.tracepoints.glock_state_change.null_lock Number of null_lock state changes. The total number of glock state changes to the null_lock state. @ gfs2.tracepoints.glock_state_change.concurrent_read Number of concurrent_read state changes. The total number of glock state changes to current_read state. @ gfs2.tracepoints.glock_state_change.concurrent_write Number of concurrent_write state changes. The total number of glock state changes to current_write state. @ gfs2.tracepoints.glock_state_change.protected_read Number of protected_read state changes. The total number of glock state changes to protected_read state. @ gfs2.tracepoints.glock_state_change.protected_write Number of protected_write state changes. The total number of glock state changes to protected_write state. @ gfs2.tracepoints.glock_state_change.exclusive Number of exclusive state changes. The total number of glock state changes to exclusive state. @ gfs2.tracepoints.glock_state_change.glocks.changed_target Number of changed locks. The number of state changes that achieved their expected state change. @ gfs2.tracepoints.glock_state_change.glocks.missed_target Number of missed locks. The number of state changes that did not achieve their expected state change. @ gfs2.tracepoints.glock_put.total Total number of glocks changed. The total number of glocks that have been changed. @ gfs2.tracepoints.glock_put.null_lock Number of released locks. The number of glocks put into the null_lock state. @ gfs2.tracepoints.glock_put.concurrent_read Number of glocks put in concurrent_read. The number of glocks put into the concurrent_read state. @ gfs2.tracepoints.glock_put.concurrent_write Number of glocks put in concurrent_write. The number of glocks put into the concurrent_write state. @ gfs2.tracepoints.glock_put.protected_read Number of glocks put in protected_read. The number of glocks put into the protected_read state. @ gfs2.tracepoints.glock_put.protected_write Number of glocks put in protected_wirte. The number of glocks put into the protected_write state. @ gfs2.tracepoints.glock_put.exclusive Number of glocks put in exclusive. The number of glocks put into the exclusive state. @ gfs2.tracepoints.demote_rq.total Total number of lock demote requests. The total number of lock demotion requests. @ gfs2.tracepoints.demote_rq.null_lock Number of lock demote requests to null_lock. The total number of lock demotion requests to the null_lock state. @ gfs2.tracepoints.demote_rq.concurrent_read Number of lock demote requests to concurrent_read. The total number of lock demotion requests to the concurrent_read state. @ gfs2.tracepoints.demote_rq.concurrent_write Number of lock demote requests to concurrent_write. The total number of lock demotion requests to the concurrent_write state. @ gfs2.tracepoints.demote_rq.protected_read Number of lock demote requests to protected_read. The total number of lock demotion requests to the protected_read state. @ gfs2.tracepoints.demote_rq.protected_write Number of lock demote requests to protected_write. The total number of lock demotion requests to the protected_write state. @ gfs2.tracepoints.demote_rq.exclusive Number of lock demote requests to exclusive. The total number of lock demotion requests to the exclusive state. @gfs2.tracepoints.demote_rq.requested.remote Number of demote requests (remote). The total number of demote requests which were requested by a remote node of the cluster. @gfs2.tracepoints.demote_rq.requested.local Number of demote requests (local). The total number od demote requests which were requested by a local node of the cluster @ gfs2.tracepoints.promote.total Total number of lock grants. The total number of lock grants. @ gfs2.tracepoints.promote.first.null_lock Number of lock grants to null_lock. The total number of successful first time lock grants to the null_lock state. @ gfs2.tracepoints.promote.first.concurrent_read Number of lock grants to concurrent_read. The total number of successful first time lock grants to the concurrent_read state. @ gfs2.tracepoints.promote.first.concurrent_write Number of lock grants to concurrent_write. The total number of successful first time lock grants to the concurrent_write state. @ gfs2.tracepoints.promote.first.protected_read Number of lock grants to protected_read. The total number of successful first time lock grants to the protected_read state. @ gfs2.tracepoints.promote.first.protected_write Number of lock grants to protected_write. The total number of successful first time lock grants to the protected_write state. @ gfs2.tracepoints.promote.first.exclusive Number of lock grants to exclusive. The total number of successful first time lock grants to the exclusive state. @gfs2.tracepoints.promote.other.null_lock Number of lock grants to null_lock. The total number of successful other time lock grants to the null_lock state. @gfs2.tracepoints.promote.other.concurrent_read Number of lock grants to concurrent_read. The total number of successful other time lock grants to the concurrent_read state. @gfs2.tracepoints.promote.other.concurrent_write Number of lock grants to concurrent_write. The total number of successful other time lock grants to the concurrent_write state. @gfs2.tracepoints.promote.other.protected_read Number of lock grants to protected_read. The total number of successful other time lock grants to the protected_read state. @gfs2.tracepoints.promote.other.protected_write Number of lock grants to protected_write. The total number of successful other time lock grants to the protected_write state. @gfs2.tracepoints.promote.other.exclusive Number of lock grants to exclusive. The total number of successful other time lock grants to the exclusive state. @gfs2.tracepoints.glock_queue.total Total numbe rof queued and dequeued requests. The total number of both queued and dequeued requests. @ gfs2.tracepoints.glock_queue.queue.total Total number of queued lock requests. The total number of queued lock requests. @ gfs2.tracepoints.glock_queue.queue.null_lock Number of null_lock requests. The number of lock requests to the null_lock state. @ gfs2.tracepoints.glock_queue.queue.concurrent_read Number of concurrent_read requests. The number of lock requests to the concurrent_read state. @ gfs2.tracepoints.glock_queue.queue.concurrent_write Number of concurrent_write requests. The number of lock requests to the concurrent_write state. @ gfs2.tracepoints.glock_queue.queue.protected_read Number of protected_read requests. The number of lock requests to the protected_read state. @ gfs2.tracepoints.glock_queue.queue.protected_write Number of protected_write requests. The number of lock requests to the protected_write state. @ gfs2.tracepoints.glock_queue.queue.exclusive Number of exclusive requests. The number of lock requests to the exclusive state. @ gfs2.tracepoints.glock_queue.dequeue.total Total number of dequeued lock requests. The total number of dequeued lock requests. @ gfs2.tracepoints.glock_queue.dequeue.null_lock Number of null_lock requests. The number of lock requests to the null_lock state. @ gfs2.tracepoints.glock_queue.dequeue.concurrent_read Number of concurrent_read requests. The number of lock requests to the concurrent_read state. @ gfs2.tracepoints.glock_queue.dequeue.concurrent_write Number of concurrent_write requests. The number of lock requests to the concurrent_write state. @ gfs2.tracepoints.glock_queue.dequeue.protected_read Number of protected_read requests. The number of lock requests to the protected_read state. @ gfs2.tracepoints.glock_queue.dequeue.protected_write Number of protected_write requests. The number of lock requests to the protected_write state. @ gfs2.tracepoints.glock_queue.dequeue.exclusive Number of exclusive requests. The number of lock requests to the exclusive state. @ gfs2.tracepoints.glock_lock_time.total Total number of lock updates. The total number of lock updates. @ gfs2.tracepoints.glock_lock_time.trans Number of trasaction lock updates. The number of updates for transaction based glocks. @ gfs2.tracepoints.glock_lock_time.inode Number of inode lock updates. The number of updates for inode based glocks. @ gfs2.tracepoints.glock_lock_time.rgrp Number of resource group lock updates. The number of updates for resource group based glocks. @ gfs2.tracepoints.glock_lock_time.meta Number of metadata lock updates. The number of updates for metadata based glocks. @ gfs2.tracepoints.glock_lock_time.iopen Number of iopen lock updates. The number of updates for iopen based glocks. @ gfs2.tracepoints.glock_lock_time.flock Number of flock lock updates. The number of updates for flock based glocks. @ gfs2.tracepoints.glock_lock_time.quota Number of quota lock updates. The number of updates for quota based glocks. @ gfs2.tracepoints.glock_lock_time.journal Number of journal lock updates. The number of updates for journal based glocks. @ gfs2.tracepoints.pin.total Total number of Pin/Unpin requests. The total number of requests to pin/unpin blocks on the log. @ gfs2.tracepoints.pin.pin_total Number of pin requests. The total number of requests to pin blocks on the log. @ gfs2.tracepoints.pin.unpin_total Number of unpin requests. The total number requests to unpin blocks on the log. @ gfs2.tracepoints.pin.longest_pinned Longests pinned. The longest pinned inode or resource group log block @ gfs2.tracepoints.log_flush.total Total log flushes. The total number of log flushes observed @ gfs2.tracepoints.log_block.total Total log blocks. The total number of blocks placed upon the log. @ gfs2.tracepoints.ail_flush.total Total AIL flushes. The total number of flushes back to the AIL. @ gfs2.tracepoints.block_alloc.total Total blocks allocated/deallocated. The total number of allocated/freed blocks this call. @ gfs2.tracepoints.block_alloc.free Freed blocks. The number of blocks freed. @ gfs2.tracepoints.block_alloc.used Used blocks. The number of blocks used. @ gfs2.tracepoints.block_alloc.dinode Dinode blocks. The number of blocks used for dinode. @ gfs2.tracepoints.block_alloc.unlinked Unlinked blocks. The number of unlinked blocks. @ gfs2.tracepoints.bmap.total Total number of bmap allocations. The total number of bmap allocations. @ gfs2.tracepoints.bmap.create Number of create bmap allocations. The number of create bmap allocations. @ gfs2.tracepoints.bmap.nocreate Number of nocreate bmap allocations. The number of nocreate bmap allocations. @ gfs2.tracepoints.rs.total Total multi-block allocations. The total number of multiblock allocations. @ gfs2.tracepoints.rs.del Number of del blocks. The number of del blocks @ gfs2.tracepoints.rs.tdel Number of tdel blocks. The number of tdel blocks. @ gfs2.tracepoints.rs.ins Number of ins blocks. The number of ins blocks. @ gfs2.tracepoints.rs.clm Number of clm blocks. The number of clm blocks. @ gfs2.worst_glock.lock_type Glock type number The metric contains the value regarding the lock type representing the type of lock, this metric requires the gfs2.control.glock_lock_time metric to be set as 1 to be enabled. @ gfs2.worst_glock.number Inode or resource group number This metric points to the inode or resource group on which the glock belongs to, this metric requires the gfs2.control.glock_lock_time metric to be set as 1 to be enabled. @ gfs2.worst_glock.srtt Non-blocking smoothed round trip time The smoothed round trip time for non-blocking dlm requests, this metric requires the gfs2.control.glock_lock_time metric to be set as 1 to be enabled. @ gfs2.worst_glock.srttvar Non-blocking smoothed variance Variance estimate for the smoothed round trip time, this metric requires the gfs2.control.glock_lock_time metric to be set as 1 to be enabled. @ gfs2.worst_glock.srttb Blocking smoothed round trip time Smoothed round trip time for (potentially) blocking dlm requests, this metric requires the gfs2.control.glock_lock_time metric to be set as 1 to be enabled. @ gfs2.worst_glock.srttvarb Blocking smoothed variance Variance estimate for smoothed round trip time for (potentially) blocking dlm requests, this metric requires the gfs2.control.glock_lock_time metric to be set as 1 to be enabled. @ gfs2.worst_glock.sirt Smoothed Inter-request time The smoothed inter-request time (for dlm requests), this metric requires the gfs2.control.glock_lock_time metric to be set as 1 to be enabled. @ gfs2.worst_glock.sirtvar Smoothed Inter-request variance Variance estimate for smoothed inter-request time, this metric requires the gfs2.control.glock_lock_time metric to be set as 1 to be enabled. @ gfs2.worst_glock.dlm Count of dlm requests The number of dlm requests made, this metric requires the gfs2.control.glock_lock_time metric to be set as 1 to be enabled. @ gfs2.worst_glock.queue Count of gfs2_holder queues The number of glock requests queued, this metric requires the gfs2.control.glock_lock_time metrics to be set as 1 to be enabled. @ gfs2.control.tracepoints.all Indication whether all glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.all 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.glock_state_change Indication whether the glock_state_change glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.glock_state_change 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.glock_put Indication whether the glock_put glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.glock_put 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.demote_rq Indication whether the glock_demote_rq glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.glock_demote_rq 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.promote Indication whether the glock_promote glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.glock_promte 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.glock_queue Indication whether the glock_queue glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.glock_queue 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.glock_lock_time Indication whether the glock_lock_time glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.glock_lock_time 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.pin Indication whether the pin glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.pin 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.log_flush Indication whether the log_flush glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.log_flush 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.log_blocks Indication whether the log_blocks glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.log_blocks 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.ail_flush Indication whether the ail_flush glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.ail_flush 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.block_alloc Indication whether the block_alloc glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.block_alloc 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.bmap Indication whether the bmap glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.bmap 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.tracepoints.rs Indication whether the rs glock statistics are enabled The gfs2 tracepoint statistics can be manually controlled using pmstore gfs2.control.tracepoints.rs 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect from tracepoint metrics or not. @ gfs2.control.global_tracing Indication whether global tracing for the system is enalbed. The global tracing can be controlled using pmstore gfs2.control.global_tracing 0 [off] or 1 [on]. This is required to be on for most of the gfs2 metrics to function. @ gfs2.control.worst_glock Indication whether gfs2.glock_lock_time statistics are enabled The gfs2.glock_lock_time statistics can be manually controlled using pmstore gfs2.control.glock_lock_time 0 [off] or 1 [on]. setting the value of the metric controls the behavior of the PMDA to whether it tries to collect the lock_time metrics or not. The machine must have the gfs2 trace-points available for the glock_lock_time based metrics to function. @ gfs2.control.glock_threshold Threshold for maximum number of glocks accepted per fetch The number of glocks that will be processed and accepted over all ftrace read trace statistics. This number can be manually altered using pmstore in order to tailor the number of glocks processed. This value must be positive. pcp-3.8.12ubuntu1/src/pmdas/pdns/0000775000000000000000000000000012272262620013443 5ustar pcp-3.8.12ubuntu1/src/pmdas/pdns/Remove0000664000000000000000000000126612272262501014626 0ustar #! /bin/sh # # Copyright (c) 2009 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the pdns PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=pdns pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/pdns/Install0000664000000000000000000000135312272262501014774 0ustar #! /bin/sh # # Copyright (c) 2009 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the pdns PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=pdns perl_opt=true daemon_opt=false forced_restart=true pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/pdns/GNUmakefile0000664000000000000000000000235712272262501015522 0ustar #!gmake # # Copyright (c) 2009 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = pdns PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/pdns/pmdapdns.pl0000664000000000000000000004334112272262501015611 0ustar # # Copyright (c) 2009-2011 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; use Time::HiRes qw ( time ); use vars qw( $pmda ); my $pdns_control = 'pdns_control'; my $rec_control = 'rec_control'; my $pdns_disable = 0; my $rec_disable = 0; my $cached = 0; my %vals = (); my %vals_rec_answers = (); sub pdns_fetch { my $now = time; if ($now - $cached > 1.0) { # $pmda->log("pdns_fetch_callback update now:$now cached:$cached\n"); %vals = (); %vals_rec_answers = (); # get the authorative server stats if ($pdns_disable == 0 && open(PIPE, "$pdns_control list |")) { $_ = ; close PIPE; $_ =~ s/-/_/g; $_ =~ s/,$//; for my $kv (split(/,/, $_)) { if ("$kv" eq '') { last; } my ($k, $v) = split(/=/, $kv); $vals{$k} = $v; } } else { $pdns_disable = 1; } # get the recursive server stats if ($rec_disable == 0 && open(PIPE, "$rec_control get-all |")) { while($_ = ) { $_ =~ s/-/_/g; my ($k, $v) = split(/\t/, $_); if ($k eq 'answers0_1') { $vals_rec_answers{0} = $v; } elsif ($k eq 'answers1_10') { $vals_rec_answers{1} = $v; } elsif ($k eq 'answers10_100') { $vals_rec_answers{2} = $v; } elsif ($k eq 'answers100_1000') { $vals_rec_answers{3} = $v; } elsif ($k eq 'answers_slow') { $vals_rec_answers{4} = $v; } else { $vals{"recursor.$k"} = $v; } } close PIPE; } else { $rec_disable = 1; } $cached = $now; } } sub pdns_fetch_callback { my ($cluster, $item, $inst) = @_; my $metric_name = pmda_pmid_name($cluster, $item); # $pmda->log("pdns_fetch_callback $metric_name $cluster:$item ($inst)\n"); if (!defined($metric_name)) { return (PM_ERR_PMID, 0); } $metric_name =~ s/^pdns\.//; if ($metric_name eq 'recursor.answers') { if ($inst == PM_IN_NULL) { return (PM_ERR_INST, 0); } return ($vals_rec_answers{$inst}, 1) if (defined($vals_rec_answers{$inst})); } else { if ($inst != PM_IN_NULL) { return (PM_ERR_INST, 0); } return ($vals{$metric_name}, 1) if (defined($vals{$metric_name})); } return (PM_ERR_APPVERSION, 0); } $pmda = PCP::PMDA->new('pdns', 101); $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.corrupt_packets", '', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.deferred_cache_inserts", '', ''); $pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.deferred_cache_lookup", '', ''); $pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_USEC,0), "pdns.latency", '', ''); $pmda->add_metric(pmda_pmid(0,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.packetcache_hit", '', ''); $pmda->add_metric(pmda_pmid(0,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.packetcache_miss", '', ''); $pmda->add_metric(pmda_pmid(0,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "pdns.packetcache_size", '', ''); $pmda->add_metric(pmda_pmid(0,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "pdns.qsize_q", '', ''); $pmda->add_metric(pmda_pmid(0,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.query_cache_hit", '', ''); $pmda->add_metric(pmda_pmid(0,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.query_cache_miss", '', ''); $pmda->add_metric(pmda_pmid(0,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursing_answers", '', ''); $pmda->add_metric(pmda_pmid(0,11), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursing_questions", '', ''); $pmda->add_metric(pmda_pmid(0,12), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.servfail_packets", '', ''); $pmda->add_metric(pmda_pmid(0,13), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.tcp_answers", '', ''); $pmda->add_metric(pmda_pmid(0,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.tcp_queries", '', ''); $pmda->add_metric(pmda_pmid(0,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.timedout_packets", '', ''); $pmda->add_metric(pmda_pmid(0,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.udp_answers", '', ''); $pmda->add_metric(pmda_pmid(0,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.udp_queries", '', ''); $pmda->add_metric(pmda_pmid(0,18), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.udp4_answers", '', ''); $pmda->add_metric(pmda_pmid(0,19), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.udp4_queries", '', ''); $pmda->add_metric(pmda_pmid(0,20), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.udp6_answers", '', ''); $pmda->add_metric(pmda_pmid(0,21), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.udp6_queries", '', ''); my $recursor_answers_indom = 1; my @recursor_answers_dom = ( 0 => '0-1 ms', 1 => '1-10 ms', 2 => '10-100 ms', 3 => '100-1000 ms', 4 => '1000+ ms', ); $pmda->add_metric(pmda_pmid(1,0),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.all_outqueries", 'counts the number of outgoing UDP queries since starting', ''); $pmda->add_metric(pmda_pmid(1,1),PM_TYPE_U64, $recursor_answers_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.answers", 'counts the number of queries answered within X miliseconds', ''); $pmda->add_metric(pmda_pmid(1,2),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "pdns.recursor.cache_entries", 'the number of entries in the cache', ''); $pmda->add_metric(pmda_pmid(1,3),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.cache_hits", 'counts the number of cache hits since starting', ''); $pmda->add_metric(pmda_pmid(1,4),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.cache_misses", 'counts the number of cache misses since starting', ''); $pmda->add_metric(pmda_pmid(1,5),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "pdns.recursor.chain_resends", 'number of queries chained to existing outstanding query', ''); $pmda->add_metric(pmda_pmid(1,6),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.client_parse_errors", 'counts number of client packets that could not be parsed', ''); $pmda->add_metric(pmda_pmid(1,7),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "pdns.recursor.concurrent_queries", 'shows the number of MThreads currently running', ''); $pmda->add_metric(pmda_pmid(1,8),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.dlg_only_drops", 'number of records dropped because of delegation only setting', ''); $pmda->add_metric(pmda_pmid(1,9),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.dont_outqueries", 'number of outgoing queries dropped because of "dont-query" setting', ''); $pmda->add_metric(pmda_pmid(1,10),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.ipv6_outqueries", 'number of outgoing queries over IPv6', ''); $pmda->add_metric(pmda_pmid(1,11),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "pdns.recursor.negcache_entries", 'shows the number of entries in the Negative answer cache', ''); $pmda->add_metric(pmda_pmid(1,12),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.noerror_answers", 'counts the number of times it answered NOERROR since starting', ''); $pmda->add_metric(pmda_pmid(1,13),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "pdns.recursor.nsspeeds_entries", 'shows the number of entries in the NS speeds map', ''); $pmda->add_metric(pmda_pmid(1,14),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.nsset_invalidations", 'number of times an nsset was dropped because it no longer worked', ''); $pmda->add_metric(pmda_pmid(1,15),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.nxdomain_answers", 'counts the number of times it answered NXDOMAIN since starting', ''); $pmda->add_metric(pmda_pmid(1,16),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.outgoing_timeouts", 'counts the number of timeouts on outgoing UDP queries since starting', ''); $pmda->add_metric(pmda_pmid(1,17),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.over_capacity_drops", 'Questions dropped because over maximum concurrent query limit', ''); $pmda->add_metric(pmda_pmid(1,18),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "pdns.recursor.packetcache_entries", 'Size of packet cache', ''); $pmda->add_metric(pmda_pmid(1,19),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.packetcache_hits", 'Packet cache hits', ''); $pmda->add_metric(pmda_pmid(1,20),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.packetcache_misses", 'Packet cache misses', ''); $pmda->add_metric(pmda_pmid(1,21),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_USEC,0), "pdns.recursor.qa_latency", 'shows the current latency average, in microseconds', ''); $pmda->add_metric(pmda_pmid(1,22),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.questions", 'counts all End-user initiated queries with the RD bit set', ''); $pmda->add_metric(pmda_pmid(1,23),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.resource_limits", 'counts number of queries that could not be performed because of resource limits', ''); $pmda->add_metric(pmda_pmid(1,24),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.server_parse_errors", 'counts number of server replied packets that could not be parsed', ''); $pmda->add_metric(pmda_pmid(1,25),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.servfail_answers", 'counts the number of times it answered SERVFAIL since starting', ''); $pmda->add_metric(pmda_pmid(1,26),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.spoof_prevents", 'number of times PowerDNS considered itself spoofed, and dropped the data', ''); $pmda->add_metric(pmda_pmid(1,27),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), "pdns.recursor.sys_msec", 'number of CPU milliseconds spent in "system" mode', ''); $pmda->add_metric(pmda_pmid(1,28),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.tcp_client_overflow", 'number of times an IP address was denied TCP access because it already had too many connections', ''); $pmda->add_metric(pmda_pmid(1,29),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.tcp_outqueries", 'counts the number of outgoing TCP queries since starting', ''); $pmda->add_metric(pmda_pmid(1,30),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.tcp_questions", 'counts all incoming TCP queries (since starting)', ''); $pmda->add_metric(pmda_pmid(1,31),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.throttled_out", 'counts the number of throttled outgoing UDP queries since starting', ''); $pmda->add_metric(pmda_pmid(1,32),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "pdns.recursor.throttle_entries", 'shows the number of entries in the throttle map', ''); $pmda->add_metric(pmda_pmid(1,33),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.unauthorized_tcp", 'number of TCP questions denied because of allow-from restrictions', ''); $pmda->add_metric(pmda_pmid(1,34),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.unauthorized_udp", 'number of UDP questions denied because of allow-from restrictions', ''); $pmda->add_metric(pmda_pmid(1,35),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.unexpected_packets", 'number of answers from remote servers that were unexpected (might point to spoofing)', ''); $pmda->add_metric(pmda_pmid(1,36),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "pdns.recursor.uptime", 'number of seconds process has been running', ''); $pmda->add_metric(pmda_pmid(1,37),PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), "pdns.recursor.user_msec", 'number of CPU milliseconds spent in "user" mode', ''); $pmda->add_indom($recursor_answers_indom, \@recursor_answers_dom, '', ''); $pmda->set_fetch_callback(\&pdns_fetch_callback); $pmda->set_fetch(\&pdns_fetch); $pmda->run; =pod =head1 NAME pmdapdns - PowerDNS performance metrics domain agent (PMDA) =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from the PowerDNS authorative daemon as well as the recursive resolver. =head1 INSTALLATION If you want access to the names and values for the PowerDNS performance metrics, do the following as root: # cd $PCP_PMDAS_DIR/pdns # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/pdns # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/pdns/Install installation script for the B agent =item $PCP_PMDAS_DIR/pdns/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/pdns.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1), pdns_control(8), and rec_control(1). pcp-3.8.12ubuntu1/src/pmdas/sendmail/0000775000000000000000000000000012272262620014273 5ustar pcp-3.8.12ubuntu1/src/pmdas/sendmail/sendmail.c0000664000000000000000000003570712272262501016245 0ustar /* * Sendmail PMDA * * Copyright (c) 1995-2000,2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include /* * Sendmail PMDA * * This PMDA uses the statistics file that sendmail optionally maintains * -- see "OS" or "O StatusFile=" in sendmail.cf and sendmail(1) * * This file (defaults to /var/sendmail.st) must be created before sendmail * will update any statistics. */ /* * list of instances */ static pmdaIndom indomtab[] = { #define MAILER_INDOM 0 { MAILER_INDOM, 0, NULL }, }; static char *statsfile = "/var/sendmail.st"; static char *username; static int nmailer; static void *ptr; static struct stat laststatbuf; static time_t *start_date; static __uint32_t *msgs_from; static __uint32_t *kbytes_from; static __uint32_t *msgs_to; static __uint32_t *kbytes_to; static pmdaMetric metrictab[] = { /* start_date */ { NULL, { PMDA_PMID(0,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* permailer.msgs_from */ { NULL, { PMDA_PMID(1,0), PM_TYPE_U32, MAILER_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* permailer.bytes_from */ { NULL, { PMDA_PMID(1,1), PM_TYPE_U32, MAILER_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* permailer.msgs_to */ { NULL, { PMDA_PMID(1,2), PM_TYPE_U32, MAILER_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* permailer.bytes_to */ { NULL, { PMDA_PMID(1,3), PM_TYPE_U32, MAILER_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* total.msgs_from */ { NULL, { PMDA_PMID(2,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* total.bytes_from */ { NULL, { PMDA_PMID(2,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* total.msgs_to */ { NULL, { PMDA_PMID(2,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* total.bytes_to */ { NULL, { PMDA_PMID(2,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, }; static void map_stats(void) { struct stat statbuf; static int fd; static int notified = 0; #define MAPSTATS_NULL 0x01 #define MAPSTATS_NOTV2STRUCT 0x02 #define MAPSTATS_MAPFAIL 0x04 /* From mailstats.h in sendmail(1) 8.x... */ struct smstat_s { #define MAXMAILERS 25 #define STAT_VERSION 2 #define STAT_MAGIC 0x1B1DE int stat_magic; /* magic number */ int stat_version; /* stat file version */ time_t stat_itime; /* file initialization time */ short stat_size; /* size of this structure */ long stat_nf[MAXMAILERS]; /* # msgs from each mailer */ long stat_bf[MAXMAILERS]; /* kbytes from each mailer */ long stat_nt[MAXMAILERS]; /* # msgs to each mailer */ long stat_bt[MAXMAILERS]; /* kbytes to each mailer */ long stat_nr[MAXMAILERS]; /* # rejects by each mailer */ long stat_nd[MAXMAILERS]; /* # discards by each mailer */ } *smstat; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "%s: map_stats: Entering:\n", pmProgname); fprintf(stderr, "%s: map_stats: Check: ptr = " PRINTF_P_PFX "%p\n", pmProgname, ptr); fprintf(stderr, "%s: map_stats: Check: statsfile = " PRINTF_P_PFX "%p\n", pmProgname, statsfile); if (statsfile != NULL) fprintf(stderr, "%s: map_stats: = %s\n", pmProgname, statsfile); } #endif if (statsfile == NULL || stat(statsfile, &statbuf) < 0) { /* if sendmail not collecting stats this is expected */ if (ptr != NULL) { /* must have gone away */ __pmMemoryUnmap(ptr, laststatbuf.st_size); close(fd); ptr = NULL; notified &= ~MAPSTATS_NOTV2STRUCT; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "%s: map_stats: (Maybe) stat() < 0; pmunmap() called\n", pmProgname); } #endif } return; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "%s: map_stats: Check: statbuf.st_ino = %lu\n", pmProgname, (unsigned long)statbuf.st_ino); fprintf(stderr, "%s: map_stats: Check: statbuf.st_dev = %lu\n", pmProgname, (unsigned long)statbuf.st_dev); fprintf(stderr, "%s: map_stats: Check: laststatbuf.st_ino = %lu\n", pmProgname, (unsigned long)laststatbuf.st_ino); fprintf(stderr, "%s: map_stats: Check: laststatbuf.st_dev = %lu\n", pmProgname, (unsigned long)laststatbuf.st_dev); } #endif if (statbuf.st_ino != laststatbuf.st_ino || statbuf.st_dev != laststatbuf.st_dev || ptr == NULL) { /* * Not the same as the file we saw last time, or statsfile is * not mapped into memory (because it was zero length). * * The file can change due to rotation or restarting sendmail... * note the times (st_atim, st_mtim and st_ctim) are all expected * to change as sendmail updates the file, hence we must use dev * and ino. * * ino is guaranteed to change for different instances of the * sendmail stats file, since a mmap()'d file is never closed * until after it's munmap()'d. */ if (ptr != NULL) { __pmMemoryUnmap(ptr, laststatbuf.st_size); close(fd); ptr = NULL; notified &= ~MAPSTATS_NOTV2STRUCT; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "%s: map_stats: statbuf.st_[dev|ido] changed; pmunmap() called\n", pmProgname); } #endif } if ((fd = open(statsfile, O_RDONLY)) < 0) { __pmNotifyErr(LOG_WARNING, "%s: map_stats: cannot open(\"%s\",...): %s", pmProgname, statsfile, osstrerror()); return; } ptr = __pmMemoryMap(fd, statbuf.st_size, 0); if (ptr == NULL) { if (!(notified & MAPSTATS_MAPFAIL)) { __pmNotifyErr(LOG_ERR, "%s: map_stats: memmap of %s failed: %s", pmProgname, statsfile, osstrerror()); } close(fd); ptr = NULL; notified |= MAPSTATS_MAPFAIL; return; } laststatbuf = statbuf; /* struct assignment */ notified &= ~(MAPSTATS_NULL | MAPSTATS_MAPFAIL); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "%s: map_stats: mmap() called, succeeded\n", pmProgname); } #endif /* Check for a statistics file from sendmail(1) 8.x: */ smstat = (struct smstat_s *)ptr; if (smstat->stat_magic != STAT_MAGIC || smstat->stat_version != STAT_VERSION) { if (! (notified & MAPSTATS_NOTV2STRUCT)) { __pmNotifyErr(LOG_WARNING, "%s: map_stats: cannot find magic number in file %s; assuming version 1 format", pmProgname, statsfile); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "%s: map_stats: smstat_s contents:\n", pmProgname); fprintf(stderr, "%s: map_stats: Version 2 format:\n", pmProgname); fprintf(stderr, "%s: map_stats: Check: stat_magic = 0x%x\n", pmProgname, smstat->stat_magic); fprintf(stderr, "%s: map_stats: Check: stat_version = 0x%x\n", pmProgname, smstat->stat_version); fprintf(stderr, "%s: map_stats: Check: stat_itime = %s", pmProgname, ctime(&(smstat->stat_itime))); fprintf(stderr, "%s: map_stats: Check: stat_size = %d\n", pmProgname, smstat->stat_size); /* We're being difficult here... using smstat_s the wrong way! */ fprintf(stderr, "%s: map_stats: Version 1 format:\n", pmProgname); fprintf(stderr, "%s: map_stats: Check: stat_itime = %s", pmProgname, ctime((time_t *)&(smstat->stat_magic))); fprintf(stderr, "%s: map_stats: Check: stat_size = %d\n", pmProgname, *((short *)&(smstat->stat_version))); } #endif notified |= MAPSTATS_NOTV2STRUCT; } /* Could be older version of stats file... here is the original code that dealt with that case */ /* * format of [older version] sendmail stats file: * word[0] time_t file first created * word[1] N/A * word[2] .. word[K+2] msgs_from mailers 0 .. K * word[K+3] .. word[2*K+3] kbytes_from mailers 0 .. K * word[2*K+3] .. word[3*K+4] msgs_to mailers 0 .. K * word[3*K+4] .. word[4*K+5] kbytes_to mailers 0 .. K */ nmailer = (statbuf.st_size - sizeof(__int32_t) - sizeof(__int32_t)) / (4 * sizeof(__uint32_t)); msgs_from = &((__uint32_t *)ptr)[2]; kbytes_from = &msgs_from[nmailer]; msgs_to = &kbytes_from[nmailer]; kbytes_to = &msgs_to[nmailer]; start_date = (time_t *)ptr; } else { /* Assign pointers to point to parts of the v2 struct */ nmailer = ((char *)smstat->stat_bf - (char *)smstat->stat_nf) / sizeof(long); msgs_from = (__uint32_t *)&(smstat->stat_nf); kbytes_from = (__uint32_t *)&(smstat->stat_bf); msgs_to = (__uint32_t *)&(smstat->stat_nt); kbytes_to = (__uint32_t *)&(smstat->stat_bt); start_date = &(smstat->stat_itime); } } } /* * logic here is similar to that used by mailstats(1) */ static void do_sendmail_cf(void) { FILE *fp; char buf[MAXPATHLEN+20]; char *bp; int i; int lineno = 0; if ((fp = fopen("/etc/sendmail.cf", "r")) == NULL) { if ((fp = fopen("/etc/mail/sendmail.cf", "r")) == NULL) { /* this is pretty serious! */ nmailer = 0; statsfile = NULL; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "Warning: cannot find sendmail.cf, so no stats!\n"); #endif return; } } nmailer = 3; indomtab[MAILER_INDOM].it_set = (pmdaInstid *)malloc(nmailer * sizeof(pmdaInstid)); indomtab[MAILER_INDOM].it_set[0].i_inst = 0; indomtab[MAILER_INDOM].it_set[0].i_name = "prog"; indomtab[MAILER_INDOM].it_set[1].i_inst = 1; indomtab[MAILER_INDOM].it_set[1].i_name = "*file*"; indomtab[MAILER_INDOM].it_set[2].i_inst = 2; indomtab[MAILER_INDOM].it_set[2].i_name = "*include*"; while (fgets(buf, sizeof(buf), fp) != NULL) { lineno++; bp = buf; if (*bp == 'M') { /* mailer definition */ bp++; while (*bp != ',' && !isspace((int)*bp) && *bp != '\0') bp++; *bp = '\0'; for (i = 0; i < nmailer; i++) { if (strcmp(&buf[1], indomtab[MAILER_INDOM].it_set[i].i_name) == 0) break; } if (i == nmailer) { indomtab[MAILER_INDOM].it_set = (pmdaInstid *)realloc(indomtab[MAILER_INDOM].it_set, (nmailer+1) * sizeof(pmdaInstid)); indomtab[MAILER_INDOM].it_set[nmailer].i_name = strdup(&buf[1]); indomtab[MAILER_INDOM].it_set[nmailer].i_inst = nmailer; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "sendmail.cf[%d]: mailer \"%s\" inst=%d\n", lineno, &buf[1], nmailer); #endif nmailer++; } } else if (*bp == 'O') { char *tp; if (strncasecmp(++bp, " StatusFile", 11) == 0 && !isalnum((int)bp[11])) { bp = strchr(bp, '='); if (bp == NULL) continue; while (isspace((int)*++bp)) continue; } else if (*bp == 'S') bp++; else continue; tp = bp++; while (*bp && !isspace((int)*bp) && *bp != '#') bp++; *bp = '\0'; statsfile = strdup(tp); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "sendmail.cf[%d]: statsfile \"%s\"\n", lineno, tp); #endif } } fclose(fp); indomtab[MAILER_INDOM].it_numinst = nmailer; } /* * callback provided to pmdaFetch */ static int sendmail_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); if (ptr == NULL) return 0; if (idp->cluster == 0) { if (idp->item == 0) { /* sendmail.start_date */ atom->cp = ctime(start_date); atom->cp[24] = '\0'; /* no newline */ return 1; } } else if (idp->cluster == 1) { if (inst >= nmailer) return 0; if (msgs_from[inst] == 0 && msgs_to[inst] == 0) { return 0; } switch (idp->item) { case 0: /* sendmail.permailer.msgs_from */ atom->ul = msgs_from[inst]; break; case 1: /* sendmail.permailer.bytes_from */ atom->ul = kbytes_from[inst]; break; case 2: /* sendmail.permailer.msgs_to */ atom->ul = msgs_to[inst]; break; case 3: /* sendmail.permailer.bytes_to */ atom->ul = kbytes_to[inst]; break; default: return PM_ERR_PMID; } return 1; } else if (idp->cluster == 2) { int i; atom->ul = 0; switch (idp->item) { case 0: /* sendmail.total.msgs_from */ for (i = 0; i < nmailer; i++) atom->ul += msgs_from[i]; break; case 1: /* sendmail.total.bytes_from */ for (i = 0; i < nmailer; i++) atom->ul += kbytes_from[i]; break; case 2: /* sendmail.total.msgs_to */ for (i = 0; i < nmailer; i++) atom->ul += msgs_to[i]; break; case 3: /* sendmail.total.bytes_to */ for (i = 0; i < nmailer; i++) atom->ul += kbytes_to[i]; break; default: return PM_ERR_PMID; } return 1; } return PM_ERR_PMID; } static int sendmail_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { map_stats(); return pmdaFetch(numpmid, pmidlist, resp, pmda); } /* * Initialise the agent */ void __PMDA_INIT_CALL sendmail_init(pmdaInterface *dp) { if (dp->status != 0) return; __pmSetProcessIdentity(username); do_sendmail_cf(); map_stats(); dp->version.two.fetch = sendmail_fetch; pmdaSetFetchCallBack(dp, sendmail_fetchCallBack); pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), metrictab, sizeof(metrictab)/sizeof(metrictab[0])); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int c, err = 0; int sep = __pmPathSeparator(); pmdaInterface dispatch; char mypath[MAXPATHLEN]; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(mypath, sizeof(mypath), "%s%c" "sendmail" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_3, pmProgname, SENDMAIL, "sendmail.log", mypath); while ((c = pmdaGetOpt(argc, argv, "D:d:l:U:?", &dispatch, &err)) != EOF) { switch(c) { case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&dispatch); sendmail_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/sendmail/README0000664000000000000000000000213712272262501015154 0ustar Sendmail PMDA ============= Export information from the sendmail statistics file. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT sendmail Installation ============ + # cd $PCP_PMDAS_DIR/sendmail + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options. Everything else is automated. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/sendmail # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/sendmail.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/sendmail/Remove0000664000000000000000000000201512272262501015447 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the sendmail PMDA # # Get standard environment . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=sendmail # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/sendmail/Install0000664000000000000000000000136712272262501015631 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the sendmail PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=sendmail pmda_interface=3 forced_restart=false pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/sendmail/GNUmakefile0000664000000000000000000000327312272262501016350 0ustar # # Copyright (c) 2000-2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = sendmail DOMAIN = SENDMAIL CMDTARGET = $(IAM)$(EXECSUFFIX) LIBTARGET = pmda_$(IAM).$(DSOSUFFIX) CFILES = sendmail.c SCRIPTS = Install Remove DFILES = README LSRCFILES= $(SCRIPTS) pmns help root Sendmail.pmchart $(DFILES) VERSION_SCRIPT = exports PMDAINIT = $(IAM)_init PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) PMCHART = $(PCP_VAR_DIR)/config/pmchart LDIRT = domain.h *.o $(IAM).log $(LIBTARGET) $(CMDTARGET) $(VERSION_SCRIPT) LLDLIBS = $(PCP_PMDALIB) LCFLAGS = $(INVISIBILITY) default_pcp default: $(CMDTARGET) $(LIBTARGET) include $(BUILDRULES) install install_pcp: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(LIBTARGET) $(PMDADIR)/$(LIBTARGET) $(INSTALL) -m 755 $(CMDTARGET) $(PMDADIR)/pmda$(IAM)$(EXECSUFFIX) $(INSTALL) -m 755 $(SCRIPTS) $(PMDADIR) $(INSTALL) -m 644 $(DFILES) pmns help root domain.h $(PMDADIR) $(INSTALL) -m 644 Sendmail.pmchart $(PMCHART)/Sendmail $(CMDTARGET): $(OBJECTS) $(LIBTARGET): $(OBJECTS) $(VERSION_SCRIPT) sendmail.o: domain.h domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) $(VERSION_SCRIPT): $(VERSION_SCRIPT_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/sendmail/root0000664000000000000000000000016512272262501015201 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { sendmail } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/sendmail/pmns0000664000000000000000000000220312272262501015166 0ustar /* * Metrics for sendmail PMDA * * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ sendmail { start_date SENDMAIL:0:0 permailer total } sendmail.permailer { msgs_from SENDMAIL:1:0 bytes_from SENDMAIL:1:1 msgs_to SENDMAIL:1:2 bytes_to SENDMAIL:1:3 } sendmail.total { msgs_from SENDMAIL:2:0 bytes_from SENDMAIL:2:1 msgs_to SENDMAIL:2:2 bytes_to SENDMAIL:2:3 } pcp-3.8.12ubuntu1/src/pmdas/sendmail/Sendmail.pmchart0000664000000000000000000000046012272262501017405 0ustar #pmchart Version 2.0 host dynamic Chart Style plot Plot Color #137bfe Host * Metric sendmail.total.bytes_from Plot Color #fefa1a Host * Metric sendmail.total.bytes_to Chart Style plot Plot Color #1e1cfe Host * Metric sendmail.total.msgs_from Plot Color #fe9913 Host * Metric sendmail.total.msgs_to pcp-3.8.12ubuntu1/src/pmdas/sendmail/help0000664000000000000000000000565412272262501015156 0ustar # # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # sendmail PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ SENDMAIL.0 Instance domain "mailer" for sendmail PMDA The mailers 0 (prog), 1 (*file*), and 2 (*include*) are fixed. Other mailers are defined by the order of any additional "M" records in the sendmail.cf file. @ sendmail.start_date Date on which sendmail stats file was created The date in ctime(2) format on which the sendmail statistics file was first created. All statistics are cumulative from that time. The sendmail statistics file is /var/sendmailst by default, but may be redefined by an "OS" or "O StatusFile" record in the sendmail.cf file. @ sendmail.permailer.msgs_from Messages received from each mailer Count of messages received from each "mailer" defined in sendmail's configuration file (/etc/sendmail.cf). @ sendmail.permailer.bytes_from Kbytes received from each mailer Count of Kbytes summed over all messages received from each "mailer" defined in sendmail's configuration file (/etc/sendmail.cf). @ sendmail.permailer.msgs_to Messages sent to each mailer Count of messages sent to each "mailer" defined in sendmail's configuration file (/etc/sendmail.cf). @ sendmail.permailer.bytes_to Kbytes sent to each mailer Count of Kbytes summed over all messages sent to each "mailer" defined in sendmail's configuration file (/etc/sendmail.cf). @ sendmail.total.msgs_from Messages received from all mailers Count of messages received by sendmail. @ sendmail.total.bytes_from Kbytes received from all mailers Count of Kbytes summed over all messages received by sendmail. @ sendmail.total.msgs_to Messages sent to all mailers Count of messages sent by sendmail. @ sendmail.total.bytes_to Kbytes sent to all mailers Count of Kbytes summed over all messages sent by sendmail. pcp-3.8.12ubuntu1/src/pmdas/gpsd/0000775000000000000000000000000012272262620013434 5ustar pcp-3.8.12ubuntu1/src/pmdas/gpsd/pmdagpsd.pl0000664000000000000000000002572312272262501015577 0ustar # # Copyright (c) 2010 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; use JSON; use Time::HiRes qw ( time ); use vars qw( $pmda ); use vars qw( %devdata %satdata ); my $gpspipe = "gpspipe -w"; my $json; my $gpsd_release = "?"; my $gpsd_rev = "?"; my $gpsd_proto_maj = -1; my $gpsd_proto_min = -1; # FIXME: the following will need changing to support multiple devices my $gpsd_device = undef; my %devdata = ( "time" => -1, "ept" => -1, "lat" => -1, "lon" => -1, "alt" => -1, "track" => -1, "speed" => -1, "climb" => -1, "mode" => 0, # 0 = no fix "xdop" => -1, "ydop" => -1, "vdop" => -1, "tdop" => -1, "hdop" => -1, "gdop" => -1, "pdop" => -1, "num_satellites" => 0, ); my $gpsd_sat_indom = 0; my @gpsd_sat_dom = (); sub gpsd_pipe_callback { (undef, $_) = @_; # $pmda->log("pipe got: $_"); my $jtxt = $json->decode($_); if ($jtxt->{"class"} eq "VERSION") { $gpsd_release = $jtxt->{"release"}; $gpsd_rev = $jtxt->{"rev"}; $gpsd_proto_maj = $jtxt->{"proto_major"}; $gpsd_proto_min = $jtxt->{"proto_minor"}; } elsif ($jtxt->{"class"} eq "DEVICES") { foreach my $dev (@{$jtxt->{"devices"}}) { if ($dev->{"class"} eq "DEVICE") { $pmda->log("gpsd_pipe_callback: oops! multiple " . "devices detected, only using the first " . "($gpsd_device)") if (defined($gpsd_device) and $dev->{"path"} ne $gpsd_device); $gpsd_device = $dev->{"path"}; } else { $pmda->log("gpsd_pipe_callback: unknown class '" . $dev->{"class"} . "'"); } } } elsif ($jtxt->{"class"} eq "DEVICE") { # nothing to do } elsif ($jtxt->{"class"} eq "WATCH") { # nothing to do } elsif ($jtxt->{"class"} eq "TPV") { return if ($jtxt->{"device"} ne $gpsd_device); $devdata{"time"} = $jtxt->{"time"}; $devdata{"ept"} = $jtxt->{"ept"}; $devdata{"lat"} = $jtxt->{"lat"}; $devdata{"lon"} = $jtxt->{"lon"}; $devdata{"alt"} = $jtxt->{"alt"}; $devdata{"track"} = $jtxt->{"track"}; $devdata{"speed"} = $jtxt->{"speed"}; $devdata{"climb"} = $jtxt->{"climb"}; $devdata{"mode"} = $jtxt->{"mode"}; } elsif ($jtxt->{"class"} eq "SKY") { return if ($jtxt->{"device"} ne $gpsd_device); $devdata{"xdop"} = $jtxt->{"xdop"}; $devdata{"ydop"} = $jtxt->{"ydop"}; $devdata{"vdop"} = $jtxt->{"vdop"}; $devdata{"tdop"} = $jtxt->{"tdop"}; $devdata{"hdop"} = $jtxt->{"hdop"}; $devdata{"gdop"} = $jtxt->{"gdop"}; $devdata{"pdop"} = $jtxt->{"pdop"}; my %sats = {}; my @dom = (); foreach my $sat (@{$jtxt->{"satellites"}}) { push(@dom, $sat->{"PRN"} => "$sat->{'PRN'}"); $sats{"el"}{$sat->{"PRN"}} = $sat->{"el"}; $sats{"az"}{$sat->{"PRN"}} = $sat->{"az"}; $sats{"ss"}{$sat->{"PRN"}} = $sat->{"ss"}; $sats{"used"}{$sat->{"PRN"}} = $sat->{"used"}; } %satdata = %sats; $pmda->replace_indom($gpsd_sat_indom, \@dom); $devdata{"num_satellites"} = scalar(@dom) / 2; } else { $pmda->log("gpsd_pipe_callback: unknown class '" . $jtxt->{"class"} . "'"); } } sub gpsd_fetch_callback { my ($cluster, $item, $inst) = @_; my $metric_name = pmda_pmid_name($cluster, $item); # $pmda->log("gpsd_fetch_callback $metric_name $cluster:$item ($inst)\n"); return (PM_ERR_PMID, 0) if (!defined($metric_name)); if ($cluster == 0) { return (PM_ERR_INST, 0) if ($inst != PM_IN_NULL); if ($metric_name eq "gpsd.release") { return ($gpsd_release, 1); } elsif ($metric_name eq "gpsd.rev") { return ($gpsd_rev, 1); } elsif ($metric_name eq "gpsd.proto.major") { return ($gpsd_proto_maj, 1); } elsif ($metric_name eq "gpsd.proto.minor") { return ($gpsd_proto_min, 1); } } $metric_name =~ s/^gpsd\.devices\.dev0\.//; if ($metric_name =~ m/^satellites\./) { # satellite info $metric_name =~ s/^satellites\.//; # $pmda->log("gpsd_fetch_callbac2 $metric_name $cluster:$item ($inst): ${satdata{$metric_name}}\n"); # $pmda->log("gpsd_fetch_callbac2 $metric_name $cluster:$item ($inst): ${satdata{$metric_name}{$inst}}\n"); return (PM_ERR_INST, 0) if ($inst == PM_IN_NULL); return (PM_ERR_PMID, 0) if (!defined($satdata{$metric_name}{$inst})); return ($satdata{$metric_name}{$inst}, 1); } return (PM_ERR_INST, 0) if ($inst != PM_IN_NULL); return (PM_ERR_PMID, 0) if (!defined($devdata{$metric_name})); return ($devdata{$metric_name}, 1); } $json = new JSON; $pmda = PCP::PMDA->new('gpsd', 105); $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.release", '', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.rev", '', ''); $pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.proto.major", '', ''); $pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.proto.minor", '', ''); $pmda->add_metric(pmda_pmid(1,0), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.time", '', ''); $pmda->add_metric(pmda_pmid(1,1), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.ept", '', ''); $pmda->add_metric(pmda_pmid(1,2), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.lat", '', ''); $pmda->add_metric(pmda_pmid(1,3), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.lon", '', ''); $pmda->add_metric(pmda_pmid(1,4), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.alt", '', ''); $pmda->add_metric(pmda_pmid(1,5), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.track", '', ''); $pmda->add_metric(pmda_pmid(1,6), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.speed", '', ''); $pmda->add_metric(pmda_pmid(1,7), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.climb", '', ''); $pmda->add_metric(pmda_pmid(1,8), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.mode", '', ''); $pmda->add_metric(pmda_pmid(1,9), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.xdop", '', ''); $pmda->add_metric(pmda_pmid(1,10), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.ydop", '', ''); $pmda->add_metric(pmda_pmid(1,11), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.vdop", '', ''); $pmda->add_metric(pmda_pmid(1,12), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.tdop", '', ''); $pmda->add_metric(pmda_pmid(1,13), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.hdop", '', ''); $pmda->add_metric(pmda_pmid(1,14), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.gdop", '', ''); $pmda->add_metric(pmda_pmid(1,15), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.pdop", '', ''); $pmda->add_metric(pmda_pmid(1,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.num_satellites", '', ''); $pmda->add_metric(pmda_pmid(1,100), PM_TYPE_U32, $gpsd_sat_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.satellites.el", '', ''); $pmda->add_metric(pmda_pmid(1,101), PM_TYPE_U32, $gpsd_sat_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.satellites.az", '', ''); $pmda->add_metric(pmda_pmid(1,102), PM_TYPE_U32, $gpsd_sat_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.satellites.ss", '', ''); $pmda->add_metric(pmda_pmid(1,103), PM_TYPE_U32, $gpsd_sat_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "gpsd.devices.dev0.satellites.used", '', ''); $pmda->add_indom($gpsd_sat_indom, \@gpsd_sat_dom, '', ''); $pmda->add_pipe($gpspipe, \&gpsd_pipe_callback, 0); $pmda->set_fetch_callback(\&gpsd_fetch_callback); $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdagpsd - gpsd performance metrics domain agent (PMDA) =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports values from the gpsd daemon. =head1 INSTALLATION If you want access to the names and values for gpsd, do the following as root: # cd $PCP_PMDAS_DIR/gpsd # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/gpsd # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/gpsd/Install installation script for the B agent =item $PCP_PMDAS_DIR/gpsd/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/gpsd.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1). pcp-3.8.12ubuntu1/src/pmdas/gpsd/Remove0000664000000000000000000000126612272262501014617 0ustar #! /bin/sh # # Copyright (c) 2010 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the gpsd PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=gpsd pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/gpsd/Install0000664000000000000000000000153512272262501014767 0ustar #! /bin/sh # # Copyright (c) 2010 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the gpsd PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=gpsd perl_opt=true daemon_opt=false forced_restart=true perl -e "use JSON" 2>/dev/null if test $? -ne 0; then echo "JSON perl module is not installed" exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/gpsd/GNUmakefile0000664000000000000000000000235712272262501015513 0ustar #!gmake # # Copyright (c) 2010 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = gpsd PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/dtsrun/0000775000000000000000000000000012272262620014016 5ustar pcp-3.8.12ubuntu1/src/pmdas/dtsrun/Remove0000775000000000000000000000132712272262501015202 0ustar #!/bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the DTS (Data Transformation Services) dtsrun log PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=dtsrun pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/dtsrun/Install0000775000000000000000000000172512272262501015355 0ustar #!/bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the DTS (Data Transformation Services) dtsrun log file PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=dtsrun perl_opt=true daemon_opt=false forced_restart=false pmdaSetup if $do_pmda then while true do echo $PCP_ECHO_PROG $PCP_ECHO_N "DTS log filename? ""$PCP_ECHO_C" read logfile [ ! -z "$logfile" ] && break echo done args="$args logfile" fi pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/dtsrun/GNUmakefile0000664000000000000000000000242712272262501016073 0ustar #!gmake # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = dtsrun PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) ifeq "$(TARGET_OS)" "mingw" install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) else install: endif default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/dtsrun/pmdadtsrun.pl0000664000000000000000000002551412272262501016541 0ustar # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; use Time::Local; my $pmda = PCP::PMDA->new('dtsrun', 102); my ( $package, $package_starttime, $instance_refresh ); my $package_indom = 0; # instance domain for DTS package my @package_instances = (); my ( $step, $step_starttime ); my $steps_indom = 1; # instance domain for DTS package steps my @steps_instances = (); use vars qw ( %lastpkg_times %lastpkg_stamp %allpkgs_times %allpkgs_count %laststep_times %laststep_stamp %laststep_offset %laststep_status %laststep_message %allsteps_times %allsteps_count %allsteps_errors %allpkgs_delta %packages %steps ); sub parsetime { shift; #$pmda->log("parsetime got dtsrun timestamp: $_"); m|(\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+) (\w+)|; my ($mm, $dd, $year, $hr, $min, $sec, $ampm) = ($1,$2,$3,$4,$5,$6,$7); $hr += 12 unless ($ampm eq 'AM'); $hr -= 1; # range 0..23 (hours) $mm -= 1; # range 0..11 (months) my $tm = timelocal($sec,$min,$hr,$dd,$mm,$year); return $tm; } sub dtsrun_parser { ( undef, $_ ) = @_; s/\r//g; # cull Windows line endings #$pmda->log("dtsrun_parser got line: $_"); if (/^Step '(\S+)' (.*)/) { $step = "$package/$1"; if (defined($steps{$step})) { $allsteps_count{$step}++; } else { # new step instance $steps{$step} = 1; $allsteps_times{$step} = 0; $allsteps_count{$step} = 1; $allsteps_errors{$step} = 0; $laststep_times{$step} = 0; $laststep_stamp{$step} = ''; $laststep_offset{$step} = 0; $laststep_status{$step} = -1; $laststep_message{$step} = ''; $instance_refresh = 1; } if ($2 eq 'succeeded') { $laststep_status{$step} = 0; } else { $laststep_status{$step} = -1; $allsteps_errors{$step}++; } $laststep_message{$step} = $2; } elsif (/^Step Execution Started: (.*)/) { $step_starttime = parsetime($1); $laststep_stamp{$step} = $1; $laststep_offset{$step} = $step_starttime - $package_starttime; } elsif (/^Total Step Execution Time: (\S+) seconds/) { $laststep_times{$step} = $1; $allsteps_times{$step} += $1; } elsif (/^Package Name: (\w+)/) { $package = $1; if (defined($packages{$package})) { $allpkgs_count{$package}++; } else { # new package instance $packages{$package} = 1; $allpkgs_delta{$package} = 0; $allpkgs_times{$package} = 0; $allpkgs_count{$package} = 1; $lastpkg_times{$package} = 0; $lastpkg_stamp{$package} = ''; $instance_refresh = 1; } } elsif (/^Execution Started: (.*)/) { my $latest = parsetime($1); if (defined($package_starttime) && $package_starttime >= 0) { $allpkgs_delta{$package} = $latest - $package_starttime; } else { $allpkgs_delta{$package} = -1; } $package_starttime = $latest; $lastpkg_stamp{$package} = $1; } elsif (/^Total Execution Time: (\S+) seconds/) { $lastpkg_times{$package} = $1; $allpkgs_times{$package} += $1; } elsif (/^\*\*\*/) { # end section, cleanup global state undef $step; undef $package; } } sub dtsrun_instance { my ( $pkgcount, $stepcount ); #$pmda->log("dtsrun_instance"); return unless (defined($instance_refresh) && $instance_refresh); @package_instances = (); @steps_instances = (); $pkgcount = $stepcount = 0; foreach my $pkgname (keys(%packages)) { push @package_instances, $pkgcount++, $pkgname; foreach my $stepname (sort keys(%steps)) { push @steps_instances, $stepcount++, $stepname; } } #$pmda->log("dtsrun_instance: $pkgcount packages, $stepcount steps"); $pmda->replace_indom($package_indom, \@package_instances); $pmda->replace_indom($steps_indom, \@steps_instances); $instance_refresh = 0; } sub dtsrun_fetch_callback { my ($cluster, $item, $inst) = @_; my $instance; #$pmda->log("dtsrun_fetch_callback for PMID: $cluster.$item ($inst)"); if ($inst == PM_IN_NULL) { return (PM_ERR_INST, 0); } if ($cluster == 0 || $cluster == 1 || $cluster == 4) { $instance = pmda_inst_name($package_indom, $inst); } else { $instance = pmda_inst_name($steps_indom, $inst); } if (!defined($instance)) { return (PM_ERR_INST, 0); } #$pmda->log("dtsrun_fetch_callback using instance $instance"); if ($cluster == 0) { # dtsrun.package.last.time if ($item == 0) { return ($lastpkg_times{$instance}, 1); } # dtsrun.package.last.timestamp elsif ($item == 1) { return ($lastpkg_stamp{$instance}, 1); } } elsif ($cluster == 1) { # dtsrun.package.total.time if ($item == 0) { return ($allpkgs_times{$instance}, 1); } # dtsrun.package.total.count elsif ($item == 1) { return ($allpkgs_count{$instance}, 1); } } elsif ($cluster == 2) { # dtsrun.package.steps.last.time if ($item == 0) { return ($laststep_times{$instance}, 1); } # dtsrun.package.steps.last.timestamp if ($item == 1) { return ($laststep_stamp{$instance}, 1); } # dtsrun.package.steps.last.offset if ($item == 2) { return ($laststep_offset{$instance}, 1); } # dtsrun.package.steps.last.status if ($item == 3) { return ($laststep_status{$instance}, 1); } # dtsrun.package.steps.last.message if ($item == 4) { return ($laststep_message{$instance}, 1); } } elsif ($cluster == 3) { # dtsrun.package.steps.total.time if ($item == 0) { return ($allsteps_times{$instance}, 1); } # dtsrun.package.steps.total.count if ($item == 1) { return ($allsteps_count{$instance}, 1); } # dtsrun.package.steps.total.errors if ($item == 2) { return ($allsteps_errors{$instance}, 1); } } elsif ($cluster == 4) { # dtsrun.package.interval if ($item == 0) { return ($allpkgs_delta{$instance}, 1); } } return (PM_ERR_PMID, 0); } sub dtsrun_setup_metrics { $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_FLOAT, $package_indom, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'dtsrun.package.lastrun.time', '', 'Time taken for DTS package to complete the last time it was run'); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_STRING, $package_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'dtsrun.package.lastrun.timestamp', '', 'Time stamp (string) of the last package run for each DTS package'); $pmda->add_metric(pmda_pmid(1,0), PM_TYPE_FLOAT, $package_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'dtsrun.package.total.time', '', 'Cumulative time taken to date for all DTS package runs.'); $pmda->add_metric(pmda_pmid(1,1), PM_TYPE_U32, $package_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'dtsrun.package.total.count', '', 'Cumulative count of all DTS package runs to date.'); $pmda->add_metric(pmda_pmid(2,0), PM_TYPE_U32, $steps_indom, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'dtsrun.package.steps.last.time', '', 'Time taken to complete the last iteration of each step.'); $pmda->add_metric(pmda_pmid(2,1), PM_TYPE_STRING, $steps_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'dtsrun.package.steps.last.timestamp', '', 'Time of completion of the last iteration of each step.'); $pmda->add_metric(pmda_pmid(2,2), PM_TYPE_U32, $steps_indom, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'dtsrun.package.steps.last.offset', '', 'Offset from package start time for this step, in seconds.'); $pmda->add_metric(pmda_pmid(2,3), PM_TYPE_32, $steps_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'dtsrun.package.steps.last.status', '', 'Indicator of success (0) or failure of last run for each step.'); $pmda->add_metric(pmda_pmid(2,4), PM_TYPE_STRING, $steps_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'dtsrun.package.steps.last.message', '', 'Message string used to determine status of last run for each step.'); $pmda->add_metric(pmda_pmid(3,0), PM_TYPE_FLOAT, $steps_indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'dtsrun.package.steps.total.time', '', 'Cumulative count of time taken for runs of each DTS package step.'); $pmda->add_metric(pmda_pmid(3,1), PM_TYPE_U32, $steps_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'dtsrun.package.steps.total.count', '', 'Cumulative count of runs of each DTS package step.'); $pmda->add_metric(pmda_pmid(3,2), PM_TYPE_U32, $steps_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'dtsrun.package.steps.total.errors', '', 'Cumulative count of errors observed for each DTS package step.'); $pmda->add_metric(pmda_pmid(4,0), PM_TYPE_32, $package_indom, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'dtsrun.package.interval', '', 'Time between consecutive observations of each DTS package run. Unknown is -1.'); } sub dtsrun_setup_instances { $package_indom = $pmda->add_indom($package_indom, [], '', ''); $steps_indom = $pmda->add_indom($steps_indom, [], '', ''); } my $logfile = ''; if (!defined($ENV{PCP_PERL_PMNS} && !defined($ENV{PCP_PERL_DOMAIN}))) { die "No dtsrun statistics file specified\n" unless (defined($ARGV[0])); $logfile = $ARGV[0]; die "Cannot find a valid dtsrun statistics file\n" unless -f $logfile; } $pmda->log("Using logfile: $logfile"); dtsrun_setup_metrics; dtsrun_setup_instances; $pmda->add_tail($logfile, \&dtsrun_parser, 0); $pmda->set_fetch(\&dtsrun_instance); $pmda->set_instance(\&dtsrun_instance); $pmda->set_fetch_callback(\&dtsrun_fetch_callback); $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdadtsrun - Data Transformation Services process (dtsrun) log file PMDA =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from the DTS run executable, which is a data transformation server, used with SQL Server. Further details on DTS can be found at http://www.dtssql.com/. =head1 INSTALLATION If you want access to the names and values for the dtsrun performance metrics, do the following as root: # cd $PCP_PMDAS_DIR/dtsrun # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/dtsrun # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item /var/log/dtsrun.log log file showing status and elapsed times exported from dtsrun =item $PCP_PMDAS_DIR/dtsrun/Install installation script for the B agent =item $PCP_PMDAS_DIR/dtsrun/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/dtsrun.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1). pcp-3.8.12ubuntu1/src/pmdas/sample/0000775000000000000000000000000012272262620013760 5ustar pcp-3.8.12ubuntu1/src/pmdas/sample/README0000664000000000000000000000341612272262501014642 0ustar Sample PMDA =========== This PMDA supports a synthetic collection of metrics that are designed to exercise various facilities of the Performance Co-Pilot. The most common reasons for installing this PMDA are a. for internal product QA, or b. as part of one of the animated tutorials or demonstrations that accompany the PCP Two variants of the PMDA are installed, namely "sample" as a daemon with an IPC channel to PMCD, and "sampledso" that is attached as a Dynamic Shared Object (DSO) by PMCD and called directly. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT sample sampledso Installation ============ + # cd $PCP_PMDAS_DIR/sample + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. Note that sampledso uses the next domain number after the one in ./domain.h, so you must check for its uniqueness as well. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options. You will be prompted to choose the IPC channel for the daemon implementation of the sample PMDA -- everything else is automated De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/sample # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/sample.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/sample/Remove0000775000000000000000000000215112272262501015140 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the sample PMDA # # source the PCP configuration environment variables . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=sample # Do it # pmdaSetup pmdaRemove # and again # iam=sampledso pmns_name=sampledso domain=30 pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/sample/Install0000775000000000000000000000331612272262501015315 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the sample PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=sample forced_restart=false pmda_interface=2 # Do it for sample # pmdaSetup echo "======================" echo "= sample daemon PMDA =" echo "======================" daemon_opt=true # can install as daemon dso_opt=false pipe_opt=true # supports pipe IPC socket_opt=true # supports socket IPC socket_inet_def=2077 # default TCP port for Internet socket IPC pmdaInstall # The name of the PMDA for sampledso # iam=sampledso # Do it for sampledso ... no pmdaSetup # echo "======================" echo "= sampledso DSO PMDA =" echo "======================" domain=30 SYMDOM=SAMPLEDSO sed -e 's/sample/sampledso/' -e 's/SAMPLE/SAMPLEDSO/' $tmp/pmns pmns_source=$tmp/pmns pmns_name=sampledso if $do_pmda then sed -e 's/sample/sampledso/' -e 's/SAMPLE/SAMPLEDSO/' dsohelp help_source=dsohelp fi dso_opt=true daemon_opt=false dso_suffix=so [ "$PCP_PLATFORM" = "mingw" ] && dso_suffix=dll [ "$PCP_PLATFORM" = "darwin" ] && dso_suffix=dylib dso_name=$PCP_PMDAS_DIR/sample/pmda_sample.$dso_suffix dso_entry=sample_init pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/sample/src/0000775000000000000000000000000012272262620014547 5ustar pcp-3.8.12ubuntu1/src/pmdas/sample/src/sample.c0000664000000000000000000024411112272262501016175 0ustar /* * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "percontext.h" #include "events.h" #include #include #include "../domain.h" #ifdef HAVE_SYSINFO /* * On Solaris, need and sysinfo() is different. * Other platforms need */ #ifdef IS_SOLARIS #include #define MAX_SYSNAME 257 #else #include #endif #else static struct sysinfo { char dummy[64]; } si = { { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '9', '[', ']', '.' } }; #endif static int need_mirage; /* only do mirage glop is someone asks for it */ static int need_dynamic;/* only do dynamic glop is someone asks for it */ /* from pmda.c: simulate PMDA busy */ extern int limbo(void); /* * all metrics supported in this PMD - one table entry for each */ static pmDesc desctab[] = { /* control */ { PMDA_PMID(0,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* daemon-pid */ { PMDA_PMID(0,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* seconds */ { PMDA_PMID(0,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, /* milliseconds */ { PMDA_PMID(0,3), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, /* load */ { PMDA_PMID(0,4), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* colour */ { PMDA_PMID(0,5), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* bin */ { PMDA_PMID(0,6), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* drift */ { PMDA_PMID(0,7), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* step */ { PMDA_PMID(0,8), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* noinst */ { PMDA_PMID(0,9), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* long.one */ { PMDA_PMID(0,10), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* long.ten */ { PMDA_PMID(0,11), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* long.hundred */ { PMDA_PMID(0,12), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* long.million */ { PMDA_PMID(0,13), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* long.write_me */ { PMDA_PMID(0,14), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* float.one */ { PMDA_PMID(0,15), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* float.ten */ { PMDA_PMID(0,16), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* float.hundred */ { PMDA_PMID(0,17), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* float.million */ { PMDA_PMID(0,18), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* float.write_me */ { PMDA_PMID(0,19), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* longlong.one */ { PMDA_PMID(0,20), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* longlong.ten */ { PMDA_PMID(0,21), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* longlong.hundred */ { PMDA_PMID(0,22), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* longlong.million */ { PMDA_PMID(0,23), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* longlong.write_me */ { PMDA_PMID(0,24), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* double.one */ { PMDA_PMID(0,25), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* double.ten */ { PMDA_PMID(0,26), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* double.hundred */ { PMDA_PMID(0,27), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* double.million */ { PMDA_PMID(0,28), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* double.write_me */ { PMDA_PMID(0,29), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* string.null */ { PMDA_PMID(0,30), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* string.hullo */ { PMDA_PMID(0,31), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* string.write_me */ { PMDA_PMID(0,32), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* aggregate.null */ { PMDA_PMID(0,33), PM_TYPE_AGGREGATE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* aggregate.hullo */ { PMDA_PMID(0,34), PM_TYPE_AGGREGATE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* aggregate.write_me */ { PMDA_PMID(0,35), PM_TYPE_AGGREGATE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* write_me */ { PMDA_PMID(0,36), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE) }, /* mirage */ { PMDA_PMID(0,37), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,-1,0,PM_SPACE_KBYTE,PM_TIME_SEC,0) }, /* mirage-longlong */ { PMDA_PMID(0,38), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_MSEC,0) }, /* sysinfo */ { PMDA_PMID(0,39), PM_TYPE_AGGREGATE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pdu */ { PMDA_PMID(0,40), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* recv-pdu */ { PMDA_PMID(0,41), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* xmit-pdu */ { PMDA_PMID(0,42), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* percontext.pdu */ { PMDA_PMID(0,43), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* percontext.recv-pdu */ { PMDA_PMID(0,44), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* percontext.xmit-pdu */ { PMDA_PMID(0,45), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* lights */ { PMDA_PMID(0,46), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* magnitude */ { PMDA_PMID(0,47), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* bucket - alias for bin, but different PMID */ { PMDA_PMID(0,48), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* needprofile - need explicit instance profile */ { PMDA_PMID(0,49), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* part_bin - bin, minus an instance or two */ { PMDA_PMID(0,50), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* bogus_bin - bin, plus an instance or two */ { PMDA_PMID(0,51), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* hordes.one */ { PMDA_PMID(0,52), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* hordes.two */ { PMDA_PMID(0,53), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* bad.unknown */ { PMDA_PMID(0,54), 0, 0, 0, PMDA_PMUNITS(0,0,0,0,0,0) }, /* bad.nosupport */ { PMDA_PMID(0,55), PM_TYPE_NOSUPPORT, PM_INDOM_NULL, 0, PMDA_PMUNITS(0,0,0,0,0,0) }, /* not_ready */ { PMDA_PMID(0,56), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* wrap.long */ { PMDA_PMID(0,57), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,0,0,0,0) }, /* wrap.ulong */ { PMDA_PMID(0,58), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,0,0,0,0) }, /* wrap.longlong */ { PMDA_PMID(0,59), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,0,0,0,0) }, /* wrap.ulonglong */ { PMDA_PMID(0,60), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,0,0,0,0) }, /* dodgey.control */ { PMDA_PMID(0,61), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* dodgey.value */ { PMDA_PMID(0,62), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* step_counter */ { PMDA_PMID(0,63), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* rapid */ { PMDA_PMID(0,64), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* scale_step.bytes_up */ { PMDA_PMID(0,65), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_SEC,0) }, /* scale_step.bytes_down */ { PMDA_PMID(0,66), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, /* scale_step.count_up */ { PMDA_PMID(0,67), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE) }, /* scale_step.count_down */ { PMDA_PMID(0,68), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* scale_step.time_up_secs */ { PMDA_PMID(0,69), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, /* scale_step.time_up_nanosecs */ { PMDA_PMID(0,70), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, /* scale_step.none_up */ { PMDA_PMID(0,71), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* const_rate.value */ { PMDA_PMID(0,72), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* const_rate.gradient */ { PMDA_PMID(0,73), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* error_code */ { PMDA_PMID(0,74), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* error_check */ { PMDA_PMID(0,75), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* dynamic.counter */ { PMDA_PMID(0,76), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* dynamic.discrete */ { PMDA_PMID(0,77), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* dynamic.instant */ { PMDA_PMID(0,78), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* many.count */ { PMDA_PMID(0,79), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,0) }, /* many.int */ { PMDA_PMID(0,80), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,0) }, /* byte_ctr */ { PMDA_PMID(0,81), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, /* byte_rate */ { PMDA_PMID(0,82), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_SEC,0) }, /* kbyte_ctr */ { PMDA_PMID(0,83), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, /* kbyte_rate */ { PMDA_PMID(0,84), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,-1,0,PM_SPACE_KBYTE,PM_TIME_SEC,0) }, /* byte_rate_per_hour */ { PMDA_PMID(0,85), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_HOUR,0) }, /* dynamic.meta.metric - pmDesc here is a fake, use magic */ { PMDA_PMID(0,86), 0, 0, 0, PMDA_PMUNITS(0,0,0,0,0,0) }, /* dynamic.meta.pmdesc.type */ { PMDA_PMID(0,87), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* dynamic.meta.pmdesc.indom */ { PMDA_PMID(0,88), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* dynamic.meta.pmdesc.sem */ { PMDA_PMID(0,89), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* dynamic.meta.pmdesc.units */ { PMDA_PMID(0,90), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* datasize */ { PMDA_PMID(0,91), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, /* darkness */ { PMDA_PMID(0,92), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* ulong.one */ { PMDA_PMID(0,93), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* ulong.ten */ { PMDA_PMID(0,94), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* ulong.hundred */ { PMDA_PMID(0,95), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* ulong.million */ { PMDA_PMID(0,96), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* ulong.write_me */ { PMDA_PMID(0,97), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* ulonglong.one */ { PMDA_PMID(0,98), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* ulonglong.ten */ { PMDA_PMID(0,99), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* ulonglong.hundred */ { PMDA_PMID(0,100), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* ulonglong.million */ { PMDA_PMID(0,101), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* ulonglong.write_me */ { PMDA_PMID(0,102), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* long.bin */ { PMDA_PMID(0,103), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* long.bin_ctr */ { PMDA_PMID(0,104), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, /* ulong.bin */ { PMDA_PMID(0,105), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* ulong.bin_ctr */ { PMDA_PMID(0,106), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, /* float.bin */ { PMDA_PMID(0,107), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* float.bin_ctr */ { PMDA_PMID(0,108), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, /* longlong.bin */ { PMDA_PMID(0,109), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* longlong.bin_ctr */ { PMDA_PMID(0,110), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, /* ulonglong.bin */ { PMDA_PMID(0,111), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* ulonglong.bin_ctr */ { PMDA_PMID(0,112), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, /* double.bin */ { PMDA_PMID(0,113), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* double.bin_ctr */ { PMDA_PMID(0,114), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, /* sample.ulong.count.base */ { PMDA_PMID(0,115), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(-1,0,1,PM_SPACE_MBYTE,0,PM_COUNT_ONE) }, /* sample.ulong.count.deca */ { PMDA_PMID(0,116), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(-1,0,1,PM_SPACE_MBYTE,0,PM_COUNT_ONE+1) }, /* sample.ulong.count.hecto */ { PMDA_PMID(0,117), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(-1,0,1,PM_SPACE_MBYTE,0,PM_COUNT_ONE+2) }, /* sample.ulong.count.kilo */ { PMDA_PMID(0,118), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(-1,0,1,PM_SPACE_MBYTE,0,PM_COUNT_ONE+3) }, /* sample.ulong.count.mega */ { PMDA_PMID(0,119), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(-1,0,1,PM_SPACE_MBYTE,0,PM_COUNT_ONE+6) }, /* scramble.version */ { PMDA_PMID(0,120), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* scramble.bin */ { PMDA_PMID(0,121), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* percontext.control.ctx */ { PMDA_PMID(0,122), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* percontext.control.active */ { PMDA_PMID(0,123), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* percontext.control.start */ { PMDA_PMID(0,124), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* percontext.control.end */ { PMDA_PMID(0,125), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* event.reset */ { PMDA_PMID(0,126), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* event.type */ { PMDA_PMID(0,127), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* event.param_32 */ { PMDA_PMID(0,128), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* event.param_u32 */ { PMDA_PMID(0,129), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* event.param_64 */ { PMDA_PMID(0,130), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* event.param_u64 */ { PMDA_PMID(0,131), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* event.param_float */ { PMDA_PMID(0,132), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* event.param_double */ { PMDA_PMID(0,133), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* event.param_string */ { PMDA_PMID(0,134), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* event.param_aggregate */ { PMDA_PMID(0,135), PM_TYPE_AGGREGATE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* event.records */ { PMDA_PMID(0,136), PM_TYPE_EVENT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* event.no_indom_records */ { PMDA_PMID(0,137), PM_TYPE_EVENT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* * dynamic PMNS ones * secret.bar */ { PMDA_PMID(0,1000), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* secret.foo.one */ { PMDA_PMID(0,1001), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* secret.foo.two */ { PMDA_PMID(0,1002), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* secret.foo.bar.three */ { PMDA_PMID(0,1003), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* secret.foo.bar.four */ { PMDA_PMID(0,1004), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* secret.foo.bar.grunt.five */ { PMDA_PMID(0,1005), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* secret.foo.bar.grunt.snort.six */ { PMDA_PMID(0,1006), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* secret.foo.bar.grunt.snort.seven */ { PMDA_PMID(0,1007), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* bigid */ { PMDA_PMID(0,1023), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* End-of-List */ { PM_ID_NULL, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } } }; static int direct_map = 1; static int ndesc = sizeof(desctab)/sizeof(desctab[0]); static pmDesc magic = { PMDA_PMID(0,86), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_SEC,0) }; static pmdaInstid _colour[] = { { 0, "red" }, { 1, "green" }, { 2, "blue" } }; static pmdaInstid _bin[] = { { 100, "bin-100" }, { 200, "bin-200" }, { 300, "bin-300" }, { 400, "bin-400" }, { 500, "bin-500" }, { 600, "bin-600" }, { 700, "bin-700" }, { 800, "bin-800" }, { 900, "bin-900" } }; static pmdaInstid _scramble[] = { { 100, "bin-100" }, { 200, "bin-200" }, { 300, "bin-300" }, { 400, "bin-400" }, { 500, "bin-500" }, { 600, "bin-600" }, { 700, "bin-700" }, { 800, "bin-800" }, { 900, "bin-900" } }; static long scramble_ver = 0; static pmdaInstid _family[] = { { 0, "colleen" }, { 1, "terry" }, { 2, "emma" }, { 3, "cathy" }, { 4, "fat bald bastard" } }; static pmdaInstid _dodgey[] = { { 1, NULL}, { 2, NULL }, { 3, NULL }, { 4, NULL }, { 5, NULL } }; static pmdaInstid _hordes[] = { { 0, "0" }, { 1, "1" }, { 2, "2" }, { 3, "3" }, { 4, "4" }, { 5, "5" }, { 6, "6" }, { 7, "7" }, { 8, "8" }, { 9, "9" }, { 10, "10" }, { 11, "11" }, { 12, "12" }, { 13, "13" }, { 14, "14" }, { 15, "15" }, { 16, "16" }, { 17, "17" }, { 18, "18" }, { 19, "19" }, { 20, "20" }, { 21, "21" }, { 22, "22" }, { 23, "23" }, { 24, "24" }, { 25, "25" }, { 26, "26" }, { 27, "27" }, { 28, "28" }, { 29, "29" }, { 30, "30" }, { 31, "31" }, { 32, "32" }, { 33, "33" }, { 34, "34" }, { 35, "35" }, { 36, "36" }, { 37, "37" }, { 38, "38" }, { 39, "39" }, { 40, "40" }, { 41, "41" }, { 42, "42" }, { 43, "43" }, { 44, "44" }, { 45, "45" }, { 46, "46" }, { 47, "47" }, { 48, "48" }, { 49, "49" }, { 50, "50" }, { 51, "51" }, { 52, "52" }, { 53, "53" }, { 54, "54" }, { 55, "55" }, { 56, "56" }, { 57, "57" }, { 58, "58" }, { 59, "59" }, { 60, "60" }, { 61, "61" }, { 62, "62" }, { 63, "63" }, { 64, "64" }, { 65, "65" }, { 66, "66" }, { 67, "67" }, { 68, "68" }, { 69, "69" }, { 70, "70" }, { 71, "71" }, { 72, "72" }, { 73, "73" }, { 74, "74" }, { 75, "75" }, { 76, "76" }, { 77, "77" }, { 78, "78" }, { 79, "79" }, { 80, "80" }, { 81, "81" }, { 82, "82" }, { 83, "83" }, { 84, "84" }, { 85, "85" }, { 86, "86" }, { 87, "87" }, { 88, "88" }, { 89, "89" }, { 90, "90" }, { 91, "91" }, { 92, "92" }, { 93, "93" }, { 94, "94" }, { 95, "95" }, { 96, "96" }, { 97, "97" }, { 98, "98" }, { 99, "99" }, {100, "100" }, {101, "101" }, {102, "102" }, {103, "103" }, {104, "104" }, {105, "105" }, {106, "106" }, {107, "107" }, {108, "108" }, {109, "109" }, {110, "110" }, {111, "111" }, {112, "112" }, {113, "113" }, {114, "114" }, {115, "115" }, {116, "116" }, {117, "117" }, {118, "118" }, {119, "119" }, {120, "120" }, {121, "121" }, {122, "122" }, {123, "123" }, {124, "124" }, {125, "125" }, {126, "126" }, {127, "127" }, {128, "128" }, {129, "129" }, {130, "130" }, {131, "131" }, {132, "132" }, {133, "133" }, {134, "134" }, {135, "135" }, {136, "136" }, {137, "137" }, {138, "138" }, {139, "139" }, {140, "140" }, {141, "141" }, {142, "142" }, {143, "143" }, {144, "144" }, {145, "145" }, {146, "146" }, {147, "147" }, {148, "148" }, {149, "149" }, {150, "150" }, {151, "151" }, {152, "152" }, {153, "153" }, {154, "154" }, {155, "155" }, {156, "156" }, {157, "157" }, {158, "158" }, {159, "159" }, {160, "160" }, {161, "161" }, {162, "162" }, {163, "163" }, {164, "164" }, {165, "165" }, {166, "166" }, {167, "167" }, {168, "168" }, {169, "169" }, {170, "170" }, {171, "171" }, {172, "172" }, {173, "173" }, {174, "174" }, {175, "175" }, {176, "176" }, {177, "177" }, {178, "178" }, {179, "179" }, {180, "180" }, {181, "181" }, {182, "182" }, {183, "183" }, {184, "184" }, {185, "185" }, {186, "186" }, {187, "187" }, {188, "188" }, {189, "189" }, {190, "190" }, {191, "191" }, {192, "192" }, {193, "193" }, {194, "194" }, {195, "195" }, {196, "196" }, {197, "197" }, {198, "198" }, {199, "199" }, {200, "200" }, {201, "201" }, {202, "202" }, {203, "203" }, {204, "204" }, {205, "205" }, {206, "206" }, {207, "207" }, {208, "208" }, {209, "209" }, {210, "210" }, {211, "211" }, {212, "212" }, {213, "213" }, {214, "214" }, {215, "215" }, {216, "216" }, {217, "217" }, {218, "218" }, {219, "219" }, {220, "220" }, {221, "221" }, {222, "222" }, {223, "223" }, {224, "224" }, {225, "225" }, {226, "226" }, {227, "227" }, {228, "228" }, {229, "229" }, {230, "230" }, {231, "231" }, {232, "232" }, {233, "233" }, {234, "234" }, {235, "235" }, {236, "236" }, {237, "237" }, {238, "238" }, {239, "239" }, {240, "240" }, {241, "241" }, {242, "242" }, {243, "243" }, {244, "244" }, {245, "245" }, {246, "246" }, {247, "247" }, {248, "248" }, {249, "249" }, {250, "250" }, {251, "251" }, {252, "252" }, {253, "253" }, {254, "254" }, {255, "255" }, {256, "256" }, {257, "257" }, {258, "258" }, {259, "259" }, {260, "260" }, {261, "261" }, {262, "262" }, {263, "263" }, {264, "264" }, {265, "265" }, {266, "266" }, {267, "267" }, {268, "268" }, {269, "269" }, {270, "270" }, {271, "271" }, {272, "272" }, {273, "273" }, {274, "274" }, {275, "275" }, {276, "276" }, {277, "277" }, {278, "278" }, {279, "279" }, {280, "280" }, {281, "281" }, {282, "282" }, {283, "283" }, {284, "284" }, {285, "285" }, {286, "286" }, {287, "287" }, {288, "288" }, {289, "289" }, {290, "290" }, {291, "291" }, {292, "292" }, {293, "293" }, {294, "294" }, {295, "295" }, {296, "296" }, {297, "297" }, {298, "298" }, {299, "299" }, {300, "300" }, {301, "301" }, {302, "302" }, {303, "303" }, {304, "304" }, {305, "305" }, {306, "306" }, {307, "307" }, {308, "308" }, {309, "309" }, {310, "310" }, {311, "311" }, {312, "312" }, {313, "313" }, {314, "314" }, {315, "315" }, {316, "316" }, {317, "317" }, {318, "318" }, {319, "319" }, {320, "320" }, {321, "321" }, {322, "322" }, {323, "323" }, {324, "324" }, {325, "325" }, {326, "326" }, {327, "327" }, {328, "328" }, {329, "329" }, {330, "330" }, {331, "331" }, {332, "332" }, {333, "333" }, {334, "334" }, {335, "335" }, {336, "336" }, {337, "337" }, {338, "338" }, {339, "339" }, {340, "340" }, {341, "341" }, {342, "342" }, {343, "343" }, {344, "344" }, {345, "345" }, {346, "346" }, {347, "347" }, {348, "348" }, {349, "349" }, {350, "350" }, {351, "351" }, {352, "352" }, {353, "353" }, {354, "354" }, {355, "355" }, {356, "356" }, {357, "357" }, {358, "358" }, {359, "359" }, {360, "360" }, {361, "361" }, {362, "362" }, {363, "363" }, {364, "364" }, {365, "365" }, {366, "366" }, {367, "367" }, {368, "368" }, {369, "369" }, {370, "370" }, {371, "371" }, {372, "372" }, {373, "373" }, {374, "374" }, {375, "375" }, {376, "376" }, {377, "377" }, {378, "378" }, {379, "379" }, {380, "380" }, {381, "381" }, {382, "382" }, {383, "383" }, {384, "384" }, {385, "385" }, {386, "386" }, {387, "387" }, {388, "388" }, {389, "389" }, {390, "390" }, {391, "391" }, {392, "392" }, {393, "393" }, {394, "394" }, {395, "395" }, {396, "396" }, {397, "397" }, {398, "398" }, {399, "399" }, {400, "400" }, {401, "401" }, {402, "402" }, {403, "403" }, {404, "404" }, {405, "405" }, {406, "406" }, {407, "407" }, {408, "408" }, {409, "409" }, {410, "410" }, {411, "411" }, {412, "412" }, {413, "413" }, {414, "414" }, {415, "415" }, {416, "416" }, {417, "417" }, {418, "418" }, {419, "419" }, {420, "420" }, {421, "421" }, {422, "422" }, {423, "423" }, {424, "424" }, {425, "425" }, {426, "426" }, {427, "427" }, {428, "428" }, {429, "429" }, {430, "430" }, {431, "431" }, {432, "432" }, {433, "433" }, {434, "434" }, {435, "435" }, {436, "436" }, {437, "437" }, {438, "438" }, {439, "439" }, {440, "440" }, {441, "441" }, {442, "442" }, {443, "443" }, {444, "444" }, {445, "445" }, {446, "446" }, {447, "447" }, {448, "448" }, {449, "449" }, {450, "450" }, {451, "451" }, {452, "452" }, {453, "453" }, {454, "454" }, {455, "455" }, {456, "456" }, {457, "457" }, {458, "458" }, {459, "459" }, {460, "460" }, {461, "461" }, {462, "462" }, {463, "463" }, {464, "464" }, {465, "465" }, {466, "466" }, {467, "467" }, {468, "468" }, {469, "469" }, {470, "470" }, {471, "471" }, {472, "472" }, {473, "473" }, {474, "474" }, {475, "475" }, {476, "476" }, {477, "477" }, {478, "478" }, {479, "479" }, {480, "480" }, {481, "481" }, {482, "482" }, {483, "483" }, {484, "484" }, {485, "485" }, {486, "486" }, {487, "487" }, {488, "488" }, {489, "489" }, {490, "490" }, {491, "491" }, {492, "492" }, {493, "493" }, {494, "494" }, {495, "495" }, {496, "496" }, {497, "497" }, {498, "498" }, {499, "499" } }; static pmdaInstid _events[] = { { 0, "fungus" }, { 1, "bogus" } }; /* all domains supported in this PMDA - one entry each */ static pmdaIndom indomtab[] = { #define COLOUR_INDOM 0 { 0, 3, _colour }, #define BIN_INDOM 1 { 0, 9, _bin }, #define MIRAGE_INDOM 2 { 0, 0, NULL }, #define FAMILY_INDOM 3 { 0, 5, _family }, #define HORDES_INDOM 4 { 0, 500, _hordes }, #define DODGEY_INDOM 5 { 0, 5, _dodgey }, #define DYNAMIC_INDOM 6 { 0, 0, NULL }, #define MANY_INDOM 7 { 0, 5, NULL }, #define SCRAMBLE_INDOM 8 { 0, 9, _scramble }, #define EVENT_INDOM 9 { 0, 2, _events }, { PM_INDOM_NULL, 0, 0 } }; static struct timeval _then; /* time we started */ static time_t _start; /* ditto */ static __pmProfile *_profile; /* last received profile */ static int _x; static pmdaIndom *_idp; static int _singular = -1; /* =0 for singular values */ static int _ordinal = -1; /* >=0 for non-singular values */ static int _control; /* the control variable */ static int _mypid; static int _drift = 200; /* starting value for drift */ static int _sign = -1; /* up/down for drift */ static int _step = 20; /* magnitude of step */ static int _write_me = 2; /* constant, but modifiable */ static __int32_t _long = 13; /* long.write_me */ static __uint32_t _ulong = 13; /* ulong.write_me */ static __int64_t _longlong = 13; /* longlong.write_me */ static __uint64_t _ulonglong = 13;/* ulonglong.write_me */ static float _float = 13; /* float.write_me */ static double _double = 13; /* double.write_me */ static char *_string; /* string.write_me */ static pmValueBlock *_aggr33; /* aggregate.null */ static pmValueBlock *_aggr34; /* aggregate.hullo */ static pmValueBlock *_aggr35; /* aggregate.write_me */ static long _col46; /* lights */ static int _n46; /* sample count for lights */ static long _mag47; /* magnitude */ static int _n47; /* sample count for magnitude */ static __uint32_t _rapid; /* counts @ 8x10^8 per fetch */ static int _dyn_max = -1; static int *_dyn_ctr; static int many_count = 5; static pmValueBlock *sivb=NULL; static __int32_t _wrap = 0; /* wrap.long */ static __uint32_t _u_wrap = 0; /* wrap.ulong */ static __int64_t _ll_wrap = 0; /* wrap.longlong */ static __uint64_t _ull_wrap = 0; /* wrap.ulonglong */ static int _error_code = 0;/* return this! */ static int dodgey = 5; /* dodgey.control */ static int tmp_dodgey = 5; static int new_dodgey = 0; static double scale_step_bytes_up = 1; static double scale_step_bytes_down = 1; static double scale_step_count_up = 1; static double scale_step_count_down = 1; static double scale_step_time_up_secs = 1; static double scale_step_time_up_nanosecs = 1; static double scale_step_none_up = 1; static int scale_step_number[7] = {0,0,0,0,0,0,0}; static __uint32_t const_rate_gradient = 0; static __uint32_t const_rate_value = 10485760; static struct timeval const_rate_timestamp = {0,0}; /* this needs to be visible in pmda.c */ int not_ready = 0; /* sleep interval in seconds */ int sample_done = 0;/* pending request to terminate, see sample_store() */ int _isDSO = 1; /* =0 I am a daemon */ /* * dynamic PMNS metrics ... nothing to do with redo_dynamic() and dynamic * InDoms */ static struct { char *name; pmID pmid; int mark; } dynamic_ones[] = { { "secret.foo.bar.max.redirect", PMDA_PMID(0,0) }, { "secret.bar", PMDA_PMID(0,1000) }, { "secret.foo.one", PMDA_PMID(0,1001) }, { "secret.foo.two", PMDA_PMID(0,1002) }, { "secret.foo.bar.three", PMDA_PMID(0,1003) }, { "secret.foo.bar.four", PMDA_PMID(0,1004) }, { "secret.foo.bar.grunt.five", PMDA_PMID(0,1005) }, { "secret.foo.bar.grunt.snort.six", PMDA_PMID(0,1006) }, { "secret.foo.bar.grunt.snort.huff.puff.seven", PMDA_PMID(0,1007) } }; static int numdyn = sizeof(dynamic_ones)/sizeof(dynamic_ones[0]); static int redo_dynamic(void) { int err; int i; int sep = __pmPathSeparator(); static struct stat lastsbuf; struct stat statbuf; pmdaIndom *idp = &indomtab[DYNAMIC_INDOM]; char mypath[MAXPATHLEN]; snprintf(mypath, sizeof(mypath), "%s%c" "sample" "%c" "dynamic.indom", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); if (stat(mypath, &statbuf) == 0) { #if defined(HAVE_ST_MTIME_WITH_E) && defined(HAVE_STAT_TIME_T) if (statbuf.st_mtime != lastsbuf.st_mtime) #elif defined(HAVE_ST_MTIME_WITH_SPEC) if ((statbuf.st_mtimespec.tv_sec != lastsbuf.st_mtimespec.tv_sec) || (statbuf.st_mtimespec.tv_nsec != lastsbuf.st_mtimespec.tv_nsec)) #elif defined(HAVE_STAT_TIMESTRUC) || defined(HAVE_STAT_TIMESPEC) || defined(HAVE_STAT_TIMESPEC_T) if ((statbuf.st_mtim.tv_sec != lastsbuf.st_mtim.tv_sec) || (statbuf.st_mtim.tv_nsec != lastsbuf.st_mtim.tv_nsec)) #else !bozo! #endif { FILE *fspec; int newinst; char newname[100]; /* hack, secret max */ int numinst; lastsbuf = statbuf; if ((fspec = fopen(mypath, "r")) != NULL) { for (i = 0; i < idp->it_numinst; i++) { free(idp->it_set[i].i_name); } for (i = 0; i <= _dyn_max; i++) { _dyn_ctr[i] = -_dyn_ctr[i]; } free(idp->it_set); idp->it_numinst = 0; idp->it_set = NULL; numinst = 0; for ( ; ; ) { if (fscanf(fspec, "%d %s", &newinst, newname) != 2) break; numinst++; if ((idp->it_set = (pmdaInstid *)realloc(idp->it_set, numinst * sizeof(pmdaInstid))) == NULL) { err = -oserror(); fclose(fspec); return err; } idp->it_set[numinst-1].i_inst = newinst; if ((idp->it_set[numinst-1].i_name = strdup(newname)) == NULL) { err = -oserror(); free(idp->it_set); idp->it_set = NULL; fclose(fspec); return err; } if (newinst > _dyn_max) { if ((_dyn_ctr = (int *)realloc(_dyn_ctr, (newinst+1)*sizeof(_dyn_ctr[0]))) == NULL) { err = -oserror(); free(idp->it_set); idp->it_set = NULL; fclose(fspec); return err; } for (i = _dyn_max+1; i <= newinst; i++) _dyn_ctr[i] = 0; _dyn_max = newinst; } _dyn_ctr[newinst] = -_dyn_ctr[newinst]; } fclose(fspec); idp->it_numinst = numinst; for (i = 0; i <= _dyn_max; i++) { if (_dyn_ctr[i] < 0) _dyn_ctr[i] = 0; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "redo instance domain for dynamic: numinst: %d\n", idp->it_numinst); for (i = 0; i < idp->it_numinst; i++) { fprintf(stderr, " %d \"%s\"", idp->it_set[i].i_inst, idp->it_set[i].i_name); } fputc('\n', stderr); } #endif } } } else { /* control file is not present, empty indom if not already so */ if (idp->it_set != NULL) { for (i = 0; i < idp->it_numinst; i++) { free(idp->it_set[i].i_name); } free(idp->it_set); idp->it_set = NULL; idp->it_numinst = 0; for (i = 0; i <= _dyn_max; i++) { _dyn_ctr[i] = 0; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "redo instance domain for dynamic: numinst: 0 (no control file)\n"); #endif } } for (i = 0; i < idp->it_numinst; i++) { _dyn_ctr[idp->it_set[i].i_inst]++; } return 0; } #define MANY_MAX_LEN 10 static int redo_many(void) { pmdaIndom *idp; int a; static char *tags=NULL; char *tag; /* sanity check, range clip */ if (many_count<0) many_count=0; if (many_count>999999) many_count=999999; idp = &indomtab[MANY_INDOM]; /* realloc instances buffer */ idp->it_set = realloc(idp->it_set, many_count*sizeof(pmdaInstid)); if (!idp->it_set) { idp->it_numinst=0; many_count=0; return -oserror(); } /* realloc string buffer */ tags = realloc(tags, many_count*MANY_MAX_LEN); if (!idp->it_set) { idp->it_numinst=0; many_count=0; return -oserror(); } /* set number of instances */ idp->it_numinst=many_count; /* generate instances */ tag=tags; for (a=0;ait_set[a].i_inst=a; idp->it_set[a].i_name=tag; tag+=sprintf(tag,"i-%d",a)+1; } return 0; } static int redo_mirage(void) { static time_t doit = 0; time_t now; int i; int j; static int newinst = 0; pmdaIndom *idp; now = time(NULL); if (now < doit) return 0; idp = &indomtab[MIRAGE_INDOM]; if (idp->it_set == NULL) { /* first time */ if ((idp->it_set = (pmdaInstid *)malloc(sizeof(pmdaInstid))) == NULL) return -oserror(); if ((idp->it_set[0].i_name = (char *)malloc(5)) == NULL) { idp->it_set = NULL; return -oserror(); } idp->it_numinst = 1; idp->it_set[0].i_inst = 0; sprintf(idp->it_set[0].i_name, "m-%02d", 0); } else { int numinst; int cull; numinst = 1; cull = idp->it_numinst > 12 ? idp->it_numinst/2 : idp->it_numinst; for (i = 1; i < idp->it_numinst; i++) { if (lrand48() % 1000 < 1000 / cull) { /* delete this one */ free(idp->it_set[i].i_name); continue; } idp->it_set[numinst++] = idp->it_set[i]; } if (numinst != idp->it_numinst) { if ((idp->it_set = (pmdaInstid *)realloc(idp->it_set, numinst * sizeof(pmdaInstid))) == NULL) { idp->it_set = NULL; idp->it_numinst = 0; return -oserror(); } idp->it_numinst = numinst; } for (i = 0; i < 2; i++) { if (lrand48() % 1000 < 500) { /* add a new one */ numinst++; if ((idp->it_set = (pmdaInstid *)realloc(idp->it_set, numinst * sizeof(pmdaInstid))) == NULL) { idp->it_set = NULL; idp->it_numinst = 0; return -oserror(); } if ((idp->it_set[numinst-1].i_name = (char *)malloc(5)) == NULL) { idp->it_set = NULL; return -oserror(); } for ( ; ; ) { newinst = (newinst + 1) % 50; for (j = 0; j < idp->it_numinst; j++) { if (idp->it_set[j].i_inst == newinst) break; } if (j == idp->it_numinst) break; } idp->it_numinst = numinst; idp->it_set[numinst-1].i_inst = newinst; sprintf(idp->it_set[numinst-1].i_name, "m-%02d", newinst); } } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "redo instance domain for mirage: numinst: %d\n", idp->it_numinst); for (i = 0; i < idp->it_numinst; i++) { fprintf(stderr, " %d \"%s\"", idp->it_set[i].i_inst, idp->it_set[i].i_name); } fputc('\n', stderr); } #endif doit = now + 10; /* no more than once every 10 seconds */ return 0; } static void redo_dodgey(void) { int j; int k; if (dodgey <= 5) { tmp_dodgey = dodgey; new_dodgey = 0; /* re-build full instance table */ for (j = 0; j < 5; j++) { _dodgey[j].i_inst = j+1; _dodgey[j].i_name[1] = '0' + j+1; } indomtab[DODGEY_INDOM].it_numinst = 5; } else { j = (int)(lrand48() % 1000); if (j < 33) tmp_dodgey = PM_ERR_NOAGENT; else if (j < 66) tmp_dodgey = PM_ERR_AGAIN; else if (j < 99) tmp_dodgey = PM_ERR_APPVERSION; else { /* * create partial instance table, instances appear * at random with prob = 0.5 */ k = 0; for (j = 0; j < 5; j++) { if (lrand48() % 100 < 49) { _dodgey[k].i_inst = j+1; _dodgey[k].i_name[1] = '0' + j+1; k++; } } tmp_dodgey = indomtab[DODGEY_INDOM].it_numinst = k; } /* fetches before re-setting */ new_dodgey = (int)(lrand48() % dodgey); } } /* * count the number of instances in an instance domain */ static int cntinst(pmInDom indom) { pmdaIndom *idp; if (indom == PM_INDOM_NULL) return 1; for (idp = indomtab; idp->it_indom != PM_INDOM_NULL; idp++) { if (idp->it_indom == indom) return idp->it_numinst; } __pmNotifyErr(LOG_WARNING, "cntinst: unknown pmInDom 0x%x", indom); return 0; } /* * commence a new round of instance selection * flag == 1 for prefetch instance counting * flag == 0 for iteration over instances to retrieve values */ static void startinst(pmInDom indom, int flag) { _ordinal = _singular = -1; if (indom == PM_INDOM_NULL) { /* singular value */ _singular = 0; return; } for (_idp = indomtab; _idp->it_indom != PM_INDOM_NULL; _idp++) { if (_idp->it_indom == indom) { /* multiple values are possible */ _ordinal = 0; if (flag == 1 && _idp == &indomtab[SCRAMBLE_INDOM]) { /* * indomtab[BIN_INDOM].it_set[] is the same size as * indomtab[SCRAMBLE_INDOM].it_set[] (maxnuminst * entries) */ int i; int k = 0; int maxnuminst = indomtab[BIN_INDOM].it_numinst; srand48((scramble_ver << 10) + 13); scramble_ver++; for (i = 0; i < maxnuminst; i++) indomtab[SCRAMBLE_INDOM].it_set[i].i_inst = PM_IN_NULL; for (i = 0; i < maxnuminst; i++) { /* skip 1/3 of instances */ if ((lrand48() % 100) < 33) continue; /* order of instances is random */ for ( ; ; ) { k = lrand48() % maxnuminst; if (indomtab[SCRAMBLE_INDOM].it_set[k].i_inst != PM_IN_NULL) continue; indomtab[SCRAMBLE_INDOM].it_set[k].i_inst = indomtab[BIN_INDOM].it_set[i].i_inst; indomtab[SCRAMBLE_INDOM].it_set[k].i_name = indomtab[BIN_INDOM].it_set[i].i_name; break; } } /* pack to remove skipped instances */ k = 0; for (i = 0; i < maxnuminst; i++) { if (indomtab[SCRAMBLE_INDOM].it_set[i].i_inst == PM_IN_NULL) continue; if (k < i) { indomtab[SCRAMBLE_INDOM].it_set[k].i_inst = indomtab[SCRAMBLE_INDOM].it_set[i].i_inst; indomtab[SCRAMBLE_INDOM].it_set[k].i_name = indomtab[SCRAMBLE_INDOM].it_set[i].i_name; } k++; } indomtab[SCRAMBLE_INDOM].it_numinst = k; } break; } } } /* * find next selected instance, if any * * EXCEPTION PCP 2.1.1: make use of __pmProfile much smarter, particularly when state for * this indom is PM_PROFILE_EXCLUDE, then only need to consider inst * values in the profile - this is a performance enhancement, and * the simple method is functionally complete, particularly for * stable (non-varying) instance domains */ static int nextinst(int *inst) { int j; if (_singular == 0) { /* PM_INDOM_NULL ... just the one value */ *inst = 0; _singular = -1; return 1; } if (_ordinal >= 0) { /* scan for next value in the profile */ for (j = _ordinal; j < _idp->it_numinst; j++) { if (__pmInProfile(_idp->it_indom, _profile, _idp->it_set[j].i_inst)) { *inst = _idp->it_set[j].i_inst; _ordinal = j+1; return 1; } } _ordinal = -1; } return 0; } /* * this routine is called at initialization to patch up any parts of the * desctab that cannot be statically initialized, and to optionally * modify our Performance Metrics Domain Id (dom) */ static void init_tables(int dom) { int i; __pmInDom_int b_indom; __pmInDom_int *indomp; __pmID_int *pmidp; pmDesc *dp; /* serial numbering is arbitrary, but must be unique in this PMD */ b_indom.flag = 0; b_indom.domain = dom; b_indom.serial = 1; indomp = (__pmInDom_int *)&indomtab[COLOUR_INDOM].it_indom; *indomp = b_indom; b_indom.serial++; indomp = (__pmInDom_int *)&indomtab[BIN_INDOM].it_indom; *indomp = b_indom; b_indom.serial++; indomp = (__pmInDom_int *)&indomtab[MIRAGE_INDOM].it_indom; *indomp = b_indom; b_indom.serial++; indomp = (__pmInDom_int *)&indomtab[FAMILY_INDOM].it_indom; *indomp = b_indom; b_indom.serial++; indomp = (__pmInDom_int *)&indomtab[HORDES_INDOM].it_indom; *indomp = b_indom; b_indom.serial++; indomp = (__pmInDom_int *)&indomtab[DODGEY_INDOM].it_indom; *indomp = b_indom; b_indom.serial++; indomp = (__pmInDom_int *)&indomtab[DYNAMIC_INDOM].it_indom; *indomp = b_indom; b_indom.serial++; indomp = (__pmInDom_int *)&indomtab[MANY_INDOM].it_indom; *indomp = b_indom; b_indom.serial++; indomp = (__pmInDom_int *)&indomtab[SCRAMBLE_INDOM].it_indom; *indomp = b_indom; b_indom.serial++; indomp = (__pmInDom_int *)&indomtab[EVENT_INDOM].it_indom; *indomp = b_indom; /* rewrite indom in desctab[] */ for (dp = desctab; dp->pmid != PM_ID_NULL; dp++) { switch (dp->pmid) { case PMDA_PMID(0,5): /* colour */ case PMDA_PMID(0,92): /* darkness */ dp->indom = indomtab[COLOUR_INDOM].it_indom; break; case PMDA_PMID(0,6): /* bin */ case PMDA_PMID(0,48): /* bucket */ case PMDA_PMID(0,50): /* part_bin */ case PMDA_PMID(0,51): /* bogus_bin */ case PMDA_PMID(0,103): /* long.bin */ case PMDA_PMID(0,104): /* long.bin_ctr */ case PMDA_PMID(0,105): /* ulong.bin */ case PMDA_PMID(0,106): /* ulong.bin_ctr */ case PMDA_PMID(0,107): /* float.bin */ case PMDA_PMID(0,108): /* float.bin_ctr */ case PMDA_PMID(0,109): /* longlong.bin */ case PMDA_PMID(0,110): /* longlong.bin_ctr */ case PMDA_PMID(0,111): /* ulonglong.bin */ case PMDA_PMID(0,112): /* ulonglong.bin_ctr */ case PMDA_PMID(0,113): /* double.bin */ case PMDA_PMID(0,114): /* double.bin_ctr */ dp->indom = indomtab[BIN_INDOM].it_indom; break; case PMDA_PMID(0,37): /* mirage */ dp->indom = indomtab[MIRAGE_INDOM].it_indom; break; case PMDA_PMID(0,38): /* mirage-longlong */ dp->indom = indomtab[MIRAGE_INDOM].it_indom; break; case PMDA_PMID(0,49): /* needprofile */ dp->indom = indomtab[FAMILY_INDOM].it_indom; break; case PMDA_PMID(0,52): /* hordes.one */ case PMDA_PMID(0,53): /* hordes.two */ dp->indom = indomtab[HORDES_INDOM].it_indom; break; case PMDA_PMID(0,62): /* dodgey.value */ dp->indom = indomtab[DODGEY_INDOM].it_indom; break; case PMDA_PMID(0,76): /* dynamic.counter */ case PMDA_PMID(0,77): /* dynamic.discrete */ case PMDA_PMID(0,78): /* dynamic.instant */ dp->indom = indomtab[DYNAMIC_INDOM].it_indom; break; case PMDA_PMID(0,80): /* many.int */ dp->indom = indomtab[MANY_INDOM].it_indom; break; case PMDA_PMID(0,121): /* scramble.bin */ dp->indom = indomtab[SCRAMBLE_INDOM].it_indom; break; case PMDA_PMID(0,136): /* event.records */ dp->indom = indomtab[EVENT_INDOM].it_indom; break; } } /* merge performance domain id part into PMIDs in pmDesc table */ for (i = 0; desctab[i].pmid != PM_ID_NULL; i++) { pmidp = (__pmID_int *)&desctab[i].pmid; pmidp->domain = dom; if (direct_map && pmidp->item != i) { direct_map = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { __pmNotifyErr(LOG_WARNING, "sample_init: direct map disabled @ desctab[%d]", i); } #endif } } ndesc--; pmidp = (__pmID_int *)&magic.pmid; pmidp->domain = dom; /* local hacks */ _string = (char *)malloc(3); strcpy(_string, "13"); _aggr33 = (pmValueBlock *)malloc(PM_VAL_HDR_SIZE); _aggr33->vlen = PM_VAL_HDR_SIZE + 0; _aggr33->vtype = PM_TYPE_AGGREGATE; _aggr34 = (pmValueBlock *)malloc(PM_VAL_HDR_SIZE+strlen("hullo world!")); _aggr34->vlen = PM_VAL_HDR_SIZE + strlen("hullo world!"); _aggr34->vtype = PM_TYPE_AGGREGATE; memcpy(_aggr34->vbuf, "hullo world!", strlen("hullo world!")); _aggr35 = (pmValueBlock *)malloc(PM_VAL_HDR_SIZE+strlen("13")); _aggr35->vlen = PM_VAL_HDR_SIZE + strlen("13"); _aggr35->vtype = PM_TYPE_AGGREGATE; memcpy(_aggr35->vbuf, "13", strlen("13")); (void)redo_many(); } static int sample_profile(__pmProfile *prof, pmdaExt *ep) { sample_inc_recv(ep->e_context); _profile = prof; return 0; } static int sample_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *ep) { int i; __pmInResult *res; pmdaIndom *idp; int err = 0; sample_inc_recv(ep->e_context); sample_inc_xmit(ep->e_context); if (not_ready > 0) { return limbo(); } if (need_mirage && (i = redo_mirage()) < 0) return i; if (need_dynamic && (i = redo_dynamic()) < 0) return i; /* * check this is an instance domain we know about -- code below * assumes this test is complete */ for (idp = indomtab; idp->it_indom != PM_INDOM_NULL; idp++) { if (idp->it_indom == indom) break; } if (idp->it_indom == PM_INDOM_NULL) return PM_ERR_INDOM; if ((res = (__pmInResult *)malloc(sizeof(*res))) == NULL) return -oserror(); res->indom = indom; if (name == NULL && inst == PM_IN_NULL) res->numinst = cntinst(indom); else res->numinst = 1; if (inst == PM_IN_NULL) { if ((res->instlist = (int *)malloc(res->numinst * sizeof(res->instlist[0]))) == NULL) { free(res); return -oserror(); } } else res->instlist = NULL; if (name == NULL) { if ((res->namelist = (char **)malloc(res->numinst * sizeof(res->namelist[0]))) == NULL) { __pmFreeInResult(res); return -oserror(); } for (i = 0; i < res->numinst; i++) res->namelist[0] = NULL; } else res->namelist = NULL; if (name == NULL && inst == PM_IN_NULL) { /* return inst and name for everything */ for (i = 0; i < res->numinst; i++) { res->instlist[i] = idp->it_set[i].i_inst; if ((res->namelist[i] = strdup(idp->it_set[i].i_name)) == NULL) { __pmFreeInResult(res); return -oserror(); } } } else if (name == NULL) { /* given an inst, return the name */ for (i = 0; i < idp->it_numinst; i++) { char *p; if (inst == idp->it_set[i].i_inst) { if ((res->namelist[0] = strdup(idp->it_set[i].i_name)) == NULL) { __pmFreeInResult(res); return -oserror(); } for (p = res->namelist[0]; *p; p++) { if (*p == ' ') { *p = '\0'; break; } } break; } } if (i == idp->it_numinst) err = 1; } else if (inst == PM_IN_NULL) { /* given a name, return an inst */ char *p; long len; for (p = name; *p; p++) { if (*p == ' ') break; } len = p - name; for (i = 0; i < idp->it_numinst; i++) { if (strncmp(name, idp->it_set[i].i_name, len) == 0 && strlen(idp->it_set[i].i_name) >= len && (idp->it_set[i].i_name[len] == '\0' || idp->it_set[i].i_name[len] == ' ')) { res->instlist[0] = idp->it_set[i].i_inst; break; } } if (i == idp->it_numinst) err = 1; } else err = 1; if (err == 1) { /* bogus arguments or instance id/name */ __pmFreeInResult(res); return PM_ERR_INST; } *result = res; return 0; } static int sample_pmid(const char *name, pmID *pmid, pmdaExt *pmda) { int i; const char *p; /* skip the sample. or sampledso. part */ for (p = name; *p != '.' && *p; p++) ; if (*p == '.') p++; for (i = 0; i < numdyn; i++) { if (strcmp(p, dynamic_ones[i].name) == 0) { *pmid = dynamic_ones[i].pmid; return 0; } } return PM_ERR_NAME; } static int sample_name(pmID pmid, char ***nameset, pmdaExt *pmda) { size_t len = 0; int nmatch = 0; int i; char *pfx; char *p; char **list; if (_isDSO) pfx = "sampledso."; else pfx = "sample."; for (i = 0; i < numdyn; i++) { if (dynamic_ones[i].pmid == pmid) { nmatch++; len += strlen(pfx)+strlen(dynamic_ones[i].name)+1; } } if (nmatch == 0) return PM_ERR_PMID; len += nmatch*sizeof(char *); /* pointers to names */ if ((list = (char **)malloc(len)) == NULL) return -oserror(); p = (char *)&list[nmatch]; nmatch = 0; for (i = 0; i < numdyn; i++) { if (dynamic_ones[i].pmid == pmid) { list[nmatch++] = p; strcpy(p, pfx); p += strlen(pfx); strcpy(p, dynamic_ones[i].name); p += strlen(dynamic_ones[i].name); *p++ = '\0'; } } *nameset = list; return nmatch; } static int sample_children(const char *name, int traverse, char ***offspring, int **status, pmdaExt *pmda) { int i; int j; int nmatch; int pfxlen; int namelen; const char *p; char *q; char *qend = NULL; char **chn = NULL; int *sts = NULL; size_t len = 0; size_t tlen = 0; /* skip the sample. or sampledso. part */ for (p = name; *p != '.' && *p; p++) ; pfxlen = p - name; if (*p == '.') p++; namelen = strlen(p); nmatch = 0; for (i = 0; i < numdyn; i++) { q = dynamic_ones[i].name; if (strncmp(p, q, namelen) != 0) { /* no prefix match */ dynamic_ones[i].mark = 0; continue; } if (traverse == 0 && q[namelen] != '.') { /* cannot be a child of name */ dynamic_ones[i].mark = 0; continue; } if (traverse == 1 && q[namelen] != '.' && q[namelen] != '\0') { /* cannot be name itself, not a child of name */ dynamic_ones[i].mark = 0; continue; } if (traverse == 0) { qend = &q[namelen+1]; while (*qend && *qend != '.') qend++; tlen = qend - &q[namelen+1]; for (j = 0; j < nmatch; j++) { if (strncmp(&q[namelen+1], chn[j], tlen) == 0) { /* already seen this child ... skip it */ break; } } } else { /* traversal ... need this one */ j = nmatch; } if (j == nmatch) { nmatch++; if ((chn = (char **)realloc(chn, nmatch*sizeof(chn[0]))) == NULL) { j = -oserror(); goto fail; } if ((sts = (int *)realloc(sts, nmatch*sizeof(sts[0]))) == NULL) { j = -oserror(); goto fail; } if (traverse == 0) { /* * descendents only ... just want the next component of * PMNS name */ if ((chn[nmatch-1] = (char *)malloc(tlen+1)) == NULL) { j = -oserror(); goto fail; } strncpy(chn[nmatch-1], &q[namelen+1], tlen); chn[nmatch-1][tlen] = '\0'; if (*qend == '.') sts[nmatch-1] = PMNS_NONLEAF_STATUS; else sts[nmatch-1] = PMNS_LEAF_STATUS; } else { /* * traversal ... want the whole name including the prefix * part */ tlen = pfxlen + strlen(dynamic_ones[i].name) + 2; if ((chn[nmatch-1] = malloc(tlen)) == NULL) { j = -oserror(); goto fail; } strncpy(chn[nmatch-1], name, pfxlen); chn[nmatch-1][pfxlen] = '.'; chn[nmatch-1][pfxlen+1] = '\0'; strcat(chn[nmatch-1], dynamic_ones[i].name); sts[nmatch-1] = PMNS_LEAF_STATUS; } len += tlen + 1; } } if (nmatch == 0) { *offspring = NULL; *status = NULL; } else { if ((chn = (char **)realloc(chn, nmatch*sizeof(chn[0])+len)) == NULL) { j = -oserror(); goto fail; } q = (char *)&chn[nmatch]; for (j = 0; j < nmatch; j++) { strcpy(q, chn[j]); free(chn[j]); chn[j] = q; q += strlen(chn[j])+1; } *offspring = chn; *status = sts; } return nmatch; fail: /* * come here with j as negative error code, and some allocation failure for * sts[] or chn[] or chn[nmatch-1][] */ if (sts != NULL) free(sts); if (chn != NULL) { for (i = 0; i < nmatch-1; i++) { if (chn[i] != NULL) free(chn[i]); } free(chn); } return j; } static int sample_attribute(int ctx, int attr, const char *value, int length, pmdaExt *pmda) { /* * We have no special security or other requirements, so we're just * going to log any connection attribute messages we happen to get * from pmcd (handy for demo and testing purposes). */ if (pmDebug & DBG_TRACE_AUTH) { char buffer[256]; if (!__pmAttrStr_r(attr, value, buffer, sizeof(buffer))) { __pmNotifyErr(LOG_ERR, "Bad Attribute: ctx=%d, attr=%d\n", ctx, attr); } else { buffer[sizeof(buffer)-1] = '\0'; __pmNotifyErr(LOG_INFO, "Attribute: ctx=%d %s", ctx, buffer); } } return 0; } /* * high precision counter */ typedef union { __uint32_t half[2]; __uint64_t full; } pmHPC_t; #ifdef HAVE_NETWORK_BYTEORDER #define PM_HPC_TOP 0 #define PM_HPC_BOTTOM 1 #else #define PM_HPC_TOP 1 #define PM_HPC_BOTTOM 0 #endif void _pmHPCincr(pmHPC_t *ctr, __uint32_t val) { if (val < ctr->half[PM_HPC_BOTTOM]) /* assume single overflow */ ctr->half[PM_HPC_TOP]++; ctr->half[PM_HPC_BOTTOM] = val; } static pmHPC_t rapid_ctr; static int sample_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *ep) { int i; /* over pmidlist[] */ int j; /* over vset->vlist[] */ int sts; int need; int inst; int numval; static pmResult *res; static int maxnpmids; static int nbyte; __uint32_t *ulp; unsigned long ul; struct timeval now; pmValueSet *vset; pmDesc *dp; __pmID_int *pmidp; pmAtomValue atom; int type; sample_inc_recv(ep->e_context); sample_inc_xmit(ep->e_context); if (not_ready > 0) { return limbo(); } if (numpmid > maxnpmids) { if (res != NULL) free(res); /* (numpmid - 1) because there's room for one valueSet in a pmResult */ need = (int)sizeof(pmResult) + (numpmid - 1) * (int)sizeof(pmValueSet *); if ((res = (pmResult *)malloc(need)) == NULL) return -oserror(); maxnpmids = numpmid; } res->timestamp.tv_sec = 0; res->timestamp.tv_usec = 0; res->numpmid = numpmid; if (need_mirage && (j = redo_mirage()) < 0) return j; if (need_dynamic && (j = redo_dynamic()) < 0) return j; if (new_dodgey < 0) redo_dodgey(); for (i = 0; i < numpmid; i++) { pmidp = (__pmID_int *)&pmidlist[i]; if (direct_map) { j = pmidp->item; if (j < ndesc && desctab[j].pmid == pmidlist[i]) { dp = &desctab[j]; goto doit; } } for (dp = desctab; dp->pmid != PM_ID_NULL; dp++) { if (dp->pmid == pmidlist[i]) break; } doit: if (dp->pmid != PM_ID_NULL) { /* the special cases */ if (pmidp->cluster == 0 && pmidp->item == 86) { dp = &magic; numval = 1; } else if (pmidp->cluster == 0 && pmidp->item == 54) numval = PM_ERR_PMID; else if (pmidp->cluster == 0 && pmidp->item == 92) /* darkness */ numval = 0; else if (pmidp->cluster == 0 && (pmidp->item == 127 || /* event.type */ pmidp->item == 128 || /* event.param_32 */ pmidp->item == 129 || /* event.param_u32 */ pmidp->item == 130 || /* event.param_64 */ pmidp->item == 131 || /* event.param_u64 */ pmidp->item == 132 || /* event.param_float */ pmidp->item == 133 || /* event.param_double */ pmidp->item == 134 || /* event.param_string */ pmidp->item == 135)) /* event.param_aggregate */ numval = 0; else if (dp->type == PM_TYPE_NOSUPPORT) numval = PM_ERR_APPVERSION; else if (dp->indom != PM_INDOM_NULL) { /* count instances in the profile */ numval = 0; /* special case(s) */ if (pmidp->cluster == 0 && pmidp->item == 49) { int kp; /* needprofile - explict instances required */ numval = PM_ERR_PROFILE; for (kp = 0; kp < _profile->profile_len; kp++) { if (_profile->profile[kp].indom != dp->indom) continue; if (_profile->profile[kp].state == PM_PROFILE_EXCLUDE && _profile->profile[kp].instances_len != 0) numval = 0; break; } } else if (pmidp->cluster == 0 && (pmidp->item == 76 || pmidp->item == 77 || pmidp->item == 78)) { /* * if $(PCP_VAR_DIR)/pmdas/sample/dynamic.indom is not present, * then numinst will be zero after the redo_dynamic() call * in sample_init(), which makes zero loops through the * fetch loop, so cannot set need_dynamic there ... * do it here if not already turned on */ if (need_dynamic == 0) { need_dynamic = 1; if ((j = redo_dynamic()) < 0) return j; } } if (numval == 0) { /* count instances in indom */ startinst(dp->indom, 1); while (nextinst(&inst)) { /* special case ... not all here for part_bin */ if (pmidp->cluster == 0 && pmidp->item == 50 && (inst % 200) == 0) continue; numval++; } } } else { /* special case(s) for singular instance domains */ if (pmidp->cluster == 0 && pmidp->item == 9) { /* surprise! no value available */ numval = 0; } else numval = 1; } } else numval = 0; /* Must use individual malloc()s because of pmFreeResult() */ if (numval >= 1) res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue)); else res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) - sizeof(pmValue)); if (vset == NULL) { if (i) { res->numpmid = i; __pmFreeResultValues(res); } return -oserror(); } vset->pmid = pmidlist[i]; vset->numval = numval; vset->valfmt = PM_VAL_INSITU; if (vset->numval <= 0) continue; if (dp->indom == PM_INDOM_NULL) inst = PM_IN_NULL; else { startinst(dp->indom, 0); nextinst(&inst); } type = dp->type; j = 0; do { if (pmidp->cluster == 0 && pmidp->item == 50 && inst % 200 == 0) goto skip; if (pmidp->cluster == 0 && pmidp->item == 51 && inst % 200 == 0) inst += 50; if (j == numval) { /* more instances than expected! */ numval++; res->vset[i] = vset = (pmValueSet *)realloc(vset, sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue)); if (vset == NULL) { if (i) { res->numpmid = i; __pmFreeResultValues(res); } return -oserror(); } } vset->vlist[j].inst = inst; /* * we mostly have cluster 0, metric already found in desctab[] * so no checking needed */ if (pmidp->cluster == 0) { switch (pmidp->item) { case 0: atom.l = _control; break; case 1: if (_mypid == 0) _mypid = (int)getpid(); atom.ul = _mypid; break; case 2: atom.ul = time(NULL) - _start; break; case 3: __pmtimevalNow(&now); atom.d = 1000 * __pmtimevalSub(&now, &_then); break; case 4: atom.l = 42; break; case 5: switch (inst) { case 0: /* "red" */ _x = (_x + 1) % 100; atom.l = _x + 100; break; case 1: /* "green" */ _x = (_x + 1) % 100; atom.l = _x + 200; break; case 2: /* "blue" */ _x = (_x + 1) % 100; atom.l = _x + 300; break; } break; case 6: case 48: case 50: case 51: case 103: /* long.bin & long.bin_ctr */ case 104: case 121: /* scramble.bin */ /* the value is the instance identifier (sic) */ atom.l = inst; break; /* and ditto for all the other type variants of "bin" */ case 105: /* ulong.bin & ulong.bin_ctr */ case 106: atom.ul = inst; break; case 107: /* float.bin & float.bin_ctr */ case 108: atom.f = inst; break; case 109: /* longlong.bin & longlong.bin_ctr */ case 110: atom.ll = inst; break; case 111: /* ulonglong.bin & ulonglong.bin_ctr */ case 112: atom.ull = inst; break; case 113: /* double.bin & double.bin_ctr */ case 114: atom.d = inst; break; case 7: /* drift */ _drift = _drift + _sign * (int)(lrand48() % 50); if (_drift < 0) _drift = 0; atom.l = _drift; if ((lrand48() % 100) < 20) { if (_sign == 1) _sign = -1; else _sign = 1; } break; case 63: /* step_counter */ case 8: /* step every 30 seconds */ atom.l = (1 + (time(NULL) - _start) / 30) * _step; break; case 40: /* total pdu count for all contexts */ atom.ll = (__int64_t)sample_get_recv(CTX_ALL) + (__int64_t)sample_get_xmit(CTX_ALL); break; case 41: /* recv pdu count for all contexts */ atom.l = sample_get_recv(CTX_ALL); break; case 42: /* xmit pdu count for all contexts */ atom.l = sample_get_xmit(CTX_ALL); break; case 43: case 44: case 45: case 122: case 123: case 124: case 125: /* percontext.pdu */ /* percontext.recv-pdu */ /* percontext.xmit-pdu */ /* percontext.control.ctx */ /* percontext.control.active */ /* percontext.control.start */ /* percontext.control.end */ atom.l = sample_ctx_fetch(ep->e_context, pmidp->item); break; case 37: /* mirage */ _x = (_x + 1) % 100; atom.l = (inst + 1) * 100 - _x; need_mirage = 1; break; case 36: /* write_me */ atom.l = _write_me; break; case 39: /* sysinfo */ if (!sivb) { /* malloc and init the pmValueBlock for * sysinfo first type around */ int size = sizeof(pmValueBlock) - sizeof(int); #ifdef IS_SOLARIS size += MAX_SYSNAME; #else size += sizeof (struct sysinfo); #endif if ((sivb = calloc(1, size)) == NULL ) return PM_ERR_GENERIC; sivb->vlen = size; sivb->vtype = PM_TYPE_AGGREGATE; } #ifdef HAVE_SYSINFO #ifdef IS_SOLARIS sysinfo(SI_SYSNAME, sivb->vbuf, MAX_SYSNAME); #else sysinfo((struct sysinfo *)sivb->vbuf); #endif #else strncpy((char *)sivb->vbuf, si.dummy, sizeof(struct sysinfo)); #endif atom.vbp = sivb; /* * pv:782029 The actual type must be PM_TYPE_AGGREGATE, * but we have to tell pmStuffValue it's a * PM_TYPE_AGGREGATE_STATIC */ type = PM_TYPE_AGGREGATE_STATIC; break; case 46: if (_n46 == 0) { _col46 = lrand48() % 3; _n46 = 1 + (int)(lrand48() % 10); } _n46--; switch (_col46) { case 0: atom.cp = "red"; break; case 1: atom.cp = "yellow"; break; case 2: atom.cp = "green"; break; } break; case 47: if (_n47 == 0) { _mag47 = 1 << (1 + (int)(lrand48() % 6)); _n47 = 1 + (int)(lrand48() % 5); } _n47--; atom.l = (__int32_t)_mag47; break; case 38: /* mirage-longlong */ _x = (_x + 1) % 100; atom.ll = (inst + 1) * 100 - _x; atom.ll *= 1000000; need_mirage = 1; break; case 49: /* need profile */ switch (inst) { case 0: /* "colleen" */ atom.f = 3.05; break; case 1: /* "terry" */ atom.f = 12.05; break; case 2: /* "emma" */ case 3: /* "cathy" */ atom.f = 11.09; break; case 4: /* "alexi" */ atom.f = 5.26; break; } break; case 10: /* long.* group */ atom.l = 1; break; case 11: atom.l = 10; break; case 12: atom.l = 100; break; case 13: atom.l = 1000000; break; case 14: atom.l = (__int32_t)_long; break; case 20: /* longlong.* group */ #if !defined(HAVE_CONST_LONGLONG) atom.ll = 1; #else atom.ll = 1LL; #endif break; case 21: #if !defined(HAVE_CONST_LONGLONG) atom.ll = 10; #else atom.ll = 10LL; #endif break; case 22: #if !defined(HAVE_CONST_LONGLONG) atom.ll = 100; #else atom.ll = 100LL; #endif break; case 23: #if !defined(HAVE_CONST_LONGLONG) atom.ll = 1000000; #else atom.ll = 1000000LL; #endif break; case 24: atom.ll = _longlong; break; case 15: /* float.* group */ atom.f = 1; break; case 16: atom.f = 10; break; case 17: atom.f = 100; break; case 18: atom.f = 1000000; break; case 19: atom.f = _float; break; case 25: /* double.* group */ atom.d = 1; break; case 26: atom.d = 10; break; case 27: atom.d = 100; break; case 28: atom.d = 1000000; break; case 29: atom.d = _double; break; case 30: atom.cp = ""; break; case 31: atom.cp = "hullo world!"; break; case 32: atom.cp = _string; break; case 33: atom.vbp = _aggr33; break; case 34: atom.vbp = _aggr34; break; case 35: atom.vbp = _aggr35; break; case 52: atom.l = inst; break; case 53: atom.l = 499 - inst; break; case 56: atom.l = not_ready; break; case 57: _wrap += INT_MAX / 2 - 1; atom.l = _wrap; break; case 58: _u_wrap += UINT_MAX / 2 - 1; atom.ul = _u_wrap; break; case 59: _ll_wrap += LONGLONG_MAX / 2 - 1; atom.ll = _ll_wrap; break; case 60: _ull_wrap += ULONGLONG_MAX / 2 - 1; atom.ull = _ull_wrap; break; case 61: atom.l = dodgey; break; case 62: if (dodgey > 5 && j == 0) new_dodgey--; if (tmp_dodgey <= 0) { j = tmp_dodgey; goto done; } else if (tmp_dodgey <= 5) { if (inst > tmp_dodgey) goto skip; } atom.l = (int)(lrand48() % 101); break; case 64: _rapid += 80000000; _pmHPCincr(&rapid_ctr, _rapid); atom.ul = (__uint32_t)(rapid_ctr.full * 10); break; case 65: /* scale_step.bytes_up */ atom.d = scale_step_bytes_up; if (++scale_step_number[0] % 5 == 0) { if (scale_step_bytes_up < 1024.0*1024.0*1024.0*1024.0) scale_step_bytes_up *= 2; else scale_step_bytes_up = 1; } break; case 66: /* scale_step.bytes_down */ atom.d = scale_step_bytes_down; if (++scale_step_number[1] % 5 == 0) { if (scale_step_bytes_down > 1) scale_step_bytes_down /= 2; else scale_step_bytes_down = 1024.0*1024.0*1024.0*1024.0; } break; case 67: /* scale_step.count_up */ atom.d = scale_step_count_up; if (++scale_step_number[2] % 5 == 0) { if (scale_step_count_up < 1.0e12) scale_step_count_up *= 10; else scale_step_count_up = 1; } break; case 68: /* scale_step.count_down */ atom.d = scale_step_count_down; if (++scale_step_number[3] % 5 == 0) { if (scale_step_count_down > 1) scale_step_count_down /= 10; else scale_step_count_down = 1.0e12; } break; case 69: /* scale_step.time_up_secs */ atom.d = scale_step_time_up_secs; if (++scale_step_number[4] % 5 == 0) { if (scale_step_time_up_secs < 60*60*24) scale_step_time_up_secs *= 10; else scale_step_time_up_secs = 1; } break; case 70: /* scale_step.time_up_nanosecs */ atom.d = scale_step_time_up_nanosecs; if (++scale_step_number[5] % 5 == 0) { if (scale_step_time_up_nanosecs < 1e9*60*60*24) scale_step_time_up_nanosecs *= 10; else scale_step_time_up_nanosecs = 1; } break; case 71: /* scale_step.none_up */ atom.d = scale_step_none_up; if (++scale_step_number[6] % 5 == 0) { if (scale_step_none_up < 10000000) scale_step_none_up *= 10; else scale_step_none_up = 1; } break; case 72: /* const_rate.value */ __pmtimevalNow(&now); atom.ul = const_rate_value + const_rate_gradient * __pmtimevalSub(&now, &const_rate_timestamp); const_rate_timestamp = now; const_rate_value = atom.ul; break; case 73: /* const_rate.gradient */ atom.ul = const_rate_gradient; break; case 74: /* error_code */ atom.l = _error_code; break; case 75: /* error_check */ if (_error_code < 0) return _error_code; atom.l = 0; break; case 76: /* dynamic.counter */ case 77: /* dynamic.discrete */ case 78: /* dynamic.instant */ if (inst > _dyn_max) { /* bad instance! */ goto done; } atom.l = _dyn_ctr[inst]; break; case 79: /* many.count */ atom.l=many_count; break; case 80: /* many.int */ atom.l = inst; break; case 81: /* byte_ctr */ nbyte += lrand48() % 1024; atom.l = nbyte; break; case 82: /* byte_rate */ atom.l = (int)(lrand48() % 1024); break; case 83: /* kbyte_ctr */ nbyte += lrand48() % 1024; atom.l = nbyte; break; case 84: /* kbyte_rate */ atom.l = (int)(lrand48() % 1024); break; case 85: /* byte_rate_per_hour */ atom.l = (int)(lrand48() % 1024); break; case 86: /* dynamic.meta.metric */ switch (magic.type) { case PM_TYPE_32: atom.l = 42; break; case PM_TYPE_U32: atom.ul = 42; break; case PM_TYPE_64: atom.ll = 42; break; case PM_TYPE_U64: atom.ull = 42; break; case PM_TYPE_FLOAT: atom.f = 42; break; case PM_TYPE_DOUBLE: atom.d = 42; break; default: /* do nothing in other cases ... return garbage */ break; } break; case 87: /* dynamic.meta.pmdesc.type */ atom.ul = magic.type; break; case 88: /* dynamic.meta.pmdesc.indom */ atom.ul = magic.indom; break; case 89: /* dynamic.meta.pmdesc.sem */ atom.ul = magic.sem; break; case 90: /* dynamic.meta.pmdesc.units */ ulp = (__uint32_t *)&magic.units; atom.ul = *ulp; break; case 91: /* datasize */ __pmProcessDataSize(&ul); atom.ul = ul; break; /* no case 92 for darkeness, handled above */ case 93: /* ulong.* group */ atom.ul = 1; break; case 94: atom.ul = 10; break; case 95: atom.ul = 100; break; case 96: atom.ul = 1000000; break; case 97: atom.ul = (__int32_t)_ulong; break; case 98: /* ulonglong.* group */ #if !defined(HAVE_CONST_LONGLONG) atom.ull = 1; #else atom.ull = 1ULL; #endif break; case 99: #if !defined(HAVE_CONST_LONGLONG) atom.ull = 10; #else atom.ull = 10ULL; #endif break; case 100: #if !defined(HAVE_CONST_LONGLONG) atom.ull = 100; #else atom.ull = 100ULL; #endif break; case 101: #if !defined(HAVE_CONST_LONGLONG) atom.ull = 1000000; #else atom.ull = 1000000ULL; #endif break; case 102: atom.ull = _ulonglong; break; case 115: /* ulong.count.base */ atom.ul = 42000000; break; case 116: /* ulong.count.deca */ atom.ul = 4200000; break; case 117: /* ulong.count.hecto */ atom.ul = 420000; break; case 118: /* ulong.count.kilo */ atom.ul = 42000; break; case 119: /* ulong.count.mega */ atom.ul = 42; break; case 120: /* scramble.version */ atom.ll = scramble_ver; break; case 126: /* event.reset */ atom.l = event_get_fetch_count(); break; case 136: /* event.records */ case 137: /* event.no_indom_records */ sts = sample_fetch_events(&atom.vbp, inst); if (sts < 0) return sts; break; case 1000: /* secret.bar */ atom.cp = "foo"; break; case 1001: /* secret.foo.one */ atom.l = 1; break; case 1002: /* secret.foo.two */ atom.l = 2; break; case 1003: /* secret.foo.bar.three */ atom.l = 3; break; case 1004: /* secret.foo.bar.four */ atom.l = 4; break; case 1005: /* secret.foo.bar.grunt.five */ atom.l = 5; break; case 1006: /* secret.foo.bar.grunt.snort.six */ atom.l = 6; break; case 1007: /* secret.foo.bar.grunt.snort.seven */ atom.l = 7; break; case 1023: /* bigid */ atom.l = 4194303; break; } } if ((sts = __pmStuffValue(&atom, &vset->vlist[j], type)) < 0) { __pmFreeResultValues(res); return sts; } vset->valfmt = sts; j++; /* next element in vlist[] for next instance */ skip: ; } while (dp->indom != PM_INDOM_NULL && nextinst(&inst)); done: vset->numval = j; } *resp = res; return PMDA_FETCH_STATIC; } static int sample_desc(pmID pmid, pmDesc *desc, pmdaExt *ep) { int i; __pmID_int *pmidp = (__pmID_int *)&pmid; sample_inc_recv(ep->e_context); sample_inc_xmit(ep->e_context); if (not_ready > 0) { return limbo(); } if (direct_map) { i = pmidp->item; if (i < ndesc && desctab[i].pmid == pmid) goto doit; } for (i = 0; desctab[i].pmid != PM_ID_NULL; i++) { if (desctab[i].pmid == pmid) { doit: /* the special cases */ if (pmidp->item == 54) return PM_ERR_PMID; else if (pmidp->item == 75 && _error_code < 0) /* error_check and error_code armed */ return _error_code; else if (pmidp->item == 86) *desc = magic; else *desc = desctab[i]; return 0; } } return PM_ERR_PMID; } static int sample_text(int ident, int type, char **buffer, pmdaExt *ep) { int sts; sample_inc_recv(ep->e_context); sample_inc_xmit(ep->e_context); if (not_ready > 0) { return limbo(); } if (ident & PM_TEXT_PMID) { __pmID_int *pmidp = (__pmID_int *)&ident; int i; if (direct_map) { i = pmidp->item; if (i < ndesc && desctab[i].pmid == (pmID)ident) goto doit; } for (i = 0; desctab[i].pmid != PM_ID_NULL; i++) { if (desctab[i].pmid == (pmID)ident) { doit: /* the special cases */ if (pmidp->item == 75 && _error_code < 0) /* error_check and error_code armed */ return _error_code; break; } } } sts = pmdaText(ident, type, buffer, ep); return sts; } static int sample_store(pmResult *result, pmdaExt *ep) { int i; pmValueSet *vsp; pmDesc *dp; __pmID_int *pmidp; int sts = 0; __int32_t *lp; pmAtomValue av; sample_inc_recv(ep->e_context); sample_inc_xmit(ep->e_context); if (not_ready > 0) { return limbo(); } for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; for (dp = desctab; dp->pmid != PM_ID_NULL; dp++) { if (dp->pmid == vsp->pmid) break; } if (dp->pmid == PM_ID_NULL) { /* not one of our metrics */ sts = PM_ERR_PMID; break; } pmidp = (__pmID_int *)&vsp->pmid; if (pmidp->cluster != 0) { sts = PM_ERR_PMID; break; } /* * for this PMD, the metrics that support modification * via pmStore() mostly demand a single value, encoded in * the result structure as PM_VAL_INSITU format */ switch (pmidp->item) { case 24: /* longlong.write_me */ case 29: /* double.write_me */ case 32: /* string.write_me */ case 35: /* aggregate.write_me */ case 102: /* ulonglong.write_me */ case 120: /* scramble.ver */ if (vsp->numval != 1 || vsp->valfmt == PM_VAL_INSITU) sts = PM_ERR_CONV; break; case 74: /* error_code */ case 73: /* const_rate.gradient */ case 61: /* dodgey.control */ case 56: /* not_ready */ case 36: case 42: case 41: case 14: /* long.write_me */ case 8: /* step */ case 7: /* drift */ case 0: /* control */ case 79: /* many.count */ case 87: /* dynamic.meta.pmdesc.type */ case 88: /* dynamic.meta.pmdesc.indom */ case 89: /* dynamic.meta.pmdesc.sem */ case 90: /* dynamic.meta.pmdesc.units */ case 97: /* ulong.write_me */ case 126: /* event.reset */ if (vsp->numval != 1 || vsp->valfmt != PM_VAL_INSITU) sts = PM_ERR_CONV; break; case 19: /* float.write_me */ if (vsp->numval != 1) sts = PM_ERR_CONV; /* accommodate both old and new encoding styles for floats */ break; case 40: /* pdu */ /* value is ignored, so valfmt does not matter */ if (vsp->numval != 1) sts = PM_ERR_CONV; break; default: sts = PM_ERR_PERMISSION; break; } if (sts != 0) break; if ((sts = pmExtractValue(vsp->valfmt, &vsp->vlist[0], dp->type, &av, dp->type)) < 0) break; /* * we only have cluster 0, metric already found in desctab[], * so no checking needed nor outer case on pmidp->cluster */ switch (pmidp->item) { case 0: /* control */ _control = av.l; switch (_control) { case -1: /* terminate, if we are not a DSO implementation */ sample_done = 1; break; default: pmDebug = _control; break; } break; case 7: /* drift */ _drift = av.l; break; case 8: /* step */ _step = av.l; break; case 14: /* long.write_me */ _long = av.l; break; case 24: /* longlong.write_me */ _longlong = av.ll; break; case 19: /* float.write_me */ _float = av.f; break; case 40: /* pdu */ /* * for the pdu group, the value is ignored, and the only * operation is to reset the counter(s) */ sample_clr_recv(CTX_ALL); sample_clr_xmit(CTX_ALL); break; case 41: sample_clr_recv(CTX_ALL); break; case 42: sample_clr_xmit(CTX_ALL); break; case 36: _write_me = av.l; break; case 29: /* double.write_me */ _double = av.d; break; case 32: /* string.write_me */ free(_string); _string = av.cp; break; case 35: /* aggregate.write_me */ free(_aggr35); _aggr35 = av.vbp; break; case 56: /* not_ready */ not_ready = av.l; break; case 61: /* dodgey.control */ dodgey = av.l; redo_dodgey(); break; case 73: /* const_rate.gradient */ const_rate_gradient = av.ul; break; case 74: /* error_code */ _error_code = av.l; break; case 79: /* many.count */ many_count = av.l; /* change the size of the many instance domain */ _error_code = redo_many(); break; case 87: /* dynamic.meta.pmdesc.type */ magic.type = av.l; break; case 88: /* dynamic.meta.pmdesc.indom */ magic.indom = av.l; break; case 89: /* dynamic.meta.pmdesc.sem */ magic.sem = av.l; break; case 90: /* dynamic.meta.pmdesc.units */ lp = (__int32_t *)&magic.units; *lp = av.l; break; case 97: /* ulong.write_me */ _ulong = av.ul; break; case 102: /* ulonglong.write_me */ _ulonglong = av.ull; break; case 120: /* scramble.version */ scramble_ver = 0; for (i = 0; i < indomtab[BIN_INDOM].it_numinst; i++) { indomtab[SCRAMBLE_INDOM].it_set[i].i_inst = indomtab[BIN_INDOM].it_set[i].i_inst; indomtab[SCRAMBLE_INDOM].it_set[i].i_name = indomtab[BIN_INDOM].it_set[i].i_name; } indomtab[SCRAMBLE_INDOM].it_numinst = indomtab[BIN_INDOM].it_numinst; break; case 126: /* event.reset */ event_set_fetch_count(av.l); break; default: sts = PM_ERR_PERMISSION; break; } } return sts; } void __PMDA_INIT_CALL sample_init(pmdaInterface *dp) { char helppath[MAXPATHLEN]; int i; if (_isDSO) { int sep = __pmPathSeparator(); snprintf(helppath, sizeof(helppath), "%s%c" "sample" "%c" "dsohelp", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_LATEST, "sample DSO", helppath); } else { __pmProcessDataSize(NULL); } if (dp->status != 0) return; dp->comm.flags |= PDU_FLAG_AUTH; dp->version.any.fetch = sample_fetch; dp->version.any.desc = sample_desc; dp->version.any.instance = sample_instance; dp->version.any.text = sample_text; dp->version.any.store = sample_store; dp->version.any.profile = sample_profile; dp->version.four.pmid = sample_pmid; dp->version.four.name = sample_name; dp->version.four.children = sample_children; dp->version.six.attribute = sample_attribute; pmdaSetEndContextCallBack(dp, sample_ctx_end); pmdaInit(dp, NULL, 0, NULL, 0); /* don't use indomtab or metrictab */ __pmtimevalNow(&_then); _start = time(NULL); init_tables(dp->domain); init_events(dp->domain); redo_mirage(); redo_dynamic(); /* initialization of domain in PMIDs for dynamic PMNS entries */ for (i = 0; i < numdyn; i++) { ((__pmID_int *)&dynamic_ones[i].pmid)->domain = dp->domain; } /* * Max Matveev wanted this sort of redirection, so first entry is * actually a redirect to PMID 2.4.1 (pmcd.agent.status) */ ((__pmID_int *)&dynamic_ones[0].pmid)->domain = 2; ((__pmID_int *)&dynamic_ones[0].pmid)->cluster = 4; ((__pmID_int *)&dynamic_ones[0].pmid)->item = 1; /* * for gcc/egcs, statically initializing these cased the strings * to be read-only, causing SEGV in redo_dynamic ... so do the * initialization dynamically here. */ _dodgey[0].i_name = strdup("d1"); _dodgey[1].i_name = strdup("d2"); _dodgey[2].i_name = strdup("d3"); _dodgey[3].i_name = strdup("d4"); _dodgey[4].i_name = strdup("d5"); } pcp-3.8.12ubuntu1/src/pmdas/sample/src/events.c0000664000000000000000000002074312272262501016223 0ustar /* * The "event" records here are all fake. But the logic does show how * a real PMDA could deliver values for metrics of type PM_TYPE_EVENT. * * Copyright (c) 2010 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "events.h" static int nfetch; static int xnfetch; static int myarray[2]; static int mydomain; void init_events(int domain) { mydomain = domain; } int event_get_fetch_count(void) { return nfetch % 4; } void event_set_fetch_count(int c) { xnfetch = nfetch = c; } int sample_fetch_events(pmValueBlock **vbpp, int inst) { int c; int sts; int flags; struct timeval stamp; pmAtomValue atom; static int first = 1; static pmValueBlock *aggr; static char aggrval[] = { '\01', '\03', '\07', '\017', '\037', '\077', '\177', '\377' }; static pmID pmid_type = PMDA_PMID(0,127); /* event.type */ static pmID pmid_32 = PMDA_PMID(0,128); /* event.param_32 */ static pmID pmid_u32 = PMDA_PMID(0,129); /* event.param_u32 */ static pmID pmid_64 = PMDA_PMID(0,130); /* event.param_64 */ static pmID pmid_u64 = PMDA_PMID(0,131); /* event.param_u64 */ static pmID pmid_float = PMDA_PMID(0,132); /* event.param_float */ static pmID pmid_double = PMDA_PMID(0,133); /* event.param_double */ static pmID pmid_string = PMDA_PMID(0,134); /* event.param_string */ static pmID pmid_aggregate = PMDA_PMID(0,135); /* event.param_aggregate */ if (nfetch >= 0) c = nfetch % 4; else { /* one of the error injection cases */ c = nfetch; } if (first) { int i; first = 0; for (i = 0; i < 2; i++) { myarray[i] = pmdaEventNewArray(); if (myarray[i] < 0) { fprintf(stderr, "pmdaEventNewArray failed: %s\n", pmErrStr(myarray[i])); exit(1); } } /* * fix the domain field in the event parameter PMIDs ... * note these PMIDs must match the corresponding metrics in * desctab[] and this cannot easily be done automatically */ ((__pmID_int *)&pmid_type)->domain = mydomain; ((__pmID_int *)&pmid_32)->domain = mydomain; ((__pmID_int *)&pmid_u32)->domain = mydomain; ((__pmID_int *)&pmid_64)->domain = mydomain; ((__pmID_int *)&pmid_u64)->domain = mydomain; ((__pmID_int *)&pmid_float)->domain = mydomain; ((__pmID_int *)&pmid_double)->domain = mydomain; ((__pmID_int *)&pmid_string)->domain = mydomain; ((__pmID_int *)&pmid_aggregate)->domain = mydomain; /* build pmValueBlock for aggregate value */ aggr = (pmValueBlock *)malloc(PM_VAL_HDR_SIZE + sizeof(aggrval)); aggr->vtype = PM_TYPE_AGGREGATE; aggr->vlen = PM_VAL_HDR_SIZE + sizeof(aggrval); memcpy(aggr->vbuf, (void *)aggrval, sizeof(aggrval)); } if (inst == PM_IN_NULL) inst = 1; pmdaEventResetArray(myarray[inst]); gettimeofday(&stamp, NULL); if (inst == 0) { /* original instance ... */ /* rebase event records 10 secs in past, add 1 sec for each new record */ stamp.tv_sec -= 10; switch (c) { case 0: /* * 1st fetch * No events */ break; case 1: /* * 2nd fetch * 1 event with NO parameters */ flags = PM_EVENT_FLAG_POINT; if ((sts = pmdaEventAddRecord(myarray[inst], &stamp, flags)) < 0) return sts; stamp.tv_sec++; break; case 2: /* * 3rd fetch * 1 event with one U32 parameter * 1 event with 2 parameters(U32 and 64 types) */ flags = PM_EVENT_FLAG_POINT; if ((sts = pmdaEventAddRecord(myarray[inst], &stamp, flags)) < 0) return sts; stamp.tv_sec++; atom.ul = 1; if ((sts = pmdaEventAddParam(myarray[inst], pmid_type, PM_TYPE_U32, &atom)) < 0) return sts; if ((sts = pmdaEventAddRecord(myarray[inst], &stamp, flags)) < 0) return sts; stamp.tv_sec++; atom.ul = 2; if ((sts = pmdaEventAddParam(myarray[inst], pmid_type, PM_TYPE_U32, &atom)) < 0) return sts; atom.ll = -3; if ((sts = pmdaEventAddParam(myarray[inst], pmid_64, PM_TYPE_64, &atom)) < 0) return sts; break; case 3: /* * 4th fetch * 1 event start with 3 parameters (U32, U64 and STRING types) * 1 event with 3 parameters (U32 and 2 DOUBLE types) * 1 event end with 6 (U32, U64, STRING, STRING, 32 and U32 types) * 7 "missed" events * 1 event with 3 parameters (U32, FLOAT and AGGREGATE types) */ flags = PM_EVENT_FLAG_START|PM_EVENT_FLAG_ID|PM_EVENT_FLAG_PARENT; if ((sts = pmdaEventAddRecord(myarray[inst], &stamp, flags)) < 0) return sts; stamp.tv_sec++; atom.ul = 4; if ((sts = pmdaEventAddParam(myarray[inst], pmid_type, PM_TYPE_U32, &atom)) < 0) return sts; atom.ull = 5; if ((sts = pmdaEventAddParam(myarray[inst], pmid_u64, PM_TYPE_U64, &atom)) < 0) return sts; atom.cp = "6"; if ((sts = pmdaEventAddParam(myarray[inst], pmid_string, PM_TYPE_STRING, &atom)) < 0) return sts; flags = PM_EVENT_FLAG_POINT; if ((sts = pmdaEventAddRecord(myarray[inst], &stamp, flags)) < 0) return sts; stamp.tv_sec++; atom.ul = 7; if ((sts = pmdaEventAddParam(myarray[inst], pmid_type, PM_TYPE_U32, &atom)) < 0) return sts; atom.d = 8; if ((sts = pmdaEventAddParam(myarray[inst], pmid_double, PM_TYPE_DOUBLE, &atom)) < 0) return sts; atom.d = -9; if ((sts = pmdaEventAddParam(myarray[inst], pmid_double, PM_TYPE_DOUBLE, &atom)) < 0) return sts; flags = PM_EVENT_FLAG_END; if ((sts = pmdaEventAddRecord(myarray[inst], &stamp, flags)) < 0) return sts; stamp.tv_sec++; atom.ul = 10; if ((sts = pmdaEventAddParam(myarray[inst], pmid_type, PM_TYPE_U32, &atom)) < 0) return sts; atom.ull = 11; if ((sts = pmdaEventAddParam(myarray[inst], pmid_u64, PM_TYPE_U64, &atom)) < 0) return sts; atom.cp = "twelve"; if ((sts = pmdaEventAddParam(myarray[inst], pmid_string, PM_TYPE_STRING, &atom)) < 0) return sts; atom.cp = "thirteen"; if ((sts = pmdaEventAddParam(myarray[inst], pmid_string, PM_TYPE_STRING, &atom)) < 0) return sts; atom.l = -14; if ((sts = pmdaEventAddParam(myarray[inst], pmid_32, PM_TYPE_32, &atom)) < 0) return sts; atom.ul = 15; if ((sts = pmdaEventAddParam(myarray[inst], pmid_u32, PM_TYPE_U32, &atom)) < 0) return sts; /* "missed" 7 records */ if ((sts = pmdaEventAddMissedRecord(myarray[inst], &stamp, 7)) < 0) return sts; stamp.tv_sec++; flags = PM_EVENT_FLAG_POINT; if ((sts = pmdaEventAddRecord(myarray[inst], &stamp, flags)) < 0) return sts; stamp.tv_sec++; atom.ul = 16; if ((sts = pmdaEventAddParam(myarray[inst], pmid_type, PM_TYPE_U32, &atom)) < 0) return sts; atom.f = -17; if ((sts = pmdaEventAddParam(myarray[inst], pmid_float, PM_TYPE_FLOAT, &atom)) < 0) return sts; atom.vbp = aggr; if ((sts = pmdaEventAddParam(myarray[inst], pmid_aggregate, PM_TYPE_AGGREGATE, &atom)) < 0) return sts; break; case -1: /* error injection */ flags = PM_EVENT_FLAG_POINT; if ((sts = pmdaEventAddRecord(myarray[inst], &stamp, flags)) < 0) return sts; stamp.tv_sec++; atom.ul = c; if ((sts = pmdaEventAddParam(myarray[inst], pmid_type, PM_TYPE_U32, &atom)) < 0) return sts; /* pmid that is not in PMNS and not known to the PMDA */ if ((sts = pmdaEventAddParam(myarray[inst], PMDA_PMID(100,200), PM_TYPE_U32, &atom)) < 0) return sts; break; } nfetch++; } else { /* * new, boring instance ..., either instance ["bogus"] for * sample.events.rrecord or singular instance for * sample.events.no_indom_records */ static char record1[20]; static char record2[] = "bingo!"; flags = PM_EVENT_FLAG_POINT; if ((sts = pmdaEventAddRecord(myarray[inst], &stamp, flags)) < 0) return sts; snprintf(record1, sizeof(record1), "fetch #%d", xnfetch); atom.cp = record1; if ((sts = pmdaEventAddParam(myarray[inst], pmid_string, PM_TYPE_STRING, &atom)) < 0) return sts; if ((xnfetch % 3) == 0) { if ((sts = pmdaEventAddRecord(myarray[inst], &stamp, flags)) < 0) return sts; atom.cp = record2; if ((sts = pmdaEventAddParam(myarray[inst], pmid_string, PM_TYPE_STRING, &atom)) < 0) return sts; } xnfetch++; } *vbpp = (pmValueBlock *)pmdaEventGetAddr(myarray[inst]); return 0; } pcp-3.8.12ubuntu1/src/pmdas/sample/src/GNUmakefile0000664000000000000000000000302112272262501016613 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../../.. include $(TOPDIR)/src/include/builddefs # # The TARGETS macro must be set to the name of the executable we # are building. # IAM = sample CMDTARGET = pmda$(IAM)$(EXECSUFFIX) LIBTARGET = pmda_$(IAM).$(DSOSUFFIX) TARGETS = $(CMDTARGET) $(LIBTARGET) PMDAINIT = $(IAM)_init PMDADIR = $(PCP_PMDAS_DIR)/sample CFILES = pmda.c sample.c percontext.c events.c HFILES = percontext.h events.h VERSION_SCRIPT = exports LDIRT = $(TARGETS) $(VERSION_SCRIPT) LCFLAGS = -DDYNAMIC_SPEC=\"$(PCP_PMDAS_DIR)/sample/dynamic.indom\" LCFLAGS += $(INVISIBILITY) LLDLIBS = $(PCP_PMDALIB) default: ../domain.h $(TARGETS) pmda.o sample.o percontext.o: percontext.h sample.o events.o: events.h pmda.o: $(VERSION_SCRIPT) ../domain.h: $(MAKE) -C .. domain.h $(VERSION_SCRIPT): $(VERSION_SCRIPT_MAKERULE) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(CMDTARGET) $(LIBTARGET) $(PMDADIR) include $(BUILDRULES) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmdas/sample/src/events.h0000664000000000000000000000165612272262501016232 0ustar /* * The "event" records here are all fake. But the logic does show how * a real PMDA could deliver values for metrics of type PM_TYPE_EVENT. * * Copyright (c) 2010 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _EVENTS_H #define _EVENTS_H extern void init_events(int); extern int sample_fetch_events(pmValueBlock **, int); extern void event_set_fetch_count(int); extern int event_get_fetch_count(void); #endif /* _EVENTS_H */ pcp-3.8.12ubuntu1/src/pmdas/sample/src/percontext.h0000664000000000000000000000201112272262501017103 0ustar /* * Some functions become per-client (of pmcd) with the introduction * of PMDA_INTERFACE_5. * * Copyright (c) 2010 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _PERCONTEXT_H #define _PERCONTEXT_H extern int sample_get_recv(int); extern int sample_get_xmit(int); extern void sample_clr_recv(int); extern void sample_clr_xmit(int); extern void sample_inc_recv(int); extern void sample_inc_xmit(int); extern int sample_ctx_fetch(int, int); extern void sample_ctx_end(int); #define CTX_ALL -1 #endif /* _PERCONTEXT_H */ pcp-3.8.12ubuntu1/src/pmdas/sample/src/pmda.c0000664000000000000000000000650212272262501015635 0ustar /* * Copyright (c) 1997-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Generic driver for a daemon-based PMDA */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "../domain.h" #include "percontext.h" extern void sample_init(pmdaInterface *); extern int sample_done; extern int not_ready; static pmdaInterface dispatch; /* * simulate PMDA busy (not responding to PDUs) */ int limbo(void) { __pmSendError(dispatch.version.two.ext->e_outfd, FROM_ANON, PM_ERR_PMDANOTREADY); while (not_ready > 0) not_ready = sleep(not_ready); return PM_ERR_PMDAREADY; } /* * callback from pmdaMain */ static int check(void) { if (access("/tmp/sample.unavail", F_OK) == 0) return PM_ERR_AGAIN; return 0; } /* * callback from pmdaMain */ static void done(void) { if (sample_done) exit(0); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" "\nExactly one of the following options may appear:\n" " -6 port expect PMCD to connect on given ipv6 port (number or name)\n" " -i port expect PMCD to connect on given inet port (number or name)\n" " -p expect PMCD to supply stdin/stdout (pipe)\n" " -u socket expect PMCD to connect on given unix domain socket\n" " -U username run under specified user account\n", stderr); exit(1); } int main(int argc, char **argv) { int c, errflag = 0; int sep = __pmPathSeparator(); char helppath[MAXPATHLEN]; char *username; extern int _isDSO; _isDSO = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(helppath, sizeof(helppath), "%s%c" "sample" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_LATEST, pmProgname, SAMPLE, "sample.log", helppath); while ((c = pmdaGetOpt(argc, argv, "D:d:i:l:pu:U:6:?", &dispatch, &errflag)) != EOF) { switch (c) { case 'U': username = optarg; break; default: errflag++; break; } } if (errflag) usage(); pmdaOpenLog(&dispatch); __pmSetProcessIdentity(username); sample_init(&dispatch); pmdaSetCheckCallBack(&dispatch, check); pmdaSetDoneCallBack(&dispatch, done); pmdaConnect(&dispatch); #ifdef HAVE_SIGHUP /* * Non-DSO agents should ignore gratuitous SIGHUPs, e.g. from xwsh * when launched by the PCP Tutorial! */ signal(SIGHUP, SIG_IGN); #endif pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/sample/src/percontext.c0000664000000000000000000001445212272262501017112 0ustar /* * Some functions become per-client (of pmcd) with the introduction * of PMDA_INTERFACE_5. * * Copyright (c) 2010 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "percontext.h" typedef struct { int state; /* active or inactive context */ int recv_pdu; /* count of PDUs received from this context */ int xmit_pdu; /* count of PDUs sent to this context */ } perctx_t; /* values for state */ #define CTX_INACTIVE 0 #define CTX_ACTIVE 1 static perctx_t *ctxtab; static int num_ctx; static int num_start; /* count of new contexts noted */ static int num_end; /* count of end context events */ static int num_recv_pdu; /* recv count from closed contexts */ static int num_xmit_pdu; /* xmit count from closed contexts */ void sample_clr_recv(int ctx) { if (ctx == CTX_ALL) { int i; for (i = 0; i < num_ctx; i++) { if (ctxtab[i].state == CTX_ACTIVE) ctxtab[i].recv_pdu = 0; } num_recv_pdu = 0; } else if (ctx < 0 || ctx >= num_ctx || ctxtab[ctx].state == CTX_INACTIVE) { fprintf(stderr, "Botch: sample_clr_recv(%d) num_ctx=%d", ctx, num_ctx); if (ctx >= 0 && ctx < num_ctx) fprintf(stderr, " ctxtab[] is inactive"); fputc('\n', stderr); } else ctxtab[ctx].recv_pdu = 0; } void sample_clr_xmit(int ctx) { if (ctx == CTX_ALL) { int i; for (i = 0; i < num_ctx; i++) { if (ctxtab[i].state == CTX_ACTIVE) ctxtab[i].xmit_pdu = 0; } num_xmit_pdu = 0; } else if (ctx < 0 || ctx >= num_ctx || ctxtab[ctx].state == CTX_INACTIVE) { fprintf(stderr, "Botch: sample_clr_xmit(%d) num_ctx=%d", ctx, num_ctx); if (ctx >= 0 && ctx < num_ctx) fprintf(stderr, " ctxtab[] is inactive"); fputc('\n', stderr); } else ctxtab[ctx].xmit_pdu = 0; } int sample_get_recv(int ctx) { if (ctx == CTX_ALL) { int i; int ans = num_recv_pdu; for (i = 0; i < num_ctx; i++) { if (ctxtab[i].state == CTX_ACTIVE) ans += ctxtab[i].recv_pdu; } return ans; } else if (ctx < 0 || ctx >= num_ctx || ctxtab[ctx].state == CTX_INACTIVE) { return PM_ERR_NOCONTEXT; } else return ctxtab[ctx].recv_pdu; } int sample_get_xmit(int ctx) { if (ctx == CTX_ALL) { int i; int ans = num_xmit_pdu; for (i = 0; i < num_ctx; i++) { if (ctxtab[i].state == CTX_ACTIVE) ans += ctxtab[i].xmit_pdu; } return ans; } else if (ctx < 0 || ctx >= num_ctx || ctxtab[ctx].state == CTX_INACTIVE) { return PM_ERR_NOCONTEXT; } else return ctxtab[ctx].xmit_pdu; } static void growtab(int ctx) { ctxtab = (perctx_t *)realloc(ctxtab, (ctx+1)*sizeof(ctxtab[0])); if (ctxtab == NULL) { __pmNoMem("growtab", (ctx+1)*sizeof(ctxtab[0]), PM_FATAL_ERR); /*NOTREACHED*/ } while (num_ctx <= ctx) { ctxtab[num_ctx].state = CTX_INACTIVE; ctxtab[num_ctx].recv_pdu = 0; ctxtab[num_ctx].xmit_pdu = 0; num_ctx++; } ctxtab[ctx].state = CTX_INACTIVE; } void sample_inc_recv(int ctx) { if (ctx < 0) { fprintf(stderr, "Botch: sample_inc_recv(%d)!\n", ctx); return; } if (ctx >= num_ctx) growtab(ctx); if (ctxtab[ctx].state == CTX_INACTIVE) { num_start++; ctxtab[ctx].state = CTX_ACTIVE; ctxtab[ctx].recv_pdu = 0; ctxtab[ctx].xmit_pdu = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "sample_inc_recv(%d) [new context, num_ctx=%d]\n", ctx, num_ctx); } #endif } ctxtab[ctx].recv_pdu++; } void sample_inc_xmit(int ctx) { if (ctx < 0 || ctx >= num_ctx || ctxtab[ctx].state == CTX_INACTIVE) { fprintf(stderr, "Botch: sample_inc_xmit(%d) num_ctx=%d", ctx, num_ctx); if (ctx >= 0 && ctx < num_ctx) fprintf(stderr, " ctxtab[] is inactive"); fputc('\n', stderr); return; } if (ctx >= num_ctx) growtab(ctx); ctxtab[ctx].xmit_pdu++; } int sample_ctx_fetch(int ctx, int item) { if (ctx < 0 || ctx >= num_ctx || ctxtab[ctx].state == CTX_INACTIVE) { fprintf(stderr, "Botch: sample_ctx_fetch(%d, %d) num_ctx=%d", ctx, item, num_ctx); if (ctx >= 0 && ctx < num_ctx) fprintf(stderr, " ctxtab[] is inactive"); fputc('\n', stderr); return PM_ERR_NOCONTEXT; } if (item == 43) { /* percontext.pdu */ return ctxtab[ctx].recv_pdu + ctxtab[ctx].xmit_pdu; } else if (item == 44) { /* percontext.recv-pdu */ return ctxtab[ctx].recv_pdu; } else if (item == 45) { /* percontext.xmit-pdu */ return ctxtab[ctx].xmit_pdu; } else if (item == 122) { /* percontext.control.ctx */ return num_ctx; } else if (item == 123) { /* percontext.control.active */ int i; int ans = 0; for (i = 0; i < num_ctx; i++) { if (ctxtab[i].state == CTX_ACTIVE) ans++; } return ans; } else if (item == 124) { /* percontext.control.start */ return num_start; } else if (item == 125) { /* percontext.control.end */ return num_end; } fprintf(stderr, "Botch: sample_ctx_fetch(%d, %d): item bad!\n", ctx, item); return PM_ERR_PMID; } void sample_ctx_end(int ctx) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "sample_ctx_end(%d) [context is ", ctx); if (ctx < 0 || ctx >= num_ctx) fprintf(stderr, "unknown, num_ctx=%d", num_ctx); else if (ctxtab[ctx].state == CTX_ACTIVE) fprintf(stderr, "active"); else if (ctxtab[ctx].state == CTX_INACTIVE) fprintf(stderr, "inactive"); else fprintf(stderr, "botched state, %d", ctxtab[ctx].state); fprintf(stderr, "]\n"); } #endif if (ctx < 0 || ctx >= num_ctx || ctxtab[ctx].state == CTX_INACTIVE) { /* * This is expected ... when a context is closed in pmcd * (or for a local context or for dbpmda or ...) all the * PMDAs with a registered pmdaEndContextCallBack will be * called end some of the PMDAs may not have not serviced * any previous requests for that context. */ return; } num_end++; num_recv_pdu += ctxtab[ctx].recv_pdu; num_xmit_pdu += ctxtab[ctx].xmit_pdu; ctxtab[ctx].state = CTX_INACTIVE; } pcp-3.8.12ubuntu1/src/pmdas/sample/Sample.pmchart0000664000000000000000000000032312272262501016555 0ustar #pmchart Version 1.2 host dynamic Chart Style plot Plot Color #-cycle Host * Metric sample.drift Chart Style plot Plot Color #-cycle Host * Metric sample.step # # Created by pmchart Mon Jul 15 08:52:18 1996 pcp-3.8.12ubuntu1/src/pmdas/sample/GNUmakefile0000664000000000000000000000326512272262501016036 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # #************************************************************************* # # Makefile - sample PMDA # #************************************************************************* TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs DOMAIN = SAMPLE DFILES = README help LSRCFILES = root pmns $(DFILES) Install Remove Sample.pmchart LDIRT = domain.h *.dir *.pag sample.log SUBDIRS = src PMDADIR = $(PCP_PMDAS_DIR)/sample default_pcp default :: domain.h $(SUBDIRS) default_pcp default :: $(SUBDIRS) $(SUBDIRS_MAKERULE) install_pcp install :: $(SUBDIRS) $(SUBDIRS_MAKERULE) install_pcp install :: default $(INSTALL) -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 $(DFILES) pmns root domain.h $(PMDADIR) $(INSTALL) -m 644 Sample.pmchart $(PCP_VAR_DIR)/config/pmchart/Sample include $(BUILDRULES) .NOTPARALLEL: .ORDER: domain.h $(OBJECTS) domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/sample/root0000664000000000000000000000034412272262501014665 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { sample sampledso } #include "pmns" #define sample sampledso #ifdef SAMPLE #undef SAMPLE #endif #define SAMPLE 30 #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/sample/pmns0000664000000000000000000001166112272262501014663 0ustar /* * Metrics for sample PMDA * * Next pmid SAMPLE:0:122 * (SAMPLE:0:1023 is taken) * * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ sample { control SAMPLE:0:0 daemon_pid SAMPLE:0:1 seconds SAMPLE:0:2 milliseconds SAMPLE:0:3 load SAMPLE:0:4 colour SAMPLE:0:5 darkness SAMPLE:0:92 bin SAMPLE:0:6 bucket SAMPLE:0:48 part_bin SAMPLE:0:50 bogus_bin SAMPLE:0:51 drift SAMPLE:0:7 step SAMPLE:0:8 step_counter SAMPLE:0:63 mirage SAMPLE:0:37 mirage_longlong SAMPLE:0:38 write_me SAMPLE:0:36 lights SAMPLE:0:46 magnitude SAMPLE:0:47 sysinfo SAMPLE:0:39 pdu SAMPLE:0:40 recv_pdu SAMPLE:0:41 xmit_pdu SAMPLE:0:42 noinst SAMPLE:0:9 needprofile SAMPLE:0:49 long ulong longlong ulonglong float double string aggregate hordes bad not_ready SAMPLE:0:56 wrap dodgey dynamic rapid SAMPLE:0:64 scale_step const_rate error_code SAMPLE:0:74 error_check SAMPLE:0:75 bigid SAMPLE:0:1023 many byte_ctr SAMPLE:0:81 byte_rate SAMPLE:0:82 kbyte_ctr SAMPLE:0:83 kbyte_rate SAMPLE:0:84 byte_rate_perhour SAMPLE:0:85 datasize SAMPLE:0:91 secret SAMPLE:*:* scramble percontext event } sample.long { one SAMPLE:0:10 ten SAMPLE:0:11 hundred SAMPLE:0:12 million SAMPLE:0:13 write_me SAMPLE:0:14 bin SAMPLE:0:103 bin_ctr SAMPLE:0:104 } sample.ulong { one SAMPLE:0:93 ten SAMPLE:0:94 hundred SAMPLE:0:95 million SAMPLE:0:96 write_me SAMPLE:0:97 bin SAMPLE:0:105 bin_ctr SAMPLE:0:106 count } sample.ulong.count { base SAMPLE:0:115 deca SAMPLE:0:116 hecto SAMPLE:0:117 kilo SAMPLE:0:118 mega SAMPLE:0:119 } sample.float { one SAMPLE:0:15 ten SAMPLE:0:16 hundred SAMPLE:0:17 million SAMPLE:0:18 write_me SAMPLE:0:19 bin SAMPLE:0:107 bin_ctr SAMPLE:0:108 } sample.longlong { one SAMPLE:0:20 ten SAMPLE:0:21 hundred SAMPLE:0:22 million SAMPLE:0:23 write_me SAMPLE:0:24 bin SAMPLE:0:109 bin_ctr SAMPLE:0:110 } sample.ulonglong { one SAMPLE:0:98 ten SAMPLE:0:99 hundred SAMPLE:0:100 million SAMPLE:0:101 write_me SAMPLE:0:102 bin SAMPLE:0:111 bin_ctr SAMPLE:0:112 } sample.double { one SAMPLE:0:25 ten SAMPLE:0:26 hundred SAMPLE:0:27 million SAMPLE:0:28 write_me SAMPLE:0:29 bin SAMPLE:0:113 bin_ctr SAMPLE:0:114 } sample.string { null SAMPLE:0:30 hullo SAMPLE:0:31 write_me SAMPLE:0:32 } sample.aggregate { null SAMPLE:0:33 hullo SAMPLE:0:34 write_me SAMPLE:0:35 } sample.hordes { one SAMPLE:0:52 two SAMPLE:0:53 } sample.bad { unknown SAMPLE:0:54 nosupport SAMPLE:0:55 } sample.wrap { long SAMPLE:0:57 ulong SAMPLE:0:58 longlong SAMPLE:0:59 ulonglong SAMPLE:0:60 } sample.dodgey { control SAMPLE:0:61 value SAMPLE:0:62 } sample.scale_step { bytes_up SAMPLE:0:65 bytes_down SAMPLE:0:66 count_up SAMPLE:0:67 count_down SAMPLE:0:68 time_up_secs SAMPLE:0:69 time_up_nanosecs SAMPLE:0:70 none_up SAMPLE:0:71 } sample.const_rate { value SAMPLE:0:72 gradient SAMPLE:0:73 } sample.dynamic { counter SAMPLE:0:76 discrete SAMPLE:0:77 instant SAMPLE:0:78 meta } sample.dynamic.meta { metric SAMPLE:0:86 pmdesc } sample.dynamic.meta.pmdesc { type SAMPLE:0:87 indom SAMPLE:0:88 sem SAMPLE:0:89 units SAMPLE:0:90 } sample.many { count SAMPLE:0:79 int SAMPLE:0:80 } sample.scramble { version SAMPLE:0:120 bin SAMPLE:0:121 } sample.percontext { control pdu SAMPLE:0:43 recv_pdu SAMPLE:0:44 xmit_pdu SAMPLE:0:45 } sample.percontext.control { ctx SAMPLE:0:122 active SAMPLE:0:123 start SAMPLE:0:124 end SAMPLE:0:125 } sample.event { records SAMPLE:0:136 no_indom_records SAMPLE:0:137 reset SAMPLE:0:126 type SAMPLE:0:127 param_32 SAMPLE:0:128 param_u32 SAMPLE:0:129 param_64 SAMPLE:0:130 param_u64 SAMPLE:0:131 param_float SAMPLE:0:132 param_double SAMPLE:0:133 param_string SAMPLE:0:134 param_aggregate SAMPLE:0:135 } pcp-3.8.12ubuntu1/src/pmdas/sample/help0000664000000000000000000005554012272262501014642 0ustar # # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # sample PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ SAMPLE.1 Instance domain "colour" for sample PMDA Universally 3 instances, "red" (0), "green" (1) and "blue" (3). @ SAMPLE.2 Instance domain "bin" for sample PMDA Universally 9 instances numbered 100 .. 900 in steps of 100, and named "bin-100" .. "bin-900" @ SAMPLE.3 Instance domain "mirage" for sample PMDA Random number of instances, that change with time. Instance "m-00" (0) is always present, while the others are numbered 1 .. 49 and named "m-01" .. "m-99" @ SAMPLE.4 Instance domain "family" for sample PMDA. A fixed set of instances: "colleen", "terry", "emma", "cathy" and "fat bald bastard" @ SAMPLE.7 Instance domain "many" for sample PMDA. A varable size set of instances controlled by sample.many.count @ sample.control A control variable for the "sample" PMDA This control variable may be modified using pmStore(). The allowed values are 0 disable debugging output in the PMDA >0 set pmDebug to this value to enable debugging output -1 force the PMDA to terminate @ sample.daemon_pid Process id of PMDA daemon The process id of PMDA daemon, -1 if the daemon is a DSO. @ sample.seconds Elapsed time (seconds) The elapsed time since the PMDA started, in seconds, i.e. as returned by time(2). @ sample.milliseconds Elapsed time (milliseconds) The elapsed time since the PMDA started, in milliseconds, i.e. as returned by gettimeofday(2), and then adjusted from microseconds to milliseconds. @ sample.load Hypothetical load The hypothetical load is always 42! @ sample.colour Metrics with a "saw-tooth" trend over time This metric has 3 instances, designated "red", "green" and "blue". The value of the metric is monotonic increasing in the range N to N+100, then back to N. The different instances have different N values, namely 100 (red), 200 (green) and 300 (blue). @ sample.darkness No values available Defined over the same instance domain as sample.colour, but this metric returns the "No values available" error for every fetch. @ sample.bin Several constant instances 9 instances labelled "bin-100" thru "bin-900", each with a constant value of 100 thru 900. @ sample.bucket Several constant instances 9 instances labelled "bin-100" thru "bin-900", each with a constant value of 100 thru 900. This is an alias for sample.bin, but with a different PMID. @ sample.part_bin Several constant instances 5 instances labelled "bin-100" thru "bin-900", each with a constant value of 100 thru 900. This is defined over the same domain as sample.part, but half of the instances are missing. @ sample.bogus_bin Several constant instances 9 instances labelled "bin-100" thru "bin-900", each with a constant value of 100 thru 900. This is defined over the same domain as sample.part, half the values are for instances not in the instance domain. @ sample.drift A random trended metric This metric returns a random value (expected mean is approximately 200), subject to a trending pattern such that the sequence is mainly monotonic, with a change in direction after on average 4 consecutive samples. Use pmStore() to modifiy the instantaneous value, which becomes the new expected mean. @ sample.step A step function (instantaneous) This metric changes magnitude every 30 seconds, between a base value and 3 times the base value. The metric has "instantaneous" semantics. See also sample.step_counter. Use pmStore() to modify the base value. @ sample.step_counter A step function (counter) This metric changes magnitude every 30 seconds, between a base value and 3 times the base value. The metric has "counter" semantics. See also sample.step. Use pmStore() to modify the base value. @ sample.needprofile Metrics that need an explicit profile Simulate behaviour similar to the "proc" PMDA where metrics values are only available if an explicit instance profile is provided. @ sample.lights Traffic lights. A singular metric that has a discrete string value, namely "red", "yellow" or "green". There is some persistance in the value, so consecutive fetches are likely to return the same value, however over a long period of time all values are equally probable. @ sample.magnitude Powers of two. A singular metric that has a discrete integer value, namely 1, 2, 4, 8, 16, 32 or 64. There is some persistance in the value, so consecutive fetches are likely to return the same value, however over a long period of time all values are equally probable. @ sample.pdu Total PDU count Count of PDUs received or transmitted. Use pmStore() to reset the counter to 0, independent of the value passed to pmStore(). @ sample.recv_pdu Count of PDUs received Count of PDUs received. Use pmStore() to reset the counter to 0, independent of the value passed to pmStore(). @ sample.xmit_pdu Count of PDUs transmitted Count of PDUs transmitted. Use pmStore() to reset the counter to 0, independent of the value passed to pmStore(). @ sample.mirage Simple saw-tooth rate, but instances come and go The metric is a rate (Kbytes/sec) that varies in a saw-tooth distribution over time. Different instances of the metric have different baselines for the saw-tooth, but all have an max-to-min range of 100. What makes this metric interesting is that instances come and go (not more often than once every 10 seconds however). Instance 0 is always present, but the other instances 1 thru 49 come and go in a cyclic pattern with a large random component influencing when each instance appears and disappears. @ sample.mirage_longlong Simple saw-tooth rate, but instances come and go The metric is a rate (bytes/msec) that varies in a saw-tooth distribution over time. Different instances of the metric have different baselines for the saw-tooth, but all have an max-to-min range of 100,000,000. What makes this metric interesting is that instances come and go (not more often than once every 10 seconds however). Instance 0 is always present, but the other instances 1 thru 49 come and go in a cyclic pattern with a large random component influencing when each instance appears and disappears. @ sample.write_me Modifiable, but otherwise constant. This metric has a 32-bit integer value of 2, unless changed via pmStore. The metric has semantics of rate, and units of events per second. @ sample.sysinfo Aggregate containing system accounting structures This metric has an aggregate value containing the following struct: struct { int len; struct sysinfo sysinfo; }; The len field contains the size of the structure enclosing it. The sysinfo field contains various system accounting structures, summed over all CPUs, as returned by sysmp(MP_SAGET, MPSA_SINFO, ...); See /usr/include/sys/sysinfo.h for the definition of the sysinfo struct. @ sample.noinst No instance available For testing, only. This metric is known, but no value is ever available @ sample.long.one 1 as a 32-bit integer @ sample.long.ten 10 as a 32-bit integer @ sample.long.hundred 100 as a 32-bit integer @ sample.long.million 1000000 as a 32-bit integer @ sample.long.write_me a 32-bit integer that can be modified @ sample.long.bin like sample.bin but type 32 @ sample.long.bin_ctr like sample.bin but type 32, SEM_COUNTER and SPACE_KBYTE @ sample.ulong.one 1 as a 32-bit unsigned integer @ sample.ulong.ten 10 as a 32-bit unsigned integer @ sample.ulong.hundred 100 as a 32-bit unsigned integer @ sample.ulong.million 1000000 as a 32-bit unsigned integer @ sample.ulong.write_me a 32-bit unsigned integer that can be modified @ sample.ulong.bin like sample.bin but type U32 @ sample.ulong.bin_ctr like sample.bin but type U32, SEM_COUNTER and SPACE_KBYTE @ sample.ulong.count.base count scale is 1, value is 42,000,000 @ sample.ulong.count.deca count scale is 10, value is 4,200,000 @ sample.ulong.count.hecto count scale is 10, value is 420,000 @ sample.ulong.count.kilo count scale is 10, value is 42,000 @ sample.ulong.count.mega count scale is 10, value is 42 @ sample.longlong.one 1 as a 64-bit integer @ sample.longlong.ten 10 as a 64-bit integer @ sample.longlong.hundred 100 as a 64-bit integer @ sample.longlong.million 1000000 as a 64-bit integer @ sample.longlong.write_me a 64-bit integer that can be modified @ sample.longlong.bin like sample.bin but type 64 @ sample.longlong.bin_ctr like sample.bin but type 64, SEM_COUNTER and SPACE_KBYTE @ sample.ulonglong.one 1 as a 64-bit unsigned integer @ sample.ulonglong.ten 10 as a 64-bit unsigned integer @ sample.ulonglong.hundred 100 as a 64-bit unsigned integer @ sample.ulonglong.million 1000000 as a 64-bit unsigned integer @ sample.ulonglong.write_me a 64-bit unsigned integer that can be modified @ sample.ulonglong.bin like sample.bin but type U64 @ sample.ulonglong.bin_ctr like sample.bin but type U64, SEM_COUNTER and SPACE_KBYTE @ sample.float.one 1 as a 32-bit floating point value @ sample.float.ten 10 as a 32-bit floating point value @ sample.float.hundred 100 as a 32-bit floating point value @ sample.float.million 1000000 as a 32-bit floating point value @ sample.float.write_me a 32-bit floating-point value that can be modified @ sample.float.bin like sample.bin but type FLOAT @ sample.float.bin_ctr like sample.bin but type FLOAT, SEM_COUNTER and SPACE_KBYTE @ sample.double.one 1 as a 64-bit floating point value @ sample.double.ten 10 as a 64-bit floating point value @ sample.double.hundred 100 as a 64-bit floating point value @ sample.double.million 1000000 as a 64-bit floating point value @ sample.double.write_me a 64-bit floating-point value that can be modified @ sample.double.bin like sample.bin but type DOUBLE @ sample.double.bin_ctr like sample.bin but type DOUBLE, SEM_COUNTER and SPACE_KBYTE @ sample.string.null a zero length string @ sample.string.hullo K&R have a lot to answer for @ sample.string.write_me a string value that can be modified @ sample.aggregate.null a zero length aggregate @ sample.aggregate.hullo K&R have a lot to answer for @ sample.aggregate.write_me a aggregate value that can be modified @ sample.hordes.one 500 instances Value of the metric is the instance identifier. @ sample.hordes.two 500 instances Value of the metric is 500 - the instance identifier. @ sample.bad.unknown Not known to the PMDA In the PMNS, but the sample agent pretends it does not know about this one. @ sample.bad.nosupport Not supported in this version of the PMDA Type is PM_NOSUPPORT, fetch returns PM_ERR_APPVERSION @ sample.not_ready interval (in seconds) during which PMDA does not respond to PDUs Store a positive number of seconds as the value of this metric. The following PDU received will result in the following sequence of events: 1. return an error PDU with PM_ERR_PMDANOTREADY to pmcd 2. sleep for the given number of seconds 3. sends an error PDU with PM_ERR_PMDAREADY to pmcd If everything went as planned, sample.not_ready returns to 0, otherwise it has a negative error code as value. @ sample.wrap.long long counter that wraps The metric value increments by INT_MAX / 2 - 1 (from ) every time it is fetched. @ sample.wrap.ulong unsigned long counter that wraps The metric value increments by UINT_MAX / 2 - 1 (from ) every time it is fetched. @ sample.wrap.longlong long long counter that wraps The metric value increments by LONGLONG_MAX / 2 - 1 (from ) every time it is fetched. @ sample.wrap.ulonglong unsigned long long counter that wraps The metric value increments by ULONGLONG_MAX / 2 - 1 (from ) every time it is fetched. @ sample.dodgey.value 5 unreliable instances The metric is a set of 5 instantaneous values, drawn at random from the range 0 to 100. The number of instances "visible" is controlled by sample.dodgey.control. @ sample.dodgey.control control values retured for sample.dodgey.value If sample.dodgey.control is <= 0, then this is returned as the "numval" component in the pmResult (0 => no values available, less than 0 => various errors). If sample.dodgey.control is between 1 and 5 (inclusive), then this many of the values will be "visible". The values will be selected in order from the underlying 5 instances. If sample.dodgey.control is > 5, then at random times (between 1 and sample.dodgey.control fetches of the metric), the number of instances available is changed according to the following probabilities ... 0.9 some number of instances in the range 0 to 5, selected at random from the underlying 5 instances. 0.1 error (PM_ERR_NOAGENT or PM_ERR_AGAIN or PM_ERR_APPVERSION) @ sample.rapid count very quickly Base counter increments by 8*10^7 per fetch. Result is 10 x base counter. @ sample.scale_step.bytes_up count up by powers of 2, wrap back to one at 10 Tbytes @ sample.scale_step.bytes_down count down by powers of 2, wrap back to 10 Tbytes at 1 @ sample.scale_step.count_up count up by powers of 10, wrap back to 1 at 10e12 @ sample.scale_step.count_down count down by powers of 10, wrap back to 10e12 at 1 @ sample.scale_step.time_up_secs count up seconds by multiples of 10, wrap back to 1 second at 1 day @ sample.scale_step.time_up_nanosecs count up nanoseconds by multiples of 10, wrap back to 1 nanosecond at 1 day @ sample.scale_step.none_up count up dimensionless by multiples of 10, wrap back to 1 at 10 million @ sample.const_rate.value constant rate counter A counter that changes with constant rate between fetches. The rate is set by storing the desired rate (counts per second) into sample.const_rate.gradient @ sample.const_rate.gradient rate per second to set sample.const_rate.value, writable @ sample.error_code Arbitrary PMAPI error code for sample.error_check The metrics sample.error_code and sample.error_check are used in tandem as follows: if sample.error_code is < 0, then any attempt to retrieve information about sample.error_check will return a sample.error_code as a PMAPI error from the PMDA. Use pmstore(1) to change sample.error_code. @ sample.error_check Return PMAPI error code from sample.error_code The metrics sample.error_code and sample.error_check are used in tandem as follows: if sample.error_code is < 0, then any attempt to retrieve information about sample.error_check will return a sample.error_code as a PMAPI error from the PMDA. Otherwise sample.error_check is a boring metric that always has the value 0. @ sample.dynamic.counter counter metric with dynamic indom Instances come from $PCP_PMDAS_DIR/sample/dynamic.indom, if it exists. Each line in this file is internal_id external_id This metric increments each time this instance has been seen when scanning the dynamic.indom file, and resets to zero each time the instance appears. @ sample.dynamic.discrete discrete metric with dynamic indom Instances come from $PCP_PMDAS_DIR/sample/dynamic.indom, if it exists. Each line in this file is internal_id external_id This metric increments each time this instance has been seen when scanning the dynamic.indom file, and resets to zero each time the instance appears. @ sample.dynamic.instant instant metric with dynamic indom Instances come from $PCP_PMDAS_DIR/sample/dynamic.indom, if it exists. Each line in this file is internal_id external_id This metric increments each time this instance has been seen when scanning the dynamic.indom file, and resets to zero each time the instance appears. @ sample.many.count number of instances in sample.many.int's domain store a value in sample.many.count to change the number of instances that appear in sample.many.int's instance domain @ sample.many.int variable sized instance domain store a value in sample.many.count to change the number of instances that appear in sample.many.int's instance domain @ sample.bigid a metric with item number bigger then 2^9 @ sample.byte_ctr counter byte counter @ sample.byte_rate instantaneous bytes/second avg rate is 512 bytes per fetch @ sample.kbyte_ctr counter Kbytes/second @ sample.kbyte_rate instantaneous Kbytes/second @ sample.byte_rate_perhour instantaneous bytes/hour @ sample.dynamic.meta.metric metric with modifiable metadata See sample.dynamic.meta.pmdesc for the metrics that can be modified to change the metadata for this metric. The value of this metric is always 42. @ sample.dynamic.meta.pmdesc.type pmDesc.type for sample.dynamic.meta.metric One of these values: PM_TYPE_NOSUPPORT -1 /* not implemented in this version */ PM_TYPE_32 0 /* 32-bit signed integer */ PM_TYPE_U32 1 /* 32-bit unsigned integer */ PM_TYPE_64 2 /* 64-bit signed integer */ PM_TYPE_U64 3 /* 64-bit unsigned integer */ PM_TYPE_FLOAT 4 /* 32-bit floating point */ PM_TYPE_DOUBLE 5 /* 64-bit floating point */ PM_TYPE_STRING 6 /* array of char */ PM_TYPE_AGGREGATE 7 /* arbitrary binary data (aggregate) */ PM_TYPE_AGGREGATE_STATIC 8 /* static pointer to aggregate */ PM_TYPE_UNKNOWN 255 /* used in pmValueBlock, not pmDesc */ Defaults to PM_TYPE_32. @ sample.dynamic.meta.pmdesc.indom pmDesc.indom for sample.dynamic.meta.metric Defaults to PM_INDOM_NULL (0xffffffff). @ sample.dynamic.meta.pmdesc.sem pmDesc.sem for sample.dynamic.meta.metric One of these values: PM_SEM_COUNTER 1 /* cumulative counter (monotonic increasing) */ PM_SEM_INSTANT 3 /* instantaneous value, continuous domain */ PM_SEM_DISCRETE 4 /* instantaneous value, discrete domain */ Defaults to PM_SEM_DISCRETE. @ sample.dynamic.meta.pmdesc.units pmDesc.units for sample.dynamic.meta.metric 6 x 4-bit values, from least-significant bit to most-significant bit: dimSpace: -1, 0, 1 dimTime: -1, 0, 1 dimCount: 0, 1 scaleSpace: PM_SPACE_BYTE 0 /* bytes */ PM_SPACE_KBYTE 1 /* Kilobytes (1024) */ PM_SPACE_MBYTE 2 /* Megabytes (1024^2) */ PM_SPACE_GBYTE 3 /* Gigabytes (1024^3) */ PM_SPACE_TBYTE 4 /* Terabytes (1024^4) */ PM_SPACE_PBYTE 5 /* Petabytes (1024^5) */ PM_SPACE_EBYTE 6 /* Exabytes (1024^6) */ scaleTime: PM_TIME_NSEC 0 /* nanoseconds */ PM_TIME_USEC 1 /* microseconds */ PM_TIME_MSEC 2 /* milliseconds */ PM_TIME_SEC 3 /* seconds */ PM_TIME_MIN 4 /* minutes */ PM_TIME_HOUR 5 /* hours */ scaleCount: PM_COUNT_ONE 0 /* 1 */ Defaults to { 1, -1, 0, PM_SPACE_BYTE, PM_TIME_SEC, 0 } @ sample.datasize Space allocated for PMDA's data segment This metric returns the amount of memory in kilobytes allocated for the data segment of the PMDA. This is handy for tracing memory utilization (and leaks) in libpcp_pmda. @ SAMPLE.0.1000 dynamic *.secret.bar metric Value "foo". @ SAMPLE.0.1001 dynamic *.secret.foo.one metric Value 1. @ SAMPLE.0.1002 dynamic *.secret.foo.two metric Value 2. @ SAMPLE.0.1003 dynamic *.secret.foo.bar.three metric Value 3. @ SAMPLE.0.1004 dynamic *.secret.foo.bar.four metric Value 4. @ SAMPLE.0.1005 dynamic *.secret.foo.bar.grunt.five metric Value 5. @ SAMPLE.0.1006 dynamic *.secret.foo.bar.grunt.snort.six metric Value 6. @ SAMPLE.0.1007 dynamic *.secret.foo.bar.grunt.snort.huff.puff.seven metric Value 7. @ sample.scramble.bin Several constant instances, instances scrambled Like sample.bin, except 1. instances are missing with probability 0.33 2. order of the instances from pmFetch is random Designed to help testing instance matching between pmFetch calls for PCP clients. @ sample.scramble.version Current state version and reset for sample.scramble.bin To make the order of instances seen from sample.scramble.bin deterministic, use pmstore(1) to trigger a reset. @ sample.percontext.control.ctx Number of PMAPI contexts seen One more than the highest PMAPI context number from PMCD. @ sample.percontext.control.active Number of active PMAPI contexts @ sample.percontext.control.start Number of new PMAPI contexts seen Incremented each time a new PMAPI context is seen from PMCD. sample.percontext.control.start - sample.percontext.control.end should equal sample.percontext.control.active. @ sample.percontext.control.end Number of PMAPI contexts closed Incremented each time PMCD closes a PMAPI context. sample.percontext.control.start - sample.percontext.control.end should equal sample.percontext.control.active. @ sample.percontext.pdu Total PDU count for the client context Count of PDUs received from or transmitted to the current PMAPI client context. Use pmStore() to reset the counter to 0, independent of the value passed to pmStore(). @ sample.percontext.recv_pdu Count of PDUs received from the client context Count of PDUs received from the current PMAPI client context. Use pmStore() to reset the counter to 0, independent of the value passed to pmStore(). @ sample.percontext.xmit_pdu Count of PDUs transmitted Count of PDUs transmitted to the current PMAPI client context. Use pmStore() to reset the counter to 0, independent of the value passed to pmStore(). @ sample.event.records Dummy event records Dummy event records are generated in a fixed pattern to help QA. Once all setups have been returned, the cycle is repeated. See event.reset to exert explicit control over the next batch of event records to be returned. @ sample.event.no_indom_records More dummy event records Like sample.event.records but without the instance domain. @ sample.event.reset reset event record state Used for QA, should take one of the values 0, 1, 2 or 3 to determine which of the dummy event record setups will be returned for the next fetch of event.records. @ sample.event.type event type parameter for event records @ sample.event.param_32 32 parameter for event records @ sample.event.param_u32 U32 parameter for event records @ sample.event.param_64 64 parameter for event records @ sample.event.param_u64 U64 parameter for event records @ sample.event.param_float FLOAT parameter for event records @ sample.event.param_double DOUBLE parameter for event records @ sample.event.param_string STRING parameter for event records @ sample.event.param_aggregate AGGREGATE parameter for event records pcp-3.8.12ubuntu1/src/pmdas/process/0000775000000000000000000000000012272262620014155 5ustar pcp-3.8.12ubuntu1/src/pmdas/process/README0000664000000000000000000000441612272262501015040 0ustar # # Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) # for the portions of the code supporting the initial agent functionality. # All rights reserved. # # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # Process PMDA ============ This PMDA monitors root processes to see if they are still running. The processes that are monitored are stored in a config file, and the PMDA returns the number of root processes with that name running. In this way, you can check to see if the number of processes is in a range, is 1, is 0, or some other combination. This source code was contributed by Alan Bailey (abailey@ncsa.uiuc.edu) to the PCP open source project. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT process Installation ============ + # cd $PCP_PMDAS_DIR/process + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use ($PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options -- everything else is automated. + Alternatively, to install just the Performance Metrics Name Space for the process metrics on the local system, but not the process PMDA (presumably because the local system is running PCP 1.x and you wish to connect to a remote system where PCP 2.0 and the process PMDA is running), make sure the Performance Metrics Domain defined in ./domain.h matches the domain chosen for the process PMDA on the remote system (check the second field in the corresponding line of the $PCP_PMCDCONF_PATH file on the remote system), then # ./Install -N De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/process # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/process.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/process/Remove0000775000000000000000000000234112272262501015336 0ustar #! /bin/sh # # Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) # for the portions of the code supporting the initial agent functionality. # All rights reserved. # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the process PMDA # # source the PCP configuration environment variables . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=process # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/process/Install0000775000000000000000000000146212272262501015512 0ustar #! /bin/sh # # Copyright (c) 2001 Alan Bailey. All Rights Reserved. # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the process PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=process pmda_interface=2 forced_restart=false pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/process/GNUmakefile0000664000000000000000000000350312272262521016230 0ustar # # Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) # for the portions of the code supporting the initial agent functionality. # All rights reserved. # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = process DOMAIN = PROCESS TARGETS = $(IAM) CFILES = process.c SCRIPTS = Install Remove DFILES = README LSRCFILES= $(SCRIPTS) pmns help root $(DFILES) process.conf PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) PMCHART = $(PCP_VAR_DIR)/config/pmchart LDIRT = domain.h *.o $(IAM).log pmda$(IAM) pmda_$(IAM).so $(TARGETS) \ help.dir help.pag LLDLIBS = $(PCP_PMDALIB) default: build-me include $(BUILDRULES) # This PMDA is only valid on platforms with a procfs # It is also superceded by the cgroup functionality on Linux # thus has not been built for some time, for reference only. #build-me: $(TARGETS) #install install_pcp : default # $(INSTALL) -m 755 -d $(PMDADIR) # $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) # $(INSTALL) -m 755 $(SCRIPTS) $(PMDADIR) # $(INSTALL) -m 644 $(DFILES) pmns help root domain.h $(PMDADIR) # $(INSTALL) -m 644 process.conf $(PMDADIR)/process.conf #else build-me: install: #endif $(IAM): $(OBJECTS) default_pcp : default install_pcp : install process.o: domain.h domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/process/root0000664000000000000000000000057112272262501015064 0ustar /* * Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) * for the portions of the code supporting the initial agent functionality. * All rights reserved. * Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. */ /* * fake "root" for validating the local PMNS subtree */ #include root { process } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/process/pmns0000664000000000000000000000203512272262501015053 0ustar /* * Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) * for the portions of the code supporting the initial agent functionality. * All rights reserved. * Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Metrics for process PMDA */ process { running PROCESS:0:0 } pcp-3.8.12ubuntu1/src/pmdas/process/process.c0000664000000000000000000003030712272262501016000 0ustar /* * The process PMDA * * This code monitors root processes to see if they are still * running. The processes that are monitored are stored in a config file, * and the PMDA returns the number of root processes with that name * running. In this way, you can check to see if the number of processes * is in a range, is 1, is 0, or some other combination. * * Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) * for the portions of the code supporting the initial agent functionality. * All rights reserved. * * Copyright (c) 2001,2003,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include #include #include /* * Process PMDA * * Metrics * process.running * The number of root processes running for each name * The process names are stored in * PCP_VAR_DIR/pmdas/process/process.conf */ static pmdaInstid *processes = NULL; static pmdaIndom indomtab[] = { #define PROC_INDOM 0 { PROC_INDOM, 0, NULL } }; static pmdaMetric metrictab[] = { /* process.running */ { NULL, { PMDA_PMID(0,0), PM_TYPE_DOUBLE, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, }; /* Variables needed for this file */ static int *num_procs = NULL; static struct stat file_change; static int npidlist = 0; static int maxpidlist = 0; int *pidlist = NULL; static int isDSO = 1; static char mypath[MAXPATHLEN]; /* Routines in this file */ static void process_clear_config_info(void); static void process_grab_config_info(void); static void process_config_file_check(void); int process_refresh_pidlist(void); static void process_config_file_check(void) { /* * This code was taken from the simple PMDA, in simple.c, for checking * to see if a file has been changed. It has been changed slightly. * Note that this then calls process_clear_config_info and * process_grab_config_info if the file has been updated. */ struct stat statbuf; static int last_error; int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "process" "%c" "process.conf", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); if (stat(mypath, &statbuf) == -1) { if (oserror() != last_error) { last_error = oserror(); __pmNotifyErr(LOG_WARNING, "stat failed on %s: %s\n", mypath, pmErrStr(-oserror())); } } else { last_error = 0; #if defined(HAVE_ST_MTIME_WITH_E) if (memcmp(&statbuf.st_mtime, &file_change.st_mtime, sizeof(statbuf.st_mtime)) != 0) #elif defined(HAVE_ST_MTIME_WITH_SPEC) if (memcmp(&statbuf.st_mtimespec, &file_change.st_mtimespec, sizeof(statbuf.st_mtimespec)) != 0) #else if (memcmp(&statbuf.st_mtim, &file_change.st_mtim, sizeof(statbuf.st_mtim)) != 0) #endif { process_clear_config_info(); process_grab_config_info(); file_change = statbuf; } } } static void process_clear_config_info(void) { /* * This function is called when the config file needs to be read in * again, so we can define new instances and such. This frees the * previous memory, if any (on startup, there won't be any), and sets * the two variables to NULL for fun. */ int i; /* Free the memory holding the process name */ for (i = 0; i < indomtab[PROC_INDOM].it_numinst; i++) { free(processes[i].i_name); } /* Free the processes structure */ if (processes != NULL) { free(processes); } /* Free the process counter structure */ if (num_procs != NULL) { free(num_procs); } num_procs = NULL; indomtab[PROC_INDOM].it_set = processes = NULL; indomtab[PROC_INDOM].it_numinst = 0; } void process_grab_config_info() { /* * This routine opens the config file and stores the information in the * processes structure. The processes structure must be reallocated as * necessary, and also the num_procs structure needs to be reallocated * as we define new processes. When all of that is done, we fill in the * values in the indomtab structure, those being the number of instances * and the pointer to the processes structure. * * A lot of this code was taken from the simple.c code, but in this * case, I changed a lot of it to fit my purposes... */ FILE *fp; char process_name[1024]; char *q; int process_number = 0; int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "process" "%c" "process.conf", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); if ((fp = fopen(mypath, "r")) == NULL) { __pmNotifyErr(LOG_ERR, "fopen on %s failed: %s\n", mypath, pmErrStr(-oserror())); if (processes != NULL) { free(processes); processes = NULL; process_number = 0; } goto done; } while (fgets(process_name, sizeof(process_name), fp) != NULL) { if (process_name[0] == '#') continue; /* Remove the newline */ if ((q = strchr(process_name, '\n')) != NULL) { *q = '\0'; } else { /* This means the line was too long */ __pmNotifyErr(LOG_WARNING, "line number %d in the config file was too long\n", process_number+1); } processes = realloc(processes, (process_number+1)*sizeof(pmdaInstid)); if (processes == NULL) { __pmNoMem("process", (process_number+1)*sizeof(pmdaInstid), PM_FATAL_ERR); /* Not reached */ } processes[process_number].i_name = malloc(strlen(process_name) + 1); strcpy(processes[process_number].i_name, process_name); processes[process_number].i_inst = process_number; process_number++; } fclose(fp); done: if (processes == NULL) { __pmNotifyErr(LOG_WARNING, "\"process\" instance domain is empty"); } indomtab[PROC_INDOM].it_set = processes; indomtab[PROC_INDOM].it_numinst = process_number; num_procs = realloc(num_procs, (process_number)*sizeof(int)); } void process_refresh_pid_checks() { /* * This code refreshes the count of all the processes that we want to * monitor. It does this by calling process_refresh_pidlist, which just * grabs a list of all the running processes (as PIDs). We then loop * through each of these processes, and check to see if it is a root * process. If so, we then open up the /proc//status file, * and see what the process name is. If it is one of our special * processes that we want to track, then we up the count for that * process in num_procs. Then we're done. */ int proc; char proc_path[30]; char cmd_line[200]; FILE *fd; int proc_name; int item; struct stat statbuf; process_refresh_pidlist(); /* Clear the variables */ for(item = 0; item < indomtab[PROC_INDOM].it_numinst; item++) { num_procs[item] = 0; } /* look to make this more efficient */ for(proc = 0; proc < npidlist; proc++) { sprintf(proc_path, "/proc/%d/status", pidlist[proc]); if (stat(proc_path, &statbuf) == -1) { /* We can't stat it, let's assume the process isn't running anymore */ continue; } else { /* This checks to make sure the process is a root process */ if (statbuf.st_uid != 0) { continue; } } if ((fd = fopen(proc_path, "r")) != NULL) { /* * matching process by name is platform specific ... this code * works for Linux when /proc//status is ascii and the * first line is of the form: * Name: */ if (fgets(cmd_line, sizeof(cmd_line), fd) == NULL) { /* * not expected, but not a disaster ... we'll just not try * to match this one */ fclose(fd); continue; } fclose(fd); for(proc_name = 0; proc_name < indomtab[PROC_INDOM].it_numinst; proc_name++) { if (strstr(cmd_line, (processes[proc_name]).i_name)) { (num_procs[proc_name])++; } } } } } int process_refresh_pidlist() { /* * This is code to read in the list of all processes running. This has * been blatantly stolen from src/pmdas/linux/proc_pid.c in the pcp * source. The only difference I've made is that it doesn't do qsort on * the resulting list, cuz I don't care about that, and it would take * precious time. */ DIR *dirp = opendir("/proc"); struct dirent *dp; if (dirp == NULL) { return -oserror(); } npidlist = 0; while ((dp = readdir(dirp)) != (struct dirent *)NULL) { if (isdigit((int)dp->d_name[0])) { if (npidlist >= maxpidlist) { maxpidlist += 16; pidlist = (int *)realloc(pidlist, maxpidlist * sizeof(int)); } pidlist[npidlist++] = atoi(dp->d_name); } } closedir(dirp); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "process_refresh_pidlist: found %d PIDs:", npidlist); if (npidlist > 0) { fprintf(stderr, " %d", pidlist[0]); if (npidlist > 1) { fprintf(stderr, " %d", pidlist[1]); if (npidlist == 3) fprintf(stderr, " %d", pidlist[2]); else if (npidlist == 4) fprintf(stderr, " %d %d", pidlist[2], pidlist[3]); else if (npidlist > 4) fprintf(stderr, " ... %d %d", pidlist[npidlist-2], pidlist[npidlist-1]); } } fprintf(stderr, "\n"); } #endif return npidlist; } static int process_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { /* * This is the wrapper over the pmdaFetch routine, to handle the problem * of varying instance domains. All this does is check to see if the * config file has been updated, and update the instance domain if so, * and refresh the pid count for the processes. */ process_config_file_check(); process_refresh_pid_checks(); return pmdaFetch(numpmid, pmidlist, resp, pmda); } /* * callback provided to pmdaFetch */ static int process_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); if (idp->cluster != 0) { return PM_ERR_PMID; } if (idp->item != 0) { return PM_ERR_PMID; } /* We have the values stored, simply grab it and return it. */ atom->d = num_procs[inst]; return 0; } /* * Initialise the agent (both daemon and DSO). */ void process_init(pmdaInterface *dp) { if (isDSO) { int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "process" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_2, "process DSO", mypath); } if (dp->status != 0) { return; } dp->version.two.fetch = process_fetch; /* Let's grab the info right away just to make sure it's there. */ process_grab_config_info(); pmdaSetFetchCallBack(dp, process_fetchCallBack); pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), metrictab, sizeof(metrictab)/sizeof(metrictab[0])); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int err = 0; int sep = __pmPathSeparator(); pmdaInterface desc; isDSO = 0; __pmSetProgname(argv[0]); snprintf(mypath, sizeof(mypath), "%s%c" "process" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&desc, PMDA_INTERFACE_2, pmProgname, PROCESS, "process.log", mypath); if (pmdaGetOpt(argc, argv, "D:d:l:?", &desc, &err) != EOF) err++; if (err) usage(); pmdaOpenLog(&desc); process_init(&desc); pmdaConnect(&desc); pmdaMain(&desc); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/process/process.conf0000664000000000000000000000043412272262501016501 0ustar # Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) # for the portions of the code supporting the initial agent functionality. # All rights reserved. # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # sshd crond inetd nfsd afsd test pcp-3.8.12ubuntu1/src/pmdas/process/help0000664000000000000000000000307412272262501015032 0ustar # # Copyright (c) 2001 Alan Bailey (bailey@mcs.anl.gov or abailey@ncsa.uiuc.edu) # for the portions of the code supporting the initial agent functionality. # All rights reserved. # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # process PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ process.running Tool for tracking running root processes This tracks the number of running root processes for processes you define pcp-3.8.12ubuntu1/src/pmdas/jbd2/0000775000000000000000000000000012272262620013320 5ustar pcp-3.8.12ubuntu1/src/pmdas/jbd2/Remove0000775000000000000000000000123412272262501014501 0ustar #!/bin/sh # # Copyright (c) 2013 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the Linux JBD2 PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=jbd2 pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/jbd2/Install0000775000000000000000000000142212272262501014651 0ustar #!/bin/sh # # Copyright (c) 2013 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the Linux JBD2 PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=jbd2 pmda_interface=4 forced_restart=false daemon_opt=true pipe_opt=true dso_opt=true pmns_source=root_jbd2 pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/jbd2/GNUmakefile0000664000000000000000000000364012272262501015373 0ustar # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = jbd2 DOMAIN = JBD2 CMDTARGET = pmdajbd2 LIBTARGET = pmda_jbd2.so PMDAINIT = jbd2_init PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) CONF_LINE = "jbd2 122 dso $(PMDAINIT) $(PMDADIR)/$(LIBTARGET)" CFILES = proc_jbd2.c pmda.c HFILES = proc_jbd2.h convert.h SCRIPTS = Install Remove VERSION_SCRIPT = exports HELPTARGETS = help.dir help.pag LSRCFILES = help root root_jbd2 $(SCRIPTS) LDIRT = $(HELPTARGETS) domain.h $(VERSION_SCRIPT) LLDLIBS = $(PCP_PMDALIB) LCFLAGS = $(INVISIBILITY) default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "linux" build-me: domain.h $(LIBTARGET) $(CMDTARGET) $(HELPTARGETS) @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 644 domain.h help $(HELPTARGETS) root root_jbd2 $(PMDADIR) $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(SCRIPTS) $(PMDADIR) $(INSTALL) -m 644 root_jbd2 $(PCP_VAR_DIR)/pmns/root_jbd2 else build-me: install: endif default_pcp : default install_pcp : install $(HELPTARGETS) : help $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_jbd2 -v 2 -o help < help $(VERSION_SCRIPT): $(VERSION_SCRIPT_MAKERULE) domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pmda.o: domain.h pmda.o proc_jbd2.o: convert.h pmda.o proc_jbd2.o: proc_jbd2.h pmda.o: $(VERSION_SCRIPT) pcp-3.8.12ubuntu1/src/pmdas/jbd2/convert.h0000664000000000000000000000215112272262501015146 0ustar /* * Size conversion for different sized types extracted from the * kernel on different platforms, particularly where the sizeof * "long" differs. * * Copyright (c) 2007-2008 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * Some metrics are exported by the kernel as "unsigned long". * On most 64bit platforms this is not the same size as an * "unsigned int". */ #if defined(HAVE_64BIT_LONG) #define KERNEL_ULONG PM_TYPE_U64 #define _pm_assign_ulong(atomp, val) do { (atomp)->ull = (val); } while (0) #else #define KERNEL_ULONG PM_TYPE_U32 #define _pm_assign_ulong(atomp, val) do { (atomp)->ul = (val); } while (0) #endif pcp-3.8.12ubuntu1/src/pmdas/jbd2/root0000664000000000000000000000014512272262501014224 0ustar /* * fake "root" for validating the local PMNS subtree */ #include #include "root_jbd2" pcp-3.8.12ubuntu1/src/pmdas/jbd2/proc_jbd2.h0000664000000000000000000000203312272262501015331 0ustar /* * Linux JBD2 (ext3/ext4) driver metrics. * * Copyright (C) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ typedef struct { __uint32_t version; __uint32_t max_buffers; __uint64_t tid; __uint64_t requested; __uint64_t waiting; __uint64_t request_delay; __uint64_t running; __uint64_t locked; __uint64_t flushing; __uint64_t logging; __uint64_t average_commit_time; __uint64_t handles; __uint64_t blocks; __uint64_t blocks_logged; } proc_jbd2_t; extern int refresh_jbd2(const char *path, pmInDom jbd2_indom); pcp-3.8.12ubuntu1/src/pmdas/jbd2/root_jbd20000664000000000000000000000252212272262501015126 0ustar /* * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ root { jbd2 } jbd2 { njournals 122:0:0 transaction } jbd2.transaction { count 122:0:1 requested 122:0:2 max_blocks 122:0:3 total average } jbd2.transaction.total { time blocks 122:0:10 blocks_logged 122:0:11 handles 122:0:12 } jbd2.transaction.total.time { waiting 122:0:4 request_delay 122:0:5 running 122:0:6 being_locked 122:0:7 flushing_ordered_mode_data 122:0:8 logging 122:0:9 } jbd2.transaction.average { time blocks 122:0:20 blocks_logged 122:0:21 handles 122:0:22 } jbd2.transaction.average.time { waiting 122:0:13 request_delay 122:0:14 running 122:0:15 being_locked 122:0:16 flushing_ordered_mode_data 122:0:17 logging 122:0:18 committing 122:0:19 } pcp-3.8.12ubuntu1/src/pmdas/jbd2/proc_jbd2.c0000664000000000000000000001001512272262501015323 0ustar /* * Linux JBD2 (ext3/ext4) driver metrics. * * Copyright (C) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include "pmapi.h" #include "pmda.h" #include "proc_jbd2.h" enum { HEADER_STATS, SEEKING_STATS, AVERAGE_STATS, }; static int refresh_journal(const char *path, const char *dev, pmInDom indom) { int n, state, indom_changed = 0; char buf[MAXPATHLEN], *id; unsigned long long value; proc_jbd2_t *jp; FILE *fp; if (dev[0] == '.') return 0; /* only interest is in device files */ if (snprintf(buf, sizeof(buf), "%s/%s/info", path, dev) == sizeof(buf)) return 0; /* ignore, dodgey command line args */ if ((fp = fopen(buf, "r")) == NULL) return 0; /* no permission, ignore this entry */ if (pmdaCacheLookupName(indom, dev, &n, (void **)&jp) < 0 || !jp) { if ((jp = (proc_jbd2_t *)calloc(1, sizeof(proc_jbd2_t))) != NULL) indom_changed++; } if (!jp) { fclose(fp); return 0; } state = HEADER_STATS; /* seeking the header, initially */ while (fgets(buf, sizeof(buf), fp) != NULL) { switch (state) { case HEADER_STATS: if (sscanf(buf, "%llu transactions (%llu requested), each up to %u blocks\n", (unsigned long long *) &jp->tid, (unsigned long long *) &jp->requested, (unsigned int *) &jp->max_buffers) == 3) { state = SEEKING_STATS; jp->version = 3; /* 3.x kernel header format */ } else if (sscanf(buf, "%llu transaction, each up to %u blocks\n", (unsigned long long *) &jp->tid, (unsigned int *) &jp->max_buffers) == 2) { state = SEEKING_STATS; jp->version = 2; /* 2.x kernel header format */ } break; case SEEKING_STATS: if (strncmp(buf, "average: \n", 8) == 0) state = AVERAGE_STATS; break; case AVERAGE_STATS: value = strtoull(buf, &id, 10); if (id == buf) continue; else if (strcmp(id, "ms waiting for transaction\n") == 0) jp->waiting = value; else if (strcmp(id, "ms request delay\n") == 0) jp->request_delay = value; else if (strcmp(id, "ms running transaction\n") == 0) jp->running = value; else if (strcmp(id, "ms transaction was being locked\n") == 0) jp->locked = value; else if (strcmp(id, "ms flushing data (in ordered mode)\n") == 0) jp->flushing = value; else if (strcmp(id, "ms logging transaction\n") == 0) jp->logging = value; else if (strcmp(id, "us average transaction commit time\n") == 0) jp->average_commit_time = value; else if (strcmp(id, " handles per transaction\n") == 0) jp->handles = value; else if (strcmp(id, " blocks per transaction\n") == 0) jp->blocks = value; else if (strcmp(id, " logged blocks per transaction\n") == 0) jp->blocks_logged = value; break; default: break; } } fclose(fp); if (state != AVERAGE_STATS) { if (indom_changed) free(jp); return 0; } pmdaCacheStore(indom, PMDA_CACHE_ADD, dev, jp); return indom_changed; } int refresh_jbd2(const char *path, pmInDom jbd2_indom) { DIR *dirp; struct dirent *dent; int indom_changes = 0; static int first = 1; if (first) { /* initialize the instance domain caches */ pmdaCacheOp(jbd2_indom, PMDA_CACHE_LOAD); indom_changes = 1; first = 0; } pmdaCacheOp(jbd2_indom, PMDA_CACHE_INACTIVE); if ((dirp = opendir(path)) == NULL) return -ENOENT; while ((dent = readdir(dirp)) != NULL) indom_changes |= refresh_journal(path, dent->d_name, jbd2_indom); closedir(dirp); if (indom_changes) pmdaCacheOp(jbd2_indom, PMDA_CACHE_SAVE); return 0; } pcp-3.8.12ubuntu1/src/pmdas/jbd2/pmda.c0000664000000000000000000002410112272262501014401 0ustar /* * Journal Block Device v2 PMDA * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include "convert.h" #include "proc_jbd2.h" static int _isDSO = 1; /* =0 I am a daemon */ static char *prefix = "/proc/fs/jbd2"; static char *username; #define JBD2_INDOM 0 #define INDOM(i) (indomtab[i].it_indom) static pmdaIndom indomtab[] = { { JBD2_INDOM, 0, NULL }, /* cached */ }; static pmdaMetric metrictab[] = { /* jbd2.njournals */ { NULL, { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* jbd2.transaction.count */ { NULL, { PMDA_PMID(0,1), KERNEL_ULONG, JBD2_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* jbd2.transaction.requested */ { NULL, { PMDA_PMID(0,2), KERNEL_ULONG, JBD2_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* jbd2.transaction.max_blocks */ { NULL, { PMDA_PMID(0,3), PM_TYPE_U32, JBD2_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* jbd2.transaction.total.time.waiting */ { NULL, { PMDA_PMID(0,4), PM_TYPE_U64, JBD2_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* jbd2.transaction.total.time.request_delay */ { NULL, { PMDA_PMID(0,5), PM_TYPE_U64, JBD2_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* jbd2.transaction.total.time.running */ { NULL, { PMDA_PMID(0,6), PM_TYPE_U64, JBD2_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* jbd2.transaction.total.time.being_locked */ { NULL, { PMDA_PMID(0,7), PM_TYPE_U64, JBD2_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* jbd2.transaction.total.time.flushing_ordered_mode_data */ { NULL, { PMDA_PMID(0,8), PM_TYPE_U64, JBD2_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* jbd2.transaction.total.time.logging */ { NULL, { PMDA_PMID(0,9), PM_TYPE_U64, JBD2_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* jbd2.transaction.total.blocks */ { NULL, { PMDA_PMID(0,10), PM_TYPE_U64, JBD2_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* jbd2.transaction.total.blocks_logged */ { NULL, { PMDA_PMID(0,11), PM_TYPE_U64, JBD2_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* jbd2.transaction.total.handles */ { NULL, { PMDA_PMID(0,12), PM_TYPE_U64, JBD2_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* jbd2.transaction.average.time.waiting */ { NULL, { PMDA_PMID(0,13), PM_TYPE_U32, JBD2_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* jbd2.transaction.average.time.request_delay */ { NULL, { PMDA_PMID(0,14), PM_TYPE_U32, JBD2_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* jbd2.transaction.average.time.running */ { NULL, { PMDA_PMID(0,15), PM_TYPE_U32, JBD2_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* jbd2.transaction.average.time.being_locked */ { NULL, { PMDA_PMID(0,16), PM_TYPE_U32, JBD2_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* jbd2.transaction.average.time.flushing_ordered_mode_data */ { NULL, { PMDA_PMID(0,17), PM_TYPE_U32, JBD2_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* jbd2.transaction.average.time.logging */ { NULL, { PMDA_PMID(0,18), PM_TYPE_U32, JBD2_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* jbd2.transaction.average.time.committing */ { NULL, { PMDA_PMID(0,19), PM_TYPE_U64, JBD2_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_USEC,0) }, }, /* jbd2.transaction.average.blocks */ { NULL, { PMDA_PMID(0,20), KERNEL_ULONG, JBD2_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* jbd2.transaction.average.blocks_logged */ { NULL, { PMDA_PMID(0,21), KERNEL_ULONG, JBD2_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* jbd2.transaction.average.handles */ { NULL, { PMDA_PMID(0,22), KERNEL_ULONG, JBD2_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, }; static int jbd2_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) { refresh_jbd2(prefix, INDOM(JBD2_INDOM)); return pmdaInstance(indom, inst, name, result, pmda); } static int jbd2_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { refresh_jbd2(prefix, INDOM(JBD2_INDOM)); return pmdaFetch(numpmid, pmidlist, resp, pmda); } static int jbd2_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); int sts; proc_jbd2_t *jbd2; switch (idp->cluster) { case 0: if (!idp->item) { /* jbd2.njournals */ atom->ul = pmdaCacheOp(INDOM(JBD2_INDOM), PMDA_CACHE_SIZE_ACTIVE); break; } /* lookup the instance (journal device) */ sts = pmdaCacheLookup(INDOM(JBD2_INDOM), inst, NULL, (void **)&jbd2); if (sts < 0) return sts; if (sts != PMDA_CACHE_ACTIVE) return PM_ERR_INST; if (jbd2->version < 2) return 0; switch (idp->item) { case 1: /* transaction.count */ _pm_assign_ulong(atom, jbd2->tid); break; case 2: /* transaction.requested */ if (jbd2->version < 3) return 0; _pm_assign_ulong(atom, jbd2->requested); break; case 3: /* transaction.max_blocks */ atom->ul = jbd2->max_buffers; break; case 4: /* transaction.total.time.waiting */ atom->ull = jbd2->waiting * jbd2->tid; break; case 5: /* transaction.total.time.request_delay */ if (jbd2->version < 3) return 0; atom->ull = jbd2->request_delay * jbd2->requested; break; case 6: /* transaction.total.time.running */ atom->ull = jbd2->running * jbd2->tid; break; case 7: /* transaction.total.time.being_locked */ atom->ull = jbd2->locked * jbd2->tid; break; case 8: /* transaction.total.time.flushing_ordered_mode_data */ atom->ull = jbd2->flushing * jbd2->tid; break; case 9: /* transaction.total.time.logging */ atom->ull = jbd2->logging * jbd2->tid; break; case 10: /* transaction.total.blocks */ atom->ull = jbd2->blocks * jbd2->tid; break; case 11: /* transaction.total.blocks_logged */ atom->ull = jbd2->blocks_logged * jbd2->tid; break; case 12: /* transaction.total.handles */ atom->ull = jbd2->handles * jbd2->tid; break; case 13: /* transaction.average.time.waiting */ atom->ul = jbd2->waiting; break; case 14: /* transaction.total.time.request_delay */ if (jbd2->version < 3) return 0; atom->ul = jbd2->request_delay; break; case 15: /* transaction.total.time.running */ atom->ul = jbd2->running; break; case 16: /* transaction.total.time.being_locked */ atom->ul = jbd2->locked; break; case 17: /* transaction.total.time.flushing_ordered_mode_data */ atom->ul = jbd2->flushing; break; case 18: /* transaction.total.time.logging */ atom->ul = jbd2->logging; break; case 19: /* transaction.average.time.committing */ atom->ull = jbd2->average_commit_time; break; case 20: /* transaction.total.blocks */ _pm_assign_ulong(atom, jbd2->blocks); break; case 21: /* transaction.total.blocks_logged */ _pm_assign_ulong(atom, jbd2->blocks_logged); break; case 22: /* transaction.total.handles */ _pm_assign_ulong(atom, jbd2->handles); break; default: return PM_ERR_PMID; } break; default: /* unknown cluster */ return PM_ERR_PMID; } return 1; } /* * Initialise the agent (both daemon and DSO). */ void __PMDA_INIT_CALL jbd2_init(pmdaInterface *dp) { size_t nmetrics, nindoms; if (_isDSO) { char helppath[MAXPATHLEN]; int sep = __pmPathSeparator(); snprintf(helppath, sizeof(helppath), "%s%c" "jbd2" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_4, "jbd2 DSO", helppath); } else { __pmSetProcessIdentity(username); } if (dp->status != 0) return; dp->version.four.instance = jbd2_instance; dp->version.four.fetch = jbd2_fetch; pmdaSetFetchCallBack(dp, jbd2_fetchCallBack); nindoms = sizeof(indomtab)/sizeof(indomtab[0]); nmetrics = sizeof(metrictab)/sizeof(metrictab[0]); pmdaSetFlags(dp, PMDA_EXT_FLAG_DIRECT); pmdaInit(dp, indomtab, nindoms, metrictab, nmetrics); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -j path path to statistics files (default \"/proc/fs/jbd2\")\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int sep = __pmPathSeparator(); int err = 0; int c; pmdaInterface dispatch; char help[MAXPATHLEN]; _isDSO = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(help, sizeof(help), "%s%c" "jbd2" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_4, pmProgname, JBD2, "jbd2.log", help); while ((c = pmdaGetOpt(argc, argv, "D:d:l:j:U:?", &dispatch, &err)) != EOF) { switch(c) { case 'j': prefix = optarg; break; case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&dispatch); jbd2_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/jbd2/help0000664000000000000000000001247112272262501014176 0ustar # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # JBD2 PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ jbd2.njournals Count of active JBD2 (Journal Block Device v2) devices @ jbd2.transaction.count Total transactions committed per journal This metric is sourced from the per-device /proc/fs/jbd2 info file. @ jbd2.transaction.requested Total journal transactions requested per journal This metric is sourced from the per-device /proc/fs/jbd2 info file. @ jbd2.transaction.max_blocks Maximum transaction blocks (buffers) per journal This metric is sourced from the per-device /proc/fs/jbd2 info file. @ jbd2.transaction.average.time.waiting Average time waiting per journal Average time spent waiting for transactions to complete since mount. Exported directly from per-device /proc/fs/jbd2 info files. @ jbd2.transaction.average.time.request_delay Average request delay per journal Average request delay for all transactions to complete since mount. Exported directly from per-device /proc/fs/jbd2 info files. @ jbd2.transaction.average.time.running Average running time per journal Average transaction running time over all transactions since mount. Exported directly from per-device /proc/fs/jbd2 info files. @ jbd2.transaction.average.time.being_locked Average locked time per journal Average transaction locked time over all transactions since mount. Exported directly from per-device /proc/fs/jbd2 info files. @ jbd2.transaction.average.time.flushing_ordered_mode_data Average data flush time per journal Average time flushing data (ordered mode) for all transactions since mount. Exported directly from per-device /proc/fs/jbd2 info files. @ jbd2.transaction.average.time.logging Average logging time per journal Average time spent logging transactions for all transactions since mount. Exported directly from per-device /proc/fs/jbd2 info files. @ jbd2.transaction.average.time.committing Average commit time per journal Average time spent committing transactions for all transactions since mount. Exported directly from per-device /proc/fs/jbd2 info files. @ jbd2.transaction.average.blocks Average transaction blocks per journal Average number of blocks per transaction for all transactions. Exported directly from per-device /proc/fs/jbd2 info files. @ jbd2.transaction.average.blocks_logged Average logged blocks per journal Average number of blocks logged per transaction for all transactions. Exported directly from per-device /proc/fs/jbd2 info files. @ jbd2.transaction.average.handles Average handle count per journal Average number of handles used per transaction for all transactions. Exported directly from per-device /proc/fs/jbd2 info files. @ jbd2.transaction.total.time.waiting Total time waiting per journal Total time spent waiting for transactions to complete since mount. Derived from values in the per-device /proc/fs/jbd2 info files. @ jbd2.transaction.total.time.request_delay Total request delay per journal Total request delay for all transactions to complete since mount. Derived from values in the per-device /proc/fs/jbd2 info files. @ jbd2.transaction.total.time.running Total running time per journal Total transaction running time over all transactions since mount. Derived from values in the per-device /proc/fs/jbd2 info files. @ jbd2.transaction.total.time.being_locked Total locked time per journal Total transaction locked time over all transactions since mount. Derived from values in the per-device /proc/fs/jbd2 info files. @ jbd2.transaction.total.time.flushing_ordered_mode_data Total data flush time per journal Total time flushing data (ordered mode) for all transactions since mount. Derived from values in per-device /proc/fs/jbd2 info files. @ jbd2.transaction.total.time.logging Total logging time per journal Total time spent logging transactions for all transactions since mount. Derived from values in per-device /proc/fs/jbd2 info files. @ jbd2.transaction.total.blocks Total transaction blocks per journal Total number of blocks in all transactions since device mounted. Derived from values in the per-device /proc/fs/jbd2 info files. @ jbd2.transaction.total.blocks_logged Total logged blocks per journal Total number of blocks logged in all transactions since mount. Derived from values in the per-device /proc/fs/jbd2 info files. @ jbd2.transaction.total.handles Total handle count per journal Total count of handles used in all transactions since mount. Derived from values in the per-device /proc/fs/jbd2 info files. pcp-3.8.12ubuntu1/src/pmdas/roomtemp/0000775000000000000000000000000012272262620014341 5ustar pcp-3.8.12ubuntu1/src/pmdas/roomtemp/README0000664000000000000000000000374412272262501015227 0ustar Roomtemp PMDA ============= This PMDA exports the temperature from one or more sensors built using the DS2480 and DS1280 chipsets and MicroLAN (aka 1-Wire) technology from Dallas Semiconductor Corporation. See http://www.dalsemi.com/ You'll need the following hardware: DS2480 Serial 1-Wire Line Driver http://www.dalsemi.com/datasheets/pdfs/2480.pdf Not needed if you obtain one of the integrated packages like the DS9097U. DS9097U Universal 1-Wire COM Port Adapter http://www.dalsemi.com/datasheets/pdfs/9097u.pdf This includes the DS2480 and I have the DS9097U-S09 variant that is a standard DB-9 female package. DS1820 1-Wire Digital Thermometer http://www.dalsemi.com/datasheets/pdfs/1820.pdf After you've got at least one DS9097U and one DS1820 you'll need a spare serial port on the host running PMCD, a soldering iron and some cable (telco or similar) with an RJ-11 male plug attached at one end. Use the ./probe application to exercise all of the hardware before you try and install the PMDA. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT roomtemp Installation ============ + # cd $PCP_PMDAS_DIR/roomtemp + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/roomtemp # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/roomtemp.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/roomtemp/dsread.h0000664000000000000000000000014712272262501015754 0ustar #include "mlan/mlan.h" extern int ReadTemperature(uchar *, float *); unsigned char *nextsensor(void); pcp-3.8.12ubuntu1/src/pmdas/roomtemp/Remove0000664000000000000000000000205412272262501015520 0ustar #! /bin/sh # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the roomtemp PMDA # # source the PCP configuration environment variables . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=roomtemp # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/roomtemp/dsread.c0000664000000000000000000000565612272262501015761 0ustar #include #include #include #include #include #include "mlan/mlan.h" //---------------------------------------------------------------------- // Read the temperature of a DS1820 // // 'SerialNum' - Serial Number of DS1820 to read temperature from // 'Temp ' - pointer to variable where that temperature will be // returned // // Returns: TRUE(1) temperature has been read and verified // FALSE(0) could not read the temperature, perhaps device is not // in contact // int ReadTemperature(uchar SerialNum[8], float *Temp) { int rt=FALSE; uchar send_block[30]; int send_cnt=0, tsht, i; float tmp,cr,cpc; DOWCRC = 0; // set the device serial number to the counter device MLanSerialNum(SerialNum,FALSE); // access the device if (MLanAccess()) { // send the convert temperature command MLanTouchByte(0x44); // set the MicroLAN to strong pull-up if (MLanLevel(MODE_STRONG5) != MODE_STRONG5) return FALSE; // sleep for 1 second msDelay(1000); // turn off the MicroLAN strong pull-up if (MLanLevel(MODE_NORMAL) != MODE_NORMAL) return FALSE; // access the device if (MLanAccess()) { // create a block to send that reads the temperature // read scratchpad command send_block[send_cnt++] = 0xBE; // now add the read bytes for data bytes and crc8 for (i = 0; i < 9; i++) send_block[send_cnt++] = 0xFF; // now send the block if (MLanBlock(FALSE,send_block,send_cnt)) { // perform the CRC8 on the last 8 bytes of packet for (i = send_cnt - 9; i < send_cnt; i++) dowcrc(send_block[i]); // verify CRC8 is correct if (DOWCRC == 0x00) { // calculate the high-res temperature tsht = send_block[1]; if (send_block[2] & 0x01) tsht |= -256; tmp = (float)(tsht/2); cr = send_block[7]; cpc = send_block[8]; if (cpc == 0) return FALSE; else tmp = tmp - (float)0.25 + (cpc - cr)/cpc; *Temp = tmp; // success rt = TRUE; } } } } // return the result flag rt return rt; } /* * find next temperature sensor */ unsigned char * nextsensor(void) { static unsigned char sn[8]; static int first = 1; if (first) { // set the search to first find for temperature family code MLanFamilySearchSetup(TEMP_FAMILY); first = 0; } for ( ; ; ) { // perform the search if (!MLanNext(TRUE, FALSE)) { return NULL; } // get serial number and verify the family code MLanSerialNum(sn, TRUE); if (sn[0] == TEMP_FAMILY) return sn; } } pcp-3.8.12ubuntu1/src/pmdas/roomtemp/Install0000664000000000000000000000243612272262501015675 0ustar #! /bin/sh # # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the roomtemp PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=roomtemp pmda_interface=2 forced_restart=true pmdaSetup if $do_pmda then if [ -c /dev/ttyf1 ] then # reasonable first guess for IRIX # tty=/dev/ttyf1 elif [ -c /dev/ttyS0 ] then # reasonable first guess for COM port on a Linux laptop # tty=/dev/ttyS0 fi while true do $PCP_ECHO_PROG $PCP_ECHO_N "Serial line for Dallas device? ""$PCP_ECHO_C" [ ! -z "$tty" ] && $PCP_ECHO_PROG $PCP_ECHO_N "[$tty] ""$PCP_ECHO_C" read ans [ ! -z "$ans" ] && tty="$ans" [ ! -z "$tty" ] && break echo echo "Ahem, you must answer the question ..." done args="$tty" fi pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/roomtemp/GNUmakefile0000664000000000000000000000302712272262501016413 0ustar # # Copyright (c) 2000-2001,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs HFILES = dsread.h CFILES = roomtemp.c dsread.c HFILES = dsread.h CMDTARGET = pmdaroomtemp LLDFLAGS = -L. LLDLIBS = -lmlan $(PCP_PMDALIB) LCFLAGS = -I. DFILES = README help LSRCFILES = Install Remove pmns $(DFILES) root SUBDIRS = mlan IAM = roomtemp DOMAIN = ROOMTEMP PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LDIRT = domain.h $(IAM).log pmda$(IAM) pmda_$(IAM).so libmlan.a default: build-me include $(BUILDRULES) .NOTPARALLEL: ifeq "$(findstring $(TARGET_OS),solaris linux)" "" build-me: $(SUBDIRS_MAKERULE) install: else build-me: domain.h libmlan.a $(CMDTARGET) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(CMDTARGET) $(PMDADIR) $(INSTALL) -m 644 $(DFILES) root pmns domain.h $(PMDADIR) endif domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) libmlan.a : $(SUBDIRS) $(SUBDIRS_MAKERULE) rm -f libmlan.a ln -sf mlan/libmlan.a . default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmdas/roomtemp/root0000664000000000000000000000016512272262501015247 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { roomtemp } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/roomtemp/pmns0000664000000000000000000000160412272262501015240 0ustar /* * Metrics for roomtemp PMDA * * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ roomtemp { celsius ROOMTEMP:0:0 fahrenheit ROOMTEMP:0:1 } pcp-3.8.12ubuntu1/src/pmdas/roomtemp/roomtemp.c0000664000000000000000000001310712272262521016351 0ustar /* * Roomtemp PMDA * * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include "dsread.h" /* * Roomtemp PMDA * * This PMDA exports the temperature from one or more sensors built using * the DS2480 and DS1280 chipsets and MicroLAN technology from Dallas * Semiconductor Corporation. */ /* * Serial device */ static char *tty; /* * list of instances */ static pmdaInstid *device = NULL; /* * list of instance domains */ static pmdaIndom indomtab[] = { #define DEVICE 0 { DEVICE, 0, NULL }, }; typedef struct { unsigned char sn[8]; } sn_t; sn_t *sntab = NULL; /* * All metrics supported in this PMDA - one table entry for each. * The 4th field specifies the serial number of the instance domain * for the metric, and must be either PM_INDOM_NULL (denoting a * metric that only ever has a single value), or the serial number * of one of the instance domains declared in the instance domain table * (i.e. in indomtab, above). */ static pmdaMetric metrictab[] = { /* roomtemp.celsius */ { NULL, { PMDA_PMID(0,0), PM_TYPE_FLOAT, DEVICE, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* roomtemp.fahrenheit */ { NULL, { PMDA_PMID(0,1), PM_TYPE_FLOAT, DEVICE, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, }; /* * callback provided to pmdaFetch */ static int roomtemp_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); char return_msg[128]; int numval = 0; if (idp->cluster == 0) { if (inst >= indomtab[DEVICE].it_numinst) return PM_ERR_INST; switch (idp->item) { case 0: /* roomtemp.celsius */ case 1: /* roomtemp.fahrenheit */ if (!Aquire1WireNet(tty, return_msg)) { fputs(return_msg, stderr); exit(1); } if (ReadTemperature(sntab[inst].sn, &atom->f)) numval = 1; Release1WireNet(return_msg); if (idp->item == 1) /* convert to fahrenheit */ atom->f = atom->f * 9 / 5 + 32; break; default: return PM_ERR_PMID; } } else return PM_ERR_PMID; return numval; } /* * Initialise the agent */ void roomtemp_init(pmdaInterface *dp) { int i; char return_msg[128]; unsigned char *p; if (dp->status != 0) return; pmdaSetFetchCallBack(dp, roomtemp_fetchCallBack); if (!Aquire1WireNet(tty, return_msg)) { fputs(return_msg, stderr); exit(1); } for (i = 0; ; i++) { if ((p = nextsensor()) == NULL) break; if ((sntab = (sn_t *)realloc(sntab, (i+1) * sizeof(sn_t))) == NULL) { __pmNoMem("roomtemp_init: realloc sntab", (i+1) * sizeof(sn_t), PM_FATAL_ERR); } if ((device = (pmdaInstid *)realloc(device, (i+1) * sizeof(pmdaInstid))) == NULL) { __pmNoMem("roomtemp_init: realloc device", (i+1) * sizeof(pmdaInstid), PM_FATAL_ERR); } if ((device[i].i_name = (char *)malloc(17)) == NULL) { __pmNoMem("roomtemp_init: malloc name", 17, PM_FATAL_ERR); } memcpy(sntab[i].sn, p, 8); /* SN for later fetch */ device[i].i_inst = i; /* internal name is ordinal number */ /* external name is SN in hex */ sprintf(device[i].i_name, "%02X%02X%02X%02X%02X%02X%02X%02X", p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); fprintf(stderr, "Found temp sensor SN %s\n", device[i].i_name); } Release1WireNet(return_msg); indomtab[DEVICE].it_numinst = i; indomtab[DEVICE].it_set = device; pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), metrictab, sizeof(metrictab)/sizeof(metrictab[0])); } static void usage(void) { fprintf(stderr, "Usage: %s [options] tty ...\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" "\nExactly one of the following options may appear:\n" " -i port expect PMCD to connect on given inet port (number or name)\n" " -p expect PMCD to supply stdin/stdout (pipe)\n" " -u socket expect PMCD to connect on given unix domain socket\n" " -6 port expect PMCD to connect on given ipv6 port (number or name)\n", stderr); exit(1); } int main(int argc, char **argv) { int err = 0; int sep = __pmPathSeparator(); pmdaInterface dispatch; char mypath[MAXPATHLEN]; __pmSetProgname(argv[0]); snprintf(mypath, sizeof(mypath), "%s%c" "roomtemp" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_3, pmProgname, ROOMTEMP, "roomtemp.log", mypath); if (pmdaGetOpt(argc, argv, "D:d:i:l:pu:6:?", &dispatch, &err) != EOF) err++; if (err) usage(); if (argc != optind+1) usage(); tty = argv[optind]; pmdaOpenLog(&dispatch); roomtemp_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/roomtemp/mlan/0000775000000000000000000000000012272262620015270 5ustar pcp-3.8.12ubuntu1/src/pmdas/roomtemp/mlan/mlantrnu.c0000664000000000000000000004334512272262501017303 0ustar //--------------------------------------------------------------------------- // Copyright (C) 1999 Dallas Semiconductor Corporation, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // Except as contained in this notice, the name of Dallas Semiconductor // shall not be used except as stated in the Dallas Semiconductor // Branding Policy. //--------------------------------------------------------------------------- // // MLanTranU.C - Transport functions for MicroLAN 1-Wire devices // using the DS2480 (U) serial interface chip. // // Version: 1.03 // // 1.02 -> 1.03 Removed caps in #includes for Linux capatibility // #include "ds2480.h" #include "mlan.h" // external low-level functions required extern int MLanTouchReset(void); extern int MLanWriteByte(int); extern int MLanReadByte(void); extern int MLanProgramPulse(void); // external network-level functions required extern int MLanAccess(); // external COM functions required extern void FlushCOM(void); extern int WriteCOM(int, uchar *); extern int ReadCOM(int, uchar *); // other external functions extern int DS2480Detect(void); extern uchar dowcrc(uchar); // external globals extern int UMode; extern int UBaud; extern int USpeed; extern uchar SerialNum[8]; extern uchar DOWCRC; // local exportable functions int MLanBlock(int, uchar *, int); int MLanReadPacketStd(int, int, uchar *); int MLanWritePacketStd(int, uchar *, int, int, int); int MLanProgramByte(int, int, int, int, int); // local functions static int Write_Scratchpad(uchar *, int, int); static int Copy_Scratchpad(int, int); unsigned short crc16(int); // global variable unsigned short CRC16; //-------------------------------------------------------------------------- // The 'MLanBlock' transfers a block of data to and from the // MicroLAN with an optional reset at the begining of communication. // The result is returned in the same buffer. // // 'DoReset' - cause a MLanTouchReset to occure at the begining of // communication TRUE(1) or not FALSE(0) // 'TransferBuffer' - pointer to a block of unsigned // chars of length 'TranferLength' that will be sent // to the MicroLAN // 'TranferLength' - length in bytes to transfer // Supported devices: all // // Returns: TRUE (1) : The optional reset returned a valid // presence (DoReset == TRUE) or there // was no reset required. // FALSE (0): The reset did not return a valid prsence // (DoReset == TRUE). // // The maximum TransferLength is 64 // int MLanBlock(int DoReset, uchar *TransferBuffer, int TransferLen) { uchar sendpacket[150]; int sendlen=0,i; // check for a block too big if (TransferLen > 64) return FALSE; // check if need to do a MLanTouchReset first if (DoReset) { if (!MLanTouchReset()) return FALSE; } // construct the packet to send to the DS2480 // check if correct mode if (UMode != MODSEL_DATA) { UMode = MODSEL_DATA; sendpacket[sendlen++] = MODE_DATA; } // add the bytes to send for (i = 0; i < TransferLen; i++) { sendpacket[sendlen++] = TransferBuffer[i]; // check for duplication of data that looks like COMMAND mode if (TransferBuffer[i] == MODE_COMMAND) sendpacket[sendlen++] = TransferBuffer[i]; } // flush the buffers FlushCOM(); // send the packet if (WriteCOM(sendlen,sendpacket)) { // read back the response if (ReadCOM(TransferLen,TransferBuffer) == TransferLen) return TRUE; } // an error occured so re-sync with DS2480 DS2480Detect(); return FALSE; } //-------------------------------------------------------------------------- // Read a Universal Data Packet from a standard NVRAM iButton // and return it in the provided buffer. The page that the // packet resides on is 'StartPage'. Note that this function is limited // to single page packets. The buffer 'ReadBuffer' must be at least // 29 bytes long. // // The Universal Data Packet always start on page boundaries but // can end anywhere. The length is the number of data bytes not // including the length byte and the CRC16 bytes. There is one // length byte. The CRC16 is first initialized to the starting // page number. This provides a check to verify the page that // was intended is being read. The CRC16 is then calculated over // the length and data bytes. The CRC16 is then inverted and stored // low byte first followed by the high byte. // // Supported devices: DS1992, DS1993, DS1994, DS1995, DS1996, DS1982, // DS1985, DS1986, DS2407, and DS1971. // // 'DoAccess' - flag to indicate if an 'MLanAccess' should be // peformed at the begining of the read. This may // be FALSE (0) if the previous call was to read the // previous page (StartPage-1). // 'StartPage' - page number to start the read from // 'ReadBuffer' - pointer to a location to store the data read // // Returns: >=0 success, number of data bytes in the buffer // -1 failed to read a valid UDP // // int MLanReadPacketStd(int DoAccess, int StartPage, uchar *ReadBuffer) { int i,length,TranCnt=0,HeadLen=0; uchar TranBuf[50]; // check if access header is done // (only use if in sequention read with one access at begining) if (DoAccess) { // match command TranBuf[TranCnt++] = 0x55; for (i = 0; i < 8; i++) TranBuf[TranCnt++] = SerialNum[i]; // read memory command TranBuf[TranCnt++] = 0xF0; // write the target address TranBuf[TranCnt++] = ((StartPage << 5) & 0xFF); TranBuf[TranCnt++] = (StartPage >> 3); // check for DS1982 exception (redirection byte) if (SerialNum[0] == 0x09) TranBuf[TranCnt++] = 0xFF; // record the header length HeadLen = TranCnt; } // read the entire page length byte for (i = 0; i < 32; i++) TranBuf[TranCnt++] = 0xFF; // send/recieve the transfer buffer if (MLanBlock(DoAccess,TranBuf,TranCnt)) { // seed crc with page number CRC16 = StartPage; // attempt to read UDP from TranBuf length = TranBuf[HeadLen]; crc16(length); // verify length is not too large if (length <= 29) { // loop to read packet including CRC for (i = 0; i < length; i++) { ReadBuffer[i] = TranBuf[i+1+HeadLen]; crc16(ReadBuffer[i]); } // read and compute the CRC16 crc16(TranBuf[i+1+HeadLen]); crc16(TranBuf[i+2+HeadLen]); // verify the CRC16 is correct if (CRC16 == 0xB001) return length; // return number of byte in record } } // failed block or incorrect CRC return -1; } //-------------------------------------------------------------------------- // Write a Universal Data Packet onto a standard NVRAM 1-Wire device // on page 'StartPage'. This function is limited to UDPs that // fit on one page. The data to write is provided as a buffer // 'WriteBuffer' with a length 'WriteLength'. // // The Universal Data Packet always start on page boundaries but // can end anywhere. The length is the number of data bytes not // including the length byte and the CRC16 bytes. There is one // length byte. The CRC16 is first initialized to the starting // page number. This provides a check to verify the page that // was intended is being read. The CRC16 is then calculated over // the length and data bytes. The CRC16 is then inverted and stored // low byte first followed by the high byte. // // Supported devices: DeviceEPROM=0 // DS1992, DS1993, DS1994, DS1995, DS1996 // DeviceEPROM=1, EPROMCRCType=0(CRC8) // DS1982 // DeviceEPROM=1, EPROMCRCType=1(CRC16) // DS1985, DS1986, DS2407 // // 'StartPage' - page number to write packet to // 'WriteBuffer' - pointer to buffer containing data to write // 'WriteLength' - number of data byte in WriteBuffer // 'DeviceEPROM' - flag set if device is an EPROM (1 EPROM, 0 NVRAM) // 'EPROMCRCType' - if DeviceEPROM=1 then indicates CRC type // (0 CRC8, 1 CRC16) // // Returns: TRUE(1) success, packet written // FALSE(0) failure to write, contact lost or device locked // // int MLanWritePacketStd(int StartPage, uchar *WriteBuffer, int WriteLength, int DeviceEPROM, int EPROMCRCType) { uchar construct_buffer[32]; int i,buffer_cnt=0,start_address,do_access; // check to see if data too long to fit on device if (WriteLength > 29) return FALSE; // seed crc with page number CRC16 = StartPage; // set length byte construct_buffer[buffer_cnt++] = (uchar)(WriteLength); crc16(WriteLength); // fill in the data to write for (i = 0; i < WriteLength; i++) { crc16(WriteBuffer[i]); construct_buffer[buffer_cnt++] = WriteBuffer[i]; } // add the crc construct_buffer[buffer_cnt++] = (uchar)(~(CRC16 & 0xFF)); construct_buffer[buffer_cnt++] = (uchar)(~((CRC16 & 0xFF00) >> 8)); // check if not EPROM if (!DeviceEPROM) { // write the page if (!Write_Scratchpad(construct_buffer,StartPage,buffer_cnt)) return FALSE; // copy the scratchpad if (!Copy_Scratchpad(StartPage,buffer_cnt)) return FALSE; // copy scratch pad was good then success return TRUE; } // is EPROM else { // calculate the start address start_address = ((StartPage >> 3) << 8) | ((StartPage << 5) & 0xFF); do_access = TRUE; // loop to program each byte for (i = 0; i < buffer_cnt; i++) { if (MLanProgramByte(construct_buffer[i], start_address + i, 0x0F, EPROMCRCType, do_access) != construct_buffer[i]) return FALSE; do_access = FALSE; } return TRUE; } } //-------------------------------------------------------------------------- // Write a byte to an EPROM 1-Wire device. // // Supported devices: CRCType=0(CRC8) // DS1982 // CRCType=1(CRC16) // DS1985, DS1986, DS2407 // // 'WRByte' - byte to program // 'Addr' - address of byte to program // 'WriteCommand' - command used to write (0x0F reg mem, 0x55 status) // 'CRCType' - CRC used (0 CRC8, 1 CRC16) // 'DoAccess' - Flag to access device for each byte // (0 skip access, 1 do the access) // WARNING, only use DoAccess=0 if programing the NEXT // byte immediatly after the previous byte. // // Returns: >=0 success, this is the resulting byte from the program // effort // -1 error, device not connected or program pulse voltage // not available // int MLanProgramByte(int WRByte, int Addr, int WriteCommand, int CRCType, int DoAccess) { // optionally access the device if (DoAccess) { if (!MLanAccess()) return -1; // send the write command if (!MLanWriteByte(WriteCommand)) return -1; // send the address if (!MLanWriteByte(Addr & 0xFF)) return -1; if (!MLanWriteByte(Addr >> 8)) return -1; } // send the data to write if (!MLanWriteByte(WRByte)) return -1; // read the CRC if (CRCType == 0) { // calculate CRC8 if (DoAccess) { DOWCRC = 0; dowcrc((uchar)WriteCommand); dowcrc((uchar)(Addr & 0xFF)); dowcrc((uchar)(Addr >> 8)); } else DOWCRC = (uchar)(Addr & 0xFF); dowcrc((uchar)WRByte); // read and calculate the read crc dowcrc((uchar)MLanReadByte()); // crc should now be 0x00 if (DOWCRC != 0) return -1; } else { // CRC16 if (DoAccess) { CRC16 = 0; crc16(WriteCommand); crc16(Addr & 0xFF); crc16(Addr >> 8); } else CRC16 = Addr; crc16(WRByte); // read and calculate the read crc crc16(MLanReadByte()); crc16(MLanReadByte()); // crc should now be 0xB001 if (CRC16 != 0xB001) return -1; } // send the program pulse if (!MLanProgramPulse()) return -1; // read back and return the resulting byte return MLanReadByte(); } //-------------------------------------------------------------------------- // Write the scratchpad of a standard NVRam device such as the DS1992,3,4 // and verify its contents. // // 'WriteBuffer' - pointer to buffer containing data to write // 'StartPage' - page number to write packet to // 'WriteLength' - number of data byte in WriteBuffer // // Returns: TRUE(1) success, the data was written and verified // FALSE(0) failure, the data could not be written // // int Write_Scratchpad(uchar *WriteBuffer, int StartPage, int WriteLength) { int i,TranCnt=0; uchar TranBuf[50]; // match command TranBuf[TranCnt++] = 0x55; for (i = 0; i < 8; i++) TranBuf[TranCnt++] = SerialNum[i]; // write scratchpad command TranBuf[TranCnt++] = 0x0F; // write the target address TranBuf[TranCnt++] = ((StartPage << 5) & 0xFF); TranBuf[TranCnt++] = (StartPage >> 3); // write packet bytes for (i = 0; i < WriteLength; i++) TranBuf[TranCnt++] = WriteBuffer[i]; // send/recieve the transfer buffer if (MLanBlock(TRUE,TranBuf,TranCnt)) { // now attempt to read back to check TranCnt = 0; // match command TranBuf[TranCnt++] = 0x55; for (i = 0; i < 8; i++) TranBuf[TranCnt++] = SerialNum[i]; // read scratchpad command TranBuf[TranCnt++] = 0xAA; // read the target address, offset and data for (i = 0; i < (WriteLength + 3); i++) TranBuf[TranCnt++] = 0xFF; // send/recieve the transfer buffer if (MLanBlock(TRUE,TranBuf,TranCnt)) { // check address and offset of scratchpad read if ((TranBuf[10] != (int)((StartPage << 5) & 0xFF)) || (TranBuf[11] != (int)(StartPage >> 3)) || (TranBuf[12] != (int)(WriteLength - 1))) return FALSE; // verify each data byte for (i = 0; i < WriteLength; i++) if (TranBuf[i+13] != WriteBuffer[i]) return FALSE; // must have verified return TRUE; } } // failed a block tranfer return FALSE; } //-------------------------------------------------------------------------- // Copy the contents of the scratchpad to its intended nv ram page. The // page and length of the data is needed to build the authorization bytes // to copy. // // 'StartPage' - page number to write packet to // 'WriteLength' - number of data bytes that are being copied // // Returns: TRUE(1) success // FALSE(0) failure // int Copy_Scratchpad(int StartPage, int WriteLength) { int i,TranCnt=0; uchar TranBuf[50]; // match command TranBuf[TranCnt++] = 0x55; for (i = 0; i < 8; i++) TranBuf[TranCnt++] = SerialNum[i]; // copy scratchpad command TranBuf[TranCnt++] = 0x55; // write the target address TranBuf[TranCnt++] = ((StartPage << 5) & 0xFF); TranBuf[TranCnt++] = (StartPage >> 3); TranBuf[TranCnt++] = WriteLength - 1; // read copy result TranBuf[TranCnt++] = 0xFF; // send/recieve the transfer buffer if (MLanBlock(TRUE,TranBuf,TranCnt)) { // check address and offset of scratchpad read if ((TranBuf[10] != (int)((StartPage << 5) & 0xFF)) || (TranBuf[11] != (int)(StartPage >> 3)) || (TranBuf[12] != (int)(WriteLength - 1)) || (TranBuf[13] & 0xF0)) return FALSE; else return TRUE; } // failed a block tranfer return FALSE; } //-------------------------------------------------------------------------- // Calculate a new CRC16 from the input data integer. Return the current // CRC16 and also update the global variable CRC16. // // 'data' - data to perform a CRC16 on // // Returns: the current CRC16 // static short oddparity[16] = { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; unsigned short crc16(int data) { data = (data ^ (CRC16 & 0xff)) & 0xff; CRC16 >>= 8; if (oddparity[data & 0xf] ^ oddparity[data >> 4]) CRC16 ^= 0xc001; data <<= 6; CRC16 ^= data; data <<= 1; CRC16 ^= data; return CRC16; } pcp-3.8.12ubuntu1/src/pmdas/roomtemp/mlan/ds2480.h0000664000000000000000000001540612272262501016371 0ustar //--------------------------------------------------------------------------- // Copyright (C) 1999 Dallas Semiconductor Corporation, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // Except as contained in this notice, the name of Dallas Semiconductor // shall not be used except as stated in the Dallas Semiconductor // Branding Policy. //--------------------------------------------------------------------------- // // DS2480.H - This file contains the DS2480 constants // // Version: 1.03 // History: 1.02 -> 1.03 Make sure uchar is not defined twice. // // // typedefs #ifndef UCHAR #define UCHAR typedef unsigned char uchar; #endif // Mode Commands #define MODE_DATA 0xE1 #define MODE_COMMAND 0xE3 #define MODE_STOP_PULSE 0xF1 // Return byte value #define RB_CHIPID_MASK 0x1C #define RB_RESET_MASK 0x03 #define RB_1WIRESHORT 0x00 #define RB_PRESENCE 0x01 #define RB_ALARMPRESENCE 0x02 #define RB_NOPRESENCE 0x03 #define RB_BIT_MASK 0x03 #define RB_BIT_ONE 0x03 #define RB_BIT_ZERO 0x00 // Masks for all bit ranges #define CMD_MASK 0x80 #define FUNCTSEL_MASK 0x60 #define BITPOL_MASK 0x10 #define SPEEDSEL_MASK 0x0C #define MODSEL_MASK 0x02 #define PARMSEL_MASK 0x70 #define PARMSET_MASK 0x0E // Command or config bit #define CMD_COMM 0x81 #define CMD_CONFIG 0x01 // Function select bits #define FUNCTSEL_BIT 0x00 #define FUNCTSEL_SEARCHON 0x30 #define FUNCTSEL_SEARCHOFF 0x20 #define FUNCTSEL_RESET 0x40 #define FUNCTSEL_CHMOD 0x60 // Bit polarity/Pulse voltage bits #define BITPOL_ONE 0x10 #define BITPOL_ZERO 0x00 #define BITPOL_5V 0x00 #define BITPOL_12V 0x10 // One Wire speed bits #define SPEEDSEL_STD 0x00 #define SPEEDSEL_FLEX 0x04 #define SPEEDSEL_OD 0x08 #define SPEEDSEL_PULSE 0x0C // Data/Command mode select bits #define MODSEL_DATA 0x00 #define MODSEL_COMMAND 0x02 // 5V Follow Pulse select bits (If 5V pulse // will be following the next byte or bit.) #define PRIME5V_TRUE 0x02 #define PRIME5V_FALSE 0x00 // Parameter select bits #define PARMSEL_PARMREAD 0x00 #define PARMSEL_SLEW 0x10 #define PARMSEL_12VPULSE 0x20 #define PARMSEL_5VPULSE 0x30 #define PARMSEL_WRITE1LOW 0x40 #define PARMSEL_SAMPLEOFFSET 0x50 #define PARMSEL_ACTIVEPULLUPTIME 0x60 #define PARMSEL_BAUDRATE 0x70 // Pull down slew rate. #define PARMSET_Slew15Vus 0x00 #define PARMSET_Slew2p2Vus 0x02 #define PARMSET_Slew1p65Vus 0x04 #define PARMSET_Slew1p37Vus 0x06 #define PARMSET_Slew1p1Vus 0x08 #define PARMSET_Slew0p83Vus 0x0A #define PARMSET_Slew0p7Vus 0x0C #define PARMSET_Slew0p55Vus 0x0E // 12V programming pulse time table #define PARMSET_32us 0x00 #define PARMSET_64us 0x02 #define PARMSET_128us 0x04 #define PARMSET_256us 0x06 #define PARMSET_512us 0x08 #define PARMSET_1024us 0x0A #define PARMSET_2048us 0x0C #define PARMSET_infinite 0x0E // 5V strong pull up pulse time table #define PARMSET_16p4ms 0x00 #define PARMSET_65p5ms 0x02 #define PARMSET_131ms 0x04 #define PARMSET_262ms 0x06 #define PARMSET_524ms 0x08 #define PARMSET_1p05s 0x0A #define PARMSET_2p10s 0x0C #define PARMSET_infinite 0x0E // Write 1 low time #define PARMSET_Write8us 0x00 #define PARMSET_Write9us 0x02 #define PARMSET_Write10us 0x04 #define PARMSET_Write11us 0x06 #define PARMSET_Write12us 0x08 #define PARMSET_Write13us 0x0A #define PARMSET_Write14us 0x0C #define PARMSET_Write15us 0x0E // Data sample offset and Write 0 recovery time #define PARMSET_SampOff3us 0x00 #define PARMSET_SampOff4us 0x02 #define PARMSET_SampOff5us 0x04 #define PARMSET_SampOff6us 0x06 #define PARMSET_SampOff7us 0x08 #define PARMSET_SampOff8us 0x0A #define PARMSET_SampOff9us 0x0C #define PARMSET_SampOff10us 0x0E // Active pull up on time #define PARMSET_PullUp0p0us 0x00 #define PARMSET_PullUp0p5us 0x02 #define PARMSET_PullUp1p0us 0x04 #define PARMSET_PullUp1p5us 0x06 #define PARMSET_PullUp2p0us 0x08 #define PARMSET_PullUp2p5us 0x0A #define PARMSET_PullUp3p0us 0x0C #define PARMSET_PullUp3p5us 0x0E // Baud rate bits #define PARMSET_9600 0x00 #define PARMSET_19200 0x02 #define PARMSET_57600 0x04 #define PARMSET_115200 0x06 // DS2480 program voltage available #define DS2480PROG_MASK 0x20 // mode bit flags #define MODE_NORMAL 0x00 #define MODE_OVERDRIVE 0x01 #define MODE_STRONG5 0x02 #define MODE_PROGRAM 0x04 #define MODE_BREAK 0x08 pcp-3.8.12ubuntu1/src/pmdas/roomtemp/mlan/ds2480ut.c0000664000000000000000000001467612272262501016745 0ustar //--------------------------------------------------------------------------- // Copyright (C) 1999 Dallas Semiconductor Corporation, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // Except as contained in this notice, the name of Dallas Semiconductor // shall not be used except as stated in the Dallas Semiconductor // Branding Policy. //--------------------------------------------------------------------------- // // ds2480ut.c - DS2480 utility functions. // // Version: 1.03 // // History: 1.00 -> 1.01 Default PDSRC changed from 0.83 to 1.37V/us // in DS2480Detect. Changed to use msDelay instead // of Delay. // // 1.01 -> 1.02 Changed global declarations from 'uchar' to 'int'. // Changed DSO/WORT from 7 to 10us in DS2480Detect. // // 1.02 -> 1.03 Removed caps in #includes for Linux capatibility #include "ds2480.h" #include "mlan.h" // external COM functions required extern void FlushCOM(void); extern int WriteCOM(int, uchar *); extern int ReadCOM(int, uchar *); extern void BreakCOM(void); //extern void SetBaudCOM(uchar); extern void msDelay(int); // exportable functions int DS2480Detect(void); int DS2480ChangeBaud(uchar); // global DS2480 state int UMode = MODSEL_COMMAND; // current DS2480 command or data mode stateuchar int UBaud = PARMSET_9600; // current DS2480 baud rate int USpeed = SPEEDSEL_FLEX; // current DS2480 MicroLAN communication speed int ULevel = MODE_NORMAL; // current DS2480 MicroLAN level //--------------------------------------------------------------------------- // Attempt to resyc and detect a DS2480 // // Returns: TRUE - DS2480 detected successfully // FALSE - Could not detect DS2480 // int DS2480Detect(void) { uchar sendpacket[10],readbuffer[10]; short sendlen=0; // reset modes UMode = MODSEL_COMMAND; UBaud = PARMSET_9600; USpeed = SPEEDSEL_FLEX; // set the baud rate to 9600 SetBaudCOM((uchar)UBaud); // send a break to reset the DS2480 BreakCOM(); // delay to let line settle msDelay(2); // flush the buffers FlushCOM(); // send the timing byte sendpacket[0] = 0xC1; if (WriteCOM(1,sendpacket) != 1) return FALSE; // set the FLEX configuration parameters // default PDSRC = 1.37Vus sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_SLEW | PARMSET_Slew1p37Vus; // default W1LT = 12us sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_WRITE1LOW | PARMSET_Write12us; // default DSO/WORT = 10us sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_SAMPLEOFFSET | PARMSET_SampOff10us; // construct the command to read the baud rate (to test command block) sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_PARMREAD | (PARMSEL_BAUDRATE >> 3); // also do 1 bit operation (to test 1-Wire block) sendpacket[sendlen++] = CMD_COMM | FUNCTSEL_BIT | UBaud | BITPOL_ONE; // flush the buffers FlushCOM(); // send the packet if (WriteCOM(sendlen,sendpacket)) { // read back the response if (ReadCOM(5,readbuffer) == 5) { // look at the baud rate and bit operation // to see if the response makes sense if (((readbuffer[3] & 0xF1) == 0x00) && ((readbuffer[3] & 0x0E) == UBaud) && ((readbuffer[4] & 0xF0) == 0x90) && ((readbuffer[4] & 0x0C) == UBaud)) return TRUE; } } return FALSE; } //--------------------------------------------------------------------------- // Change the DS2480 from the current baud rate to the new baud rate. // // 'newbaud' - the new baud rate to change to, defined as: // PARMSET_9600 0x00 // PARMSET_19200 0x02 // PARMSET_57600 0x04 // PARMSET_115200 0x06 // // Returns: current DS2480 baud rate. // int DS2480ChangeBaud(uchar newbaud) { int rt=FALSE; uchar readbuffer[5],sendpacket[5],sendpacket2[5]; int sendlen=0,sendlen2=0; // see if diffenent then current baud rate if (UBaud == newbaud) return TRUE; else { // build the command packet // check if correct mode if (UMode != MODSEL_COMMAND) { UMode = MODSEL_COMMAND; sendpacket[sendlen++] = MODE_COMMAND; } // build the command sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_BAUDRATE | newbaud; // flush the buffers FlushCOM(); // send the packet if (!WriteCOM(sendlen,sendpacket)) rt = FALSE; else { // make sure buffer is flushed msDelay(5); // change our baud rate SetBaudCOM(newbaud); UBaud = newbaud; // wait for things to settle msDelay(5); // build a command packet to read back baud rate sendpacket2[sendlen2++] = CMD_CONFIG | PARMSEL_PARMREAD | (PARMSEL_BAUDRATE >> 3); // flush the buffers FlushCOM(); // send the packet if (WriteCOM(sendlen2,sendpacket2)) { // read back the 1 byte response if (ReadCOM(1,readbuffer) == 1) { // verify correct baud if (((readbuffer[0] & 0x0E) == (sendpacket[sendlen-1] & 0x0E))) rt = TRUE; } } } } // if lost communication with DS2480 then reset if (rt != TRUE) DS2480Detect(); return UBaud; } pcp-3.8.12ubuntu1/src/pmdas/roomtemp/mlan/mlan.h0000664000000000000000000000623012272262501016367 0ustar //--------------------------------------------------------------------------- // Copyright (C) 1999 Dallas Semiconductor Corporation, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // Except as contained in this notice, the name of Dallas Semiconductor // shall not be used except as stated in the Dallas Semiconductor // Branding Policy. //--------------------------------------------------------------------------- // // MLan.H - Include file for MicroLAN library // // Version: 1.03 // History: 1.02 -> 1.03 Make sure uchar is not defined twice. // // Typedefs #ifndef UCHAR #define UCHAR typedef unsigned char uchar; #endif #if 0 // not needed most places - kenmcd typedef unsigned short ushort; typedef unsigned long ulong; #endif // general defines #define WRITE_FUNCTION 1 #define READ_FUNCTION 0 // error codes #define READ_ERROR -1 #define INVALID_DIR -2 #define NO_FILE -3 #define WRITE_ERROR -4 #define WRONG_TYPE -5 #define FILE_TOO_BIG -6 // Misc #define FALSE 0 #define TRUE 1 // mode bit flags #define MODE_NORMAL 0x00 #define MODE_OVERDRIVE 0x01 #define MODE_STRONG5 0x02 #define MODE_PROGRAM 0x04 #define MODE_BREAK 0x08 // product families #define TEMP_FAMILY 0x10 #define SWITCH_FAMILY 0x12 #define COUNT_FAMILY 0x1D #define DIR_FAMILY 0x01 // externs extern uchar DOWCRC; // debugging extern int MLanDebug; // function prototypes extern int Aquire1WireNet(char *, char *); extern void Release1WireNet(char *); extern int MLanAccess(void); extern int MLanBlock(int DoReset, uchar *TransferBuffer, int TransferLen); extern void MLanFamilySearchSetup(int SearchFamily); extern int MLanLevel(int NewLevel); extern int MLanNext(int DoReset, int OnlyAlarmingDevices); extern void MLanSerialNum(uchar *SerialNumBuf, int DoRead); extern int MLanTouchByte(int sendbyte); extern int MLanVerify(int OnlyAlarmingDevices); extern uchar dowcrc(uchar x); extern void msDelay(int len); extern int DS2480ChangeBaud(uchar newbaud); extern void SetBaudCOM(int new_baud); pcp-3.8.12ubuntu1/src/pmdas/roomtemp/mlan/GNUmakefile0000664000000000000000000000232312272262501017340 0ustar #!gmake # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../../../.. include $(TOPDIR)/src/include/builddefs CFILES=mlannetu.c mlansesu.c mlanllu.c linuxlnk.c ds2480ut.c mlantrnu.c HFILES=mlan.h ds2480.h STATICLIBTARGET = libmlan.a LDIRT = libmlan.a LCFLAGS = -g default : $(STATICLIBTARGET) ifeq "$(findstring $(TARGET_OS),solaris linux)" "" default: else default : $(STATICLIBTARGET) endif .NOTPARALLEL: install : default_pcp : default install_pcp : install include $(BUILDRULES) pcp-3.8.12ubuntu1/src/pmdas/roomtemp/mlan/mlanllu.c0000664000000000000000000003362012272262501017102 0ustar //--------------------------------------------------------------------------- // Copyright (C) 1999 Dallas Semiconductor Corporation, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // Except as contained in this notice, the name of Dallas Semiconductor // shall not be used except as stated in the Dallas Semiconductor // Branding Policy. //--------------------------------------------------------------------------- // // MLanLLU.C - Link Layer MicroLAN functions using the DS2480 (U) // serial interface chip. // // Version: 1.03 // // History: 1.00 -> 1.01 DS2480 version number now ignored in // MLanTouchReset. // 1.02 -> 1.03 Removed caps in #includes for Linux capatibility // Removed #include // Add #include "mlan.h" to define TRUE,FALSE #include "ds2480.h" #include "mlan.h" // external COM functions required extern void FlushCOM(void); extern int WriteCOM(int, uchar *); extern int ReadCOM(int, uchar *); //extern void SetBaudCOM(int); // external DS2480 utility function extern int DS2480Detect(void); //extern int DS2480ChangeBaud(int); // local functions int MLanTouchReset(void); int MLanTouchBit(int sendbit); int MLanTouchByte(int sendbyte); int MLanWriteByte(int sendbyte); int MLanReadByte(void); int MLanSpeed(int); int MLanLevel(int); int MLanProgramPulse(void); // external globals extern int UMode; // current DS2480 command or data mode state extern int UBaud; // current DS2480 baud rate extern int USpeed; // current DS2480 MicroLAN communication speed extern int ULevel; // current DS2480 MicroLAN level // local varable flag, true if program voltage available static int ProgramAvailable=FALSE; //-------------------------------------------------------------------------- // Reset all of the devices on the MicroLAN and return the result. // // Returns: TRUE(1): presense pulse(s) detected, device(s) reset // FALSE(0): no presense pulses detected // // WARNING: This routine will not function correctly on some // Alarm reset types of the DS1994/DS1427/DS2404 with // Rev 1 and 2 of the DS2480. // int MLanTouchReset(void) { uchar readbuffer[10],sendpacket[10]; int sendlen=0; // make sure normal level MLanLevel(MODE_NORMAL); // check if correct mode if (UMode != MODSEL_COMMAND) { UMode = MODSEL_COMMAND; sendpacket[sendlen++] = MODE_COMMAND; } // construct the command sendpacket[sendlen++] = (uchar)(CMD_COMM | FUNCTSEL_RESET | USpeed); // flush the buffers FlushCOM(); // send the packet if (WriteCOM(sendlen,sendpacket)) { // read back the 1 byte response if (ReadCOM(1,readbuffer) == 1) { // make sure this byte looks like a reset byte if (((readbuffer[0] & RB_RESET_MASK) == RB_PRESENCE) || ((readbuffer[0] & RB_RESET_MASK) == RB_ALARMPRESENCE)) { // check if programming voltage available ProgramAvailable = ((readbuffer[0] & 0x20) == 0x20); return TRUE; } else return FALSE; } } // an error occured so re-sync with DS2480 DS2480Detect(); return FALSE; } //-------------------------------------------------------------------------- // Send 1 bit of communication to the MicroLAN and return the // result 1 bit read from the MicroLAN. The parameter 'sendbit' // least significant bit is used and the least significant bit // of the result is the return bit. // // 'sendbit' - the least significant bit is the bit to send // // Returns: 0: 0 bit read from sendbit // 1: 1 bit read from sendbit // int MLanTouchBit(int sendbit) { uchar readbuffer[10],sendpacket[10]; int sendlen=0; // make sure normal level MLanLevel(MODE_NORMAL); // check if correct mode if (UMode != MODSEL_COMMAND) { UMode = MODSEL_COMMAND; sendpacket[sendlen++] = MODE_COMMAND; } // construct the command sendpacket[sendlen] = (sendbit != 0) ? BITPOL_ONE : BITPOL_ZERO; sendpacket[sendlen++] |= CMD_COMM | FUNCTSEL_BIT | USpeed; // flush the buffers FlushCOM(); // send the packet if (WriteCOM(sendlen,sendpacket)) { // read back the response if (ReadCOM(1,readbuffer) == 1) { // interpret the response if (((readbuffer[0] & 0xE0) == 0x80) && ((readbuffer[0] & RB_BIT_MASK) == RB_BIT_ONE)) return 1; else return 0; } } // an error occured so re-sync with DS2480 DS2480Detect(); return 0; } //-------------------------------------------------------------------------- // Send 8 bits of communication to the MicroLAN and verify that the // 8 bits read from the MicroLAN is the same (write operation). // The parameter 'sendbyte' least significant 8 bits are used. // // 'sendbyte' - 8 bits to send (least significant byte) // // Returns: TRUE: bytes written and echo was the same // FALSE: echo was not the same // int MLanWriteByte(int sendbyte) { return (MLanTouchByte(sendbyte) == sendbyte) ? TRUE : FALSE; } //-------------------------------------------------------------------------- // Send 8 bits of read communication to the MicroLAN and and return the // result 8 bits read from the MicroLAN. // // Returns: 8 bytes read from MicroLAN // int MLanReadByte(void) { return MLanTouchByte(0xFF); } //-------------------------------------------------------------------------- // Send 8 bits of communication to the MicroLAN and return the // result 8 bits read from the MicroLAN. The parameter 'sendbyte' // least significant 8 bits are used and the least significant 8 bits // of the result is the return byte. // // 'sendbyte' - 8 bits to send (least significant byte) // // Returns: 8 bytes read from sendbyte // int MLanTouchByte(int sendbyte) { uchar readbuffer[10],sendpacket[10]; int sendlen=0; // make sure normal level MLanLevel(MODE_NORMAL); // check if correct mode if (UMode != MODSEL_DATA) { UMode = MODSEL_DATA; sendpacket[sendlen++] = MODE_DATA; } // add the byte to send sendpacket[sendlen++] = (uchar)sendbyte; // check for duplication of data that looks like COMMAND mode if (sendbyte == MODE_COMMAND) sendpacket[sendlen++] = (uchar)sendbyte; // flush the buffers FlushCOM(); // send the packet if (WriteCOM(sendlen,sendpacket)) { // read back the 1 byte response if (ReadCOM(1,readbuffer) == 1) { // return the response return (int)readbuffer[0]; } } // an error occured so re-sync with DS2480 DS2480Detect(); return 0; } //-------------------------------------------------------------------------- // Set the MicroLAN communucation speed. // // 'NewSpeed' - new speed defined as // MODE_NORMAL 0x00 // MODE_OVERDRIVE 0x01 // // Returns: current MicroLAN speed // int MLanSpeed(int NewSpeed) { uchar sendpacket[5]; short sendlen=0; int rt = FALSE; // check if change from current mode if (((NewSpeed == MODE_OVERDRIVE) && (USpeed != SPEEDSEL_OD)) || ((NewSpeed == MODE_NORMAL) && (USpeed != SPEEDSEL_FLEX))) { if (NewSpeed == MODE_OVERDRIVE) { // if overdrive then switch to 115200 baud if (DS2480ChangeBaud(PARMSET_57600) == PARMSET_57600) { USpeed = SPEEDSEL_OD; rt = TRUE; } } else if (NewSpeed == MODE_NORMAL) { // else normal so set to 9600 baud if (DS2480ChangeBaud(PARMSET_9600) == PARMSET_9600) { USpeed = SPEEDSEL_FLEX; rt = TRUE; } } // if baud rate is set correctly then change DS2480 speed if (rt) { // check if correct mode if (UMode != MODSEL_COMMAND) { UMode = MODSEL_COMMAND; sendpacket[sendlen++] = MODE_COMMAND; } // proceed to set the DS2480 communication speed sendpacket[sendlen++] = CMD_COMM | FUNCTSEL_SEARCHOFF | USpeed; // send the packet if (!WriteCOM(sendlen,sendpacket)) { rt = FALSE; // lost communication with DS2480 then reset DS2480Detect(); } } } // return the current speed return (USpeed == SPEEDSEL_OD) ? MODE_OVERDRIVE : MODE_NORMAL; } //-------------------------------------------------------------------------- // Set the MicroLAN line level. The values for NewLevel are // as follows: // // 'NewLevel' - new level defined as // MODE_NORMAL 0x00 // MODE_STRONG5 0x02 // MODE_PROGRAM 0x04 // MODE_BREAK 0x08 (not supported) // // Returns: current MicroLAN level // int MLanLevel(int NewLevel) { uchar sendpacket[10],readbuffer[10]; short sendlen=0; short rt=FALSE; // check if need to change level if (NewLevel != ULevel) { // check if just putting back to normal if (NewLevel == MODE_NORMAL) { // check if correct mode if (UMode != MODSEL_COMMAND) { UMode = MODSEL_COMMAND; sendpacket[sendlen++] = MODE_COMMAND; } // stop pulse command sendpacket[sendlen++] = MODE_STOP_PULSE; // flush the buffers FlushCOM(); // send the packet if (WriteCOM(sendlen,sendpacket)) { // read back the 1 byte response if (ReadCOM(1,readbuffer) == 1) { // check response byte if ((readbuffer[0] & 0xE0) == 0xE0) { rt = TRUE; ULevel = MODE_NORMAL; } } } } // set new level else { // check if correct mode if (UMode != MODSEL_COMMAND) { UMode = MODSEL_COMMAND; sendpacket[sendlen++] = MODE_COMMAND; } // strong 5 volts if (NewLevel == MODE_STRONG5) { // set the SPUD time value sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_5VPULSE | PARMSET_infinite; // add the command to begin the pulse sendpacket[sendlen++] = CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_5V; } // 12 volts else if (NewLevel == MODE_PROGRAM) { // check if programming voltage available if (!ProgramAvailable) return MODE_NORMAL; // set the PPD time value sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_12VPULSE | PARMSET_infinite; // add the command to begin the pulse sendpacket[sendlen++] = CMD_COMM | FUNCTSEL_CHMOD | SPEEDSEL_PULSE | BITPOL_12V; } // flush the buffers FlushCOM(); // send the packet if (WriteCOM(sendlen,sendpacket)) { // read back the 1 byte response from setting time limit if (ReadCOM(1,readbuffer) == 1) { // check response byte if ((readbuffer[0] & 0x81) == 0) { ULevel = NewLevel; rt = TRUE; } } } } // if lost communication with DS2480 then reset if (rt != TRUE) DS2480Detect(); } // return the current level return ULevel; } //-------------------------------------------------------------------------- // This procedure creates a fixed 480 microseconds 12 volt pulse // on the MicroLAN for programming EPROM iButtons. // // Returns: TRUE successful // FALSE program voltage not available // int MLanProgramPulse(void) { uchar sendpacket[10],readbuffer[10]; short sendlen=0; // check if programming voltage available if (!ProgramAvailable) return FALSE; // make sure normal level MLanLevel(MODE_NORMAL); // check if correct mode if (UMode != MODSEL_COMMAND) { UMode = MODSEL_COMMAND; sendpacket[sendlen++] = MODE_COMMAND; } // set the SPUD time value sendpacket[sendlen++] = CMD_CONFIG | PARMSEL_12VPULSE | PARMSET_512us; // pulse command sendpacket[sendlen++] = CMD_COMM | FUNCTSEL_CHMOD | BITPOL_12V | SPEEDSEL_PULSE; // flush the buffers FlushCOM(); // send the packet if (WriteCOM(sendlen,sendpacket)) { // read back the 2 byte response if (ReadCOM(2,readbuffer) == 2) { // check response byte if (((readbuffer[0] | CMD_CONFIG) == (CMD_CONFIG | PARMSEL_12VPULSE | PARMSET_512us)) && ((readbuffer[1] & 0xFC) == (0xFC & (CMD_COMM | FUNCTSEL_CHMOD | BITPOL_12V | SPEEDSEL_PULSE)))) return TRUE; } } // an error occured so re-sync with DS2480 DS2480Detect(); return FALSE; } pcp-3.8.12ubuntu1/src/pmdas/roomtemp/mlan/mlannetu.c0000664000000000000000000004641512272262501017267 0ustar //--------------------------------------------------------------------------- // Copyright (C) 1999 Dallas Semiconductor Corporation, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // Except as contained in this notice, the name of Dallas Semiconductor // shall not be used except as stated in the Dallas Semiconductor // Branding Policy. //--------------------------------------------------------------------------- // // MLanNetU.C - Network functions for MicroLAN 1-Wire devices // using the DS2480 (U) serial interface chip. // // Version: 1.03 // // 1.02 -> 1.03 Removed caps in #includes for Linux capatibility // #include "ds2480.h" #include "mlan.h" // external MicroLAN functions required extern int MLanTouchReset(void); extern int MLanTouchBit(int); extern int MLanWriteByte(int sendbyte); extern int MLanReadByte(void); extern int MLanSpeed(int); extern int MLanLevel(int); extern int MLanBlock(int, uchar *, int); // external COM functions required extern void FlushCOM(void); extern int WriteCOM(int, uchar *); extern int ReadCOM(int, uchar *); // external DS2480 utility function extern int DS2480Detect(void); // exportable functions int MLanFirst(int,int); int MLanNext(int,int); void MLanSerialNum(uchar *, int); void MLanFamilySearchSetup(int); void MLanSkipFamily(void); int MLanAccess(void); int MLanVerify(int); int MLanOverdriveAccess(void); // local functions int bitacc(int, int, int, uchar *); uchar dowcrc(uchar); // global variables for this module to hold search state information static int LastDiscrepancy; static int LastFamilyDiscrepancy; static int LastDevice; uchar DOWCRC; uchar SerialNum[8]; // external globals extern int UMode; extern int UBaud; extern int USpeed; //-------------------------------------------------------------------------- // The 'MLanFirst' finds the first device on the MicroLAN This function // contains one parameter 'OnlyAlarmingDevices'. When // 'OnlyAlarmingDevices' is TRUE (1) the find alarm command 0xEC is // sent instead of the normal search command 0xF0. // Using the find alarm command 0xEC will limit the search to only // 1-Wire devices that are in an 'alarm' state. // // 'DoReset' - TRUE (1) perform reset before search, FALSE (0) do not // perform reset before search. // 'OnlyAlarmDevices' - TRUE (1) the find alarm command 0xEC is // sent instead of the normal search command 0xF0 // // Returns: TRUE (1) : when a 1-Wire device was found and it's // Serial Number placed in the global SerialNum // FALSE (0): There are no devices on the MicroLAN. // int MLanFirst(int DoReset, int OnlyAlarmingDevices) { // reset the search state LastDiscrepancy = 0; LastDevice = FALSE; LastFamilyDiscrepancy = 0; return MLanNext(DoReset, OnlyAlarmingDevices); } //-------------------------------------------------------------------------- // The 'MLanNext' function does a general search. This function // continues from the previos search state. The search state // can be reset by using the 'MLanFirst' function. // This function contains one parameter 'OnlyAlarmingDevices'. // When 'OnlyAlarmingDevices' is TRUE (1) the find alarm command // 0xEC is sent instead of the normal search command 0xF0. // Using the find alarm command 0xEC will limit the search to only // 1-Wire devices that are in an 'alarm' state. // // 'DoReset' - TRUE (1) perform reset before search, FALSE (0) do not // perform reset before search. // 'OnlyAlarmDevices' - TRUE (1) the find alarm command 0xEC is // sent instead of the normal search command 0xF0 // // Returns: TRUE (1) : when a 1-Wire device was found and it's // Serial Number placed in the global SerialNum // FALSE (0): when no new device was found. Either the // last search was the last device or there // are no devices on the MicroLAN. // int MLanNext(int DoReset, int OnlyAlarmingDevices) { int i,TempLastDescrepancy,pos; uchar TempSerialNum[8]; uchar readbuffer[20],sendpacket[40]; int sendlen=0; // if the last call was the last one if (LastDevice) { // reset the search LastDiscrepancy = 0; LastDevice = FALSE; LastFamilyDiscrepancy = 0; return FALSE; } // check if reset first is requested if (DoReset) { // reset the 1-wire // if there are no parts on 1-wire, return FALSE if (!MLanTouchReset()) { // reset the search LastDiscrepancy = 0; LastFamilyDiscrepancy = 0; return FALSE; } } // build the command stream // call a function that may add the change mode command to the buff // check if correct mode if (UMode != MODSEL_DATA) { UMode = MODSEL_DATA; sendpacket[sendlen++] = MODE_DATA; } // search command if (OnlyAlarmingDevices) sendpacket[sendlen++] = 0xEC; // issue the alarming search command else sendpacket[sendlen++] = 0xF0; // issue the search command // change back to command mode UMode = MODSEL_COMMAND; sendpacket[sendlen++] = MODE_COMMAND; // search mode on sendpacket[sendlen++] = (uchar)(CMD_COMM | FUNCTSEL_SEARCHON | USpeed); // change back to data mode UMode = MODSEL_DATA; sendpacket[sendlen++] = MODE_DATA; // set the temp Last Descrep to none TempLastDescrepancy = 0xFF; // add the 16 bytes of the search pos = sendlen; for (i = 0; i < 16; i++) sendpacket[sendlen++] = 0; // only modify bits if not the first search if (LastDiscrepancy != 0xFF) { // set the bits in the added buffer for (i = 0; i < 64; i++) { // before last discrepancy if (i < (LastDiscrepancy - 1)) bitacc(WRITE_FUNCTION, bitacc(READ_FUNCTION,0,i,&SerialNum[0]), (short)(i * 2 + 1), &sendpacket[pos]); // at last discrepancy else if (i == (LastDiscrepancy - 1)) bitacc(WRITE_FUNCTION,1, (short)(i * 2 + 1), &sendpacket[pos]); // after last discrepancy so leave zeros } } // change back to command mode UMode = MODSEL_COMMAND; sendpacket[sendlen++] = MODE_COMMAND; // search OFF sendpacket[sendlen++] = (uchar)(CMD_COMM | FUNCTSEL_SEARCHOFF | USpeed); // flush the buffers FlushCOM(); // send the packet if (WriteCOM(sendlen,sendpacket)) { // read back the 1 byte response if (ReadCOM(17,readbuffer) == 17) { // interpret the bit stream for (i = 0; i < 64; i++) { // get the SerialNum bit bitacc(WRITE_FUNCTION, bitacc(READ_FUNCTION,0,(short)(i * 2 + 1),&readbuffer[1]), i, &TempSerialNum[0]); // check LastDiscrepancy if ((bitacc(READ_FUNCTION,0,(short)(i * 2),&readbuffer[1]) == 1) && (bitacc(READ_FUNCTION,0,(short)(i * 2 + 1),&readbuffer[1]) == 0)) { TempLastDescrepancy = i + 1; // check LastFamilyDiscrepancy if (i < 8) LastFamilyDiscrepancy = i + 1; } } // do dowcrc DOWCRC = 0; for (i = 0; i < 8; i++) dowcrc(TempSerialNum[i]); // check results if ((DOWCRC != 0) || (LastDiscrepancy == 63) || (TempSerialNum[0] == 0)) { // error during search // reset the search LastDiscrepancy = 0; LastDevice = FALSE; LastFamilyDiscrepancy = 0; return FALSE; } // successful search else { // check for lastone if ((TempLastDescrepancy == LastDiscrepancy) || (TempLastDescrepancy == 0xFF)) LastDevice = TRUE; // copy the SerialNum to the buffer for (i = 0; i < 8; i++) SerialNum[i] = TempSerialNum[i]; // set the count LastDiscrepancy = TempLastDescrepancy; return TRUE; } } } // an error occured so re-sync with DS2480 DS2480Detect(); // reset the search LastDiscrepancy = 0; LastDevice = FALSE; LastFamilyDiscrepancy = 0; return FALSE; } //-------------------------------------------------------------------------- // The 'MLanSerialNum' function either reads or sets the SerialNum buffer // that is used in the search functions 'MLanFirst' and 'MLanNext'. // This function contains two parameters, 'SerialNumBuf' is a pointer // to a buffer provided by the caller. 'SerialNumBuf' should point to // an array of 8 unsigned chars. The second parameter is a flag called // 'DoRead' that is TRUE (1) if the operation is to read and FALSE // (0) if the operation is to set the internal SerialNum buffer from // the data in the provided buffer. // // 'SerialNumBuf' - buffer to that contains the serial number to set // when DoRead = FALSE (0) and buffer to get the serial // number when DoRead = TRUE (1). // 'DoRead' - flag to indicate reading (1) or setting (0) the current // serial number. // void MLanSerialNum(uchar *SerialNumBuf, int DoRead) { int i; // read the internal buffer and place in 'SerialNumBuf' if (DoRead) { for (i = 0; i < 8; i++) SerialNumBuf[i] = SerialNum[i]; } // set the internal buffer from the data in 'SerialNumBuf' else { for (i = 0; i < 8; i++) SerialNum[i] = SerialNumBuf[i]; } } //-------------------------------------------------------------------------- // Setup the search algorithm to find a certain family of devices // the next time a search function is called 'MLanNext'. // // 'SearchFamily' - family code type to set the search algorithm to find // next. // void MLanFamilySearchSetup(int SearchFamily) { int i; // set the search state to find SearchFamily type devices SerialNum[0] = (uchar)SearchFamily; for (i = 1; i < 8; i++) SerialNum[i] = 0; LastDiscrepancy = 64; LastDevice = FALSE; } //-------------------------------------------------------------------------- // Set the current search state to skip the current family code. // void MLanSkipFamily(void) { // set the Last discrepancy to last family discrepancy LastDiscrepancy = LastFamilyDiscrepancy; // check for end of list if (LastDiscrepancy == 0) LastDevice = TRUE; } //-------------------------------------------------------------------------- // The 'MLanAccess' function resets the 1-Wire and sends a MATCH Serial // Number command followed by the current SerialNum code. After this // function is complete the 1-Wire device is ready to accept device-specific // commands. // // Returns: TRUE (1) : reset indicates present and device is ready // for commands. // FALSE (0): reset does not indicate presence or echos 'writes' // are not correct. // int MLanAccess(void) { uchar TranBuf[9]; int i; // reset the 1-wire if (MLanTouchReset()) { // create a buffer to use with block function // match Serial Number command 0x55 TranBuf[0] = 0x55; // Serial Number for (i = 1; i < 9; i++) TranBuf[i] = SerialNum[i-1]; // send/recieve the transfer buffer if (MLanBlock(FALSE,TranBuf,9)) { // verify that the echo of the writes was correct for (i = 1; i < 9; i++) if (TranBuf[i] != SerialNum[i-1]) return FALSE; if (TranBuf[0] != 0x55) return FALSE; else return TRUE; } } // reset or match echo failed return FALSE; } //---------------------------------------------------------------------- // The function 'MLanVerify' verifies that the current device // is in contact with the MicroLAN. // Using the find alarm command 0xEC will verify that the device // is in contact with the MicroLAN and is in an 'alarm' state. // // 'OnlyAlarmingDevices' - TRUE (1) the find alarm command 0xEC // is sent instead of the normal search // command 0xF0. // // Returns: TRUE (1) : when the 1-Wire device was verified // to be on the MicroLAN // with OnlyAlarmingDevices == FALSE // or verified to be on the MicroLAN // AND in an alarm state when // OnlyAlarmingDevices == TRUE. // FALSE (0): the 1-Wire device was not on the // MicroLAN or if OnlyAlarmingDevices // == TRUE, the device may be on the // MicroLAN but in a non-alarm state. // int MLanVerify(int OnlyAlarmingDevices) { int i,TranCnt=0,goodbits=0,cnt=0,s,tst; uchar TranBuf[50]; // construct the search rom if (OnlyAlarmingDevices) TranBuf[TranCnt++] = 0xEC; // issue the alarming search command else TranBuf[TranCnt++] = 0xF0; // issue the search command // set all bits at first for (i = 1; i <= 24; i++) TranBuf[TranCnt++] = 0xFF; // now set or clear apropriate bits for search for (i = 0; i < 64; i++) bitacc(WRITE_FUNCTION,bitacc(READ_FUNCTION,0,i,&SerialNum[0]),(int)((i+1)*3-1),&TranBuf[1]); // send/recieve the transfer buffer if (MLanBlock(TRUE,TranBuf,TranCnt)) { // check results to see if it was a success for (i = 0; i < 192; i += 3) { tst = (bitacc(READ_FUNCTION,0,i,&TranBuf[1]) << 1) | bitacc(READ_FUNCTION,0,(int)(i+1),&TranBuf[1]); s = bitacc(READ_FUNCTION,0,cnt++,&SerialNum[0]); if (tst == 0x03) // no device on line { goodbits = 0; // number of good bits set to zero break; // quit } if (((s == 0x01) && (tst == 0x02)) || ((s == 0x00) && (tst == 0x01)) ) // correct bit goodbits++; // count as a good bit } // check too see if there were enough good bits to be successful if (goodbits >= 8) return TRUE; } // block fail or device not present return FALSE; } //---------------------------------------------------------------------- // Perform a overdrive MATCH command to select the 1-Wire device with // the address in the ID data register. // // Returns: TRUE: If the device is present on the MicroLAN and // can do overdrive then the device is selected. // FALSE: Device is not present or not capable of overdrive. // // *Note: This function could be converted to send DS2480 // commands in one packet. // int MLanOverdriveAccess(void) { uchar TranBuf[8]; int i, EchoBad = FALSE; // make sure normal level MLanLevel(MODE_NORMAL); // force to normal communication speed MLanSpeed(MODE_NORMAL); // call the MicroLAN reset function if (MLanTouchReset()) { // send the match command 0x69 if (MLanWriteByte(0x69)) { // switch to overdrive communication speed MLanSpeed(MODE_OVERDRIVE); // create a buffer to use with block function // Serial Number for (i = 0; i < 8; i++) TranBuf[i] = SerialNum[i]; // send/recieve the transfer buffer if (MLanBlock(FALSE,TranBuf,8)) { // verify that the echo of the writes was correct for (i = 0; i < 8; i++) if (TranBuf[i] != SerialNum[i]) EchoBad = TRUE; // if echo ok then success if (!EchoBad) return TRUE; } } } // failure, force back to normal communication speed MLanSpeed(MODE_NORMAL); return FALSE; } //-------------------------------------------------------------------------- // Update the Dallas Semiconductor One Wire CRC (DOWCRC) from the global // variable DOWCRC and the argument. // // 'x' - data byte to calculate the 8 bit crc from // // Returns: the updated DOWCRC. // uchar dscrc_table[] = { 0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65, 157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220, 35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98, 190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255, 70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7, 219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154, 101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36, 248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185, 140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205, 17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80, 175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238, 50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115, 202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139, 87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22, 233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168, 116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53}; uchar dowcrc(uchar x) { DOWCRC = dscrc_table[DOWCRC ^ x]; return DOWCRC; } //-------------------------------------------------------------------------- // Bit utility to read and write a bit in the buffer 'buf'. // // 'op' - operation (1) to set and (0) to read // 'state' - set (1) or clear (0) if operation is write (1) // 'loc' - bit number location to read or write // 'buf' - pointer to array of bytes that contains the bit // to read or write // // Returns: 1 if operation is set (1) // 0/1 state of bit number 'loc' if operation is reading // int bitacc(int op, int state, int loc, uchar *buf) { int nbyt,nbit; nbyt = (loc / 8); nbit = loc - (nbyt * 8); if (op == WRITE_FUNCTION) { if (state) buf[nbyt] |= (0x01 << nbit); else buf[nbyt] &= ~(0x01 << nbit); return 1; } else return ((buf[nbyt] >> nbit) & 0x01); } pcp-3.8.12ubuntu1/src/pmdas/roomtemp/mlan/mlansesu.c0000664000000000000000000000664512272262501017274 0ustar //--------------------------------------------------------------------------- // Copyright (C) 1999 Dallas Semiconductor Corporation, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // Except as contained in this notice, the name of Dallas Semiconductor // shall not be used except as stated in the Dallas Semiconductor // Branding Policy. //--------------------------------------------------------------------------- // // MLanSesU.C - Aquire and release a Session on the 1-Wire Net. // // Version: 1.03 // #include "pmapi.h" #include "mlan.h" // external function prototypes extern int OpenCOM(char *); extern void CloseCOM(void); extern int DS2480Detect(void); // local function prototypes int Aquire1WireNet(char *, char *); void Release1WireNet(char *); // keep port name for later message when closing char portname[128]; // debugging int MLanDebug = 0; //--------------------------------------------------------------------------- // Attempt to aquire a 1-Wire net using a com port and a DS2480 based // adapter. // // 'port_zstr' - zero terminated port name. For this platform // use format COMX where X is the port number. // 'return_msg' - zero terminated return message. // // Returns: TRUE - success, COM port opened // int Aquire1WireNet(char *port_zstr, char *return_msg) { int cnt=0; portname[0] = 0; // attempt to open the communications port if (OpenCOM(port_zstr) >= 0) cnt += sprintf(&return_msg[cnt],"%s opened\n",port_zstr); else { cnt += sprintf(&return_msg[cnt],"Could not open port %s: %s," " aborting.\nClosing port %s.\n",port_zstr,osstrerror(),port_zstr); return FALSE; } // detect DS2480 if (DS2480Detect()) cnt += sprintf(&return_msg[cnt],"DS2480-based adapter detected\n"); else { cnt += sprintf(&return_msg[cnt],"DS2480-based adapter not detected, aborting program\n"); cnt += sprintf(&return_msg[cnt],"Closing port %s.\n",port_zstr); CloseCOM(); return FALSE; } // success sprintf(portname,"%s",port_zstr); return TRUE; } //--------------------------------------------------------------------------- // Release the previously aquired a 1-Wire net. // // 'return_msg' - zero terminated return message. // void Release1WireNet(char *return_msg) { // close the communications port sprintf(return_msg,"Closing port %s.\n",portname); CloseCOM(); } pcp-3.8.12ubuntu1/src/pmdas/roomtemp/mlan/linuxlnk.c0000664000000000000000000003246512272262501017310 0ustar //--------------------------------------------------------------------------- // Copyright (C) 1999 Dallas Semiconductor Corporation, All Rights Reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES // OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. // // Except as contained in this notice, the name of Dallas Semiconductor // shall not be used except as stated in the Dallas Semiconductor // Branding Policy. //--------------------------------------------------------------------------- // // TODO.C - COM functions required by MLANLL.C, MLANTRNU, MLANNETU.C and // MLanFile.C for MLANU to communicate with the DS2480 based // Universal Serial Adapter 'U'. Fill in the platform specific code. // // Version: 1.02 // // History: 1.00 -> 1.01 Added function msDelay. // // 1.01 -> 1.02 Changed to generic OpenCOM/CloseCOM for easier // use with other platforms. // //-------------------------------------------------------------------------- // Copyright (C) 1998 Andrea Chambers and University of Newcastle upon Tyne, // All Rights Reserved. //-------------------------------------------------------------------------- // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE UNIVERSITY OF NEWCASTLE UPON TYNE OR ANDREA CHAMBERS // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH // THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //--------------------------------------------------------------------------- // // LinuxLNK.C - COM functions required by MLANLLU.C, MLANTRNU.C, MLANNETU.C // and MLanFile.C for MLANU to communicate with the DS2480 based // Universal Serial Adapter 'U'. Platform specific code. // // Version: 1.03 // History: 1.00 -> 1.03 modifications by David Smiczek // Changed to use generic OpenCOM/CloseCOM // Pass port name to OpenCOM instead of hard coded // Changed msDelay to handle long delays // Reformatted to look like 'TODO.C' // Added #include "ds2480.h" to use constants. // Added function SetBaudCOM() // Added function msGettick() // Removed delay from WriteCOM(), used tcdrain() // Added wait for byte available with timeout using // select() in ReadCOM() /* cfmakeraw function from nut-0.45.0 package common.c - common useful functions Copyright (C) 2000 Russell Kroll This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include "mlan.h" #include "ds2480.h" #include "pmapi.h" // Exportable functions required for MLANLL.C, MLANTRNU.C, or MLANNETU.C void FlushCOM(void); int WriteCOM(int, unsigned char*); int ReadCOM(int, unsigned char*); void BreakCOM(void); void msDelay(int); long msGettick(void); // Exportable functions for opening/closing serial port int OpenCOM(char *); void CloseCOM(void); // LinuxLNK global int fd; #ifdef IS_SOLARIS int cfmakeraw(struct termios *termios_p) { termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|IGNCR|ICRNL|IXON); termios_p->c_oflag &= ~OPOST; termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); termios_p->c_cflag &= ~(CSIZE|PARENB); termios_p->c_cflag |= CS8; return 0; } #endif //-------------------------------------------------------------------------- // Write an array of bytes to the COM port, verify that it was // sent out. Assume that baud rate has been set. // // Returns 1 for success and 0 for failure // int WriteCOM(int outlen, uchar *outbuf) { long count = outlen; int i; int sts; if (MLanDebug) { fprintf(stderr, "WriteCOM: calling write: %d bytes:", outlen); for (i = 0; i < outlen; i++) fprintf(stderr, " %02x", 0xff & outbuf[i]); fputc('\n', stderr); fflush(stderr); } i = write(fd, outbuf, outlen); if (MLanDebug) { fprintf(stderr, "WriteCOM: write returns %d\nWriteCOM: calling tcdrain\n", i); fflush(stderr); } sts = tcdrain(fd); if (MLanDebug) { fprintf(stderr, "WriteCOM: tcdrain returns %d\n", sts); fflush(stderr); } return (i == count); } //-------------------------------------------------------------------------- // Read an array of bytes to the COM port, verify that it was // sent out. Assume that baud rate has been set. // // Returns number of characters read // int ReadCOM(int inlen, uchar *inbuf) { fd_set filedescr; struct timeval tval; int cnt; int sts; if (MLanDebug) { fprintf(stderr, "ReadCOM: calling read: want %d bytes:", inlen); fflush(stderr); } // loop to wait until each byte is available and read it for (cnt = 0; cnt < inlen; cnt++) { // set a descriptor to wait for a character available FD_ZERO(&filedescr); FD_SET(fd,&filedescr); // set timeout to 10ms tval.tv_sec = 0; tval.tv_usec = 10000; // if byte available read or return bytes read if (0 != select(fd+1,&filedescr,NULL,NULL,&tval)) { if ((sts = read(fd,&inbuf[cnt],1)) != 1) { if (MLanDebug) { fprintf(stderr, ": read returns %d, got %d bytes\n", sts, cnt); fflush(stderr); } return cnt; } if (MLanDebug) { fprintf(stderr, " %02x", 0xff & inbuf[cnt]); fflush(stderr); } } else { if (MLanDebug) { fprintf(stderr, ": select timeout, got %d bytes\n", cnt); fflush(stderr); } return cnt; } } // success, so return desired length if (MLanDebug) { fprintf(stderr, ": got 'em all\n"); fflush(stderr); } return inlen; } //--------------------------------------------------------------------------- // Description: // flush the rx and tx buffers // void FlushCOM(void) { tcflush (fd, TCIOFLUSH); } //-------------------------------------------------------------------------- // Description: // Delay for at least 'len' ms // void msDelay(int len) { struct timespec s; // Set aside memory space on the stack s.tv_sec = len / 1000; s.tv_nsec = (len - (s.tv_sec * 1000)) * 1000000; nanosleep(&s, NULL); } //-------------------------------------------------------------------------- // Description: // Send a break on the com port for at least 2 ms // void BreakCOM(void) { int duration = 0; // see man termios break may be tcsendbreak(fd, duration); // too long } //--------------------------------------------------------------------------- // Attempt to open a com port. // Set the starting baud rate to 9600. // // 'port_zstr' - zero terminate port name. Format is platform // dependent. // // Returns: TRUE - success, COM port opened // int OpenCOM(char *port_zstr) { struct termios t; // see man termios - declared as above int rc; fd = open(port_zstr, O_RDWR|O_NONBLOCK); if (fd<0) return fd; rc = tcgetattr (fd, &t); if (rc < 0) { int tmp; tmp = oserror(); close(fd); setoserror(tmp); return rc; } if (MLanDebug) { fprintf(stderr, "OpenCOM: initial tty settings\niflag: %07o oflag: %07o lflag: %07o cflag: %07o\n", (unsigned int)t.c_iflag, (unsigned int)t.c_oflag, (unsigned int)t.c_lflag, (unsigned int)t.c_cflag); fflush(stderr); } cfsetospeed(&t, B9600); cfsetispeed (&t, B9600); #ifdef IRIX // IRIX tty games ... // // per the Linux man page cfmakeraw sets the terminal attributes as follows: // t.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON); t.c_iflag &= ~(ISTRIP|INLCR|IGNCR|ICRNL|IXON); t.c_oflag &= ~OPOST; t.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN); t.c_cflag &= ~(CSIZE|PARENB); t.c_cflag |= CS8; // to this we have to clear the additional IRIX goodies like: // t.c_iflag &= ~(IXANY|IGNPAR); t.c_oflag &= ~(TAB3); // and finally, CLOCAL is in c_cflag, not c_lflag // t.c_cflag |= CLOCAL; // ignore modem signals #else // assumed to be Linux // cfmakeraw(&t); // don't generate signals, translate or echo t.c_lflag |= CLOCAL; // ignore modem signals #endif if (MLanDebug) { fprintf(stderr, "OpenCOM: new tty settings\niflag: %07o oflag: %07o lflag: %07o cflag: %07o\n", (unsigned int)t.c_iflag, (unsigned int)t.c_oflag, (unsigned int)t.c_lflag, (unsigned int)t.c_cflag); fprintf(stderr, "OpenCOM: calling tcsetattr\n"); fflush(stderr); } rc = tcsetattr (fd, TCSAFLUSH, &t); if (MLanDebug) { fprintf(stderr, "OpenCOM: tcsetattr returns %d\n", rc); fflush(stderr); } if (rc < 0) { int tmp; tmp = oserror(); close(fd); setoserror(tmp); return rc; } return fd; } //--------------------------------------------------------------------------- // Closes the connection to the port. // void CloseCOM(void) { FlushCOM(); close(fd); } //-------------------------------------------------------------------------- // Set the baud rate on the com port. The possible baud rates for // 'new_baud' are: // // PARMSET_9600 0x00 // PARMSET_19200 0x02 // PARMSET_57600 0x04 // PARMSET_115200 0x06 // void SetBaudCOM(int new_baud) { struct termios t; int rc; speed_t baud = B0; // read the attribute structure rc = tcgetattr(fd, &t); if (rc < 0) { close(fd); return; } // convert parameter to linux baud rate switch(new_baud) { case PARMSET_9600: baud = B9600; break; case PARMSET_19200: baud = B19200; break; case PARMSET_57600: #ifdef B57600 baud = B57600; break; #else #define ERR_MSG_57600 "SetBaudCOM: no support for 57600 baud, sorry!" write(2, ERR_MSG_57600, strlen(ERR_MSG_57600)); exit(1); #endif case PARMSET_115200: #ifdef B115200 baud = B115200; break; #else #define ERR_MSG_115200 "SetBaudCOM: no support for 115200 baud, sorry!" write(2, ERR_MSG_115200, strlen(ERR_MSG_115200)); exit(1); #endif } // set baud in structure cfsetospeed(&t, baud); cfsetispeed(&t, baud); // change baud on port rc = tcsetattr(fd, TCSAFLUSH, &t); if (rc < 0) close(fd); } //-------------------------------------------------------------------------- // Get the current millisecond tick count. Does not have to represent // an actual time, it just needs to be an incrementing timer. // long msGettick(void) { struct timezone tmzone; struct timeval tmval; long ms; gettimeofday(&tmval,&tmzone); ms = (tmval.tv_sec & 0xFFFF) * 1000 + tmval.tv_usec / 1000; return ms; } pcp-3.8.12ubuntu1/src/pmdas/roomtemp/help0000664000000000000000000000315612272262501015217 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # roomtemp PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ ROOMTEMP.0 Instance domain "device" for roomtemp PMDA One instance for each temperature sensor device. The external instance identifiers are the serial numbers (in hexadecimal) of the DS1280 chips that were discovered when the MicroLAN was probed. @ roomtemp.celsius Temperature in degrees celsius. @ roomtemp.fahrenheit Temperature in degrees fahrenheit. pcp-3.8.12ubuntu1/src/pmdas/linux_proc/0000775000000000000000000000000012272262620014661 5ustar pcp-3.8.12ubuntu1/src/pmdas/linux_proc/proc_pid.c0000664000000000000000000005741612272262501016637 0ustar /* * Linux proc//{stat,statm,status,...} Clusters * * Copyright (c) 2013 Red Hat. * Copyright (c) 2000,2004,2006 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2010 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include #include #include #include "proc_pid.h" #include "indom.h" static proc_pid_list_t pids; static int compare_pid(const void *pa, const void *pb) { int a = *(int *)pa; int b = *(int *)pb; return a - b; } static void pidlist_append_pid(int pid) { if (pids.count >= pids.size) { pids.size += 64; if (!(pids.pids = (int *)realloc(pids.pids, pids.size * sizeof(int)))) { perror("pidlist_append: out of memory"); pids.size = pids.count = 0; return; /* soldier on bravely */ } } pids.pids[pids.count++] = pid; } static void pidlist_append(const char *pidname) { pidlist_append_pid(atoi(pidname)); } static void tasklist_append(const char *pid) { DIR *taskdirp; struct dirent *tdp; char taskpath[1024]; sprintf(taskpath, "/proc/%s/task", pid); if ((taskdirp = opendir(taskpath)) != NULL) { while ((tdp = readdir(taskdirp)) != NULL) { if (!isdigit((int)tdp->d_name[0]) || strcmp(pid, tdp->d_name) == 0) continue; pidlist_append(tdp->d_name); } closedir(taskdirp); } } static int refresh_cgroup_pidlist(int want_threads, const char *cgroup) { char path[MAXPATHLEN]; FILE *fp; int pid; /* * We're running in cgroups mode where a subset of the processes is * going to be returned based on the cgroup specified earlier via a * store into the proc.control.{all,perclient}.cgroups metric. * * Use the "cgroup.procs" or "tasks" file depending on want_threads. * Note that both these files are already sorted, ascending numeric. */ if (want_threads) snprintf(path, sizeof(path), "%s/tasks", cgroup); else snprintf(path, sizeof(path), "%s/cgroup.procs", cgroup); if ((fp = fopen(path, "r")) != NULL) { while (fscanf(fp, "%d\n", &pid) == 1) pidlist_append_pid(pid); fclose(fp); } return 0; } static int refresh_global_pidlist(int want_threads) { DIR *dirp; struct dirent *dp; if ((dirp = opendir("/proc")) == NULL) return -oserror(); /* note: readdir on /proc ignores threads */ while ((dp = readdir(dirp)) != NULL) { if (isdigit((int)dp->d_name[0])) { pidlist_append(dp->d_name); if (want_threads) tasklist_append(dp->d_name); } } closedir(dirp); qsort(pids.pids, pids.count, sizeof(int), compare_pid); return 0; } static void refresh_proc_pidlist(proc_pid_t *proc_pid) { int i; int fd; char *p; char buf[1024]; __pmHashNode *node, *next, *prev; proc_pid_entry_t *ep; pmdaIndom *indomp = proc_pid->indom; if (indomp->it_numinst < pids.count) indomp->it_set = (pmdaInstid *)realloc(indomp->it_set, pids.count * sizeof(pmdaInstid)); indomp->it_numinst = pids.count; /* * invalidate all entries so we can harvest pids that have exited */ for (i=0; i < proc_pid->pidhash.hsize; i++) { for (node=proc_pid->pidhash.hash[i]; node != NULL; node = node->next) { ep = (proc_pid_entry_t *)node->data; ep->flags = 0; } } /* * walk pid list and add new pids to the hash table, * marking entries valid as we go ... */ for (i=0; i < pids.count; i++) { node = __pmHashSearch(pids.pids[i], &proc_pid->pidhash); if (node == NULL) { int k = 0; ep = (proc_pid_entry_t *)malloc(sizeof(proc_pid_entry_t)); memset(ep, 0, sizeof(proc_pid_entry_t)); ep->id = pids.pids[i]; sprintf(buf, "/proc/%d/cmdline", pids.pids[i]); if ((fd = open(buf, O_RDONLY)) >= 0) { sprintf(buf, "%06d ", pids.pids[i]); if ((k = read(fd, buf+7, sizeof(buf)-8)) > 0) { p = buf + k +7; *p-- = '\0'; /* Skip trailing nils, i.e. don't replace them */ while (buf+7 < p) { if (*p-- != '\0') { break; } } /* Remove NULL terminators from cmdline string array */ /* Suggested by Mike Mason */ while (buf+7 < p) { if (*p == '\0') *p = ' '; p--; } } close(fd); } if (k == 0) { /* * If a process is swapped out, /proc//cmdline * returns an empty string so we have to get it * from /proc//status or /proc//stat */ sprintf(buf, "/proc/%d/status", pids.pids[i]); if ((fd = open(buf, O_RDONLY)) >= 0) { /* We engage in a bit of a hanky-panky here: * the string should look like "123456 (name)", * we get it from /proc/XX/status as "Name: name\n...", * to fit the 6 digits of PID and opening parenthesis, * save 2 bytes at the start of the buffer. * And don't forget to leave 2 bytes for the trailing * parenthesis and the nil. Here is * an example of what we're trying to achieve: * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | | | N| a| m| e| :|\t| i| n| i| t|\n| S|... * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * | 0| 0| 0| 0| 0| 1| | (| i| n| i| t| )|\0|... * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+ */ if ((k = read(fd, buf+2, sizeof(buf)-4)) > 0) { int bc; if ((p = strchr(buf+2, '\n')) == NULL) p = buf+k; p[0] = ')'; p[1] = '\0'; bc = sprintf(buf, "%06d ", pids.pids[i]); buf[bc] = '('; } close(fd); } } if (k <= 0) { /* hmm .. must be exiting */ sprintf(buf, "%06d ", pids.pids[i]); } ep->name = strdup(buf); __pmHashAdd(pids.pids[i], (void *)ep, &proc_pid->pidhash); // fprintf(stderr, "## ADDED \"%s\" to hash table\n", buf); } else ep = (proc_pid_entry_t *)node->data; /* mark pid as still existing */ ep->flags |= PROC_PID_FLAG_VALID; /* refresh the indom pointer */ indomp->it_set[i].i_inst = ep->id; indomp->it_set[i].i_name = ep->name; } /* * harvest exited pids from the pid hash table */ for (i=0; i < proc_pid->pidhash.hsize; i++) { for (prev=NULL, node=proc_pid->pidhash.hash[i]; node != NULL;) { next = node->next; ep = (proc_pid_entry_t *)node->data; // fprintf(stderr, "CHECKING key=%d node=" PRINTF_P_PFX "%p prev=" PRINTF_P_PFX "%p next=" PRINTF_P_PFX "%p ep=" PRINTF_P_PFX "%p valid=%d\n", // ep->id, node, prev, node->next, ep, ep->valid); if (!(ep->flags & PROC_PID_FLAG_VALID)) { // fprintf(stderr, "DELETED key=%d name=\"%s\"\n", ep->id, ep->name); if (ep->name != NULL) free(ep->name); if (ep->stat_buf != NULL) free(ep->stat_buf); if (ep->status_buf != NULL) free(ep->status_buf); if (ep->statm_buf != NULL) free(ep->statm_buf); if (ep->maps_buf != NULL) free(ep->maps_buf); if (ep->schedstat_buf != NULL) free(ep->schedstat_buf); if (ep->io_buf != NULL) free(ep->io_buf); if (ep->wchan_buf != NULL) free(ep->wchan_buf); if (prev == NULL) proc_pid->pidhash.hash[i] = node->next; else prev->next = node->next; free(ep); free(node); } else { prev = node; } if ((node = next) == NULL) break; } } } int refresh_proc_pid(proc_pid_t *proc_pid, int threads, const char *cgroups) { int sts; pids.count = 0; pids.threads = threads; sts = (cgroups && cgroups[0] != '\0') ? refresh_cgroup_pidlist(threads, cgroups) : refresh_global_pidlist(threads); if (sts < 0) return sts; #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) fprintf(stderr, "refresh_proc_pid: %d pids (threads=%d, cgroups=\"%s\")\n", sts, threads, cgroups ? cgroups : ""); #endif refresh_proc_pidlist(proc_pid); return 0; } /* * Open a proc file, taking into account that we may want thread info * rather than process information. * * We make (ab)use of some obscure Linux procfs mechanisms here! * Even though readdir(/proc) does not contain tasks, we can still open * taskid directory files; on top of that, the tasks sub-directory in a * task group has all (peer) tasks in that group, even for "children". */ static int proc_open(const char *base, proc_pid_entry_t *ep) { int fd; char buf[128]; if (pids.threads) { sprintf(buf, "/proc/%d/task/%d/%s", ep->id, ep->id, base); if ((fd = open(buf, O_RDONLY)) >= 0) return fd; /* fallback to /proc path if task path open fails */ } sprintf(buf, "/proc/%d/%s", ep->id, base); return open(buf, O_RDONLY); } static DIR * proc_opendir(const char *base, proc_pid_entry_t *ep) { DIR *dir; char buf[128]; if (pids.threads) { sprintf(buf, "/proc/%d/task/%d/%s", ep->id, ep->id, base); if ((dir = opendir(buf)) != NULL) return dir; /* fallback to /proc path if task path opendir fails */ } sprintf(buf, "/proc/%d/%s", ep->id, base); return opendir(buf); } /* * fetch a proc//stat entry for pid */ proc_pid_entry_t * fetch_proc_pid_stat(int id, proc_pid_t *proc_pid) { int fd; int sts = 0; int n; __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); proc_pid_entry_t *ep; char buf[1024]; if (node == NULL) { #if PCP_DEBUG if ((pmDebug & (DBG_TRACE_LIBPMDA|DBG_TRACE_DESPERATE)) == (DBG_TRACE_LIBPMDA|DBG_TRACE_DESPERATE)) { char ibuf[1024]; fprintf(stderr, "fetch_proc_pid_stat: __pmHashSearch(%d, hash[%s]) -> NULL\n", id, pmInDomStr_r(proc_pid->indom->it_indom, ibuf, sizeof(ibuf))); } #endif return NULL; } ep = (proc_pid_entry_t *)node->data; if (!(ep->flags & PROC_PID_FLAG_STAT_FETCHED)) { if ((fd = proc_open("stat", ep)) < 0) { sts = -oserror(); #if PCP_DEBUG if ((pmDebug & (DBG_TRACE_LIBPMDA|DBG_TRACE_DESPERATE)) == (DBG_TRACE_LIBPMDA|DBG_TRACE_DESPERATE)) { char ibuf[1024]; char ebuf[1024]; fprintf(stderr, "fetch_proc_pid_stat: proc_open(\"stat\", ...) failed: id=%d, indom=%s, sts=%s\n", id, pmInDomStr_r(proc_pid->indom->it_indom, ibuf, sizeof(ibuf)), pmErrStr_r(sts, ebuf, sizeof(ebuf))); } #endif } else { if ((n = read(fd, buf, sizeof(buf))) < 0) { sts = -oserror(); #if PCP_DEBUG if ((pmDebug & (DBG_TRACE_LIBPMDA|DBG_TRACE_DESPERATE)) == (DBG_TRACE_LIBPMDA|DBG_TRACE_DESPERATE)) { char ibuf[1024]; char ebuf[1024]; fprintf(stderr, "fetch_proc_pid_stat: read \"stat\" failed: id=%d, indom=%s, sts=%s\n", id, pmInDomStr_r(proc_pid->indom->it_indom, ibuf, sizeof(ibuf)), pmErrStr_r(sts, ebuf, sizeof(ebuf))); } #endif } else { if (n == 0) { /* eh? */ sts = -1; #if PCP_DEBUG if ((pmDebug & (DBG_TRACE_LIBPMDA|DBG_TRACE_DESPERATE)) == (DBG_TRACE_LIBPMDA|DBG_TRACE_DESPERATE)) { char ibuf[1024]; fprintf(stderr, "fetch_proc_pid_stat: read \"stat\" EOF?: id=%d, indom=%s\n", id, pmInDomStr_r(proc_pid->indom->it_indom, ibuf, sizeof(ibuf))); } #endif } else { if (ep->stat_buflen <= n) { ep->stat_buflen = n; ep->stat_buf = (char *)realloc(ep->stat_buf, n); } memcpy(ep->stat_buf, buf, n); ep->stat_buf[n-1] = '\0'; sts = 0; } } } if (fd >= 0) close(fd); ep->flags |= PROC_PID_FLAG_STAT_FETCHED; } if (!(ep->flags & PROC_PID_FLAG_WCHAN_FETCHED)) { if ((fd = proc_open("wchan", ep)) < 0) { /* ignore failure here, backwards compat */ ; } else { if ((n = read(fd, buf, sizeof(buf)-1)) < 0) { sts = -oserror(); #if PCP_DEBUG if ((pmDebug & (DBG_TRACE_LIBPMDA|DBG_TRACE_DESPERATE)) == (DBG_TRACE_LIBPMDA|DBG_TRACE_DESPERATE)) { char ibuf[1024]; char ebuf[1024]; fprintf(stderr, "fetch_proc_pid_stat: read \"wchan\" failed: id=%d, indom=%s, sts=%s\n", id, pmInDomStr_r(proc_pid->indom->it_indom, ibuf, sizeof(ibuf)), pmErrStr_r(sts, ebuf, sizeof(ebuf))); } #endif } else { if (n == 0) { /* wchan is empty, nothing to add here */ ; } else { n++; /* no terminating null (from kernel) */ if (ep->wchan_buflen <= n) { ep->wchan_buflen = n; ep->wchan_buf = (char *)realloc(ep->wchan_buf, n); } memcpy(ep->wchan_buf, buf, n-1); ep->wchan_buf[n-1] = '\0'; } } } if (fd >= 0) close(fd); ep->flags |= PROC_PID_FLAG_WCHAN_FETCHED; } if (sts < 0) return NULL; return ep; } /* * fetch a proc//status entry for pid * Added by Mike Mason */ proc_pid_entry_t * fetch_proc_pid_status(int id, proc_pid_t *proc_pid) { int sts = 0; __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); proc_pid_entry_t *ep; if (node == NULL) return NULL; ep = (proc_pid_entry_t *)node->data; if (!(ep->flags & PROC_PID_FLAG_STATUS_FETCHED)) { int fd; int n; char buf[1024]; char *curline; if ((fd = proc_open("status", ep)) < 0) sts = -oserror(); else if ((n = read(fd, buf, sizeof(buf))) < 0) sts = -oserror(); else { if (n == 0) sts = -1; else { if (ep->status_buflen < n) { ep->status_buflen = n; ep->status_buf = (char *)realloc(ep->status_buf, n); } if (ep->status_buf == NULL) sts = -1; else { memcpy(ep->status_buf, buf, n); ep->status_buf[n-1] = '\0'; } } } if (sts == 0) { /* assign pointers to individual lines in buffer */ curline = ep->status_buf; while (strncmp(curline, "Uid:", 4)) { curline = index(curline, '\n') + 1; } /* user & group IDs */ ep->status_lines.uid = strsep(&curline, "\n"); ep->status_lines.gid = strsep(&curline, "\n"); while (curline) { if (strncmp(curline, "VmSize:", 7) == 0) { /* memory info - these lines don't exist for kernel threads */ ep->status_lines.vmsize = strsep(&curline, "\n"); ep->status_lines.vmlck = strsep(&curline, "\n"); if (strncmp(curline, "VmRSS:", 6) != 0) curline = index(curline, '\n') + 1; // Have VmPin: ? if (strncmp(curline, "VmRSS:", 6) != 0) curline = index(curline, '\n') + 1; // Have VmHWM: ? ep->status_lines.vmrss = strsep(&curline, "\n"); ep->status_lines.vmdata = strsep(&curline, "\n"); ep->status_lines.vmstk = strsep(&curline, "\n"); ep->status_lines.vmexe = strsep(&curline, "\n"); ep->status_lines.vmlib = strsep(&curline, "\n"); curline = index(curline, '\n') + 1; // skip VmPTE ep->status_lines.vmswap = strsep(&curline, "\n"); ep->status_lines.threads = strsep(&curline, "\n"); } else if (strncmp(curline, "SigPnd:", 7) == 0) { /* signal masks */ ep->status_lines.sigpnd = strsep(&curline, "\n"); ep->status_lines.sigblk = strsep(&curline, "\n"); ep->status_lines.sigign = strsep(&curline, "\n"); ep->status_lines.sigcgt = strsep(&curline, "\n"); break; /* we're done */ } else { curline = index(curline, '\n') + 1; } } } if (fd >= 0) close(fd); ep->flags |= PROC_PID_FLAG_STATUS_FETCHED; } return (sts < 0) ? NULL : ep; } /* * fetch a proc//statm entry for pid */ proc_pid_entry_t * fetch_proc_pid_statm(int id, proc_pid_t *proc_pid) { int sts = 0; __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); proc_pid_entry_t *ep; if (node == NULL) return NULL; ep = (proc_pid_entry_t *)node->data; if (!(ep->flags & PROC_PID_FLAG_STATM_FETCHED)) { char buf[1024]; int fd, n; if ((fd = proc_open("statm", ep)) < 0) sts = -oserror(); else if ((n = read(fd, buf, sizeof(buf))) < 0) sts = -oserror(); else { if (n == 0) /* eh? */ sts = -1; else { if (ep->statm_buflen <= n) { ep->statm_buflen = n; ep->statm_buf = (char *)realloc(ep->statm_buf, n); } memcpy(ep->statm_buf, buf, n); ep->statm_buf[n-1] = '\0'; } } if (fd >= 0) close(fd); ep->flags |= PROC_PID_FLAG_STATM_FETCHED; } return (sts < 0) ? NULL : ep; } /* * fetch a proc//maps entry for pid * WARNING: This can be very large! Only ask for it if you really need it. * Added by Mike Mason */ proc_pid_entry_t * fetch_proc_pid_maps(int id, proc_pid_t *proc_pid) { int sts = 0; __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); proc_pid_entry_t *ep; char *maps_bufptr = NULL; if (node == NULL) return NULL; ep = (proc_pid_entry_t *)node->data; if (!(ep->flags & PROC_PID_FLAG_MAPS_FETCHED)) { int fd; if ((fd = proc_open("maps", ep)) < 0) sts = -oserror(); else { char buf[1024]; int n, len = 0; while ((n = read(fd, buf, sizeof(buf))) > 0) { len += n; if (ep->maps_buflen <= len) { ep->maps_buflen = len + 1; ep->maps_buf = (char *)realloc(ep->maps_buf, ep->maps_buflen); } maps_bufptr = ep->maps_buf + len - n; memcpy(maps_bufptr, buf, n); } ep->flags |= PROC_PID_FLAG_MAPS_FETCHED; /* If there are no maps, make maps_buf point to a zero length string. */ if (ep->maps_buflen == 0) { ep->maps_buf = (char *)malloc(1); ep->maps_buflen = 1; } ep->maps_buf[ep->maps_buflen - 1] = '\0'; close(fd); } } return (sts < 0) ? NULL : ep; } /* * fetch a proc//schedstat entry for pid */ proc_pid_entry_t * fetch_proc_pid_schedstat(int id, proc_pid_t *proc_pid) { int sts = 0; __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); proc_pid_entry_t *ep; if (node == NULL) return NULL; ep = (proc_pid_entry_t *)node->data; if (!(ep->flags & PROC_PID_FLAG_SCHEDSTAT_FETCHED)) { int fd, n; char buf[1024]; if ((fd = proc_open("schedstat", ep)) < 0) sts = -oserror(); else if ((n = read(fd, buf, sizeof(buf))) < 0) sts = -oserror(); else { if (n == 0) /* eh? */ sts = -1; else { if (ep->schedstat_buflen <= n) { ep->schedstat_buflen = n; ep->schedstat_buf = (char *)realloc(ep->schedstat_buf, n); } memcpy(ep->schedstat_buf, buf, n); ep->schedstat_buf[n-1] = '\0'; } } if (fd >= 0) { close(fd); } ep->flags |= PROC_PID_FLAG_SCHEDSTAT_FETCHED; } return (sts < 0) ? NULL : ep; } /* * fetch a proc//io entry for pid * * Depends on kernel built with CONFIG_TASK_IO_ACCOUNTING=y * which means the following must also be set: * CONFIG_TASKSTATS=y * CONFIG_TASK_DELAY_ACCT=y * CONFIG_TASK_XACCT=y */ proc_pid_entry_t * fetch_proc_pid_io(int id, proc_pid_t *proc_pid) { int sts = 0; __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); proc_pid_entry_t *ep; if (node == NULL) return NULL; ep = (proc_pid_entry_t *)node->data; if (!(ep->flags & PROC_PID_FLAG_IO_FETCHED)) { int fd, n; char buf[1024]; char *curline; if ((fd = proc_open("io", ep)) < 0) sts = -oserror(); else if ((n = read(fd, buf, sizeof(buf))) < 0) sts = -oserror(); else { if (n == 0) sts = -1; else { if (ep->io_buflen < n) { ep->io_buflen = n; ep->io_buf = (char *)realloc(ep->io_buf, n); } if (ep->io_buf == NULL) sts = -1; else { memcpy(ep->io_buf, buf, n); ep->io_buf[n-1] = '\0'; } } } if (sts == 0) { /* assign pointers to individual lines in buffer */ curline = ep->io_buf; ep->io_lines.rchar = strsep(&curline, "\n"); ep->io_lines.wchar = strsep(&curline, "\n"); ep->io_lines.syscr = strsep(&curline, "\n"); ep->io_lines.syscw = strsep(&curline, "\n"); ep->io_lines.readb = strsep(&curline, "\n"); ep->io_lines.writeb = strsep(&curline, "\n"); ep->io_lines.cancel = strsep(&curline, "\n"); ep->flags |= PROC_PID_FLAG_IO_FETCHED; } if (fd >= 0) close(fd); } return (sts < 0) ? NULL : ep; } /* * fetch a proc//fd entry for pid */ proc_pid_entry_t * fetch_proc_pid_fd(int id, proc_pid_t *proc_pid) { __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); proc_pid_entry_t *ep; if (node == NULL) return NULL; ep = (proc_pid_entry_t *)node->data; if (!(ep->flags & PROC_PID_FLAG_FD_FETCHED)) { uint32_t de_count = 0; DIR *dir = proc_opendir("fd", ep); if (dir == NULL) { #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) fprintf(stderr, "failed to open fd path for pid %d\n", ep->id); #endif return NULL; } while (readdir(dir) != NULL) { de_count++; } closedir(dir); ep->fd_count = de_count - 2; /* subtract cwd and parent entries */ ep->flags |= PROC_PID_FLAG_FD_FETCHED; } return ep; } /* * From the kernel format for a single process cgroup set: * 2:cpu:/ * 1:cpuset:/ * * Produce the same one-line format string that "ps" uses: * "cpu:/;cpuset:/" */ static void proc_cgroup_reformat(char *buf, int len, char *fmt) { char *target = fmt, *p, *s = NULL; *target = '\0'; for (p = buf; p - buf < len; p++) { if (*p == '\0') break; if (*p == ':' && !s) /* position "s" at start */ s = p + 1; if (*p != '\n' || !s) /* find end of this line */ continue; if (target != fmt) /* not the first cgroup? */ strncat(target, ";", 2); /* have a complete cgroup line now, copy it over */ strncat(target, s, (p - s)); target += (p - s); s = NULL; /* reset it for new line */ } } /* * fetch a proc//cgroup entry for pid */ proc_pid_entry_t * fetch_proc_pid_cgroup(int id, proc_pid_t *proc_pid) { __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); proc_pid_entry_t *ep; int sts = 0; if (node == NULL) return NULL; ep = (proc_pid_entry_t *)node->data; if (!(ep->flags & PROC_PID_FLAG_CGROUP_FETCHED)) { char buf[1024]; char fmt[1024]; int n, fd; if ((fd = proc_open("cgroup", ep)) < 0) sts = -oserror(); else if ((n = read(fd, buf, sizeof(buf))) < 0) sts = -oserror(); else { if (n == 0) sts = -1; else { /* reformat the buffer to match "ps" output format, then hash */ proc_cgroup_reformat(&buf[0], n, &fmt[0]); ep->cgroup_id = proc_strings_insert(fmt); } } if (fd >= 0) close(fd); ep->flags |= PROC_PID_FLAG_CGROUP_FETCHED; } return (sts < 0) ? NULL : ep; } /* * fetch a proc//attr/current entry for pid */ proc_pid_entry_t * fetch_proc_pid_label(int id, proc_pid_t *proc_pid) { __pmHashNode *node = __pmHashSearch(id, &proc_pid->pidhash); proc_pid_entry_t *ep; int sts = 0; if (node == NULL) return NULL; ep = (proc_pid_entry_t *)node->data; if (!(ep->flags & PROC_PID_FLAG_LABEL_FETCHED)) { char buf[1024]; int n, fd; if ((fd = proc_open("attr/current", ep)) < 0) sts = -oserror(); else if ((n = read(fd, buf, sizeof(buf))) < 0) sts = -oserror(); else { if (n == 0) sts = -1; else { /* buffer matches "ps" output format, direct hash */ buf[sizeof(buf)-1] = '\0'; ep->label_id = proc_strings_insert(buf); } } if (fd >= 0) close(fd); ep->flags |= PROC_PID_FLAG_LABEL_FETCHED; } return (sts < 0) ? NULL : ep; } /* * Extract the ith (space separated) field from a char buffer. * The first field starts at zero. * BEWARE: return copy is in a static buffer. */ char * _pm_getfield(char *buf, int field) { static int retbuflen = 0; static char *retbuf = NULL; char *p; int i; if (buf == NULL) return NULL; for (p=buf, i=0; i < field; i++) { /* skip to the next space */ for (; *p && !isspace((int)*p); p++) {;} /* skip to the next word */ for (; *p && isspace((int)*p); p++) {;} } /* return a null terminated copy of the field */ for (i=0; ; i++) { if (isspace((int)p[i]) || p[i] == '\0' || p[i] == '\n') break; } if (i >= retbuflen) { retbuflen = i+4; retbuf = (char *)realloc(retbuf, retbuflen); } memcpy(retbuf, p, i); retbuf[i] = '\0'; return retbuf; } pcp-3.8.12ubuntu1/src/pmdas/linux_proc/filesys.c0000664000000000000000000000500412272262501016500 0ustar /* * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2012 Red Hat, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "filesys.h" char * scan_filesys_options(const char *options, const char *option) { static char buffer[128]; char *s; strncpy(buffer, options, sizeof(buffer)); buffer[sizeof(buffer)-1] = '\0'; s = strtok(buffer, ","); while (s) { if (strcmp(s, option) == 0) return s; s = strtok(NULL, ","); } return NULL; } int refresh_filesys(pmInDom indom) { char buf[MAXPATHLEN]; filesys_t *fs; FILE *fp; char *path, *device, *type, *options; int sts; pmdaCacheOp(indom, PMDA_CACHE_INACTIVE); if ((fp = fopen("/proc/mounts", "r")) == (FILE *)NULL) return -oserror(); while (fgets(buf, sizeof(buf), fp) != NULL) { device = strtok(buf, " "); path = strtok(NULL, " "); type = strtok(NULL, " "); options = strtok(NULL, " "); if (strcmp(type, "cgroup") != 0) continue; sts = pmdaCacheLookupName(indom, path, NULL, (void **)&fs); if (sts == PMDA_CACHE_ACTIVE) /* repeated line in /proc/mounts? */ continue; if (sts == PMDA_CACHE_INACTIVE) { /* re-activate an old mount */ pmdaCacheStore(indom, PMDA_CACHE_ADD, path, fs); if (strcmp(path, fs->path) != 0) { /* old device, new path */ free(fs->path); fs->path = strdup(path); } if (strcmp(options, fs->options) != 0) { /* old device, new opts */ free(fs->options); fs->options = strdup(options); } } else { /* new mount */ if ((fs = malloc(sizeof(filesys_t))) == NULL) continue; fs->device = strdup(device); fs->path = strdup(path); fs->options = strdup(options); #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { fprintf(stderr, "refresh_filesys: add \"%s\" \"%s\"\n", fs->path, device); } #endif pmdaCacheStore(indom, PMDA_CACHE_ADD, path, fs); } fs->flags = 0; } /* * success */ fclose(fp); return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux_proc/Remove0000775000000000000000000000125212272262501016042 0ustar #!/bin/sh # # Copyright (c) 2013 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the Linux per-process (proc) PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=proc pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/linux_proc/Install0000775000000000000000000000137612272262501016222 0ustar #!/bin/sh # # Copyright (c) 2013 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the Linux per-process (proc) PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=proc pmda_interface=6 daemon_opt=true pipe_opt=true pmns_source=root_proc pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/linux_proc/GNUmakefile0000664000000000000000000000503212272262501016731 0ustar # # Copyright (c) 2000,2003,2004,2008 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2007-2010 Aconex. All Rights Reserved. # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = proc DOMAIN = PROC CMDTARGET = pmdaproc LIBTARGET = pmda_proc.so PMDAINIT = proc_init PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) CONF_LINE = "proc 3 pipe binary $(PMDADIR)/$(CMDTARGET) -d 3" CFILES = pmda.c cgroups.c filesys.c proc_pid.c proc_runq.c \ ksym.c getinfo.c contexts.c HFILES = cgroups.h clusters.h proc_pid.h indom.h getinfo.h \ proc_runq.h ksym.h filesys.h contexts.h SCRIPTS = Install Remove VERSION_SCRIPT = exports HELPTARGETS = help.dir help.pag LSRCFILES = help root root_proc linux_proc_migrate.conf $(SCRIPTS) LDIRT = $(HELPTARGETS) domain.h $(VERSION_SCRIPT) LLDLIBS = $(PCP_PMDALIB) LCFLAGS = $(INVISIBILITY) # Uncomment these flags for profiling # LCFLAGS += -pg # LLDFLAGS += -pg default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "linux" build-me: domain.h $(LIBTARGET) $(CMDTARGET) $(HELPTARGETS) @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 644 domain.h help help.dir help.pag root root_proc $(PMDADIR) $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(SCRIPTS) $(PMDADIR) $(INSTALL) -m 644 root_proc $(PCP_VAR_DIR)/pmns/root_proc $(INSTALL) -m 644 linux_proc_migrate.conf $(PCP_VAR_DIR)/config/pmlogrewrite/linux_proc_migrate.conf else build-me: install: endif default_pcp : default install_pcp : install $(HELPTARGETS) : help $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_proc -v 2 -o help < help $(VERSION_SCRIPT): $(VERSION_SCRIPT_MAKERULE) domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) cgroups.o pmda.o: clusters.h cgroups.o pmda.o: cgroups.h cgroups.o pmda.o proc_pid.o proc_runq.o: proc_pid.h pmda.o proc_runq.o: proc_runq.h filesys.o: filesys.h ksym.o pmda.o: ksym.h pmda.o: domain.h pmda.o: indom.h pmda.o: getinfo.h pmda.o: $(VERSION_SCRIPT) pcp-3.8.12ubuntu1/src/pmdas/linux_proc/cgroups.c0000664000000000000000000005070612272262501016515 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2010 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "cgroups.h" #include "filesys.h" #include "clusters.h" #include "proc_pid.h" #include #ifdef HAVE_STRINGS_H #include #endif #include /* Add namespace entries and prepare values for one cgroupfs directory entry */ struct cgroup_subsys; typedef int (*cgroup_prepare_t)(__pmnsTree *, const char *, struct cgroup_subsys *, const char *, int, int, int); static int prepare_ull(__pmnsTree *, const char *, struct cgroup_subsys *, const char *, int, int, int); static int prepare_string(__pmnsTree *, const char *, struct cgroup_subsys *, const char *, int, int, int); static int prepare_named_ull(__pmnsTree *, const char *, struct cgroup_subsys *, const char *, int, int, int); /* * Critical data structures for cgroup subsystem in pmdalinux... * Initial comment for each struct talks about lifecycle of that * data, in terms of what pmdalinux must do with it (esp. memory * allocation related). */ typedef struct { /* contents depends on individual kernel cgroups */ int item; /* PMID == domain:cluster:[id:item] */ int dynamic; /* do we need an extra free (string) */ cgroup_prepare_t prepare; /* setup metric name(s) and value(s) */ char *suffix; /* cpus/mems/rss/... */ } cgroup_metrics_t; typedef struct { /* some metrics are multi-valued, but most have only one */ int item; /* PMID == domain:cluster:[id:item] */ int atom_count; pmAtomValue *atoms; } cgroup_values_t; typedef struct { /* contains data for each group users have created, if any */ int id; /* PMID == domain:cluster:[id:item] */ int refreshed; /* boolean: are values all uptodate */ proc_pid_list_t process_list; cgroup_values_t *metric_values; } cgroup_group_t; typedef struct cgroup_subsys { /* contents covers the known kernel cgroups */ const char *name; /* cpuset/memory/... */ int cluster; /* PMID == domain:cluster:[id:item] */ int unused; /* unused, just padding now */ int group_count; /* number of groups (dynamic) */ int metric_count; /* number of metrics (fixed) */ cgroup_group_t *groups; /* array of groups (dynamic) */ cgroup_metrics_t *metrics; /* array of metrics (fixed) */ } cgroup_subsys_t; static cgroup_metrics_t cpusched_metrics[] = { { .item = 0, .suffix = "shares", .prepare = prepare_ull }, }; static cgroup_metrics_t cpuacct_metrics[] = { { .item = 0, .suffix = "stat.user", .prepare = prepare_named_ull }, { .item = 1, .suffix = "stat.system", .prepare = prepare_named_ull }, { .item = 2, .suffix = "usage", .prepare = prepare_ull }, { .item = 3, .suffix = "usage_percpu", .prepare = prepare_ull }, }; static cgroup_metrics_t cpuset_metrics[] = { { .item = 0, .suffix = "cpus", .prepare = prepare_string, .dynamic = 1 }, { .item = 1, .suffix = "mems", .prepare = prepare_string, .dynamic = 1 }, }; static cgroup_metrics_t memory_metrics[] = { { .item = 0, .suffix = "stat.cache", .prepare = prepare_named_ull }, { .item = 1, .suffix = "stat.rss", .prepare = prepare_named_ull }, { .item = 2, .suffix = "stat.pgin", .prepare = prepare_named_ull }, { .item = 3, .suffix = "stat.pgout", .prepare = prepare_named_ull }, { .item = 4, .suffix = "stat.swap", .prepare = prepare_named_ull }, { .item = 5, .suffix = "stat.active_anon", .prepare = prepare_named_ull }, { .item = 6, .suffix = "stat.inactive_anon", .prepare = prepare_named_ull }, { .item = 7, .suffix = "stat.active_file", .prepare = prepare_named_ull }, { .item = 8, .suffix = "stat.inactive_file", .prepare = prepare_named_ull }, { .item = 9, .suffix = "stat.unevictable", .prepare = prepare_named_ull }, }; static cgroup_metrics_t netclass_metrics[] = { { .item = 0, .suffix = "classid", .prepare = prepare_ull }, }; static cgroup_subsys_t controllers[] = { { .name = "cpu", .cluster = CLUSTER_CPUSCHED_GROUPS, .metrics = cpusched_metrics, .metric_count = sizeof(cpusched_metrics) / sizeof(cpusched_metrics[0]), }, { .name = "cpuset", .cluster = CLUSTER_CPUSET_GROUPS, .metrics = cpuset_metrics, .metric_count = sizeof(cpuset_metrics) / sizeof(cpuset_metrics[0]), }, { .name = "cpuacct", .cluster = CLUSTER_CPUACCT_GROUPS, .metrics = cpuacct_metrics, .metric_count = sizeof(cpuacct_metrics) / sizeof(cpuacct_metrics[0]), }, { .name = "memory", .cluster = CLUSTER_MEMORY_GROUPS, .metrics = memory_metrics, .metric_count = sizeof(memory_metrics) / sizeof(memory_metrics[0]), }, { .name = "net_cls", .cluster = CLUSTER_NET_CLS_GROUPS, .metrics = netclass_metrics, .metric_count = sizeof(netclass_metrics) / sizeof(netclass_metrics[0]), }, }; static int read_values(char *buffer, int size, const char *path, const char *subsys, const char *metric) { int fd, count; snprintf(buffer, size, "%s/%s.%s", path, subsys, metric); if ((fd = open(buffer, O_RDONLY)) < 0) return -oserror(); count = read(fd, buffer, size); close(fd); if (count < 0) return -oserror(); buffer[count-1] = '\0'; return 0; } static void update_pmns(__pmnsTree *pmns, cgroup_subsys_t *subsys, const char *name, cgroup_metrics_t *metrics, int group, int domain) { char entry[MAXPATHLEN]; pmID pmid; snprintf(entry, sizeof(entry), "%s.groups.%s%s.%s", CGROUP_ROOT, subsys->name, name, metrics->suffix); pmid = cgroup_pmid_build(domain, subsys->cluster, group, metrics->item); __pmAddPMNSNode(pmns, pmid, entry); } static int prepare_ull(__pmnsTree *pmns, const char *path, cgroup_subsys_t *subsys, const char *name, int metric, int group, int domain) { int count = 0; unsigned long long value; char buffer[MAXPATHLEN]; char *endp, *p = &buffer[0]; cgroup_group_t *groups = &subsys->groups[group]; cgroup_metrics_t *metrics = &subsys->metrics[metric]; pmAtomValue *atoms = groups->metric_values[metric].atoms; if (read_values(p, sizeof(buffer), path, subsys->name, metrics->suffix) < 0) return -oserror(); while (p && *p) { value = strtoull(p, &endp, 0); if ((atoms = realloc(atoms, (count + 1) * sizeof(pmAtomValue))) == NULL) return -oserror(); atoms[count++].ull = value; if (endp == '\0' || endp == p) break; p = endp; while (p && isspace((int)*p)) p++; } groups->metric_values[metric].item = metric; groups->metric_values[metric].atoms = atoms; groups->metric_values[metric].atom_count = count; update_pmns(pmns, subsys, name, metrics, group, domain); return 0; } static int prepare_named_ull(__pmnsTree *pmns, const char *path, cgroup_subsys_t *subsys, const char *name, int metric, int group, int domain) { int i, count; unsigned long long value; char filename[64], buffer[MAXPATHLEN]; char *offset, *p = &buffer[0]; cgroup_group_t *groups = &subsys->groups[group]; cgroup_metrics_t *metrics = &subsys->metrics[metric]; if (groups->refreshed) return 0; /* metric => e.g. stat.user and stat.system - split it up first */ offset = index(metrics->suffix, '.'); if (!offset) return PM_ERR_CONV; count = (offset - metrics->suffix); strncpy(filename, metrics->suffix, count); filename[count] = '\0'; if (read_values(p, sizeof(buffer), path, subsys->name, filename) < 0) return -oserror(); /* buffer contains pairs */ while (p && *p) { char *endp, *field, *offset; if ((field = index(p, ' ')) == NULL) return PM_ERR_CONV; offset = field + 1; *field = '\0'; field = p; /* field now points to */ p = offset; value = strtoull(p, &endp, 0); p = endp; while (p && isspace((int)*p)) p++; for (i = 0; i < subsys->metric_count; i++) { pmAtomValue *atoms = groups->metric_values[i].atoms; metrics = &subsys->metrics[i]; if (strcmp(field, metrics->suffix + count + 1) != 0) continue; if ((atoms = calloc(1, sizeof(pmAtomValue))) == NULL) return -oserror(); atoms[0].ull = value; groups->metric_values[i].item = i; groups->metric_values[i].atoms = atoms; groups->metric_values[i].atom_count = 1; update_pmns(pmns, subsys, name, metrics, group, domain); break; } } groups->refreshed = 1; return 0; } static int prepare_string(__pmnsTree *pmns, const char *path, cgroup_subsys_t *subsys, const char *name, int metric, int group, int domain) { char buffer[MAXPATHLEN]; cgroup_group_t *groups = &subsys->groups[group]; cgroup_metrics_t *metrics = &subsys->metrics[metric]; pmAtomValue *atoms = groups->metric_values[metric].atoms; char *p = &buffer[0]; if (read_values(p, sizeof(buffer), path, subsys->name, metrics->suffix) < 0) return -oserror(); if ((atoms = malloc(sizeof(pmAtomValue))) == NULL) return -oserror(); if ((atoms[0].cp = strdup(buffer)) == NULL) { free(atoms); return -oserror(); } groups->metric_values[metric].item = metric; groups->metric_values[metric].atoms = atoms; groups->metric_values[metric].atom_count = 1; update_pmns(pmns, subsys, name, metrics, group, domain); return 0; } static void translate(char *dest, const char *src, size_t size) { char *p; if (*src != '\0') /* non-root */ *dest = '.'; strncpy(dest, src, size); for (p = dest; *p; p++) { if (*p == '/') *p = '.'; } } static int namespace(__pmnsTree *pmns, cgroup_subsys_t *subsys, const char *cgrouppath, const char *cgroupname, int domain) { int i, id, sts; cgroup_values_t *cvp; char group[128]; translate(&group[0], cgroupname, sizeof(group)); /* allocate space for this group */ sts = (subsys->group_count + 1) * sizeof(cgroup_group_t); subsys->groups = (cgroup_group_t *)realloc(subsys->groups, sts); if (subsys->groups == NULL) return -oserror(); /* allocate space for all values up-front */ sts = subsys->metric_count * sizeof(cgroup_values_t); if ((cvp = (cgroup_values_t *)calloc(1, sts)) == NULL) return -oserror(); id = subsys->group_count++; memset(&subsys->groups[id], 0, sizeof(cgroup_group_t)); subsys->groups[id].id = id; subsys->groups[id].metric_values = cvp; for (i = 0; i < subsys->metric_count; i++) { cgroup_metrics_t *metrics = &subsys->metrics[i]; metrics->prepare(pmns, cgrouppath, subsys, group, i, id, domain); } return 1; } int refresh_cgroup_subsys(pmInDom indom) { char buf[4096]; char name[MAXPATHLEN]; unsigned int numcgroups, enabled; int sts; long *data; long hierarchy; FILE *fp; if ((fp = fopen("/proc/cgroups", "r")) == NULL) return 1; while (fgets(buf, sizeof(buf), fp) != NULL) { /* skip lines starting with hash (header) */ if (buf[0] == '#') continue; if (sscanf(buf, "%s %ld %u %u", &name[0], &hierarchy, &numcgroups, &enabled) != 4) continue; sts = pmdaCacheLookupName(indom, name, NULL, (void **)&data); if (sts == PMDA_CACHE_ACTIVE) { if (*data != hierarchy) { /* * odd ... instance name repeated but different * hierarchy ... we cannot support more than one hierarchy * yet */ fprintf(stderr, "refresh_cgroup_subsys: \"%s\": entries for hierarchy %ld ignored (hierarchy %ld seen first)\n", name, hierarchy, *data); } continue; } else if (sts != PMDA_CACHE_INACTIVE) { if ((data = (long *)malloc(sizeof(long))) == NULL) { #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) fprintf(stderr, "refresh_cgroup_subsys: \"%s\": malloc failed\n", name); #endif continue; } *data = hierarchy; } pmdaCacheStore(indom, PMDA_CACHE_ADD, name, (void *)data); #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) fprintf(stderr, "refresh_cgroup_subsys: add \"%s\" [hierarchy %ld]\n", name, hierarchy); #endif } fclose(fp); return 0; } /* * Parse a (comma-separated) mount option string to find one of the known * cgroup subsystems, and return a pointer to it or "?" if none found. */ char * cgroup_find_subsys(pmInDom indom, const char *options) { static char dunno[] = "?"; static char opts[128]; char buffer[128]; char *s, *out = NULL; memset(opts, 0, sizeof(opts)); strncpy(buffer, options, sizeof(buffer)); s = strtok(buffer, ","); while (s) { if (pmdaCacheLookupName(indom, s, NULL, NULL) == PMDA_CACHE_ACTIVE) { if (out) { /* append option */ strcat(out, ","); strcat(out, s); out += strlen(s) + 1; /* +1 => cater for comma */ } else { /* first option */ strcat(opts, s); out = opts + strlen(s); } } s = strtok(NULL, ","); } if (out) return opts; return dunno; } /* Ensure cgroup name can be used as a PCP namespace entry, ignore it if not */ static int valid_pmns_name(char *name) { if (!isalpha((int)name[0])) return 0; for (; *name != '\0'; name++) if (!isalnum((int)*name) && *name != '_') return 0; return 1; } static int cgroup_namespace(__pmnsTree *pmns, const char *options, const char *cgrouppath, const char *cgroupname, int domain) { int i, sts = 0; /* use options to tell which cgroup controller(s) are active here */ for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { int lsts; cgroup_subsys_t *subsys = &controllers[i]; if (scan_filesys_options(options, subsys->name) == NULL) continue; lsts = namespace(pmns, subsys, cgrouppath, cgroupname, domain); if (lsts > 0) sts = 1; } return sts; } static int cgroup_scan(const char *mnt, const char *path, const char *options, int domain, __pmnsTree *pmns, int root) { int sts, length; DIR *dirp; struct stat sbuf; struct dirent *dp; char *cgroupname; char cgrouppath[MAXPATHLEN]; if (root) { strncpy(cgrouppath, mnt, sizeof(cgrouppath)); cgrouppath[sizeof(cgrouppath)-1] = '\0'; length = strlen(cgrouppath); } else { snprintf(cgrouppath, sizeof(cgrouppath), "%s/%s", mnt, path); length = strlen(mnt) + 1; } if ((dirp = opendir(cgrouppath)) == NULL) return -oserror(); cgroupname = &cgrouppath[length]; sts = cgroup_namespace(pmns, options, cgrouppath, cgroupname, domain); /* * readdir - descend into directories to find all cgroups, then * populate namespace with [.]. */ while ((dp = readdir(dirp)) != NULL) { int lsts; if (!valid_pmns_name(dp->d_name)) continue; if (path[0] == '\0') snprintf(cgrouppath, sizeof(cgrouppath), "%s/%s", mnt, dp->d_name); else snprintf(cgrouppath, sizeof(cgrouppath), "%s/%s/%s", mnt, path, dp->d_name); cgroupname = &cgrouppath[length]; if (stat(cgrouppath, &sbuf) < 0) continue; if (!(S_ISDIR(sbuf.st_mode))) continue; lsts = cgroup_namespace(pmns, options, cgrouppath, cgroupname, domain); if (lsts > 0) sts = 1; /* * also scan for any child cgroups, but cgroup_scan() may return * an error */ lsts = cgroup_scan(mnt, cgroupname, options, domain, pmns, 0); if (lsts > 0) sts = 1; } closedir(dirp); return sts; } static void cgroup_regulars(__pmnsTree *pmns, int domain) { int i; static struct { int item; int cluster; char *name; } regulars[] = { { 0, CLUSTER_CGROUP_SUBSYS, CGROUP_ROOT ".subsys.hierarchy" }, { 1, CLUSTER_CGROUP_SUBSYS, CGROUP_ROOT ".subsys.count" }, { 0, CLUSTER_CGROUP_MOUNTS, CGROUP_ROOT ".mounts.subsys" }, { 1, CLUSTER_CGROUP_MOUNTS, CGROUP_ROOT ".mounts.count" }, }; for (i = 0; i < 4; i++) { pmID pmid = pmid_build(domain, regulars[i].cluster, regulars[i].item); __pmAddPMNSNode(pmns, pmid, regulars[i].name); } } int refresh_cgroup_groups(pmdaExt *pmda, pmInDom mounts, __pmnsTree **pmns) { int i, j, k, a; int sts, mtab = 0, domain = pmda->e_domain; filesys_t *fs; __pmnsTree *tree = pmns ? *pmns : NULL; if (tree) __pmFreePMNS(tree); if ((sts = __pmNewPMNS(&tree)) < 0) { __pmNotifyErr(LOG_ERR, "%s: failed to create new pmns: %s\n", pmProgname, pmErrStr(sts)); if (pmns) *pmns = NULL; return 0; } cgroup_regulars(tree, domain); /* reset our view of subsystems and groups */ for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { cgroup_subsys_t *subsys = &controllers[i]; for (j = 0; j < subsys->group_count; j++) { cgroup_group_t *group = &subsys->groups[j]; for (k = 0; k < subsys->metric_count; k++) { pmAtomValue *atoms = group->metric_values[k].atoms; if (subsys->metrics[k].dynamic) for (a = 0; a < group->metric_values[k].atom_count; a++) free(atoms[a].cp); free(atoms); } free(group->metric_values); if (group->process_list.size) free(group->process_list.pids); memset(group, 0, sizeof(cgroup_group_t)); } controllers[i].group_count = 0; } pmdaCacheOp(mounts, PMDA_CACHE_WALK_REWIND); while ((sts = pmdaCacheOp(mounts, PMDA_CACHE_WALK_NEXT)) != -1) { int lsts; if (!pmdaCacheLookup(mounts, sts, NULL, (void **)&fs)) continue; /* walk this cgroup mount finding groups (subdirs) */ lsts = cgroup_scan(fs->path, "", fs->options, domain, tree, 1); if (lsts > 0) mtab = 1; } if (pmns) *pmns = tree; else __pmFreePMNS(tree); return mtab; } int cgroup_group_fetch(int cluster, int item, unsigned int inst, pmAtomValue *atom) { int i, j, k, gid; gid = cgroup_pmid_group(item); item = cgroup_pmid_metric(item); for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { cgroup_subsys_t *subsys = &controllers[i]; if (subsys->cluster != cluster) continue; for (j = 0; j < subsys->group_count; j++) { cgroup_group_t *group = &subsys->groups[j]; if (group->id != gid) continue; for (k = 0; k < subsys->metric_count; k++) { cgroup_values_t *cvp = &group->metric_values[k]; if (cvp->item != item) continue; if (cvp->atom_count <= 0) return PM_ERR_VALUE; if (inst == PM_IN_NULL) inst = 0; else if (inst >= cvp->atom_count) return PM_ERR_INST; *atom = cvp->atoms[inst]; return 1; } } } return PM_ERR_PMID; } /* * Needs to answer the question: how much extra space needs to be allocated * in the metric table for (dynamic) cgroup metrics"? We have static entries * for group ID zero - if we have any non-zero group IDs, we need entries to * cover those. Return value is the number of additional entries needed. */ static void size_metrictable(int *total, int *trees) { int i, j, maxid = 0, count = 0; for (i = 0; i < sizeof(controllers)/sizeof(controllers[0]); i++) { cgroup_subsys_t *subsys = &controllers[i]; for (j = 0; j < subsys->group_count; j++) { cgroup_group_t *group = &subsys->groups[j]; if (group->id > maxid) maxid = group->id; } count += subsys->metric_count + 0; /* +1 for task.pid */ } *total = count; *trees = maxid; if (pmDebug & DBG_TRACE_LIBPMDA) fprintf(stderr, "cgroups size_metrictable: %d total x %d trees\n", *total, *trees); } /* * Create new metric table entry for a group based on an existing one. */ static void refresh_metrictable(pmdaMetric *source, pmdaMetric *dest, int id) { int domain = pmid_domain(source->m_desc.pmid); int cluster = pmid_cluster(source->m_desc.pmid); int item = pmid_item(source->m_desc.pmid); memcpy(dest, source, sizeof(pmdaMetric)); dest->m_desc.pmid = cgroup_pmid_build(domain, cluster, id, item); if (pmDebug & DBG_TRACE_LIBPMDA) fprintf(stderr, "cgroup refresh_metrictable: (%p -> %p) " "metric ID dup: %d.%d.%d.%d -> %d.%d.%d.%d\n", source, dest, domain, cluster, cgroup_pmid_group(source->m_desc.pmid), cgroup_pmid_metric(source->m_desc.pmid), pmid_domain(dest->m_desc.pmid), pmid_cluster(dest->m_desc.pmid), cgroup_pmid_group(dest->m_desc.pmid), cgroup_pmid_metric(dest->m_desc.pmid)); } static int cgroup_text(pmdaExt *pmda, pmID pmid, int type, char **buf) { return PM_ERR_TEXT; } void cgroup_init(pmdaMetric *metrics, int nmetrics) { int set[] = { CLUSTER_CPUSET_GROUPS, CLUSTER_CPUACCT_GROUPS, CLUSTER_CPUSCHED_GROUPS, CLUSTER_MEMORY_GROUPS, CLUSTER_NET_CLS_GROUPS, }; pmdaDynamicPMNS(CGROUP_ROOT, set, sizeof(set)/sizeof(int), refresh_cgroups, cgroup_text, refresh_metrictable, size_metrictable, metrics, nmetrics); } pcp-3.8.12ubuntu1/src/pmdas/linux_proc/root0000664000000000000000000000014412272262501015564 0ustar /* * fake "root" for validating the local PMNS subtree */ #include #include "root_xfs" pcp-3.8.12ubuntu1/src/pmdas/linux_proc/contexts.c0000664000000000000000000001222012272262501016667 0ustar /* * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "contexts.h" static proc_perctx_t *ctxtab; static int num_ctx; static uid_t baseuid; static gid_t basegid; static void proc_ctx_clear(int ctx) { ctxtab[ctx].state = CTX_INACTIVE; ctxtab[ctx].uid = -1; ctxtab[ctx].gid = -1; ctxtab[ctx].threads = 1; ctxtab[ctx].cgroups = NULL; } void proc_ctx_end(int ctx) { if (ctx < 0 || ctx >= num_ctx || ctxtab[ctx].state == CTX_INACTIVE) return; if (ctxtab[ctx].state & CTX_CGROUPS) free((void *)ctxtab[ctx].cgroups); proc_ctx_clear(ctx); } static void proc_ctx_growtab(int ctx) { size_t need; if (ctx < num_ctx) return; need = (ctx + 1) * sizeof(ctxtab[0]); ctxtab = (proc_perctx_t *)realloc(ctxtab, need); if (ctxtab == NULL) __pmNoMem("proc ctx table", need, PM_FATAL_ERR); while (num_ctx <= ctx) proc_ctx_clear(num_ctx++); } static void proc_ctx_set_userid(int ctx, const char *value) { proc_ctx_growtab(ctx); ctxtab[ctx].uid = atoi(value); ctxtab[ctx].state |= (CTX_ACTIVE | CTX_USERID); } static void proc_ctx_set_groupid(int ctx, const char *value) { proc_ctx_growtab(ctx); ctxtab[ctx].gid = atoi(value); ctxtab[ctx].state |= (CTX_ACTIVE | CTX_GROUPID); } int proc_ctx_attrs(int ctx, int attr, const char *value, int length, pmdaExt *pmda) { if (pmDebug & DBG_TRACE_AUTH) { char buffer[256]; if (!__pmAttrStr_r(attr, value, buffer, sizeof(buffer))) { __pmNotifyErr(LOG_ERR, "Bad Attribute: ctx=%d, attr=%d\n", ctx, attr); } else { buffer[sizeof(buffer)-1] = '\0'; __pmNotifyErr(LOG_INFO, "Attribute: ctx=%d %s", ctx, buffer); } } switch (attr) { case PCP_ATTR_USERID: proc_ctx_set_userid(ctx, value); break; case PCP_ATTR_GROUPID: proc_ctx_set_groupid(ctx, value); break; default: break; } return 0; } void proc_ctx_init(void) { baseuid = getuid(); basegid = getgid(); } int proc_ctx_access(int ctx) { proc_perctx_t *pp; int accessible = 0; if (ctx < 0 || ctx >= num_ctx) return accessible; pp = &ctxtab[ctx]; if (pp->state == CTX_INACTIVE) return accessible; if (pp->state & CTX_GROUPID) { accessible++; if (basegid != pp->gid) { if (setegid(pp->gid) < 0) { __pmNotifyErr(LOG_ERR, "setegid(%d) access failed: %s\n", pp->gid, osstrerror()); accessible--; } } } if (pp->state & CTX_USERID) { accessible++; if (baseuid != pp->uid) { if (seteuid(pp->uid) < 0) { __pmNotifyErr(LOG_ERR, "seteuid(%d) access failed: %s\n", pp->uid, osstrerror()); accessible--; } } } return (accessible > 1); } int proc_ctx_revert(int ctx) { proc_perctx_t *pp; if (ctx < 0 || ctx >= num_ctx) return 0; pp = &ctxtab[ctx]; if (pp->state == CTX_INACTIVE) return 0; if ((pp->state & CTX_USERID) && baseuid != pp->uid) { if (seteuid(baseuid) < 0) __pmNotifyErr(LOG_ERR, "seteuid(%d) revert failed: %s\n", baseuid, osstrerror()); } if ((pp->state & CTX_GROUPID) && basegid != pp->gid) { if (setegid(basegid) < 0) __pmNotifyErr(LOG_ERR, "setegid(%d) revert failed: %s\n", basegid, osstrerror()); } return 0; } unsigned int proc_ctx_threads(int ctx, unsigned int threads) { proc_perctx_t *pp; if (ctx < 0 || ctx >= num_ctx) return threads; /* fallback to default */ pp = &ctxtab[ctx]; if (pp->state == CTX_INACTIVE) return threads; /* fallback to default */ if (pp->state & CTX_THREADS) return pp->threads; /* client setting */ return threads; /* fallback to default */ } int proc_ctx_set_threads(int ctx, unsigned int threads) { proc_perctx_t *pp; if (ctx < 0 || ctx >= num_ctx) return PM_ERR_NOCONTEXT; pp = &ctxtab[ctx]; if (pp->state == CTX_INACTIVE) return PM_ERR_NOCONTEXT; if (threads > 1) return PM_ERR_CONV; pp->state |= CTX_THREADS; pp->threads = threads; return 0; } const char * proc_ctx_cgroups(int ctx, const char *cgroups) { proc_perctx_t *pp; if (ctx < 0 || ctx >= num_ctx) return cgroups; /* fallback to default */ pp = &ctxtab[ctx]; if (pp->state == CTX_INACTIVE) return cgroups; /* fallback to default */ if (pp->state & CTX_CGROUPS) return pp->cgroups; /* client setting */ return cgroups; /* fallback to default */ } int proc_ctx_set_cgroups(int ctx, const char *cgroups) { proc_perctx_t *pp; if (ctx < 0 || ctx >= num_ctx) return PM_ERR_NOCONTEXT; pp = &ctxtab[ctx]; if (pp->state == CTX_INACTIVE) return PM_ERR_NOCONTEXT; if (cgroups == NULL || cgroups[0] == '\0') return PM_ERR_CONV; pp->state |= CTX_CGROUPS; pp->cgroups = cgroups; return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux_proc/proc_pid.h0000664000000000000000000002024512272262501016632 0ustar /* * Linux /proc//... Clusters * * Copyright (c) 2013 Red Hat. * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _PROC_PID_H #define _PROC_PID_H /* * /proc//stat metrics */ #define PROC_PID_STAT_PID 0 #define PROC_PID_STAT_CMD 1 #define PROC_PID_STAT_STATE 2 #define PROC_PID_STAT_PPID 3 #define PROC_PID_STAT_PGRP 4 #define PROC_PID_STAT_SESSION 5 #define PROC_PID_STAT_TTY 6 #define PROC_PID_STAT_TTY_PGRP 7 #define PROC_PID_STAT_FLAGS 8 #define PROC_PID_STAT_MINFLT 9 #define PROC_PID_STAT_CMIN_FLT 10 #define PROC_PID_STAT_MAJ_FLT 11 #define PROC_PID_STAT_CMAJ_FLT 12 #define PROC_PID_STAT_UTIME 13 #define PROC_PID_STAT_STIME 14 #define PROC_PID_STAT_CUTIME 15 #define PROC_PID_STAT_CSTIME 16 #define PROC_PID_STAT_PRIORITY 17 #define PROC_PID_STAT_NICE 18 #define PROC_PID_STAT_REMOVED 19 #define PROC_PID_STAT_IT_REAL_VALUE 20 #define PROC_PID_STAT_START_TIME 21 #define PROC_PID_STAT_VSIZE 22 #define PROC_PID_STAT_RSS 23 #define PROC_PID_STAT_RSS_RLIM 24 #define PROC_PID_STAT_START_CODE 25 #define PROC_PID_STAT_END_CODE 26 #define PROC_PID_STAT_START_STACK 27 #define PROC_PID_STAT_ESP 28 #define PROC_PID_STAT_EIP 29 #define PROC_PID_STAT_SIGNAL 30 #define PROC_PID_STAT_BLOCKED 31 #define PROC_PID_STAT_SIGIGNORE 32 #define PROC_PID_STAT_SIGCATCH 33 #define PROC_PID_STAT_WCHAN 34 #define PROC_PID_STAT_NSWAP 35 #define PROC_PID_STAT_CNSWAP 36 #define PROC_PID_STAT_EXIT_SIGNAL 37 #define PROC_PID_STAT_PROCESSOR 38 #define PROC_PID_STAT_TTYNAME 39 #define PROC_PID_STAT_WCHAN_SYMBOL 40 #define PROC_PID_STAT_PSARGS 41 /* number of fields in proc_pid_stat_entry_t */ #define NR_PROC_PID_STAT 42 /* * metrics in /proc//status * Added by Mike Mason */ #define PROC_PID_STATUS_UID 0 #define PROC_PID_STATUS_EUID 1 #define PROC_PID_STATUS_SUID 2 #define PROC_PID_STATUS_FSUID 3 #define PROC_PID_STATUS_GID 4 #define PROC_PID_STATUS_EGID 5 #define PROC_PID_STATUS_SGID 6 #define PROC_PID_STATUS_FSGID 7 #define PROC_PID_STATUS_UID_NM 8 #define PROC_PID_STATUS_EUID_NM 9 #define PROC_PID_STATUS_SUID_NM 10 #define PROC_PID_STATUS_FSUID_NM 11 #define PROC_PID_STATUS_GID_NM 12 #define PROC_PID_STATUS_EGID_NM 13 #define PROC_PID_STATUS_SGID_NM 14 #define PROC_PID_STATUS_FSGID_NM 15 #define PROC_PID_STATUS_SIGNAL 16 #define PROC_PID_STATUS_BLOCKED 17 #define PROC_PID_STATUS_SIGIGNORE 18 #define PROC_PID_STATUS_SIGCATCH 19 #define PROC_PID_STATUS_VMSIZE 20 #define PROC_PID_STATUS_VMLOCK 21 #define PROC_PID_STATUS_VMRSS 22 #define PROC_PID_STATUS_VMDATA 23 #define PROC_PID_STATUS_VMSTACK 24 #define PROC_PID_STATUS_VMEXE 25 #define PROC_PID_STATUS_VMLIB 26 #define PROC_PID_STATUS_VMSWAP 27 #define PROC_PID_STATUS_THREADS 28 /* number of metrics from /proc//status */ #define NR_PROC_PID_STATUS 27 /* * metrics in /proc//statm & /proc//maps */ #define PROC_PID_STATM_SIZE 0 #define PROC_PID_STATM_RSS 1 #define PROC_PID_STATM_SHARE 2 #define PROC_PID_STATM_TEXTRS 3 #define PROC_PID_STATM_LIBRS 4 #define PROC_PID_STATM_DATRS 5 #define PROC_PID_STATM_DIRTY 6 #define PROC_PID_STATM_MAPS 7 /* number of fields in proc_pid_statm_entry_t */ #define NR_PROC_PID_STATM 8 /* * metrics in /proc//schedstat */ #define PROC_PID_SCHED_CPUTIME 0 #define PROC_PID_SCHED_RUNDELAY 1 #define PROC_PID_SCHED_PCOUNT 2 #define NR_PROC_PID_SCHED 3 /* * metrics in /proc//io */ #define PROC_PID_IO_RCHAR 0 #define PROC_PID_IO_WCHAR 1 #define PROC_PID_IO_SYSCR 2 #define PROC_PID_IO_SYSCW 3 #define PROC_PID_IO_READ_BYTES 4 #define PROC_PID_IO_WRITE_BYTES 5 #define PROC_PID_IO_CANCELLED_BYTES 6 /* * metrics in /proc//fd */ #define PROC_PID_FD_COUNT 0 /* * metrics in /proc//cgroup */ #define PROC_PID_CGROUP 0 /* * metrics in /proc//attr/current */ #define PROC_PID_LABEL 0 typedef struct { /* /proc//status */ char *uid; char *gid; char *sigpnd; char *sigblk; char *sigign; char *sigcgt; char *vmsize; char *vmlck; char *vmrss; char *vmdata; char *vmstk; char *vmexe; char *vmlib; char *vmswap; char *threads; } status_lines_t; typedef struct { /* /proc//io */ char *rchar; char *wchar; char *syscr; char *syscw; char *readb; char *writeb; char *cancel; } io_lines_t; enum { PROC_PID_FLAG_VALID = 1<<0, PROC_PID_FLAG_STAT_FETCHED = 1<<1, PROC_PID_FLAG_STATM_FETCHED = 1<<2, PROC_PID_FLAG_MAPS_FETCHED = 1<<3, PROC_PID_FLAG_STATUS_FETCHED = 1<<4, PROC_PID_FLAG_SCHEDSTAT_FETCHED = 1<<5, PROC_PID_FLAG_IO_FETCHED = 1<<6, PROC_PID_FLAG_WCHAN_FETCHED = 1<<7, PROC_PID_FLAG_FD_FETCHED = 1<<8, PROC_PID_FLAG_CGROUP_FETCHED = 1<<9, PROC_PID_FLAG_LABEL_FETCHED = 1<<10, }; typedef struct { int id; /* pid, hash key and internal instance id */ int flags; /* combinations of PROC_PID_FLAG_* values */ char *name; /* external instance name ( cmdline) */ /* /proc//stat cluster */ int stat_buflen; char *stat_buf; /* /proc//statm and /proc//maps cluster */ int statm_buflen; char *statm_buf; int maps_buflen; char *maps_buf; /* /proc//status cluster */ int status_buflen; char *status_buf; status_lines_t status_lines; /* /proc//schedstat cluster */ int schedstat_buflen; char *schedstat_buf; /* /proc//io cluster */ int io_buflen; char *io_buf; io_lines_t io_lines; /* /proc//wchan cluster */ int wchan_buflen; char *wchan_buf; /* /proc//fd cluster */ int fd_buflen; uint32_t fd_count; char *fd_buf; /* /proc//cgroup cluster */ int cgroup_id; /* /proc//attr/current cluster */ int label_id; } proc_pid_entry_t; typedef struct { __pmHashCtl pidhash; /* hash table for current pids */ pmdaIndom *indom; /* instance domain table */ } proc_pid_t; typedef struct { int count; /* number of processes in the list */ int size; /* size of the buffer (pids) allocated */ int *pids; /* array of process identifiers */ int threads; /* /proc/PID/{xxx,task/PID/xxx} flag */ } proc_pid_list_t; /* refresh the proc indom, reset all "fetched" flags */ extern int refresh_proc_pid(proc_pid_t *, int, const char *); /* fetch a proc//stat entry for pid */ extern proc_pid_entry_t *fetch_proc_pid_stat(int, proc_pid_t *); /* fetch a proc//statm entry for pid */ extern proc_pid_entry_t *fetch_proc_pid_statm(int, proc_pid_t *); /* fetch a proc//status entry for pid */ extern proc_pid_entry_t *fetch_proc_pid_status(int, proc_pid_t *); /* fetch a proc//maps entry for pid */ extern proc_pid_entry_t *fetch_proc_pid_maps(int, proc_pid_t *); /* fetch a proc//schedstat entry for pid */ extern proc_pid_entry_t *fetch_proc_pid_schedstat(int, proc_pid_t *); /* fetch a proc//io entry for pid */ extern proc_pid_entry_t *fetch_proc_pid_io(int, proc_pid_t *); /* fetch a proc//fd entry for pid */ extern proc_pid_entry_t *fetch_proc_pid_fd(int, proc_pid_t *); /* fetch a proc//cgroup entry for pid */ extern proc_pid_entry_t *fetch_proc_pid_cgroup(int, proc_pid_t *); /* fetch a proc//attr/current entry for pid */ extern proc_pid_entry_t *fetch_proc_pid_label(int, proc_pid_t *); /* extract the ith space separated field from a buffer */ extern char *_pm_getfield(char *, int); #endif /* _PROC_PID_H */ pcp-3.8.12ubuntu1/src/pmdas/linux_proc/root_proc0000664000000000000000000000623412272262501016615 0ustar /* * Metrics for the Linux proc PMDA * * Note: * names and pmids migrated from the Linux PMDA, with the domain * number changed from LINUX (60) to 3 (3) */ #ifndef PROC #define PROC 3 #endif root { cgroup PROC:*:* /* dynamic */ proc } proc { nprocs PROC:8:99 psinfo memory runq id io schedstat fd control } proc.psinfo { pid PROC:8:0 cmd PROC:8:1 sname PROC:8:2 ppid PROC:8:3 pgrp PROC:8:4 session PROC:8:5 tty PROC:8:6 tty_pgrp PROC:8:7 flags PROC:8:8 minflt PROC:8:9 cmin_flt PROC:8:10 maj_flt PROC:8:11 cmaj_flt PROC:8:12 utime PROC:8:13 stime PROC:8:14 cutime PROC:8:15 cstime PROC:8:16 priority PROC:8:17 nice PROC:8:18 /* not valid in 2.2.1 PROC:8:19 */ it_real_value PROC:8:20 start_time PROC:8:21 vsize PROC:8:22 rss PROC:8:23 rss_rlim PROC:8:24 start_code PROC:8:25 end_code PROC:8:26 start_stack PROC:8:27 esp PROC:8:28 eip PROC:8:29 signal PROC:8:30 blocked PROC:8:31 sigignore PROC:8:32 sigcatch PROC:8:33 wchan PROC:8:34 nswap PROC:8:35 cnswap PROC:8:36 exit_signal PROC:8:37 processor PROC:8:38 ttyname PROC:8:39 wchan_s PROC:8:40 psargs PROC:8:41 signal_s PROC:24:16 blocked_s PROC:24:17 sigignore_s PROC:24:18 sigcatch_s PROC:24:19 threads PROC:24:28 cgroups PROC:11:0 labels PROC:12:0 } proc.id { uid PROC:24:0 euid PROC:24:1 suid PROC:24:2 fsuid PROC:24:3 gid PROC:24:4 egid PROC:24:5 sgid PROC:24:6 fsgid PROC:24:7 uid_nm PROC:24:8 euid_nm PROC:24:9 suid_nm PROC:24:10 fsuid_nm PROC:24:11 gid_nm PROC:24:12 egid_nm PROC:24:13 sgid_nm PROC:24:14 fsgid_nm PROC:24:15 } proc.memory { size PROC:9:0 rss PROC:9:1 share PROC:9:2 textrss PROC:9:3 librss PROC:9:4 datrss PROC:9:5 dirty PROC:9:6 maps PROC:9:7 vmsize PROC:24:20 vmlock PROC:24:21 vmrss PROC:24:22 vmdata PROC:24:23 vmstack PROC:24:24 vmexe PROC:24:25 vmlib PROC:24:26 vmswap PROC:24:27 } proc.runq { runnable PROC:13:0 blocked PROC:13:1 sleeping PROC:13:2 stopped PROC:13:3 swapped PROC:13:4 defunct PROC:13:5 unknown PROC:13:6 kernel PROC:13:7 } proc.io { rchar PROC:32:0 wchar PROC:32:1 syscr PROC:32:2 syscw PROC:32:3 read_bytes PROC:32:4 write_bytes PROC:32:5 cancelled_write_bytes PROC:32:6 } proc.schedstat { cpu_time PROC:31:0 run_delay PROC:31:1 pcount PROC:31:2 } proc.fd { count PROC:51:0 } proc.control { all perclient } proc.control.all { threads PROC:10:1 } proc.control.perclient { threads PROC:10:2 cgroups PROC:10:3 } #undef PROC pcp-3.8.12ubuntu1/src/pmdas/linux_proc/contexts.h0000664000000000000000000000321312272262501016676 0ustar /* * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _CONTEXTS_H #define _CONTEXTS_H /* * Handle newly arriving clients, security attributes being set on 'em, * switching to alternative accounts (temporarily) and back, and client * termination. State maintained in a global table, with a high-water * allocator and active/inactive entry tracking. * * The proc.control.perclient metrics also have state tracked here now. */ enum { CTX_INACTIVE = 0x0, CTX_ACTIVE = 0x1, CTX_USERID = 0x2, CTX_GROUPID = 0x4, CTX_THREADS = 0x8, CTX_CGROUPS = 0x10, }; typedef struct { unsigned int state; uid_t uid; gid_t gid; unsigned int threads; const char *cgroups; } proc_perctx_t; extern void proc_ctx_init(void); extern int proc_ctx_attrs(int, int, const char *, int, pmdaExt *); extern void proc_ctx_end(int); extern int proc_ctx_access(int); extern int proc_ctx_revert(int); extern unsigned int proc_ctx_threads(int, unsigned int); extern int proc_ctx_set_threads(int, unsigned int); extern const char *proc_ctx_cgroups(int, const char *); extern int proc_ctx_set_cgroups(int, const char *); #endif /* _CONTEXTS_H */ pcp-3.8.12ubuntu1/src/pmdas/linux_proc/filesys.h0000664000000000000000000000162612272262501016513 0ustar /* * Linux Filesystem Cluster * * Copyright (c) 2000,2004,2007 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2012 Red Hat, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ typedef struct filesys { int id; unsigned int flags; char *device; char *path; char *options; } filesys_t; extern int refresh_filesys(pmInDom); extern char *scan_filesys_options(const char *, const char *); pcp-3.8.12ubuntu1/src/pmdas/linux_proc/indom.h0000664000000000000000000000310112272262501016131 0ustar /* * Copyright (c) 2005,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2010 Aconex. All Rights Reserved. * Copyright (c) 2012 Red Hat, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _INDOM_H #define _INDOM_H /* * indom serial numbers ... to manage the indom migration after the * linux -> linux + proc PMDAs split, these need to match the enum * assigned values for *_INDOM from the linux PMDA. Consequently, * the proc indom table is sparse. */ #define CPU_INDOM 0 /* - percpu */ #define PROC_INDOM 9 /* - processes */ #define STRINGS_INDOM 10 /* - fake indom, string hash */ #define CGROUP_SUBSYS_INDOM 20 /* - control group subsystems */ #define CGROUP_MOUNTS_INDOM 21 /* - control group mounts */ #define MIN_INDOM 0 /* first indom number we use here */ #define NUM_INDOMS 22 /* one more than highest indom number we use here */ /* * static string dictionary - one copy of oft-repeated strings; * implemented using STRINGS_INDOM and pmdaCache(3) routines. */ char *proc_strings_lookup(int); int proc_strings_insert(const char *); #endif /* _INDOM_H */ pcp-3.8.12ubuntu1/src/pmdas/linux_proc/cgroups.h0000664000000000000000000000313612272262501016515 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 2010 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * Note: cgroup metrics have an "extra" component - the final item part * of the PMID (10 bits) is split into two (5 bits each) - top contains * the metric ID (item), bottom holds the cgroup ID (index - e.g. this * is the 3rd cgroup we've seen). */ #define CGROUP_ROOT "cgroup" /* cgroup root pmns node */ static inline pmID cgroup_pmid_build(unsigned int domain, unsigned int cluster, unsigned int gid, unsigned int metric) { return pmid_build(domain, cluster, (gid << 5) | metric); } static inline unsigned int cgroup_pmid_group(pmID id) { return pmid_item(id) >> 5; } static inline unsigned int cgroup_pmid_metric(pmID id) { return pmid_item(id) & ((1 << 5) - 1); } extern void cgroup_init(pmdaMetric *, int); extern char *cgroup_find_subsys(pmInDom, const char *); extern int refresh_cgroups(pmdaExt *, __pmnsTree **); extern int refresh_cgroup_subsys(pmInDom); extern int refresh_cgroup_groups(pmdaExt *, pmInDom, __pmnsTree **); extern int cgroup_group_fetch(int, int, unsigned int, pmAtomValue *); pcp-3.8.12ubuntu1/src/pmdas/linux_proc/clusters.h0000664000000000000000000000410412272262501016673 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 2005,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _CLUSTERS_H #define _CLUSTERS_H /* * fetch cluster numbers ... to manage the PMID migration after the * linux -> linux + proc PMDAs split, these need to match the enum * assigned values for CLUSTER_* from the linux PMDA. */ #define CLUSTER_PID_STAT 8 /* /proc//stat */ #define CLUSTER_PID_STATM 9 /* /proc//statm + /proc//maps */ #define CLUSTER_CONTROL 10 /* instance + value fetch control metrics */ #define CLUSTER_PID_CGROUP 11 /* /proc//cgroup */ #define CLUSTER_PID_LABEL 12 /* /proc//attr/current (label) */ #define CLUSTER_PROC_RUNQ 13 /* number of processes in various states */ #define CLUSTER_PID_STATUS 24 /* /proc//status */ #define CLUSTER_PID_SCHEDSTAT 31 /* /proc//schedstat */ #define CLUSTER_PID_IO 32 /* /proc//io */ #define CLUSTER_CGROUP_SUBSYS 37 /* /proc/cgroups control group subsystems */ #define CLUSTER_CGROUP_MOUNTS 38 /* /proc/mounts active control groups */ #define CLUSTER_CPUSET_GROUPS 39 /* cpuset control groups */ #define CLUSTER_CPUACCT_GROUPS 41 /* cpu accounting control groups */ #define CLUSTER_CPUSCHED_GROUPS 43 /* scheduler control groups */ #define CLUSTER_MEMORY_GROUPS 45 /* memory control groups */ #define CLUSTER_NET_CLS_GROUPS 47 /* network classification control groups */ #define CLUSTER_PID_FD 51 /* /proc//fd */ #define MIN_CLUSTER 8 /* first cluster number we use here */ #define NUM_CLUSTERS 52 /* one more than highest cluster number used */ #endif /* _CLUSTERS_H */ pcp-3.8.12ubuntu1/src/pmdas/linux_proc/ksym.h0000664000000000000000000000234212272262501016014 0ustar /* * Copyright (c) International Business Machines Corp., 2002 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * This code contributed by Mike Mason (mmlnx@us.ibm.com) */ #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) #define INIT_KSIZE 8192 #define INCR_KSIZE 2048 #define KSYM_FOUND_MISMATCH -1 #define KSYM_NOT_FOUND 0 #define KSYM_FOUND 1 #define KSYM_MISMATCH_MAX_ALLOWED 10 struct ksym { __psint_t addr; char *name; char *module; }; extern char *wchan(__psint_t); extern void read_ksym_sources(const char *); pcp-3.8.12ubuntu1/src/pmdas/linux_proc/getinfo.c0000664000000000000000000000275612272262501016470 0ustar /* * Copyright (c) 2010 Aconex. All Rights Reserved. * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include "pmapi.h" char * get_ttyname_info(int pid, dev_t dev, char *ttyname) { DIR *dir; struct dirent *dp; struct stat sbuf; int found=0; char procpath[MAXPATHLEN]; char ttypath[MAXPATHLEN]; sprintf(procpath, "/proc/%d/fd", pid); if ((dir = opendir(procpath)) != NULL) { while ((dp = readdir(dir)) != NULL) { if (!isdigit((int)dp->d_name[0])) continue; sprintf(procpath, "/proc/%d/fd/%s", pid, dp->d_name); if (realpath(procpath, ttypath) == NULL || stat(ttypath, &sbuf) < 0) continue; if (S_ISCHR(sbuf.st_mode) && dev == sbuf.st_rdev) { found=1; break; } } closedir(dir); } if (!found) strcpy(ttyname, "?"); else /* skip the "/dev/" prefix */ strcpy(ttyname, &ttypath[5]); return ttyname; } pcp-3.8.12ubuntu1/src/pmdas/linux_proc/pmda.c0000664000000000000000000013723712272262501015761 0ustar /* * proc PMDA * * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * Portions Copyright (c) 2002 International Business Machines Corp. * Portions Copyright (c) 2007-2011 Aconex. All Rights Reserved. * Portions Copyright (c) 2012-2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include "contexts.h" #include #include #include #include #include #include #include #include #include #include "../linux/convert.h" #include "filesys.h" #include "clusters.h" #include "indom.h" #include "getinfo.h" #include "proc_pid.h" #include "proc_runq.h" #include "ksym.h" #include "cgroups.h" /* globals */ static int _isDSO = 1; /* for local contexts */ static proc_pid_t proc_pid; static struct utsname kernel_uname; static proc_runq_t proc_runq; static int all_access; /* =1 no access checks */ static int have_access; /* =1 recvd uid/gid */ static size_t _pm_system_pagesize; static unsigned int threads; /* control.all.threads */ static char * cgroups; /* control.all.cgroups */ /* * The proc instance domain table is direct lookup and sparse. * It is initialized in proc_init(), see below. */ static pmdaIndom indomtab[NUM_INDOMS]; #define INDOM(x) (indomtab[x].it_indom) /* * all metrics supported in this PMDA - one table entry for each */ static pmdaMetric metrictab[] = { /* * proc//stat cluster */ /* proc.nprocs */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,99), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.pid */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.cmd */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,1), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.sname */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,2), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.ppid */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,3), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.pgrp */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,4), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.session */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,5), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.tty */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,6), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.tty_pgrp */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,7), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.flags */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,8), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.minflt */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,9), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.psinfo.cmin_flt */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,10), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.psinfo.maj_flt */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,11), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.psinfo.cmaj_flt */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,12), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.psinfo.utime */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,13), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, /* proc.psinfo.stime */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,14), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, /* proc.psinfo.cutime */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,15), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, /* proc.psinfo.cstime */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,16), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) } }, /* proc.psinfo.priority */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,17), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.nice */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,18), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, #if 0 /* invalid field */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,19), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, #endif /* proc.psinfo.it_real_value */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,20), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.start_time */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,21), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) } }, /* proc.psinfo.vsize */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,22), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* proc.psinfo.rss */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,23), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* proc.psinfo.rss_rlim */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,24), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* proc.psinfo.start_code */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,25), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.end_code */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,26), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.start_stack */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,27), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.esp */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,28), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.eip */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,29), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.signal */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,30), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.blocked */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,31), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.sigignore */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,32), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.sigcatch */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,33), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.wchan */ #if defined(HAVE_64BIT_PTR) { NULL, { PMDA_PMID(CLUSTER_PID_STAT,34), PM_TYPE_U64, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, #elif defined(HAVE_32BIT_PTR) { NULL, { PMDA_PMID(CLUSTER_PID_STAT,34), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, #else error! unsupported pointer size #endif /* proc.psinfo.nswap */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,35), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.psinfo.cnswap */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,36), PM_TYPE_U32, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.psinfo.exit_signal */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,37), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.processor -- added by Mike Mason */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,38), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.psinfo.ttyname */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,39), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.psinfo.wchan_s -- added by Mike Mason */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,40), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.psinfo.psargs -- modified by Mike Mason */ { NULL, { PMDA_PMID(CLUSTER_PID_STAT,41), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* * proc//status cluster * Cluster added by Mike Mason */ /* proc.id.uid */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.euid */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,1), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.suid */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,2), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.fsuid */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,3), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.gid */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,4), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.egid */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,5), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.sgid */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,6), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.fsgid */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,7), PM_TYPE_U32, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.uid_nm */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,8), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.euid_nm */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,9), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.suid_nm */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,10), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.fsuid_nm */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,11), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.gid_nm */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,12), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.egid_nm */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,13), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.sgid_nm */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,14), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.id.fsgid_nm */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,15), PM_TYPE_STRING, PROC_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.psinfo.signal_s */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,16), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.psinfo.blocked_s */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,17), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.psinfo.sigignore_s */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,18), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.psinfo.sigcatch_s */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,19), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.memory.vmsize */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,20), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, /* proc.memory.vmlock */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,21), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, /* proc.memory.vmrss */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,22), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, /* proc.memory.vmdata */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,23), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, /* proc.memory.vmstack */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,24), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, /* proc.memory.vmexe */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,25), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, /* proc.memory.vmlib */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,26), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, /* proc.memory.vmswap */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,27), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, /* proc.psinfo.threads */ { NULL, { PMDA_PMID(CLUSTER_PID_STATUS,28), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.psinfo.cgroups */ { NULL, { PMDA_PMID(CLUSTER_PID_CGROUP,0), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* proc.psinfo.labels */ { NULL, { PMDA_PMID(CLUSTER_PID_LABEL,0), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* * proc//statm cluster */ /* proc.memory.size */ { NULL, { PMDA_PMID(CLUSTER_PID_STATM,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* proc.memory.rss */ { NULL, { PMDA_PMID(CLUSTER_PID_STATM,1), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* proc.memory.share */ { NULL, { PMDA_PMID(CLUSTER_PID_STATM,2), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* proc.memory.textrss */ { NULL, { PMDA_PMID(CLUSTER_PID_STATM,3), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* proc.memory.librss */ { NULL, { PMDA_PMID(CLUSTER_PID_STATM,4), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* proc.memory.datrss */ { NULL, { PMDA_PMID(CLUSTER_PID_STATM,5), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* proc.memory.dirty */ { NULL, { PMDA_PMID(CLUSTER_PID_STATM,6), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* proc.memory.maps -- added by Mike Mason */ { NULL, { PMDA_PMID(CLUSTER_PID_STATM,7), PM_TYPE_STRING, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* * proc//schedstat cluster */ /* proc.schedstat.cpu_time */ { NULL, { PMDA_PMID(CLUSTER_PID_SCHEDSTAT,0), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0)}}, /* proc.schedstat.run_delay */ { NULL, { PMDA_PMID(CLUSTER_PID_SCHEDSTAT,1), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0)}}, /* proc.schedstat.pcount */ { NULL, { PMDA_PMID(CLUSTER_PID_SCHEDSTAT,2), KERNEL_ULONG, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, /* * proc//io cluster */ /* proc.io.rchar */ { NULL, { PMDA_PMID(CLUSTER_PID_IO,0), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0)}}, /* proc.io.wchar */ { NULL, { PMDA_PMID(CLUSTER_PID_IO,1), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0)}}, /* proc.io.syscr */ { NULL, { PMDA_PMID(CLUSTER_PID_IO,2), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, /* proc.io.syscw */ { NULL, { PMDA_PMID(CLUSTER_PID_IO,3), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, /* proc.io.read_bytes */ { NULL, { PMDA_PMID(CLUSTER_PID_IO,4), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0)}}, /* proc.io.write_bytes */ { NULL, { PMDA_PMID(CLUSTER_PID_IO,5), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0)}}, /* proc.io.cancelled_write_bytes */ { NULL, { PMDA_PMID(CLUSTER_PID_IO,6), PM_TYPE_U64, PROC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0)}}, /* * proc.runq cluster */ /* proc.runq.runnable */ { &proc_runq.runnable, { PMDA_PMID(CLUSTER_PROC_RUNQ, 0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.runq.blocked */ { &proc_runq.blocked, { PMDA_PMID(CLUSTER_PROC_RUNQ, 1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.runq.sleeping */ { &proc_runq.sleeping, { PMDA_PMID(CLUSTER_PROC_RUNQ, 2), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.runq.stopped */ { &proc_runq.stopped, { PMDA_PMID(CLUSTER_PROC_RUNQ, 3), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.runq.swapped */ { &proc_runq.swapped, { PMDA_PMID(CLUSTER_PROC_RUNQ, 4), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.runq.defunct */ { &proc_runq.defunct, { PMDA_PMID(CLUSTER_PROC_RUNQ, 5), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.runq.unknown */ { &proc_runq.unknown, { PMDA_PMID(CLUSTER_PROC_RUNQ, 6), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* proc.runq.kernel */ { &proc_runq.kernel, { PMDA_PMID(CLUSTER_PROC_RUNQ, 7), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* * control groups cluster */ /* cgroups.subsys.hierarchy */ { NULL, {PMDA_PMID(CLUSTER_CGROUP_SUBSYS,0), PM_TYPE_U32, CGROUP_SUBSYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* cgroups.subsys.count */ { NULL, {PMDA_PMID(CLUSTER_CGROUP_SUBSYS,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* cgroups.mounts.subsys */ { NULL, {PMDA_PMID(CLUSTER_CGROUP_MOUNTS,0), PM_TYPE_STRING, CGROUP_MOUNTS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* cgroups.mounts.count */ { NULL, {PMDA_PMID(CLUSTER_CGROUP_MOUNTS,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* cgroup.groups.cpuset.[.]cpus */ { NULL, {PMDA_PMID(CLUSTER_CPUSET_GROUPS,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* cgroup.groups.cpuset.[.]mems */ { NULL, {PMDA_PMID(CLUSTER_CPUSET_GROUPS,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* cgroup.groups.cpuacct.[.]stat.user */ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* cgroup.groups.cpuacct.[.]stat.system */ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* cgroup.groups.cpuacct.[.]usage */ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, /* cgroup.groups.cpuacct.[.]usage_percpu */ { NULL, {PMDA_PMID(CLUSTER_CPUACCT_GROUPS,3), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, /* cgroup.groups.cpusched.[.]shares */ { NULL, {PMDA_PMID(CLUSTER_CPUSCHED_GROUPS,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* cgroup.groups.memory.[.]stat.cache */ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* cgroup.groups.memory.[.]stat.rss */ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* cgroup.groups.memory.[.]stat.pgin */ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* cgroup.groups.memory.[.]stat.pgout */ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* cgroup.groups.memory.[.]stat.swap */ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* cgroup.groups.memory.[.]stat.active_anon */ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* cgroup.groups.memory.[.]stat.inactive_anon */ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* cgroup.groups.memory.[.]stat.active_file */ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* cgroup.groups.memory.[.]stat.inactive_file */ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* cgroup.groups.memory.[.]stat.unevictable */ { NULL, {PMDA_PMID(CLUSTER_MEMORY_GROUPS,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* cgroup.groups.netclass.[.]classid */ { NULL, {PMDA_PMID(CLUSTER_NET_CLS_GROUPS,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* * proc//fd cluster */ /* proc.fd.count */ { NULL, { PMDA_PMID(CLUSTER_PID_FD,0), PM_TYPE_U32, PROC_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* * Metrics control cluster */ /* proc.control.all.threads */ { &threads, { PMDA_PMID(CLUSTER_CONTROL, 1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.control.perclient.threads */ { NULL, { PMDA_PMID(CLUSTER_CONTROL, 2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* proc.control.perclient.cgroups */ { NULL, { PMDA_PMID(CLUSTER_CONTROL, 3), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, }; static int refresh_cpu_indom(pmInDom indom) { char buf[MAXPATHLEN]; char *space; FILE *fp; if ((fp = fopen("/proc/stat", "r")) == (FILE *)NULL) return -oserror(); pmdaCacheOp(indom, PMDA_CACHE_INACTIVE); while (fgets(buf, sizeof(buf), fp) != NULL) { if (strncmp(buf, "cpu", 3) == 0 && isdigit((int)buf[3])) { if ((space = strchr(buf, ' ')) != NULL) { *space = '\0'; pmdaCacheStore(indom, PMDA_CACHE_ADD, buf, NULL); } } } fclose(fp); return pmdaCacheOp(indom, PMDA_CACHE_SIZE_ACTIVE); } int refresh_cgroups(pmdaExt *pmda, __pmnsTree **tree) { int changed; time_t rightnow = 0; static time_t previoustime; static __pmnsTree *previoustree; if (tree) { if ((rightnow = time(NULL)) == previoustime) { *tree = previoustree; return 0; } } refresh_cpu_indom(INDOM(CPU_INDOM)); refresh_filesys(INDOM(CGROUP_MOUNTS_INDOM)); refresh_cgroup_subsys(INDOM(CGROUP_SUBSYS_INDOM)); changed = refresh_cgroup_groups(pmda, INDOM(CGROUP_MOUNTS_INDOM), tree); if (tree) { previoustime = rightnow; previoustree = *tree; } return changed; } static void proc_refresh(pmdaExt *pmda, int *need_refresh) { int need_refresh_mtab = 0; if (need_refresh[CLUSTER_CGROUP_SUBSYS] || need_refresh[CLUSTER_CGROUP_MOUNTS] || need_refresh[CLUSTER_CPUSET_GROUPS] || need_refresh[CLUSTER_CPUACCT_GROUPS] || need_refresh[CLUSTER_CPUSCHED_GROUPS] || need_refresh[CLUSTER_MEMORY_GROUPS] || need_refresh[CLUSTER_NET_CLS_GROUPS]) { need_refresh_mtab |= refresh_cgroups(pmda, NULL); } if (need_refresh[CLUSTER_PID_STAT] || need_refresh[CLUSTER_PID_STATM] || need_refresh[CLUSTER_PID_STATUS] || need_refresh[CLUSTER_PID_IO] || need_refresh[CLUSTER_PID_LABEL] || need_refresh[CLUSTER_PID_CGROUP] || need_refresh[CLUSTER_PID_SCHEDSTAT] || need_refresh[CLUSTER_PID_FD]) { refresh_proc_pid(&proc_pid, proc_ctx_threads(pmda->e_context, threads), proc_ctx_cgroups(pmda->e_context, cgroups)); } if (need_refresh[CLUSTER_PROC_RUNQ]) refresh_proc_runq(&proc_runq); if (need_refresh_mtab) pmdaDynamicMetricTable(pmda); } static int proc_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) { __pmInDom_int *indomp = (__pmInDom_int *)&indom; int need_refresh[NUM_CLUSTERS] = { 0 }; char newname[16]; /* see Note below */ int sts; switch (indomp->serial) { case CPU_INDOM: /* * Used by cgroup.groups.cpuacct.[.]usage_percpu * and cgroup.groups.cpuacct.usage_percpu */ need_refresh[CLUSTER_CPUACCT_GROUPS]++; break; case PROC_INDOM: need_refresh[CLUSTER_PID_STAT]++; need_refresh[CLUSTER_PID_STATM]++; need_refresh[CLUSTER_PID_STATUS]++; need_refresh[CLUSTER_PID_LABEL]++; need_refresh[CLUSTER_PID_CGROUP]++; need_refresh[CLUSTER_PID_SCHEDSTAT]++; need_refresh[CLUSTER_PID_IO]++; need_refresh[CLUSTER_PID_FD]++; break; case CGROUP_SUBSYS_INDOM: need_refresh[CLUSTER_CGROUP_SUBSYS]++; break; case CGROUP_MOUNTS_INDOM: need_refresh[CLUSTER_CGROUP_MOUNTS]++; break; /* no default label : pmdaInstance will pick up errors */ } if (indomp->serial == PROC_INDOM && inst == PM_IN_NULL && name != NULL) { /* * For the proc indom, if the name is a pid (as a string), and it * contains only digits (i.e. it's not a full instance name) then * reformat it to be exactly six digits, with leading zeros. * * Note that although format %06d is used here and in proc_pid.c, * the pid could be longer than this (in which case there * are no leading zeroes. The size of newname[] is chosen * to comfortably accommodate a 32-bit pid (Linux maximum), * or max value of 4294967295 (10 digits) */ char *p; for (p = name; *p != '\0'; p++) { if (!isdigit((int)*p)) break; } if (*p == '\0') { snprintf(newname, sizeof(newname), "%06d", atoi(name)); name = newname; } } sts = PM_ERR_PERMISSION; have_access = proc_ctx_access(pmda->e_context) || all_access; if (have_access || indomp->serial != PROC_INDOM) { proc_refresh(pmda, need_refresh); sts = pmdaInstance(indom, inst, name, result, pmda); } have_access = proc_ctx_revert(pmda->e_context); return sts; } /* * callback provided to pmdaFetch */ static int proc_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); int sts; unsigned long ul; const char *cp; char *f; int *ip; proc_pid_entry_t *entry; struct filesys *fs; static long hz = -1; char *tail; if (hz == -1) hz = sysconf(_SC_CLK_TCK); if (mdesc->m_user != NULL) { /* * The metric value is extracted directly via the address specified * in metrictab. Note: not all metrics support this - those that * don't have NULL for the m_user field in their respective * metrictab slot. */ switch (mdesc->m_desc.type) { case PM_TYPE_32: atom->l = *(__int32_t *)mdesc->m_user; break; case PM_TYPE_U32: atom->ul = *(__uint32_t *)mdesc->m_user; break; case PM_TYPE_64: atom->ll = *(__int64_t *)mdesc->m_user; break; case PM_TYPE_U64: atom->ull = *(__uint64_t *)mdesc->m_user; break; case PM_TYPE_FLOAT: atom->f = *(float *)mdesc->m_user; break; case PM_TYPE_DOUBLE: atom->d = *(double *)mdesc->m_user; break; case PM_TYPE_STRING: cp = *(char **)mdesc->m_user; atom->cp = (char *)(cp ? cp : ""); break; default: return 0; } } else switch (idp->cluster) { case CLUSTER_PID_STAT: if (idp->item == 99) /* proc.nprocs */ atom->ul = proc_pid.indom->it_numinst; else { static char ttyname[MAXPATHLEN]; if (!have_access) return PM_ERR_PERMISSION; if ((entry = fetch_proc_pid_stat(inst, &proc_pid)) == NULL) return PM_ERR_INST; switch (idp->item) { case PROC_PID_STAT_PID: atom->ul = entry->id; break; case PROC_PID_STAT_TTYNAME: if ((f = _pm_getfield(entry->stat_buf, PROC_PID_STAT_TTY)) == NULL) atom->cp = "?"; else { dev_t dev = (dev_t)atoi(f); atom->cp = get_ttyname_info(inst, dev, ttyname); } break; case PROC_PID_STAT_CMD: if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) return PM_ERR_INST; atom->cp = f + 1; atom->cp[strlen(atom->cp)-1] = '\0'; break; case PROC_PID_STAT_PSARGS: atom->cp = entry->name + 7; break; case PROC_PID_STAT_STATE: /* * string */ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) return PM_ERR_INST; atom->cp = f; break; case PROC_PID_STAT_VSIZE: case PROC_PID_STAT_RSS_RLIM: /* * bytes converted to kbytes */ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) return PM_ERR_INST; atom->ul = (__uint32_t)strtoul(f, &tail, 0); atom->ul /= 1024; break; case PROC_PID_STAT_RSS: /* * pages converted to kbytes */ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) return PM_ERR_INST; atom->ul = (__uint32_t)strtoul(f, &tail, 0); atom->ul *= _pm_system_pagesize / 1024; break; case PROC_PID_STAT_UTIME: case PROC_PID_STAT_STIME: case PROC_PID_STAT_CUTIME: case PROC_PID_STAT_CSTIME: /* * unsigned jiffies converted to unsigned milliseconds */ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) return PM_ERR_INST; ul = (__uint32_t)strtoul(f, &tail, 0); _pm_assign_ulong(atom, 1000 * (double)ul / hz); break; case PROC_PID_STAT_PRIORITY: case PROC_PID_STAT_NICE: /* * signed decimal int */ if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) return PM_ERR_INST; atom->l = (__int32_t)strtol(f, &tail, 0); break; case PROC_PID_STAT_WCHAN: if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) return PM_ERR_INST; #if defined(HAVE_64BIT_PTR) atom->ull = (__uint64_t)strtoull(f, &tail, 0); #else atom->ul = (__uint32_t)strtoul(f, &tail, 0); #endif break; case PROC_PID_STAT_WCHAN_SYMBOL: if (entry->wchan_buf) /* 2.6 kernel, /proc//wchan */ atom->cp = entry->wchan_buf; else { /* old school (2.4 kernels, at least) */ char *wc; /* * Convert address to symbol name if requested * Added by Mike Mason */ f = _pm_getfield(entry->stat_buf, PROC_PID_STAT_WCHAN); if (f == NULL) return PM_ERR_INST; #if defined(HAVE_64BIT_PTR) atom->ull = (__uint64_t)strtoull(f, &tail, 0); if ((wc = wchan(atom->ull))) atom->cp = wc; else atom->cp = atom->ull ? f : ""; #else atom->ul = (__uint32_t)strtoul(f, &tail, 0); if ((wc = wchan((__psint_t)atom->ul))) atom->cp = wc; else atom->cp = atom->ul ? f : ""; #endif } break; default: /* * unsigned decimal int */ if (idp->item < NR_PROC_PID_STAT) { if ((f = _pm_getfield(entry->stat_buf, idp->item)) == NULL) return PM_ERR_INST; atom->ul = (__uint32_t)strtoul(f, &tail, 0); } else return PM_ERR_PMID; break; } } break; case CLUSTER_PID_STATM: if (!have_access) return PM_ERR_PERMISSION; if (idp->item == PROC_PID_STATM_MAPS) { /* proc.memory.maps */ if ((entry = fetch_proc_pid_maps(inst, &proc_pid)) == NULL) return PM_ERR_INST; atom->cp = entry->maps_buf; } else { if ((entry = fetch_proc_pid_statm(inst, &proc_pid)) == NULL) return PM_ERR_INST; if (idp->item <= PROC_PID_STATM_DIRTY) { /* unsigned int */ if ((f = _pm_getfield(entry->statm_buf, idp->item)) == NULL) return PM_ERR_INST; atom->ul = (__uint32_t)strtoul(f, &tail, 0); atom->ul *= _pm_system_pagesize / 1024; } else return PM_ERR_PMID; } break; case CLUSTER_PID_SCHEDSTAT: if (!have_access) return PM_ERR_PERMISSION; if ((entry = fetch_proc_pid_schedstat(inst, &proc_pid)) == NULL) return (oserror() == ENOENT) ? PM_ERR_APPVERSION : PM_ERR_INST; if (idp->item < NR_PROC_PID_SCHED) { if ((f = _pm_getfield(entry->schedstat_buf, idp->item)) == NULL) return PM_ERR_INST; if (idp->item == PROC_PID_SCHED_PCOUNT && mdesc->m_desc.type == PM_TYPE_U32) atom->ul = (__uint32_t)strtoul(f, &tail, 0); else #if defined(HAVE_64BIT_PTR) atom->ull = (__uint64_t)strtoull(f, &tail, 0); #else atom->ul = (__uint32_t)strtoul(f, &tail, 0); #endif } else return PM_ERR_PMID; break; case CLUSTER_PID_IO: if (!have_access) return PM_ERR_PERMISSION; if ((entry = fetch_proc_pid_io(inst, &proc_pid)) == NULL) return (oserror() == ENOENT) ? PM_ERR_APPVERSION : PM_ERR_INST; switch (idp->item) { case PROC_PID_IO_RCHAR: if ((f = _pm_getfield(entry->io_lines.rchar, 1)) == NULL) atom->ull = 0; else atom->ull = (__uint64_t)strtoull(f, &tail, 0); break; case PROC_PID_IO_WCHAR: if ((f = _pm_getfield(entry->io_lines.wchar, 1)) == NULL) atom->ull = 0; else atom->ull = (__uint64_t)strtoull(f, &tail, 0); break; case PROC_PID_IO_SYSCR: if ((f = _pm_getfield(entry->io_lines.syscr, 1)) == NULL) atom->ull = 0; else atom->ull = (__uint64_t)strtoull(f, &tail, 0); break; case PROC_PID_IO_SYSCW: if ((f = _pm_getfield(entry->io_lines.syscw, 1)) == NULL) atom->ull = 0; else atom->ull = (__uint64_t)strtoull(f, &tail, 0); break; case PROC_PID_IO_READ_BYTES: if ((f = _pm_getfield(entry->io_lines.readb, 1)) == NULL) atom->ull = 0; else atom->ull = (__uint64_t)strtoull(f, &tail, 0); break; case PROC_PID_IO_WRITE_BYTES: if ((f = _pm_getfield(entry->io_lines.writeb, 1)) == NULL) atom->ull = 0; else atom->ull = (__uint64_t)strtoull(f, &tail, 0); break; case PROC_PID_IO_CANCELLED_BYTES: if ((f = _pm_getfield(entry->io_lines.cancel, 1)) == NULL) atom->ull = 0; else atom->ull = (__uint64_t)strtoull(f, &tail, 0); break; default: return PM_ERR_PMID; } break; /* * Cluster added by Mike Mason */ case CLUSTER_PID_STATUS: if (!have_access) return PM_ERR_PERMISSION; if ((entry = fetch_proc_pid_status(inst, &proc_pid)) == NULL) return PM_ERR_INST; switch (idp->item) { case PROC_PID_STATUS_UID: case PROC_PID_STATUS_EUID: case PROC_PID_STATUS_SUID: case PROC_PID_STATUS_FSUID: case PROC_PID_STATUS_UID_NM: case PROC_PID_STATUS_EUID_NM: case PROC_PID_STATUS_SUID_NM: case PROC_PID_STATUS_FSUID_NM: { struct passwd *pwe; if ((f = _pm_getfield(entry->status_lines.uid, (idp->item % 4) + 1)) == NULL) return PM_ERR_INST; atom->ul = (__uint32_t)strtoul(f, &tail, 0); if (idp->item > PROC_PID_STATUS_FSUID) { if ((pwe = getpwuid((uid_t)atom->ul)) != NULL) atom->cp = pwe->pw_name; else atom->cp = "UNKNOWN"; } } break; case PROC_PID_STATUS_GID: case PROC_PID_STATUS_EGID: case PROC_PID_STATUS_SGID: case PROC_PID_STATUS_FSGID: case PROC_PID_STATUS_GID_NM: case PROC_PID_STATUS_EGID_NM: case PROC_PID_STATUS_SGID_NM: case PROC_PID_STATUS_FSGID_NM: { struct group *gre; if ((f = _pm_getfield(entry->status_lines.gid, (idp->item % 4) + 1)) == NULL) return PM_ERR_INST; atom->ul = (__uint32_t)strtoul(f, &tail, 0); if (idp->item > PROC_PID_STATUS_FSGID) { if ((gre = getgrgid((gid_t)atom->ul)) != NULL) { atom->cp = gre->gr_name; } else { atom->cp = "UNKNOWN"; } } } break; case PROC_PID_STATUS_SIGNAL: if ((atom->cp = _pm_getfield(entry->status_lines.sigpnd, 1)) == NULL) return PM_ERR_INST; break; case PROC_PID_STATUS_BLOCKED: if ((atom->cp = _pm_getfield(entry->status_lines.sigblk, 1)) == NULL) return PM_ERR_INST; break; case PROC_PID_STATUS_SIGCATCH: if ((atom->cp = _pm_getfield(entry->status_lines.sigcgt, 1)) == NULL) return PM_ERR_INST; break; case PROC_PID_STATUS_SIGIGNORE: if ((atom->cp = _pm_getfield(entry->status_lines.sigign, 1)) == NULL) return PM_ERR_INST; break; case PROC_PID_STATUS_VMSIZE: if ((f = _pm_getfield(entry->status_lines.vmsize, 1)) == NULL) atom->ul = 0; else atom->ul = (__uint32_t)strtoul(f, &tail, 0); break; case PROC_PID_STATUS_VMLOCK: if ((f = _pm_getfield(entry->status_lines.vmlck, 1)) == NULL) atom->ul = 0; else atom->ul = (__uint32_t)strtoul(f, &tail, 0); break; case PROC_PID_STATUS_VMRSS: if ((f = _pm_getfield(entry->status_lines.vmrss, 1)) == NULL) atom->ul = 0; else atom->ul = (__uint32_t)strtoul(f, &tail, 0); break; case PROC_PID_STATUS_VMDATA: if ((f = _pm_getfield(entry->status_lines.vmdata, 1)) == NULL) atom->ul = 0; else atom->ul = (__uint32_t)strtoul(f, &tail, 0); break; case PROC_PID_STATUS_VMSTACK: if ((f = _pm_getfield(entry->status_lines.vmstk, 1)) == NULL) atom->ul = 0; else atom->ul = (__uint32_t)strtoul(f, &tail, 0); break; case PROC_PID_STATUS_VMEXE: if ((f = _pm_getfield(entry->status_lines.vmexe, 1)) == NULL) atom->ul = 0; else atom->ul = (__uint32_t)strtoul(f, &tail, 0); break; case PROC_PID_STATUS_VMLIB: if ((f = _pm_getfield(entry->status_lines.vmlib, 1)) == NULL) atom->ul = 0; else atom->ul = (__uint32_t)strtoul(f, &tail, 0); break; case PROC_PID_STATUS_VMSWAP: if ((f = _pm_getfield(entry->status_lines.vmswap, 1)) == NULL) atom->ul = 0; else atom->ul = (__uint32_t)strtoul(f, &tail, 0); break; case PROC_PID_STATUS_THREADS: if ((f = _pm_getfield(entry->status_lines.threads, 1)) == NULL) atom->ul = 0; else atom->ul = (__uint32_t)strtoul(f, &tail, 0); break; default: return PM_ERR_PMID; } break; case CLUSTER_CGROUP_SUBSYS: switch (idp->item) { case 0: /* cgroup.subsys.hierarchy */ sts = pmdaCacheLookup(INDOM(CGROUP_SUBSYS_INDOM), inst, NULL, (void **)&ip); if (sts < 0) return sts; if (sts != PMDA_CACHE_ACTIVE) return PM_ERR_INST; atom->ul = *ip; break; case 1: /* cgroup.subsys.count */ atom->ul = pmdaCacheOp(INDOM(CGROUP_SUBSYS_INDOM), PMDA_CACHE_SIZE_ACTIVE); break; } break; case CLUSTER_CGROUP_MOUNTS: switch (idp->item) { case 0: /* cgroup.mounts.subsys */ sts = pmdaCacheLookup(INDOM(CGROUP_MOUNTS_INDOM), inst, NULL, (void **)&fs); if (sts < 0) return sts; if (sts != PMDA_CACHE_ACTIVE) return PM_ERR_INST; atom->cp = cgroup_find_subsys(INDOM(CGROUP_SUBSYS_INDOM), fs->options); break; case 1: /* cgroup.mounts.count */ atom->ul = pmdaCacheOp(INDOM(CGROUP_MOUNTS_INDOM), PMDA_CACHE_SIZE_ACTIVE); break; } break; case CLUSTER_CPUSET_GROUPS: case CLUSTER_CPUACCT_GROUPS: case CLUSTER_CPUSCHED_GROUPS: case CLUSTER_MEMORY_GROUPS: case CLUSTER_NET_CLS_GROUPS: return cgroup_group_fetch(idp->cluster, idp->item, inst, atom); case CLUSTER_PID_FD: if (!have_access) return PM_ERR_PERMISSION; if (idp->item > PROC_PID_FD_COUNT) return PM_ERR_PMID; if ((entry = fetch_proc_pid_fd(inst, &proc_pid)) == NULL) return PM_ERR_INST; atom->ul = entry->fd_count; break; case CLUSTER_PID_CGROUP: if (!have_access) return PM_ERR_PERMISSION; if (idp->item > PROC_PID_CGROUP) return PM_ERR_PMID; if ((entry = fetch_proc_pid_cgroup(inst, &proc_pid)) == NULL) return (oserror() == ENOENT) ? PM_ERR_APPVERSION : PM_ERR_INST; atom->cp = proc_strings_lookup(entry->cgroup_id); break; case CLUSTER_PID_LABEL: if (!have_access) return PM_ERR_PERMISSION; if (idp->item > PROC_PID_LABEL) return PM_ERR_PMID; if ((entry = fetch_proc_pid_label(inst, &proc_pid)) == NULL) return (oserror() == ENOENT) ? PM_ERR_APPVERSION : PM_ERR_INST; atom->cp = proc_strings_lookup(entry->label_id); break; case CLUSTER_CONTROL: switch (idp->item) { /* case 1: not reached -- proc.control.all.threads is direct */ case 2: /* proc.control.perclient.threads */ atom->ul = proc_ctx_threads(pmdaGetContext(), threads); break; case 3: /* proc.control.perclient.cgroups */ cp = proc_ctx_cgroups(pmdaGetContext(), cgroups); atom->cp = (char *)(cp ? cp : ""); break; default: return PM_ERR_PMID; } break; default: /* unknown cluster */ return PM_ERR_PMID; } return PMDA_FETCH_STATIC; } static int proc_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i, sts; int need_refresh[NUM_CLUSTERS] = { 0 }; for (i = 0; i < numpmid; i++) { __pmID_int *idp = (__pmID_int *)&(pmidlist[i]); if (idp->cluster >= MIN_CLUSTER && idp->cluster < NUM_CLUSTERS) need_refresh[idp->cluster]++; } have_access = proc_ctx_access(pmda->e_context) || all_access; proc_refresh(pmda, need_refresh); sts = pmdaFetch(numpmid, pmidlist, resp, pmda); have_access = proc_ctx_revert(pmda->e_context); return sts; } static int proc_store(pmResult *result, pmdaExt *pmda) { int i, sts = 0; have_access = proc_ctx_access(pmda->e_context) || all_access; for (i = 0; i < result->numpmid; i++) { pmValueSet *vsp = result->vset[i]; __pmID_int *idp = (__pmID_int *)&(vsp->pmid); pmAtomValue av; if (idp->cluster != CLUSTER_CONTROL) sts = PM_ERR_PERMISSION; else if (vsp->numval != 1) sts = PM_ERR_INST; else switch (idp->item) { case 1: /* proc.control.all.threads */ if (!have_access) sts = PM_ERR_PERMISSION; else if ((sts = pmExtractValue(vsp->valfmt, &vsp->vlist[0], PM_TYPE_U32, &av, PM_TYPE_U32)) >= 0) { if (av.ul > 1) /* only zero or one allowed */ sts = PM_ERR_CONV; else threads = av.ul; } break; case 2: /* proc.control.perclient.threads */ if ((sts = pmExtractValue(vsp->valfmt, &vsp->vlist[0], PM_TYPE_U32, &av, PM_TYPE_U32)) >= 0) { sts = proc_ctx_set_threads(pmda->e_context, av.ul); } break; case 3: /* proc.control.perclient.cgroups */ if ((sts = pmExtractValue(vsp->valfmt, &vsp->vlist[0], PM_TYPE_STRING, &av, PM_TYPE_STRING)) >= 0) { if ((sts = proc_ctx_set_cgroups(pmda->e_context, av.cp)) < 0) free(av.cp); } break; default: sts = PM_ERR_PERMISSION; } if (sts < 0) break; } have_access = proc_ctx_revert(pmda->e_context); return sts; } static int proc_text(int ident, int type, char **buf, pmdaExt *pmda) { if ((type & PM_TEXT_PMID) == PM_TEXT_PMID) { int sts = pmdaDynamicLookupText(ident, type, buf, pmda); if (sts != -ENOENT) return sts; } return pmdaText(ident, type, buf, pmda); } static int proc_pmid(const char *name, pmID *pmid, pmdaExt *pmda) { pmdaNameSpace *tree = pmdaDynamicLookupName(pmda, name); if (tree == NULL) return PM_ERR_NAME; return pmdaTreePMID(tree, name, pmid); } static int proc_name(pmID pmid, char ***nameset, pmdaExt *pmda) { pmdaNameSpace *tree = pmdaDynamicLookupPMID(pmda, pmid); if (tree == NULL) return PM_ERR_PMID; return pmdaTreeName(tree, pmid, nameset); } static int proc_children(const char *name, int flag, char ***kids, int **sts, pmdaExt *pmda) { pmdaNameSpace *tree = pmdaDynamicLookupName(pmda, name); if (tree == NULL) return PM_ERR_NAME; return pmdaTreeChildren(tree, name, flag, kids, sts); } /* * Helper routines for accessing a generic static string dictionary */ char * proc_strings_lookup(int index) { char *value; pmInDom dict = INDOM(STRINGS_INDOM); if (pmdaCacheLookup(dict, index, &value, NULL) == PMDA_CACHE_ACTIVE) return value; return ""; } int proc_strings_insert(const char *buf) { pmInDom dict = INDOM(STRINGS_INDOM); return pmdaCacheStore(dict, PMDA_CACHE_ADD, buf, NULL); } /* * Initialise the agent (both daemon and DSO). */ void __PMDA_INIT_CALL proc_init(pmdaInterface *dp) { int nindoms = sizeof(indomtab)/sizeof(indomtab[0]); int nmetrics = sizeof(metrictab)/sizeof(metrictab[0]); _pm_system_pagesize = getpagesize(); if (_isDSO) { char helppath[MAXPATHLEN]; int sep = __pmPathSeparator(); snprintf(helppath, sizeof(helppath), "%s%c" "proc" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_6, "proc DSO", helppath); } if (dp->status != 0) return; dp->comm.flags |= PDU_FLAG_AUTH; dp->version.six.instance = proc_instance; dp->version.six.store = proc_store; dp->version.six.fetch = proc_fetch; dp->version.six.text = proc_text; dp->version.six.pmid = proc_pmid; dp->version.six.name = proc_name; dp->version.six.children = proc_children; dp->version.six.attribute = proc_ctx_attrs; pmdaSetEndContextCallBack(dp, proc_ctx_end); pmdaSetFetchCallBack(dp, proc_fetchCallBack); /* * Initialize the instance domain table. */ indomtab[CPU_INDOM].it_indom = CPU_INDOM; indomtab[PROC_INDOM].it_indom = PROC_INDOM; indomtab[STRINGS_INDOM].it_indom = STRINGS_INDOM; indomtab[CGROUP_SUBSYS_INDOM].it_indom = CGROUP_SUBSYS_INDOM; indomtab[CGROUP_MOUNTS_INDOM].it_indom = CGROUP_MOUNTS_INDOM; proc_pid.indom = &indomtab[PROC_INDOM]; /* * Read System.map and /proc/ksyms. Used to translate wait channel * addresses to symbol names. * Added by Mike Mason */ read_ksym_sources(kernel_uname.release); cgroup_init(metrictab, nmetrics); proc_ctx_init(); pmdaSetFlags(dp, PMDA_EXT_FLAG_HASHED); pmdaInit(dp, indomtab, nindoms, metrictab, nmetrics); /* string metrics use the pmdaCache API for value indexing */ pmdaCacheOp(INDOM(STRINGS_INDOM), PMDA_CACHE_STRINGS); /* cgroup metrics use the pmdaCache API for indom indexing */ pmdaCacheOp(INDOM(CPU_INDOM), PMDA_CACHE_CULL); pmdaCacheOp(INDOM(CGROUP_SUBSYS_INDOM), PMDA_CACHE_CULL); pmdaCacheOp(INDOM(CGROUP_MOUNTS_INDOM), PMDA_CACHE_CULL); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -A no access checks will be performed (insecure, beware!)\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -L include threads in the all-processes instance domain\n" " -r cgroup restrict monitoring to processes in the named cgroup\n" " -U username account to run under (default is root)\n", stderr); exit(1); } int main(int argc, char **argv) { int sep = __pmPathSeparator(); int err = 0; int c; pmdaInterface dispatch; char helppath[MAXPATHLEN]; char *username = "root"; _isDSO = 0; __pmSetProgname(argv[0]); snprintf(helppath, sizeof(helppath), "%s%c" "proc" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_6, pmProgname, PROC, "proc.log", helppath); while ((c = pmdaGetOpt(argc, argv, "AD:d:l:Lr:U:?", &dispatch, &err)) != EOF) { switch (c) { case 'A': all_access = 1; break; case 'L': threads = 1; break; case 'r': cgroups = optarg; break; case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&dispatch); __pmSetProcessIdentity(username); proc_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/linux_proc/proc_runq.c0000664000000000000000000000534512272262501017042 0ustar /* * Linux /proc/runq metrics cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include #include #include #include "proc_pid.h" #include "proc_runq.h" int refresh_proc_runq(proc_runq_t *proc_runq) { int sz; int fd; char *p; int sname; DIR *dir; struct dirent *d; char fullpath[MAXPATHLEN]; char buf[4096]; memset(proc_runq, 0, sizeof(proc_runq_t)); if ((dir = opendir("/proc")) == NULL) return -oserror(); while((d = readdir(dir)) != NULL) { if (!isdigit((int)d->d_name[0])) continue; sprintf(fullpath, "/proc/%s/stat", d->d_name); if ((fd = open(fullpath, O_RDONLY)) < 0) continue; sz = read(fd, buf, sizeof(buf)); close(fd); buf[sizeof(buf)-1] = '\0'; /* * defunct (state name is 'Z') */ if (sz <= 0 || (p = _pm_getfield(buf, PROC_PID_STAT_STATE)) == NULL) { proc_runq->unknown++; continue; } if ((sname = *p) == 'Z') { proc_runq->defunct++; continue; } /* * kernel process (not defunct and virtual size is zero) */ if ((p = _pm_getfield(buf, PROC_PID_STAT_VSIZE)) == NULL) { proc_runq->unknown++; continue; } if (strcmp(p, "0") == 0) { proc_runq->kernel++; continue; } /* * swapped (resident set size is zero) */ if ((p = _pm_getfield(buf, PROC_PID_STAT_RSS)) == NULL) { proc_runq->unknown++; continue; } if (strcmp(p, "0") == 0) { proc_runq->swapped++; continue; } /* * All other states */ switch (sname) { case 'R': proc_runq->runnable++; break; case 'S': proc_runq->sleeping++; break; case 'T': proc_runq->stopped++; break; case 'D': proc_runq->blocked++; break; /* case 'Z': break; -- already counted above */ default: fprintf(stderr, "UNKNOWN %c : %s\n", sname, buf); proc_runq->unknown++; break; } } closedir(dir); #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { fprintf(stderr, "refresh_runq: runnable=%d sleeping=%d stopped=%d blocked=%d unknown=%d\n", proc_runq->runnable, proc_runq->sleeping, proc_runq->stopped, proc_runq->blocked, proc_runq->unknown); } #endif return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux_proc/proc_runq.h0000664000000000000000000000207712272262501017046 0ustar /* * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _PROC_RUNQ_H #define _PROC_RUNQ_H typedef struct { int runnable; int blocked; int sleeping; int stopped; int swapped; int kernel; int defunct; int unknown; } proc_runq_t; extern int refresh_proc_runq(proc_runq_t *); #endif /* _PROC_RUNQ_H */ pcp-3.8.12ubuntu1/src/pmdas/linux_proc/help0000664000000000000000000003026012272262501015533 0ustar # # Copyright (c) 2000,2004-2008 Silicon Graphics, Inc. All Rights Reserved. # Portions Copyright (c) International Business Machines Corp., 2002 # Portions Copyright (c) 2007-2009 Aconex. All Rights Reserved. # Portions Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Linux proc PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ proc.nprocs instantaneous number of processes @ proc.psinfo.pid process identifier @ proc.psinfo.psargs full command string @ proc.psinfo.cmd command name @ proc.psinfo.sname process state identifier (see ps(1)). See also proc.runq metrics. @ proc.psinfo.ppid parent process identifier @ proc.psinfo.pgrp process group identifier @ proc.psinfo.session process session identifier @ proc.psinfo.tty controlling tty device number (zero if none) @ proc.psinfo.tty_pgrp controlling tty process group identifier @ proc.psinfo.flags process state flags, as a bitmap @ proc.psinfo.minflt count of minor page faults (i.e. reclaims) @ proc.psinfo.cmin_flt count of minor page faults (i.e. reclaims) of all exited children @ proc.psinfo.maj_flt count of page faults other than reclaims @ proc.psinfo.cmaj_flt count of page faults other than reclaims of all exited children @ proc.psinfo.utime time (in ms) spent executing user code since process started @ proc.psinfo.stime time (in ms) spent executing system code (calls) since process started @ proc.psinfo.cutime time (in ms) spent executing user code of all exited children @ proc.psinfo.cstime time (in ms) spent executing system code of all exited children @ proc.psinfo.priority priority value @ proc.psinfo.nice process nice value (negative nice values are lower priority) @ proc.psinfo.it_real_value current interval timer value (zero if none) @ proc.psinfo.start_time start time of the process relative to system boot time in seconds @ proc.psinfo.vsize virtual size of the process in Kbytes @ proc.psinfo.rss resident set size (i.e. physical memory) of the process @ proc.psinfo.rss_rlim limit on resident set size of process @ proc.psinfo.start_code address of the start of the code segment for the process @ proc.psinfo.end_code address of the end of the code segment for the process @ proc.psinfo.start_stack address of the stack segment for the process @ proc.psinfo.esp the value in the esp field of struct task_struct for the process @ proc.psinfo.eip the value in the eip field of struct task_struct for the process @ proc.psinfo.signal the value in the signal field of struct task_struct for the process @ proc.psinfo.blocked the value in the blocked field of struct task_struct for the process @ proc.psinfo.sigignore the value in the sigignore field of struct task_struct for the process @ proc.psinfo.sigcatch the value in the sigcatch field of struct task_struct for the process @ proc.psinfo.wchan wait channel, kernel address this process is blocked or sleeping on @ proc.psinfo.nswap count of page swap operations @ proc.psinfo.cnswap count of page swap operations of all exited children @ proc.psinfo.exit_signal the value in the exit_signal field of struct task_struct for the process @ proc.psinfo.ttyname name of controlling tty device, or "?" if none. See also proc.psinfo.tty. @ proc.psinfo.processor last CPU the process was running on @ proc.psinfo.wchan_s name of an event for which the process is sleeping (if blank, the process is running). This field needs access to a namelist file for proper address-to-symbol name translation. If no namelist file is available, the address is printed instead. The namelist file must match the current Linux kernel exactly. The search path for the namelist file is as follows: /boot/System.map-`uname -r` /boot/System.map /lib/modules/`uname -r`/System.map /usr/src/linux/System.map /System.map @ proc.psinfo.signal_s pending signals mask in string form (from /proc//status) @ proc.psinfo.blocked_s blocked signals mask in string form (from /proc//status) @ proc.psinfo.sigignore_s ignored signals mask in string form (from /proc//status) @ proc.psinfo.sigcatch_s caught signals mask in string form (from /proc//status) @ proc.psinfo.threads number of threads (from /proc//status) @ proc.psinfo.cgroups list of processes cgroups (from /proc//cgroup) @ proc.psinfo.labels list of processes security labels (from /proc//attr/current) @ proc.memory.size instantaneous virtual size of process, excluding page table and task structure. @ proc.memory.rss instantaneous resident size of process, excluding page table and task structure. @ proc.memory.share instantaneous amount of memory shared by this process with other processes @ proc.memory.textrss instantaneous resident size of process code segment in Kbytes @ proc.memory.librss instantaneous resident size of library code mapped by the process, in Kbytes @ proc.memory.datrss instantaneous resident size of process data segment, in Kbytes @ proc.memory.dirty instantaneous amount of memory that has been modified by the process, in Kbytes @ proc.memory.maps table of memory mapped by process in string form from /proc//maps @ proc.memory.vmsize total virtual memory (from /proc//status) @ proc.memory.vmlock locked virtual memory (from /proc//status) @ proc.memory.vmrss resident virtual memory (from /proc//status) @ proc.memory.vmdata virtual memory used for data (from /proc//status) @ proc.memory.vmstack virtual memory used for stack (from /proc//status) @ proc.memory.vmexe virtual memory used for non-library executable code (from /proc//status) @ proc.memory.vmlib virtual memory used for libraries (from /proc//status) @ proc.memory.vmswap virtual memory that has been brought in and out. @ proc.id.uid real user ID from /proc//status @ proc.id.euid effective user ID from /proc//status @ proc.id.suid saved user ID from /proc//status @ proc.id.fsuid filesystem user ID from /proc//status @ proc.id.gid real group ID from /proc//status @ proc.id.egid effective group ID from /proc//status @ proc.id.sgid saved group ID from /proc//status @ proc.id.fsgid filesystem group ID from /proc//status @ proc.id.uid_nm real user name based on real user ID from /proc//status @ proc.id.euid_nm effective user name based on effective user ID from /proc//status @ proc.id.suid_nm saved user name based on saved user ID from /proc//status @ proc.id.fsuid_nm filesystem user name based on filesystem user ID from /proc//status @ proc.id.gid_nm real group name based on real group ID from /proc//status @ proc.id.egid_nm effective group name based on effective group ID from /proc//status @ proc.id.sgid_nm saved group name based on saved group ID from /proc//status @ proc.id.fsgid_nm filesystem group name based on filesystem group ID from /proc//status @ proc.runq.runnable number of runnable (on run queue) processes Instantaneous number of runnable (on run queue) processes, state 'R' in ps @ proc.runq.blocked number of processes in uninterruptible sleep Instantaneous number of processes in uninterruptible sleep, state 'D' in ps @ proc.runq.sleeping number of processes sleeping Instantaneous number of processes sleeping, state 'S' in ps @ proc.runq.stopped number of traced, stopped or suspended processes Instantaneous number of traced, stopped or suspended processes, state 'T' in ps @ proc.runq.swapped number of processes that are swapped Instantaneous number of processes (excluding kernel threads) that are swapped, state 'SW' in ps @ proc.runq.defunct number of defunct/zombie processes Instantaneous number of defunct/zombie processes, state 'Z' in ps @ proc.runq.unknown number of processes is an unknown state Instantaneous number of processes is an unknown state, including all kernel threads @ proc.runq.kernel number of kernel threads Instantaneous number of processes with virtual size of zero (kernel threads) @ proc.io.rchar read(), readv() and sendfile() receive bytes Extended accounting information - count of the number of bytes that have passed over the read(2), readv(2) and sendfile(2) syscalls by each process. @ proc.io.wchar write(), writev() and sendfile() send bytes Extended accounting information - count of the number of bytes that have passed over the write(2), writev(2) and sendfile(2) syscalls by each process. @ proc.io.syscr read(), readv() and sendfile() receive system calls Extended accounting information - count of number of calls to the read(2), readv(2) and sendfile(2) syscalls by each process. @ proc.io.syscw write(), writev() and sendfile() send system calls Extended accounting information - count of number of calls to the write(2), writev(2) and sendfile(2) syscalls by each process. @ proc.io.read_bytes physical device read bytes Number of bytes physically read on by devices on behalf of this process. @ proc.io.write_bytes physical device write bytes Number of bytes physically written to devices on behalf of this process. This must be reduced by any truncated I/O (proc.io.cancelled_write_bytes). @ proc.io.cancelled_write_bytes physical device write cancelled bytes Number of bytes cancelled via truncate by this process. Actual physical writes for an individual process can be calculated as: proc.io.write_bytes - proc.io.cancelled_write_bytes. @ proc.schedstat.cpu_time runnable (scheduled) + run time Length of time in nanoseconds that a process has been running, including scheduling time. @ proc.schedstat.run_delay run queue time Length of time in nanoseconds that a process spent waiting to be scheduled to run in the run queue. @ proc.schedstat.pcount number of times a process is allowed to run Number of times a process has been scheduled to run on a CPU (this is incremented when a task actually reaches a CPU to run on, not simply when it is added to the run queue). @ proc.fd.count open file descriptors Number of file descriptors this process has open. @ proc.control.all.threads process indom includes threads If set to one, the process instance domain as reported by pmdaproc contains all threads as well as the processes that started them. If set to zero, the process instance domain contains only processes. This setting is persistent for the life of pmdaproc and affects all client tools that request instances and values from pmdaproc. Use either pmstore(1) or pmStore(3) to modify this metric. @ proc.control.perclient.threads for a client, process indom includes threads If set to one, the process instance domain as reported by pmdaproc contains all threads as well as the processes that started them. If set to zero, the process instance domain contains only processes. This setting is only visible to the active client context. In other words, storing into this metric has no effect for other monitoring tools. See proc.control.all.threads, if that is the desired outcome. Only pmStore(3) can effectively set this metric (pmstore(1) cannot). @ proc.control.perclient.cgroups for a client, process indom reflects specific cgroups If set to the empty string (the default), the process instance domain as reported by pmdaproc contains all processes. However, a cgroup name (full path) can be stored into this metric in order to restrict processes reported to only those within the specified cgroup. This set is further affected by the value of proc.control.perclient.threads. This setting is only visible to the active client context. In other words, storing into this metric has no effect for other monitoring tools. pmStore(3) must be used to set this metric (not pmstore(1)). pcp-3.8.12ubuntu1/src/pmdas/linux_proc/ksym.c0000664000000000000000000003161112272262501016010 0ustar /* * Copyright (c) International Business Machines Corp., 2002 * Copyright (c) 2003,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * This code originally contributed by Mike Mason * with hints from the procps and ksymoops projects. */ #include #include #include #include #include "pmapi.h" #include "impl.h" #include "ksym.h" static struct ksym *ksym_a; static size_t ksym_a_sz; static int find_index(__psint_t addr, int lo, int hi) { int mid; if (lo > hi) { return -1; } mid = lo + ((hi - lo) / 2); if (addr == ksym_a[mid].addr || (addr > ksym_a[mid].addr && addr < ksym_a[mid+1].addr)) { return mid; } if (addr > ksym_a[mid].addr) return find_index(addr, mid+1, hi); else return find_index(addr, lo, mid-1); } static char * find_name_by_addr(__psint_t addr) { int ix = -1; if (ksym_a) ix = find_index(addr, 0, ksym_a_sz - 1); if (ix < 0) return NULL; return ksym_a[ix].name; } static int find_dup_name(int maxix, __psint_t addr, char *name) { int i, res; for (i = 0; i < maxix; i++) { if (ksym_a[i].name) { res = strcmp(ksym_a[i].name, name); if (res > 0) break; if (res == 0) { if (addr == ksym_a[i].addr) return KSYM_FOUND; else return KSYM_FOUND_MISMATCH; } } } return KSYM_NOT_FOUND; } /* Brute force linear search to determine if the kernel version in System.map matches the running kernel version and returns a tri-state result as follows: 0 no match 1 _end not found but version matched 2 _end found and matched */ static int validate_sysmap(FILE *fp, char *version, __psint_t end_addr) { __psint_t addr; char type; int ret = 0; char kname[128]; while (fscanf(fp, "%p %c %s", (void **)&addr, &type, kname) != EOF) { if (end_addr && strcmp(kname, "_end") == 0) { ret = (end_addr == addr) ? 2 : 0; break; /* no need to look any further */ } if (strcmp(kname, version) == 0) ret = 1; } return ret; } char * wchan(__psint_t addr) { static char zero; char *p = NULL; if (addr == 0) /* 0 address means not in kernel space */ p = &zero; else if ((p = find_name_by_addr(addr))) { /* strip off "sys_" or leading "_"s if necessary */ if (strncmp(p, "sys_", 4) == 0) p += 4; while (*p == '_' && *p) ++p; } return p; } static int ksym_compare_addr(const void *e1, const void *e2) { struct ksym *ks1 = (struct ksym *) e1; struct ksym *ks2 = (struct ksym *) e2; if (ks1->addr < ks2->addr) return -1; if (ks1->addr > ks2->addr) return 1; return 0; } static int ksym_compare_name(const void *e1, const void *e2) { struct ksym *ks1 = (struct ksym *) e1; struct ksym *ks2 = (struct ksym *) e2; return(strcmp(ks1->name, ks2->name)); } static int read_ksyms(__psint_t *end_addr) { char inbuf[256]; char *ip; char *sp; char *tp; char *p; int ix = 0; int l = 0; int len; int err; FILE *fp; struct ksym *ksym_tmp; char *ksyms_path = "/proc/ksyms"; *end_addr = 0; if ((fp = fopen(ksyms_path, "r")) == NULL) return -oserror(); while (fgets(inbuf, sizeof(inbuf), fp) != NULL) { l++; /* * /proc/ksyms lines look like this on ia32 ... * * c8804060 __insmod_rtc_S.text_L4576 [rtc] * c010a320 disable_irq_nosync * * else on ia64 ... * * a0000000003e0d28 debug [arsess] * e002100000891140 disable_irq_nosync */ if (strstr(inbuf, "\n") == NULL) { fprintf(stderr, "read_ksyms: truncated /proc/ksyms line [%d]: %s\n", l-1, inbuf); continue; } /* Increase array size, if necessary */ if (ksym_a_sz < ix+1) { if (ksym_a_sz > 0) ksym_a_sz += INCR_KSIZE; else ksym_a_sz = INIT_KSIZE; ksym_tmp = (struct ksym *)realloc(ksym_a, ksym_a_sz * sizeof(struct ksym)); if (ksym_tmp == NULL) { err = -oserror(); free(ksym_a); fclose(fp); return err; } ksym_a = ksym_tmp; } ip = inbuf; /* parse over address */ while (isxdigit((int)*ip)) ip++; if (!isspace((int)*ip) || ip-inbuf < 4) { /* bad format line */ #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "read_ksyms: bad addr? %c[%d] line=\"%s\"\n", *ip, (int)(ip-inbuf), inbuf); } #endif continue; } sscanf(inbuf, "%p", (void **)&ksym_a[ix].addr); while (isblank((int)*ip)) ip++; /* next should be the symbol name */ sp = ip++; while (!isblank((int)*ip) &&*ip != '\n') ip++; /* strip off GPLONLY_ prefix, if found */ if (strncmp(sp, "GPLONLY_", 8) == 0) sp += 8; /* * strip off symbol version suffix, if found ... looking for * trailing pattern of the form _R.*[0-9a-fA-F]{8,} * - find rightmost _R, if any */ tp = sp; while ((p = strstr(tp, "_R")) != NULL) tp = p+2; if (tp > sp) { /* * found _R, need the last 8 digits to be hex */ if (ip - tp + 1 >= 8) { for (p = &ip[-8]; p < ip; p++) { if (!isxdigit((int)*p)) { tp = sp; break; } } } else { /* not enough characters for [0-9a-fA-f]{8,} at the end */ tp = sp; } } if (tp > sp) /* need to strip the trailing _R.*[0-9a-fA-f]{8,} */ len = tp - sp - 2; else len = ip - sp + 1; ksym_a[ix].name = strndup(sp, len); if (ksym_a[ix].name == NULL) { err = -oserror(); fclose(fp); return err; } ksym_a[ix].name[len-1] = '\0'; if (*end_addr == 0 && strcmp(ksym_a[ix].name, "_end") == 0) *end_addr = ksym_a[ix].addr; if (*ip == '\n') /* nothing after the symbol name, so no module name */ goto next; while (isblank((int)*ip)) ip++; /* next expect module name */ if (*ip != '[') { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "read_ksyms: bad start module name %c[%d] != [ line=\"%s\"\n", *ip, (int)(ip-inbuf), inbuf); } #endif free(ksym_a[ix].name); continue; } sp = ++ip; while (!isblank((int)*ip) && *ip != ']') ip++; if (*ip != ']') { #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "read_ksyms: bad end module name %c[%d] != ] line=\"%s\"\n", *ip, (int)(ip-inbuf), inbuf); } #endif free(ksym_a[ix].name); continue; } ksym_a[ix].module = strndup(sp, ip - sp + 1); if (ksym_a[ix].module == NULL) { err = -oserror(); fclose(fp); free(ksym_a[ix].name); return err; } ksym_a[ix].module[ip - sp] = '\0'; next: ix++; } /* release unused ksym array entries */ if (ix) { ksym_tmp = (struct ksym *)realloc(ksym_a, ix * sizeof(struct ksym)); if (ksym_tmp == NULL) { free(ksym_a); fclose(fp); return -oserror(); } ksym_a = ksym_tmp; } ksym_a_sz = ix; qsort(ksym_a, ksym_a_sz, sizeof(struct ksym), ksym_compare_name); fclose(fp); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "symbols from ksyms ...\n"); for (ix = 0; ix < ksym_a_sz; ix++) { fprintf(stderr, "ksym[%d] " PRINTF_P_PFX "%p %s", ix, (void *)ksym_a[ix].addr, ksym_a[ix].name); if (ksym_a[ix].module != NULL) fprintf(stderr, " [%s]", ksym_a[ix].module); fprintf(stderr, "\n"); } } #endif return ksym_a_sz; } static int read_sysmap(const char *release, __psint_t end_addr) { char inbuf[256], path[MAXPATHLEN], **fmt; struct ksym *ksym_tmp; __psint_t addr; int ix, res, e; int l = 0; char *ip; char *sp; int major, minor, patch; FILE *fp; char *bestpath = NULL; int ksym_mismatch_count; char *sysmap_paths[] = { /* Paths to check for System.map file */ "/boot/System.map-%s", "/boot/System.map", "/lib/modules/%s/System.map", "/usr/src/linux/System.map", "/System.map", NULL }; /* Create version symbol name to look for in System.map */ if (sscanf(release, "%d.%d.%d", &major, &minor, &patch) < 3 ) return -1; sprintf(inbuf, "Version_%u", KERNEL_VERSION(major, minor, patch)); /* * Walk through System.map path list looking for one that matches * either _end from /proc/ksyms or the uts version. */ for (fmt = sysmap_paths; *fmt; fmt++) { snprintf(path, MAXPATHLEN, *fmt, release); if ((fp = fopen(path, "r"))) { if ((e = validate_sysmap(fp, inbuf, end_addr)) != 0) { if (e == 2) { /* matched _end, so this is the right System.map */ if (bestpath) free(bestpath); bestpath = strdup(path); } else if (e == 1 && !bestpath) bestpath = strdup(path); } fclose(fp); if (e == 2) { /* _end matched => don't look any further */ break; } } } if (bestpath) fprintf(stderr, "NOTICE: using \"%s\" for kernel symbols map.\n", bestpath); else { /* Didn't find a valid System.map */ fprintf(stderr, "Warning: Valid System.map file not found!\n"); fprintf(stderr, "Warning: proc.psinfo.wchan_s symbol names cannot be derived!\n"); fprintf(stderr, "Warning: Addresses will be returned for proc.psinfo.wchan_s instead!\n"); /* Free symbol array */ for (ix = 0; ix < ksym_a_sz; ix++) { if (ksym_a[ix].name) free(ksym_a[ix].name); if (ksym_a[ix].module) free(ksym_a[ix].module); } free(ksym_a); ksym_a = NULL; ksym_a_sz = 0; return -1; } /* scan the System map */ if ((fp = fopen(bestpath, "r")) == NULL) return -oserror(); ix = ksym_a_sz; /* Read each line in System.map */ ksym_mismatch_count = 0; while (fgets(inbuf, sizeof(inbuf), fp) != NULL) { /* * System.map lines look like this on ia32 ... * * c010a320 T disable_irq_nosync * * else on ia64 ... * * e002000000014c80 T disable_irq_nosync */ if (strstr(inbuf, "\n") == NULL) { fprintf(stderr, "read_sysmap: truncated System.map line [%d]: %s\n", l-1, inbuf); continue; } /* Increase array size, if necessary */ if (ksym_a_sz < ix+1) { ksym_a_sz += INCR_KSIZE; ksym_tmp = (struct ksym *)realloc(ksym_a, ksym_a_sz * sizeof(struct ksym)); if (ksym_tmp == NULL) { free(ksym_a); goto fail; } ksym_a = ksym_tmp; } ip = inbuf; /* parse over address */ while (isxdigit((int)*ip)) ip++; if (!isspace((int)*ip) || ip-inbuf < 4) { /* bad format line */ #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "read_sysmap: bad addr? %c[%d] line=\"%s\"\n", *ip, (int)(ip-inbuf), inbuf); } #endif continue; } sscanf(inbuf, "%p", (void **)&addr); while (isblank((int)*ip)) ip++; /* Only interested in symbol types that map to code addresses, * so: t, T, W or A */ if (*ip != 't' && *ip != 'T' && *ip != 'W' && *ip != 'A') continue; ip++; while (isblank((int)*ip)) ip++; /* next should be the symbol name */ sp = ip++; while (!isblank((int)*ip) && *ip != '\n') ip++; *ip = '\0'; /* Determine if symbol is already in ksym array. If so, make sure the addresses match. */ res = find_dup_name(ix - 1, addr, sp); if (res == KSYM_NOT_FOUND) { /* add it */ ksym_a[ix].name = strdup(sp); if (ksym_a[ix].name == NULL) goto fail; ksym_a[ix].addr = addr; ix++; } else if (res == KSYM_FOUND_MISMATCH) { if (ksym_mismatch_count++ < KSYM_MISMATCH_MAX_ALLOWED) { /* * ia64 function pointer descriptors make this validation * next to useless. So only report the first * KSYM_MISMATCH_MAX_ALLOWED mismatches found. */ fprintf(stderr, "Warning: mismatch for \"%s\" between System.map" " and /proc/ksyms.\n", sp); } } } if (ksym_mismatch_count > KSYM_MISMATCH_MAX_ALLOWED) { fprintf(stderr, "Warning: only reported first %d out of %d mismatches " "between System.map and /proc/ksyms.\n", KSYM_MISMATCH_MAX_ALLOWED, ksym_mismatch_count); } /* release unused ksym array entries */ ksym_tmp = (struct ksym *)realloc(ksym_a, ix * sizeof(struct ksym)); if (ksym_tmp == NULL) { free(ksym_a); goto fail; } ksym_a = ksym_tmp; ksym_a_sz = ix; qsort(ksym_a, ksym_a_sz, sizeof(struct ksym), ksym_compare_addr); #if PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "symbols from ksyms + sysmap ...\n"); for (ix = 0; ix < ksym_a_sz; ix++) { fprintf(stderr, "ksym[%d] " PRINTF_P_PFX "%p %s", ix, (void *)ksym_a[ix].addr, ksym_a[ix].name); if (ksym_a[ix].module != NULL) fprintf(stderr, " [%s]", ksym_a[ix].module); fprintf(stderr, "\n"); } } #endif fclose(fp); return ksym_a_sz; fail: e = -oserror(); if (fp) fclose(fp); return e; } void read_ksym_sources(const char *release) { __psint_t end_addr; if (read_ksyms(&end_addr) > 0) /* read /proc/ksyms first */ read_sysmap(release, end_addr); /* then System.map */ } pcp-3.8.12ubuntu1/src/pmdas/linux_proc/linux_proc_migrate.conf0000664000000000000000000000426112272262501021423 0ustar # Copyright 2012 Red Hat, Inc. All Rights Reserved # # pmlogrewrite configuration for migrating archives containing proc metrics # that were captured prior to the proc PMDA split-off from the Linux PMDA. # # Basically, the PMID domain changed from 60 (linux) to 3 (proc) but all # cluster and item numbers remain unchanged. # # Note that the CPU indom is not migrated, even though it is # used for cgroup.groups.cpuacct.[.]usage_percpu and # cgroup.groups.cpuacct.usage_percpu because these metrics use a # the dynamic pmns. To migrate archives containing these metrics, # a script would be needed to generate the pmlogwrite config based # on the metric names actually present in the source archive. # # Migrate instance domains indom 60.9 { indom -> 3.9 } # per-process indom indom 60.20 { indom -> 3.20 } # cgroup hierarchy indom indom 60.21 { indom -> 3.21 } # cgroup mount subsys indom # # Migrate the pmid domain for each cluster metric 60.8.* { pmid -> 3.*.* } # CLUSTER_PID_STAT metric 60.9.* { pmid -> 3.*.* } # CLUSTER_PID_STATM metric 60.13.* { pmid -> 3.*.* } # CLUSTER_PROC_RUNQ metric 60.24.* { pmid -> 3.*.* } # CLUSTER_PID_STATUS metric 60.31.* { pmid -> 3.*.* } # CLUSTER_PID_SCHEDSTAT metric 60.32.* { pmid -> 3.*.* } # CLUSTER_PID_IO metric 60.51.* { pmid -> 3.*.* } # CLUSTER_PID_FD metric 60.37.* { pmid -> 3.*.* } # CLUSTER_CGROUP_SUBSYS metric 60.38.* { pmid -> 3.*.* } # CLUSTER_CGROUP_MOUNTS metric 60.39.* { pmid -> 3.*.* } # CLUSTER_CPUSET_GROUPS metric 60.40.* { pmid -> 3.*.* } # CLUSTER_CPUSET_PROCS metric 60.41.* { pmid -> 3.*.* } # CLUSTER_CPUACCT_GROUPS metric 60.42.* { pmid -> 3.*.* } # CLUSTER_CPUACCT_PROCS metric 60.43.* { pmid -> 3.*.* } # CLUSTER_CPUSCHED_GROUPS metric 60.44.* { pmid -> 3.*.* } # CLUSTER_CPUSCHED_PROCS metric 60.45.* { pmid -> 3.*.* } # CLUSTER_MEMORY_GROUPS metric 60.46.* { pmid -> 3.*.* } # CLUSTER_MEMORY_PROCS metric 60.47.* { pmid -> 3.*.* } # CLUSTER_NET_CLS_GROUPS metric 60.48.* { pmid -> 3.*.* } # CLUSTER_NET_CLS_PROCS # # These two proc.io metrics were incorrectly classified # metric proc.io.rchar { sem -> counter units -> 1,0,0,BYTE,0,0 } metric proc.io.wchar { sem -> counter units -> 1,0,0,BYTE,0,0 } pcp-3.8.12ubuntu1/src/pmdas/linux_proc/getinfo.h0000664000000000000000000000115012272262501016460 0ustar /* * Copyright (c) 2010 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ extern char *get_ttyname_info(int, dev_t, char *); pcp-3.8.12ubuntu1/src/pmdas/mailq/0000775000000000000000000000000012272262620013602 5ustar pcp-3.8.12ubuntu1/src/pmdas/mailq/mailq.c0000664000000000000000000002266312272262501015060 0ustar /* * Mailq PMDA * * Copyright (c) 2012 Red Hat. * Copyright (c) 1997-2000,2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #ifdef HAVE_REGEX_H #include #endif #include /* * histogram for binning messages based on queue time */ typedef struct { long count; /* number in this bin */ time_t delay; /* in queue for at least this long (seconds) */ } histo_t; static histo_t *histo; static int numhisto; static int queue; /* * list of instances - indexes must match histo[] above */ static pmdaInstid *_delay; static char *queuedir = "/var/spool/mqueue"; static char startdir[MAXPATHLEN]; static char *username; static char *regexstring; static regex_t mq_regex; /* * list of instance domains */ static pmdaIndom indomtab[] = { #define DELAY_INDOM 0 { DELAY_INDOM, 0, NULL }, }; /* * all metrics supported in this PMDA - one table entry for each */ static pmdaMetric metrictab[] = { /* length */ { NULL, { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* deferred */ { NULL, { PMDA_PMID(0,1), PM_TYPE_U32, DELAY_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, }; static int compar(const void *a, const void *b) { histo_t *ha = (histo_t *)a; histo_t *hb = (histo_t *)b; return hb->delay - ha->delay; } /* * callback provided to pmdaFetch */ static int mailq_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); int b; if (idp->cluster == 0) { if (idp->item == 0) { /* mailq.length */ if (inst == PM_IN_NULL) atom->ul = queue; else return PM_ERR_INST; } else if (idp->item == 1) { /* mailq.deferred */ /* inst is unsigned, so always >= 0 */ for (b = 0; b < numhisto; b++) { if (histo[b].delay == inst) break; } if (b < numhisto) atom->ul = histo[b].count; else return PM_ERR_INST; } else return PM_ERR_PMID; } else return PM_ERR_PMID; return 0; } /* * wrapper for pmdaFetch which refreshes the metrics */ static int mailq_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { static int warn = 0; int num; int i; int b; struct stat sbuf; time_t now; static time_t last_refresh = 0; time_t waiting; char *p; struct dirent **list; time(&now); /* clip refresh rate to at most once per 30 seconds */ if (now - last_refresh > 30) { last_refresh = now; queue = 0; for (b = 0; b < numhisto; b++) histo[b].count = 0; if (chdir(queuedir) < 0) { if (warn == 0) { __pmNotifyErr(LOG_ERR, "chdir(\"%s\") failed: %s\n", queuedir, osstrerror()); warn = 1; } } else { if (warn == 1) { __pmNotifyErr(LOG_INFO, "chdir(\"%s\") success\n", queuedir); warn = 0; } num = scandir(".", &list, NULL, NULL); for (i = 0; i < num; i++) { p = list[i]->d_name; /* only file names that match the regular expression */ if (regexstring && regexec(&mq_regex, list[i]->d_name, 0, NULL, 0)) continue; else if (!regexstring && (*p != 'd' || *(p+1) != 'f')) continue; if (stat(p, &sbuf) != 0) { /* * ENOENT expected sometimes if sendmail is doing its job */ if (oserror() == ENOENT) continue; fprintf(stderr, "stat(\"%s\"): %s\n", p, osstrerror()); continue; } if (sbuf.st_size > 0 && S_ISREG(sbuf.st_mode)) { /* really in the queue */ #if defined(HAVE_ST_MTIME_WITH_E) waiting = now - sbuf.st_mtime; #elif defined(HAVE_ST_MTIME_WITH_SPEC) waiting = now - sbuf.st_mtimespec.tv_sec; #else waiting = now - sbuf.st_mtim.tv_sec; #endif for (b = 0; b < numhisto; b++) { if (waiting >= histo[b].delay) { histo[b].count++; break; } } queue++; } } for (i = 0; i < num; i++) free(list[i]); if (num > 0) free(list); } if (chdir(startdir) < 0) { __pmNotifyErr(LOG_ERR, "chdir(\"%s\") failed: %s\n", startdir, osstrerror()); } } return pmdaFetch(numpmid, pmidlist, resp, pmda); } /* * Initialise the agent (daemon only). */ void mailq_init(pmdaInterface *dp) { if (dp->status != 0) return; __pmSetProcessIdentity(username); dp->version.two.fetch = mailq_fetch; pmdaSetFetchCallBack(dp, mailq_fetchCallBack); pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), metrictab, sizeof(metrictab)/sizeof(metrictab[0])); } static void usage(void) { fprintf(stderr, "Usage: %s [options] [queuedir]\n\n", pmProgname); fputs("Options:\n" " -b binlist times to be used for histogram bins as comma\n" " separated values in pmParseInterval(3) format\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -r regex regular expression for matching mail file names\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int err = 0; int sep = __pmPathSeparator(); int c; int sts; int i; time_t tmp; pmdaInterface dispatch; char *q; char *errmsg; char namebuf[30]; struct timeval tv; char mypath[MAXPATHLEN]; __pmSetProgname(argv[0]); __pmGetUsername(&username); if (getcwd(startdir, sizeof(startdir)) == NULL) { fprintf(stderr, "%s: getcwd() failed: %s\n", pmProgname, pmErrStr(-oserror())); exit(1); } snprintf(mypath, sizeof(mypath), "%s%c" "mailq" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_2, pmProgname, MAILQ, "mailq.log", mypath); while ((c = pmdaGetOpt(argc, argv, "b:D:d:l:r:U:?", &dispatch, &err)) != EOF) { switch (c) { case 'b': q = strtok(optarg, ","); while (q != NULL) { sts = pmParseInterval((const char *)q, &tv, &errmsg); if (sts < 0) { fprintf(stderr, "%s: bad -b argument:\n%s\n", pmProgname, errmsg); err++; } numhisto++; histo = (histo_t *)realloc(histo, numhisto * sizeof(histo[0])); if (histo == NULL) { __pmNoMem("histo", numhisto * sizeof(histo[0]), PM_FATAL_ERR); } histo[numhisto-1].delay = tv.tv_sec; q = strtok(NULL, ","); } break; case 'r': regexstring = optarg; c = regcomp(&mq_regex, regexstring, REG_EXTENDED | REG_NOSUB); if (c != 0) { regerror(c, &mq_regex, mypath, sizeof(mypath)); fprintf(stderr, "Cannot compile regular expression: %s\n", mypath); exit(1); } break; case 'U': username = optarg; break; default: err++; break; } } if (optind == argc-1) queuedir = argv[optind]; else if (optind != argc) err++; if (err) { usage(); } if (histo == NULL) { /* default histo bins, if not already done above ... */ numhisto = 7; histo = (histo_t *)malloc(numhisto * sizeof(histo[0])); if (histo == NULL) { __pmNoMem("histo", numhisto * sizeof(histo[0]), PM_FATAL_ERR); } histo[0].delay = 7 * 24 * 3600; histo[1].delay = 3 * 24 * 3600; histo[2].delay = 24 * 3600; histo[3].delay = 8 * 3600; histo[4].delay = 4 * 3600; histo[5].delay = 1 * 3600; histo[6].delay = 0; } else { /* need to add last one and sort on descending time */ numhisto++; histo = (histo_t *)realloc(histo, numhisto * sizeof(histo[0])); if (histo == NULL) { __pmNoMem("histo", numhisto * sizeof(histo[0]), PM_FATAL_ERR); } histo[numhisto-1].delay = 0; qsort(histo, numhisto, sizeof(histo[0]), compar); } _delay = (pmdaInstid *)malloc(numhisto * sizeof(_delay[0])); if (_delay == NULL) { __pmNoMem("_delay", numhisto * sizeof(_delay[0]), PM_FATAL_ERR); } for (i = 0; i < numhisto; i++) { _delay[i].i_inst = histo[i].delay; histo[i].count = 0; if (histo[i].delay == 0) sprintf(namebuf, "recent"); else if (histo[i].delay < 60) sprintf(namebuf, "%d-secs", (int)histo[i].delay); else if (histo[i].delay < 60 * 60) { tmp = histo[i].delay / 60; if (tmp <= 1) sprintf(namebuf, "1-min"); else sprintf(namebuf, "%d-mins", (int)tmp); } else if (histo[i].delay < 24 * 60 * 60) { tmp = histo[i].delay / (60 * 60); if (tmp <= 1) sprintf(namebuf, "1-hour"); else sprintf(namebuf, "%d-hours", (int)tmp); } else { tmp = histo[i].delay / (24 * 60 * 60); if (tmp <= 1) sprintf(namebuf, "1-day"); else sprintf(namebuf, "%d-days", (int)tmp); } _delay[i].i_name = strdup(namebuf); if (_delay[i].i_name == NULL) { __pmNoMem("_delay[i].i_name", strlen(namebuf), PM_FATAL_ERR); } } indomtab[DELAY_INDOM].it_numinst = numhisto; indomtab[DELAY_INDOM].it_set = _delay; pmdaOpenLog(&dispatch); mailq_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/mailq/README0000664000000000000000000000205712272262501014464 0ustar Mailq PMDA ========== This PMDA exports information about the sendmail(1) queue. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT mailq Installation ============ + # cd $PCP_PMDAS_DIR/mailq + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/mailq # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/mailq.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/mailq/Remove0000664000000000000000000000200712272262501014757 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the mailq PMDA # # Get standard environment . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=mailq # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/mailq/Install0000664000000000000000000000476212272262501015142 0ustar #! /bin/sh # # Copyright (c) 1997-2000,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the mailq PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=mailq pmda_interface=2 forced_restart=false # Do it # pmdaSetup if $do_pmda then dso_opt=false socket_opt=false pipe_opt=true mqueue="" chk="" if [ -f /etc/sendmail.cf ] then chk=`sed -n '/^O *QueueDirectory *= */s///p' /etc/sendmail.cf` [ -z "$chk" ] && chk=`sed -n '/^O *Q *\//s//\//p' /etc/sendmail.cf` fi if [ ! -z "$chk" -a -d "$chk" ] then mqueue="$chk" else mqueue=/var/spool/mqueue fi while true do $PCP_ECHO_PROG $PCP_ECHO_N 'Mail queue directory ['"$mqueue"'] '"$PCP_ECHO_C" read ans [ -z "$ans" ] && break if [ -d "$ans" ] then mqueue="$ans" break fi echo "Error: \"$ans\" is not a directory" done echo regex="" $PCP_ECHO_PROG $PCP_ECHO_N 'Mail basename regex ['"$regex"'] '"$PCP_ECHO_C" read regex [ -z "$regex" ] || args="$args -r $regex" echo args="$args $mqueue" while true do echo 'The default delay thresholds for grouping the pending mail items are:' echo ' 1 hour, 4 hours, 8 hours, 1 day, 3 days and 7 days' echo $PCP_ECHO_PROG $PCP_ECHO_N 'Do you wish to use the default delay thresholds [y]? '"$PCP_ECHO_C" read ans if [ -z "$ans" -o "$ans" = "y" -o "$ans" = "Y" ] then break else bucketlist='' while true do $PCP_ECHO_PROG $PCP_ECHO_N 'Threshold? [return if no more] '"$PCP_ECHO_C" read ans [ -z "$ans" ] && break # strip blanks so args in pmcd.conf get passed correctly to # the mailqpmda binary # ans=`echo "$ans" | sed -e 's/ //g'` if [ -z "$bucketlist" ] then bucketlist="$ans" else bucketlist="$bucketlist,$ans" fi done if [ ! -z "$bucketlist" ] then args="$args -b $bucketlist" break fi echo echo 'Error: you must specify at least one threshold' echo fi done echo fi pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/mailq/pmlogconf.summary0000664000000000000000000000020612272262501017201 0ustar #pmlogconf-setup 2.0 ident mailq PMDA summary information probe mailq.length exists ? include : exclude mailq.length mailq.deferred pcp-3.8.12ubuntu1/src/pmdas/mailq/GNUmakefile0000664000000000000000000000265112272262501015656 0ustar # # Copyright (c) 2000-2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = mailq DOMAIN = MAILQ CMDTARGET = $(IAM)$(EXECSUFFIX) CFILES = mailq.c DFILES = README LSRCFILES = Install Remove root help pmns $(DFILES) pmlogconf.summary LLDLIBS = $(PCP_PMDALIB) $(LIB_FOR_REGEX) PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LDIRT = domain.h *.log *.dir *.pag so_locations default: $(CMDTARGET) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(CMDTARGET) $(PMDADIR)/pmda$(CMDTARGET) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 $(DFILES) root help pmns domain.h $(PMDADIR) $(INSTALL) -m 755 -d $(PCP_VAR_DIR)/config/pmlogconf/$(IAM) $(INSTALL) -m 644 pmlogconf.summary $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)/summary mailq.o: domain.h domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmdas/mailq/root0000664000000000000000000000016212272262501014505 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { mailq } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/mailq/pmns0000664000000000000000000000156512272262501014507 0ustar /* * Metrics for mailq PMDA * * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ mailq { length MAILQ:0:0 deferred MAILQ:0:1 } pcp-3.8.12ubuntu1/src/pmdas/mailq/help0000664000000000000000000000373612272262501014464 0ustar # # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # mailq PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ MAILQ.1 Instance domain used to "bin" messages based on how long they have been deferred @ mailq.length Number of messages in the queue The total number of messages in the mail queue. @ mailq.deferred Histogram of pending messages based on how long they have been deferred Counts of the number of messages in the sendmail queue grouped by how long the mail delivery has been deferred. The groups are based on the how long a message has been in the queue: 1-week at least a week 3-days at least 3 days and less than a week 1-day at least one day and less than 3 days 8-hours more than 8 hours and less than one day 4-hours between 4 and 8 hours 1-hour between 1 and 4 hours recent less than an hour pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/0000775000000000000000000000000012272262620014671 5ustar pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/lustrecomm.c0000664000000000000000000002215212272262501017227 0ustar /* * Lustre common /proc PMDA * * Original author: Scott Emery * * Copyright (c) 2012 Red Hat. * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "libreadfiles.h" #include #include "domain.h" /* * Lustrecomm PMDA * * This PMDA gathers Lustre statistics from /proc, it is constructed using * libpcp_pmda. * * * Metrics * lustrecomm.time - time in seconds since the 1st of Jan, 1970. */ #define PROC_SYS_LNET_STATS 0 #define PROC_SYS_LNET_NIS 1 #define PROC_SYS_LNET_PEERS 2 #define FILESTATETABSIZE 3 /* * all metrics supported in this PMDA - one table entry for each */ static pmdaMetric metrictab[] = { /* timeout */ { NULL, { PMDA_PMID(0,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* ldlm_timeout */ { NULL, { PMDA_PMID(0,1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* dump_on_timeout */ { NULL, { PMDA_PMID(0,2), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) } }, /* lustre_memused */ { NULL, { PMDA_PMID(0,3), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* lnet_memused */ { NULL, { PMDA_PMID(0,4), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* data pulled from /proc/sys/lnet/stats */ /*0 42 0 22407486 23426580 0 0 135850271989 472430974209 0 0*/ /* stats.msgs_alloc */ { NULL, { PMDA_PMID(1,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* stats.msgs_max */ { NULL, { PMDA_PMID(1,1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* stats.errors */ { NULL, { PMDA_PMID(1,2), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* stats.send_count */ { NULL, { PMDA_PMID(1,3), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* stats.recv_count */ { NULL, { PMDA_PMID(1,4), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* stats.route_count */ { NULL, { PMDA_PMID(1,5), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* stats.drop_count */ { NULL, { PMDA_PMID(1,6), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* stats.send_length */ { NULL, { PMDA_PMID(1,7), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* stats.recv_length */ { NULL, { PMDA_PMID(1,8), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* stats.route_length */ { NULL, { PMDA_PMID(1,9), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } }, /* stats.drop_length */ { NULL, { PMDA_PMID(1,10), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) } } }; struct file_state filestatetab[] = { { { 0 , 0 } , "/proc/sys/lnet/stats", 0, 0, NULL}, { { 0 , 0 } , "/proc/sys/lnet/nis", 0, 0, NULL}, { { 0 , 0 } , "/proc/sys/lnet/peers", 0, 0, NULL} }; static int isDSO = 1; /* =0 I am a daemon */ static char mypath[MAXPATHLEN]; static char *username; /* * callback provided to pmdaFetch */ static int lustrecomm_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); void *vp; /* check for PMID errors */ if ( !((idp->cluster == 0) && (idp->item <= 4)) && !((idp->cluster == 1) && (idp->item <= 10)) ) return PM_ERR_PMID; else if (inst != PM_IN_NULL) return PM_ERR_INST; /* refresh and store data */ if (idp->cluster == 0) { vp = malloc (4); int aux = 10; /* not saving any time fussing with "how recent", just do it */ switch (idp->item) { case 0: /* consider mdesc->m_desc.type */ /* problem: the way it's stored in PCP isn't necessarily */ /* the way it's presented by the OS */ file_single("/proc/sys/lustre/timeout", PM_TYPE_32, &aux, &vp); atom->l = *((long *) vp); break; case 1: file_single("/proc/sys/lustre/ldlm_timeout", PM_TYPE_32, &aux, &vp); atom->l = *((long *) vp); break; case 2: file_single("/proc/sys/lustre/dump_on_timeout", PM_TYPE_32, &aux, &vp); atom->l = *((long *) vp); break; case 3: file_single("/proc/sys/lustre/memused", PM_TYPE_32, &aux, &vp); atom->l = *((long *) vp); break; case 4: file_single("/proc/sys/lnet/memused", PM_TYPE_32, &aux, &vp); atom->l = *((long *) vp); break; default: printf ("PMID %d:%d non-existant\n",idp->cluster,idp->item); break; } free (vp); } if (idp->cluster == 1) { vp = malloc (4); int aux = 10; switch(idp->item) { case 0: file_indexed(&filestatetab[PROC_SYS_LNET_STATS], PM_TYPE_32,&aux, &vp, 0); atom->l = *((long *) vp); break; case 1: file_indexed(&filestatetab[PROC_SYS_LNET_STATS], PM_TYPE_32,&aux, &vp, 1); atom->l = *((long *) vp); break; case 2: file_indexed(&filestatetab[PROC_SYS_LNET_STATS], PM_TYPE_32,&aux, &vp, 2); atom->l = *((long *) vp); break; case 3: file_indexed(&filestatetab[PROC_SYS_LNET_STATS], PM_TYPE_32,&aux, &vp, 3); atom->l = *((long *) vp); break; case 4: file_indexed(&filestatetab[PROC_SYS_LNET_STATS], PM_TYPE_32,&aux, &vp, 4); atom->l = *((long *) vp); break; case 5: file_indexed(&filestatetab[PROC_SYS_LNET_STATS], PM_TYPE_32,&aux, &vp, 5); atom->l = *((long *) vp); break; case 6: file_indexed(&filestatetab[PROC_SYS_LNET_STATS], PM_TYPE_32,&aux, &vp, 6); atom->l = *((long *) vp); break; case 7: file_indexed(&filestatetab[PROC_SYS_LNET_STATS], PM_TYPE_32,&aux, &vp, 7); atom->l = *((long *) vp); break; case 8: file_indexed(&filestatetab[PROC_SYS_LNET_STATS], PM_TYPE_32,&aux, &vp, 8); atom->l = *((long *) vp); break; case 9: file_indexed(&filestatetab[PROC_SYS_LNET_STATS], PM_TYPE_32,&aux, &vp, 9); atom->l = *((long *) vp); break; case 10: file_indexed(&filestatetab[PROC_SYS_LNET_STATS], PM_TYPE_32,&aux, &vp, 10); atom->l = *((long *) vp); break; default: break; } free(vp); } return 0; } /* * Initialise the agent (both daemon and DSO). */ void lustrecomm_init(pmdaInterface *dp) { if (isDSO) { int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "lustrecomm" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_2, "lustrecomm DSO", mypath); } else { __pmSetProcessIdentity(username); } if (dp->status != 0) return; pmdaSetFetchCallBack(dp, lustrecomm_fetchCallBack); pmdaInit(dp, NULL, 0, metrictab, sizeof(metrictab)/sizeof(metrictab[0])); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int c, err = 0; int sep = __pmPathSeparator(); pmdaInterface desc; isDSO = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(mypath, sizeof(mypath), "%s%c" "lustrecomm" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&desc, PMDA_INTERFACE_2, pmProgname, LUSTRECOMM, "lustrecomm.log", mypath); while ((c = pmdaGetOpt(argc, argv, "D:d:l:U:?", &desc, &err)) != EOF) { switch(c) { case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&desc); lustrecomm_init(&desc); pmdaConnect(&desc); pmdaMain(&desc); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/README0000664000000000000000000000306612272262501015554 0ustar lustrecomm PMDA =============== This PMDA collects statistics common to all lustre implementations, the statistics found in /proc/lustre and /proc/lnet Note: This PMDA may be remade from source and hence requires IDO (or more specifically a C compiler) to be installed. Uses of make(1) may fail (without removing or clobbering files) if the C compiler cannot be found. This is most likely to happen when running the PMDA ./Install script. The only remedial action is to install the C compiler, or hand-craft changes to the Makefile. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT lustrecomm Installation ============ + # cd $PCP_PMDAS_DIR/lustrecomm + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options -- everything else is automated. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/lustrecomm # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/trivial.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/libreadfiles.h0000664000000000000000000000327012272262501017467 0ustar /* * Lustre common /proc PMDA * * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. * * Author: Scott Emery * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include #include #include #include #include #include struct file_state { struct timespec ts; char *filename; int fd; int datas; void *datap; }; #define BUFFERBLOCK 4096 #ifndef FILE_TIME_OFFSET extern struct timespec file_time_offset; #endif /* timespec_routines.c */ extern struct timespec timespec_add (struct timespec *a, struct timespec *b); extern int timespec_le ( struct timespec *lhs, struct timespec *rhs); /* refresh_file.c */ extern int refresh_file( struct file_state *f_s ); /* file_indexed.c */ extern int file_indexed (struct file_state *f_s, int type, int *base, void **vpp, int index); /* file_single.c */ extern int file_single (char *filename, int type, int *base, void **vpp); pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/refresh_file.c0000664000000000000000000000470712272262501017500 0ustar /* * Lustre common /proc PMDA * * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. * * Author: Scott Emery * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define FILE_TIME_OFFSET 1 #include "libreadfiles.h" static struct timespec file_time_offset = { 0 , 900000000 }; int refresh_file( struct file_state *f_s ){ struct timespec now, tmp; int i = 0; if (f_s->datap) { /* get time */ if ( clock_gettime(CLOCK_MONOTONIC, &now) < 0 ) { /* if we don't know what time it is */ /* there's nothing we can do with this */ return 0; } /* if time since last refresh > delta */ tmp = timespec_add( &f_s->ts, &file_time_offset); if ( timespec_le( &now, &tmp) ) { /* file is recent */ return 0; } f_s->ts = now; /* clear old data, make errors obvious, autoterm trailing strings */ memset ( f_s->datap, 0, f_s->datas ); } /* if fd is null open file */ if ( f_s->fd <= 0) { if (( f_s->fd = open (f_s->filename, O_RDONLY)) < 0) { perror("refresh_file: open"); return -1; } } if ( lseek (f_s->fd, 0, SEEK_SET) < 0 ) { perror("refresh_file: initial seek"); return -1; } /* only grow, never shrink... what would be the point? */ while (f_s->datap && (i = read (f_s->fd, f_s->datap, f_s->datas)) >= f_s->datas ){ /* oh heck, what do I do if this fails? */ f_s->datas += BUFFERBLOCK; if ((f_s->datap = realloc(f_s->datap, f_s->datas)) == NULL){ free((char *)f_s->datap); perror("refresh_file: realloc"); return -1; } if ( lseek (f_s->fd, 0, SEEK_SET) < 0 ) { perror("refresh_file: subsequent seek"); return -1; } } if (i < 0 ){ /* read failed */ perror("refresh_file: file read failed"); return -1; } return 0; } pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/Remove0000775000000000000000000000205412272262501016053 0ustar #! /bin/sh # # Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. # # Author: Scott Emery # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # source the PCP configuration environment variables . /etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=lustrecomm # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/Install0000775000000000000000000000135712272262501016231 0ustar #! /bin/sh # # Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. # # Author: Scott Emery # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # . /etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=lustrecomm pmda_interface=2 forced_restart=false pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/GNUmakefile0000664000000000000000000000312512272262501016742 0ustar # # Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. # # Author: Scott Emery # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = lustrecomm DOMAIN = LUSTRECOMM PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) DFILES = README HFILES = libreadfiles.h CFILES = $(IAM).c file_indexed.c file_single.c refresh_file.c timespec_routines.c LIBTARGET = pmda_$(IAM).so CMDTARGET = pmda$(IAM) TARGETS = $(CMDTARGET) #TARGETS = $(LIBTARGET) LDOPTS = LSRCFILES = Install Remove README help pmns root LLDLIBS = $(PCP_PMDALIB) -lrt LCFLAGS = -I. LDIRT = domain.h *.o $(IAM).log pmda$(IAM) pmda_$(IAM).so default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "linux" build-me: domain.h $(TARGETS) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(CMDTARGET) $(PMDADIR)/$(CMDTARGET) #$(INSTALL) -m 755 $(LIBTARGET) $(PMDADIR)/$(LIBTARGET) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 $(DFILES) root pmns domain.h help $(PMDADIR) else build-me: install: endif default_pcp: default install_pcp: install domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/root0000664000000000000000000000016712272262501015601 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { lustrecomm } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/pmns0000664000000000000000000000311012272262501015562 0ustar /* * Metrics for lustrecomm PMDA * * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. * * Author: Scott Emery * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ lustrecomm { timeout LUSTRECOMM:0:0 ldlm_timeout LUSTRECOMM:0:1 dump_on_timeout LUSTRECOMM:0:2 lustre_memused LUSTRECOMM:0:3 lnet_memused LUSTRECOMM:0:4 stats } lustrecomm.stats { /* data pulled from /proc/sys/lnet/stats */ /*0 42 0 22407486 23426580 0 0 135850271989 472430974209 0 0*/ msgs_alloc LUSTRECOMM:1:0 msgs_max LUSTRECOMM:1:1 errors LUSTRECOMM:1:2 send_count LUSTRECOMM:1:3 recv_count LUSTRECOMM:1:4 route_count LUSTRECOMM:1:5 drop_count LUSTRECOMM:1:6 send_length LUSTRECOMM:1:7 recv_length LUSTRECOMM:1:8 route_length LUSTRECOMM:1:9 drop_length LUSTRECOMM:1:10 } pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/file_indexed.c0000664000000000000000000000633712272262501017463 0ustar /* * Lustre common /proc PMDA * * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. * * Author: Scott Emery * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libreadfiles.h" /* int file_indexed (struct file_state *f_s, * int type, int base, void *vpp, int index) * - Get single value from file containing multiple values * struct file_state *f_s - struct for access to single file * type - PCP type described by the PMAPI PM_TYPE_* enum * base - for integer types, base as stored in the file * - for string and aggregate types, size of memory pointed to * ---------------- size may be changed by realloc * vpp - pointer to pointer to storage allocated to contain value * - pointed to pointer may change * ---------------- pointer may be changed by realloc * index - value is the n'th strtok token in the file * consider specifying token seperator, default whitespace is fine for now */ int file_indexed (struct file_state *f_s, int type, int *base, void **vpp, int index) { int i; char *cp, *sp; /* reload file if it hasn't been reloaded in x */ if (refresh_file( f_s ) <0 ) { __pmNotifyErr(LOG_ERR, "file_indexed: refresh_file error"); return -1; } /* file_indexed assumes that the file contains one line * if the file may ever contain more than one line, consider file_arrayed * (if that ever gets written) * strtok to the appropriate spot * strtok screws up the target string, so make a copy of the file data */ cp = malloc ( f_s->datas ); strcpy ( cp, f_s->datap ); sp = strtok( cp, " " ); for (i = 0; i < index; i++){ sp = strtok( NULL, " "); } /* otherwise, a lot like file_single (see below) * one would eventually write a configure script to make * sure that the right routines are used below.. defining * a STRTO32 and STRTOU32, etc. */ switch (type) { case PM_TYPE_32: *((long *)(*vpp)) = strtol(sp,0,*base); break; case PM_TYPE_U32: *((unsigned long *)(*vpp)) = strtoul(sp,0,*base); break; case PM_TYPE_64: *((long long *)(*vpp)) = strtoll(sp,0,*base); break; case PM_TYPE_U64: *((unsigned long long *)(*vpp)) = strtoull(sp,0,*base); break; case PM_TYPE_FLOAT: *((float *)(*vpp)) = strtof(sp,0); break; case PM_TYPE_DOUBLE: *((double *)(*vpp)) = strtod(sp,0); break; default: fprintf(stderr,"file_indexed: type %s not supported\n", pmTypeStr(type)); break; } /* so, write it up and slice and dice */ free (cp); return 0; } pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/timespec_routines.c0000664000000000000000000000255612272262501020604 0ustar /* * Lustre common /proc PMDA * * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. * * Author: Scott Emery * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include struct timespec timespec_add (struct timespec *a, struct timespec *b){ struct timespec tret; tret.tv_nsec = (a->tv_nsec + b->tv_nsec) % 1000000000; tret.tv_sec = a->tv_sec + b->tv_sec + ((a->tv_nsec + b->tv_nsec)/1000000000); return tret; } int timespec_le ( struct timespec *lhs, struct timespec *rhs) { if (rhs->tv_sec < lhs->tv_sec) { /* false */ return 0; } if (lhs->tv_sec == rhs->tv_sec) { if (rhs->tv_nsec < lhs->tv_nsec) { /* false */ return 0; } } return 1; } pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/file_single.c0000664000000000000000000000624412272262501017321 0ustar /* * Lustre common /proc PMDA * * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. * * Author: Scott Emery * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libreadfiles.h" /* file_single (char *filename, int type, int *base, void **vpp) * - Get a value from a file containing single value * filename - name of file * type - PCP type described by the PMAPI PM_TYPE_* enum * base - for integer types, base as stored in the file * - for string and aggregate types, size of memory pointed to * ---------------- size may be changed by realloc * vpp - pointer to pointer to storage allocated to contain value * - pointed to pointer may change * ---------------- pointer may be changed by realloc * allocating and deallocating space for value is the responsibility * of the caller */ int file_single (char *filename, int type, int *base, void **vpp) { int fd; int n; /* overlarge */ char b[80] = { 0 }; /* Read in the file into the buffer b */ if (( fd = open (filename, O_RDONLY)) < 0) { perror("file_single: open"); return -1; } /* Okay this presents a problem vis a vis some lustre proc files. * While the present scheme is adequate for lustre common in most * cases, some lustre proc files have *ridiculously* large amounts * of data stored in them. Need to come up with some dynamic * memory buffer system for other lustre PMDAs */ switch (type) { case PM_TYPE_32: case PM_TYPE_U32: case PM_TYPE_64: case PM_TYPE_U64: case PM_TYPE_FLOAT: case PM_TYPE_DOUBLE: if ((n = read (fd, b, sizeof(b))) < 0 ){ perror("file_single: read"); close(fd); return -1; } close(fd); break; default: fprintf(stderr,"file_single: type %s not supported\n", pmTypeStr(type)); close(fd); return -1; } /* One would eventually write a configure script to make * sure that the right routines are used below.. defining * a STRTO32 and STRTOU32, etc. */ switch (type) { case PM_TYPE_32: *((long *)(*vpp)) = strtol(b,0,*base); break; case PM_TYPE_U32: *((unsigned long *)(*vpp)) = strtoul(b,0,*base); break; case PM_TYPE_64: *((long long *)(*vpp)) = strtoll(b,0,*base); break; case PM_TYPE_U64: *((unsigned long long *)(*vpp)) = strtoull(b,0,*base); break; case PM_TYPE_FLOAT: *((float *)(*vpp)) = strtof(b,0); break; case PM_TYPE_DOUBLE: *((double *)(*vpp)) = strtod(b,0); break; } return 0; } pcp-3.8.12ubuntu1/src/pmdas/lustrecomm/help0000664000000000000000000001055212272262501015545 0ustar # # Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. # # Author: Scott Emery # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # # lustrecomm PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ lustrecomm.timeout contents of /proc/sys/lustre/timeout The time period that a client waits for a server to complete an RPC (default in 1.6 is 100s). Servers wait half this time for a normal client RPC to compelte and a quarter of this time for a single bulk request to complete. The client pings recoverable targets (MDS and OSTs) at one quarter of the timeout, and the server waits on and a half times the timeout before evicting a client for being "stale". (source: Lustre 1.6 Operations Manual) @ lustrecomm.ldlm_timeout contents of /proc/sys/lustre/ldlm_timeout This is the time period for which a server will wait for a client to reply to an initial AST (lock cancellation request). The default is 20s for an OST and 6s for an MDS. (source: Lustre 1.6 Operations Manual) @ lustrecomm.dump_on_timeout contents of /proc/sys/lustre/ldlm_timeout A 1 triggers dumps of the Lustre debug log when timeouts occur. Default value 0. (source: Lustre 1.6 Operations Manual) @ lustrecomm.lustre_memused contents of /proc/sys/lustre/memused lustre/obdclass/linux/linux-sysctl.c: &proc_memory_alloc lustre/include/obd_support.h: obd_memory_sum() Total bytes allocated by Lustre (inferred from lustre/include/obd_support.h) @ lustrecomm.lnet_memused contents of /proc/sys/lnet/memused lnet/libcfs/linux/linux-proc.c: (int *)&libcfs_kmemory.counter Total bytes allocated by LNET. (inferred from lustre/include/obd_support.h) @ lustrecomm.stats.msgs_alloc first number from /proc/sys/lnet/stats routerstat source file: messages currently allocated (first number after M) @ lustrecomm.stats.msgs_max second number from /proc/sys/lnet/stats routerstat source file: messages maximum (highwater mark) (second number after M) @ lustrecomm.stats.errors third number from /proc/sys/lnet/stats routerstat source file: errors (number after E) @ lustrecomm.stats.send_count fourth number from /proc/sys/lnet/stats routerstat source file: send_count (raw data from which second number after S is derived). @ lustrecomm.stats.recv_count fifth number from /proc/sys/lnet/stats routerstat source file: recv_count (raw data from which second number after R is derived) @ lustrecomm.stats.route_count sixth number from /proc/sys/lnet/stats routerstat source file: route_count (raw data from which second number after R is derived) @ lustrecomm.stats.drop_count seventh number from /proc/sys/lnet/stats routerstat source file: drop_count (raw data from which second number after D is derived) @ lustrecomm.stats.send_length eigth number from /proc/sys/lnet/stats routerstat source file: send_length (raw data from which first number after S is derived) @ lustrecomm.stats.recv_length ninth number from /proc/sys/lnet/stats routerstat source file: recv_length (raw data from which first number after S is derived) @ lustrecomm.stats.route_length tenth number from /proc/sys/lnet/stats routerstat source file: route_length (raw data from which first number after R is derived) @ lustrecomm.stats.drop_length eleventh number from /proc/sys/lnet/stats routerstat source file: drop_length (raw data from which first number after D is derived) pcp-3.8.12ubuntu1/src/pmdas/GNUmakefile0000664000000000000000000000364012272262501014552 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs CPMDAS = pmcd linux darwin freebsd solaris aix windows \ sample simple trivial sendmail mailq txmon \ cisco trace apache shping mounts weblog \ lmsensors process roomtemp summary hotproc \ lustrecomm linux_proc mmv etw logger bash \ systemd gfs2 netbsd linux_xfs infiniband jbd2 \ rpm PLPMDAS = bonding netfilter zimbra postgresql \ dbping memcache systemtap mysql vmware kvm \ named news pdns samba dtsrun postfix gpsd \ rsyslog elasticsearch snmp nginx PYPMDAS = gluster SUBDIRS = $(CPMDAS) $(PLPMDAS) $(PYPMDAS) LDIRT = pmcd.conf default :: default_pcp default_pcp : $(SUBDIRS) @echo '# Performance Metrics Domain Specifications' > pmcd.conf @echo '# ' >> pmcd.conf @echo '# This file is automatically generated during the build' >> pmcd.conf @echo '# Name Id IPC IPC Params File/Cmd' >> pmcd.conf $(SUBDIRS_MAKERULE) @echo >> pmcd.conf @echo '[access]' >> pmcd.conf @echo 'disallow ".*" : store;' >> pmcd.conf @echo 'disallow ":*" : store;' >> pmcd.conf @echo 'allow "local:*" : all;' >> pmcd.conf install :: install_pcp install_pcp :: $(SUBDIRS) $(SUBDIRS_MAKERULE) install_pcp :: default_pcp $(INSTALL) -m 755 -d `dirname $(PCP_PMCDCONF_PATH)` $(INSTALL) -m 644 pmcd.conf $(PCP_PMCDCONF_PATH) include $(BUILDRULES) pcp-3.8.12ubuntu1/src/pmdas/vmware/0000775000000000000000000000000012272262620014000 5ustar pcp-3.8.12ubuntu1/src/pmdas/vmware/Remove0000775000000000000000000000160412272262501015162 0ustar #! /bin/sh # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the VMware PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=vmware pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/vmware/Install0000775000000000000000000000156612272262501015342 0ustar #!/bin/sh # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the VMware PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=vmware perl_opt=true daemon_opt=false forced_restart=false perl -e "use VMware::VIRuntime" 2>/dev/null if test $? -ne 0; then echo "VMware Infrastructure Perl Toolkit is not installed" exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/vmware/GNUmakefile0000664000000000000000000000271412272262501016054 0ustar #!gmake # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = vmware DOMAIN = VMWARE PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif LDIRT = domain.h root pmns *.log $(MAN_PAGES) default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/vmware/pmdavmware.pl0000664000000000000000000004201112272262501016474 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; use VMware::VIRuntime; use vars qw( $host $server $username $password ); use vars qw( $pmda $entity $view $interval $metric_info %metric_values ); # Configuration files for setting VMware host connection parameters for my $file ( pmda_config('PCP_PMDAS_DIR') . '/vmware/vmware.conf', './vmware.conf' ) { eval `cat $file` unless ! -f $file; } die 'VMware host not setup, stopped' unless defined($host); die 'VMware server not setup, stopped' unless defined($server); die 'VMware username not setup, stopped' unless defined($username); die 'VMware password not setup, stopped' unless defined($password); Opts::set_option('server' => $server); Opts::set_option('username' => $username); Opts::set_option('password' => $password); Opts::parse(); sub vmware_connect { $Util::script_version = '1.0'; Util::connect(); $entity = Vim::find_entity_view(view_type => 'HostSystem', filter => {'name' => $host}); return unless defined($entity); $view = Vim::get_view(mo_ref => Vim::get_service_content()->perfManager); my $summary = $view->QueryPerfProviderSummary(entity => $entity); $interval = $summary->refreshRate; # absolute, in seconds $interval = 20 unless defined($interval); # the vmware default } sub vmware_timer_callback { return unless !defined($entity); $pmda->log("Connecting to VMware services on $host ($server)"); vmware_connect(); return unless defined($entity); $pmda->log("Successfully connected."); } sub vmware_disconnect { Util::disconnect(); } sub vmware_metric_ids { my @filtered_list; my $counter_info = $view->perfCounter; my $available_id = $view->QueryAvailablePerfMetric(entity => $entity); foreach (@$counter_info) { my $key = $_->key; $metric_info->{$key} = $_; } foreach (@$available_id) { my $id = $_->counterId; if (defined $metric_info->{$id}) { my $metric = PerfMetricId->new(counterId => $id, instance => ''); push @filtered_list, $metric; } } return \@filtered_list; } sub vmware_fetch { return unless defined($entity); my @metric_ids = vmware_metric_ids(); my $query_spec = PerfQuerySpec->new(entity => $entity, metricId => @metric_ids, 'format' => 'normal', intervalId => $interval, maxSample => 1); my $values; eval { $values = $view->QueryPerf(querySpec => $query_spec); }; if ($@) { if (ref($@) eq 'SoapFault') { if (ref($@->detail) eq 'InvalidArgument') { $pmda->log('QueryPerf parameters are not correct'); } else { $pmda->log('QueryPerf failed - Soap protocol error'); } } else { $pmda->log('QueryPerf failed - cause unknown - good luck!'); } } elsif (!@$values) { $pmda->log('VMware performance data unavailable'); } foreach (@$values) { my $value_array = $_->value; foreach (@$value_array) { my $counter_id = $_->id->counterId; my $counter = $metric_info->{$counter_id}; my $key = $counter->nameInfo->label; $metric_values{$key} = $_; # $pmda->log("Value found: $key maps to $counter_id\n"); } } } sub vmware_fetch_callback { my ($cluster, $item, $inst) = @_; if ($cluster == 0) { if ($item == 0) { return ($host, 1); } if ($item == 1) { return ($interval, 1); } } return (PM_ERR_NOTCONN, 0) unless defined($entity); my $key = pmda_pmid_text($cluster, $item); return (PM_ERR_PMID, 0) unless defined($key); # $pmda->log("vmware_fetch_callback $key $cluster:$item ($inst)\n"); my $pmvalue = $metric_values{$key}; return (PM_ERR_AGAIN, 0) unless defined($pmvalue); my $counters = ($pmvalue->value)[0]; if ($cluster == 0 && $item == 3) { my $uptime = pmda_uptime($counters->[0]); return ($uptime, 1); } return ($counters->[0], 1); } $pmda = PCP::PMDA->new('vmware', 90); $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.sys.host', 'Name of monitored VMware host', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'vmware.sys.interval', 'Interval at which VMware internally refreshes values', ''); $pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'vmware.sys.uptime', 'Uptime', 'Total time elapsed since last startup'); $pmda->add_metric(pmda_pmid(0,3), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.sys.uptime_s', 'Uptime', 'Total time elapsed since last startup'); $pmda->add_metric(pmda_pmid(1,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,-1,0,PM_SPACE_KBYTE,PM_TIME_SEC,0), 'vmware.net.usage', 'Network Usage (Average/Rate)', 'Aggregated network performance statistics.'); $pmda->add_metric(pmda_pmid(2,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,-1,0,PM_SPACE_KBYTE,PM_TIME_SEC,0), 'vmware.disk.usage', 'Disk Usage (Average/Rate)', 'Aggregated storage performance statistics.'); $pmda->add_metric(pmda_pmid(3,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.mem.usage', 'Memory Usage (Average/Absolute)', 'Memory usage as percentage of total configured or available memory'); $pmda->add_metric(pmda_pmid(3,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'vmware.mem.reserved_capacity', 'Memory Reserved Capacity', 'Amount of memory reserved by the virtual machines'); $pmda->add_metric(pmda_pmid(3,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.swap_in', 'Memory Swap In (Average/Absolute)', 'Amount of memory that is swapped in'); $pmda->add_metric(pmda_pmid(3,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.balloon', 'Memory Balloon (Average/Absolute)', 'Amount of memory used by memory control'); $pmda->add_metric(pmda_pmid(3,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.swap_out', 'Memory Swap Out (Average/Absolute)', 'Amount of memory that is swapped out'); $pmda->add_metric(pmda_pmid(3,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.unreserved', 'Memory Unreserved (Average/Absolute)', 'Amount of memory that is unreserved'); $pmda->add_metric(pmda_pmid(3,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.heap', 'Memory Heap (Average/Absolute)', 'Amount of memory allocated for heap'); $pmda->add_metric(pmda_pmid(3,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.overhead', 'Memory Overhead (Average/Absolute)', 'Amount of additional host memory allocated to the virtual machine'); $pmda->add_metric(pmda_pmid(3,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.zeroed', 'Memory Zero (Average/Absolute)', 'Amount of memory that is zeroed out'); $pmda->add_metric(pmda_pmid(3,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.active', 'Memory Active (Average/Absolute)', 'Amount of memory that is actively used'); $pmda->add_metric(pmda_pmid(3,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.swap_used', 'Memory Swap Used (Average/Absolute)', 'Amount of memory that is used by swap'); $pmda->add_metric(pmda_pmid(3,11), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.shared', 'Memory Shared (Average/Absolute)', 'Amount of memory that is shared'); $pmda->add_metric(pmda_pmid(3,12), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.granted', 'Memory Granted (Average/Absolute)', 'Amount of memory granted.'); $pmda->add_metric(pmda_pmid(3,13), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.consumed', 'Memory Consumed (Average/Absolute)', 'Amount of host memory consumed by the virtual machine for guest memory'); $pmda->add_metric(pmda_pmid(3,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.heap_free', 'Memory Heap Free (Average/Absolute)', 'Free space in memory heap'); $pmda->add_metric(pmda_pmid(3,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.state', 'Memory State', 'Memory State'); $pmda->add_metric(pmda_pmid(3,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.shared_common', 'Memory Shared Common (Average/Absolute)', 'Amount of memory that is shared by common'); $pmda->add_metric(pmda_pmid(3,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_KBYTE,0,0), 'vmware.mem.vmkernel', 'Memory Used by vmkernel', 'Amount of memory used by the vmkernel'); $pmda->add_metric(pmda_pmid(4,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE), 'vmware.cpu.usage', 'CPU Usage (Average/Rate)', 'CPU usage as a percentage over the collected interval'); $pmda->add_metric(pmda_pmid(4,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE), 'vmware.cpu.usage_mhz', 'CPU Usage in MHz (Average/Rate)', 'CPU usage in MHz over the collected interval.'); $pmda->add_metric(pmda_pmid(4,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE), 'vmware.cpu.reserved_capacity', 'CPU Reserved Capacity', 'Total CPU capacity reserved by the virtual machines'); $pmda->add_metric(pmda_pmid(5,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.throttled.one_min_average', 'CPU Throttled (1 min. average)', 'Amount of CPU resources over the limit that were refused, average over 1 minute'); $pmda->add_metric(pmda_pmid(5,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.throttled.five_min_average', 'CPU Throttled (5 min. average)', 'Amount of CPU resources over the limit that were refused, average over 5 minutes'); $pmda->add_metric(pmda_pmid(5,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.throttled.fifteen_min_average', 'CPU Throttled (15 min. average)', "Amount of CPU resources over the limit that were refused,\n" . "average over 15 minutes\n"); $pmda->add_metric(pmda_pmid(5,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.running.one_min_peak', 'CPU running peak over 1 minute', ''); $pmda->add_metric(pmda_pmid(5,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.running.five_min_peak', 'CPU running peak over 5 minutes', ''); $pmda->add_metric(pmda_pmid(5,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.running.fifteen_min_peak', 'CPU running peak over 15 minutes', ''); $pmda->add_metric(pmda_pmid(5,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'vmware.rescpu.group_sample_count', 'Group CPU Sample Count', 'Group CPU sample count'); $pmda->add_metric(pmda_pmid(5,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.active.one_min_peak', 'CPU Active (1 min. peak)', 'CPU active peak over 1 minute'); $pmda->add_metric(pmda_pmid(5,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.active.five_min_peak', 'CPU Active (5 min. peak)', 'CPU active peak over 5 minutes'); $pmda->add_metric(pmda_pmid(5,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.active.fifteen_min_peak', 'CPU Active (15 min. peak)', 'CPU active peak over 15 minutes'); $pmda->add_metric(pmda_pmid(5,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.running.one_min_average', 'CPU Running (1 min. average)', 'CPU running average over 1 minute'); $pmda->add_metric(pmda_pmid(5,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.running.five_min_average', 'CPU Running (5 min. average)', 'CPU running average over 5 minutes'); $pmda->add_metric(pmda_pmid(5,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.running.fifteen_min_average', 'CPU Running (15 min. average)', 'CPU running average over 15 minutes'); $pmda->add_metric(pmda_pmid(5,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.running.one_min_peak', 'CPU Running (1 min. peak)', 'CPU running peak over 1 minute'); $pmda->add_metric(pmda_pmid(5,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.running.five_min_peak', 'CPU Running (5 min. peak)', 'CPU running peak over 5 minutes'); $pmda->add_metric(pmda_pmid(5,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.running.fifteen_min_peak', 'CPU Running (15 min. peak)', 'CPU running peak over 15 minutes'); $pmda->add_metric(pmda_pmid(5,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'vmware.rescpu.group_sample_period', 'Group CPU Sample Period', 'Group CPU sample period'); $pmda->add_metric(pmda_pmid(5,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.active.one_min_average', 'CPU Active (1 min. average)', 'CPU active average over 1 minute'); $pmda->add_metric(pmda_pmid(5,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.active.five_min_average', 'CPU Active (5 min. average)', 'CPU active average over 5 minutes'); $pmda->add_metric(pmda_pmid(5,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'vmware.rescpu.active.fifteen_min_average', 'CPU Active (15 min. average)', 'CPU active average over 15 minutes'); $pmda->set_fetch(\&vmware_fetch); $pmda->set_fetch_callback(\&vmware_fetch_callback); $pmda->add_timer(5, \&vmware_timer_callback, 0); $pmda->set_user('pcp'); $pmda->run; vmware_disconnect(); =pod =head1 NAME pmdavmware - VMware performance metrics domain agent (PMDA) =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from a (possibly remote) VMware virtualisation host. This implementation uses the VMare Perl API (refer to the online docs at http://www.vmware.com/support/developer/viperltoolkit). VIPerl is a prerequisite for this PMDA, it needs to be installed and configured before attempting to use this agent. It is highly recommended that you test your VIPerl installation using the demo programs that are shipped with VIPerl, before attempting to use this PMDA. =head1 INSTALLATION In order to access performance data using the VIPerl API, it is necessary to be able to login to the metrics source. Hence, a valid VMware server name, user name and pass word are needed by the PMDA. These can be passed in on the command line (via the pmcd.conf file) or via a vmware.conf file in the PMDA directory. # cd $PCP_PMDAS_DIR/vmware # [ edit vmware.conf ] This file should contain three lines, such as: $server = 'vm.server.net'; $username = 'XXXX'; $password = 'YYYY'; Once this is setup, you can access the names and values for the vmware performance metrics by doing the following as root: # cd $PCP_PMDAS_DIR/vmware # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/vmware # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/vmware/vmware.conf configuration file for the B agent =item $PCP_PMDAS_DIR/vmware/Install installation script for the B agent =item $PCP_PMDAS_DIR/vmware/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/vmware.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1). pcp-3.8.12ubuntu1/src/pmdas/bonding/0000775000000000000000000000000012272262620014117 5ustar pcp-3.8.12ubuntu1/src/pmdas/bonding/Remove0000775000000000000000000000160512272262501015302 0ustar #!/bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the bonding PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=bonding pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/bonding/Install0000775000000000000000000000226412272262501015455 0ustar #!/bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Install the Bonding PMDA (bonded network interfaces) # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=bonding perl_opt=true daemon_opt=false forced_restart=false if ! test -d /sys/class/net; then echo "SYSFS not enabled in your kernel" exit 1 fi if ! test -f /sys/class/net/bonding_masters; then echo "Bonding statistics unavailable (load bonding module)" exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/bonding/GNUmakefile0000664000000000000000000000275412272262501016177 0ustar #!gmake # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = bonding PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) ifeq "$(TARGET_OS)" "linux" install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) else install: endif default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/bonding/pmdabonding.pl0000664000000000000000000001066012272262501016737 0ustar # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; my $pmda = PCP::PMDA->new('bonding', 96); my $sysfs = '/sys/class/net/'; sub bonding_interface_check { my @interfaces = (); my $instanceid = 0; if (open(BONDS, $sysfs . 'bonding_masters')) { my @bonds = split / /, ; foreach my $bond (@bonds) { chomp $bond; push @interfaces, $instanceid++, $bond; } close BONDS; } $pmda->replace_indom(0, \@interfaces); } sub bonding_fetch_callback { my ($cluster, $item, $inst) = @_; my $metric_name = pmda_pmid_name($cluster, $item); my ($path, $name, $value, $fh, @vals); #$pmda->log("bonding_fetch_callback $metric_name $cluster:$item ($inst)\n"); if ($inst == PM_IN_NULL) { return (PM_ERR_INST, 0); } if (!defined($metric_name)) { return (PM_ERR_PMID, 0); } # special case: failures count from /proc (no sysfs equivalent) if ($item == 7) { $value = 0; $name = '/proc/net/bonding/' . 'bond' . $inst; open($fh, $name) || return (PM_ERR_APPVERSION, 0); while (<$fh>) { if (m/^Link Failure Count: (\d+)$/) { $value += $1; } } close $fh; } else { $name = $metric_name; $path = $sysfs . 'bond' . $inst . '/bonding/'; $name =~ s/^bonding\./$path/; # special case: mode contains two values (name and type) if ($item == 5) { $name =~ s/\.type$//; } if ($item == 6) { $name =~ s/\.name$//; } open($fh, $name) || return (PM_ERR_APPVERSION, 0); $value = <$fh>; close $fh; if (!defined($value)) { return (PM_ERR_APPVERSION, 0); } if ($item == 5) { @vals = split / /, $value; $value = $vals[1]; } if ($item == 6) { @vals = split / /, $value; $value = $vals[0]; } chomp $value; } return ($value, 1); } $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_STRING, 0, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "bonding.slaves", '', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_STRING, 0, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "bonding.active_slave", '', ''); $pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U32, 0, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "bonding.use_carrier", '', ''); $pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U32, 0, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), "bonding.updelay", '', ''); $pmda->add_metric(pmda_pmid(0,4), PM_TYPE_U32, 0, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), "bonding.downdelay", '', ''); $pmda->add_metric(pmda_pmid(0,5), PM_TYPE_U32, 0, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "bonding.mode.type", '', ''); $pmda->add_metric(pmda_pmid(0,6), PM_TYPE_STRING, 0, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "bonding.mode.name", '', ''); $pmda->add_metric(pmda_pmid(0,7), PM_TYPE_U32, 0, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "bonding.failures", '', ''); $pmda->add_indom(0, [], '', ''); $pmda->set_fetch(\&bonding_interface_check); $pmda->set_instance(\&bonding_interface_check); $pmda->set_fetch_callback(\&bonding_fetch_callback); $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdabonding - Linux bonded interface performance metrics domain agent (PMDA) =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from bonded network interfaces in the Linux kernel. =head1 INSTALLATION If you want access to the names and values for the bonding performance metrics, do the following as root: # cd $PCP_PMDAS_DIR/bonding # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/bonding # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/bonding/Install installation script for the B agent =item $PCP_PMDAS_DIR/bonding/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/bonding.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1) and ifenslave(8). pcp-3.8.12ubuntu1/src/pmdas/gluster/0000775000000000000000000000000012272262620014164 5ustar pcp-3.8.12ubuntu1/src/pmdas/gluster/pmdagluster.python0000664000000000000000000003360312272262501017761 0ustar ''' Performance Metrics Domain Agent exporting Gluster filesystem metrics. ''' # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # import cpmapi as c_api from pcp.pmapi import pmUnits from pcp.pmda import PMDA, pmdaMetric, pmdaIndom from ctypes import c_int, c_long, c_float, POINTER, cast, Structure import xml.etree.cElementTree as xmltree from os import getenv import subprocess VOL_INFO_COMMAND = 'gluster --xml volume info' VOL_STOP_COMMAND = 'gluster --xml volume profile %s stop' VOL_START_COMMAND = 'gluster --xml volume profile %s start' VOL_STATS_COMMAND = 'gluster --xml volume profile %s info' FILEOPS = [ # append only, do not change the order (changes PMID) 'ACCESS', 'CREATE', 'DISCARD', 'ENTRYLK', 'FALLOCATE', 'FENTRYLK', 'FGETXATTR', 'FINODELK', 'FLUSH', 'FREMOVEXATTR', 'FSETATTR', 'FSETXATTR', 'FSTAT', 'FSYNC', 'FSYNCDIR', 'FTRUNCATE', 'FXATTROP', 'GETSPEC', 'GETXATTR', 'INODELK', 'LINK', 'LK', 'LOOKUP', 'MKDIR', 'MKNOD', 'OPEN', 'OPENDIR', 'RCHECKSUM', 'READDIR', 'READDIRP', 'READLINK', 'READV', 'REMOVEXATTR', 'RENAME', 'RMDIR', 'SETATTR', 'SETXATTR', 'STAT', 'STATFS', 'SYMLINK', 'TRUNCATE', 'UNLINK', 'WRITEV', 'XATTROP', ] FILEOPS_INDICES = {} class GlusterVolume(Structure): ''' Statistic values per-gluster-volume (volume indom cache lookup) ''' _fields_ = [("distCount", c_int), ("stripeCount", c_int), ("replicaCount", c_int), ("fopHitsEnabled", c_int), ("latencyEnabled", c_int)] class GlusterBrick(Structure): ''' Statistic values per-gluster-brick, within a volume (brick indom) ''' _fields_ = [("mintime", c_long * len(FILEOPS)), ("maxtime", c_long * len(FILEOPS)), ("avgtime", c_float * len(FILEOPS)), ("count", c_long * len(FILEOPS)), ("read_bytes", c_long), ("write_bytes", c_long)] class GlusterPMDA(PMDA): ''' Performance Metrics Domain Agent exporting gluster brick metrics. Install it and make basic use of it if you use glusterfs, as follows: # $PCP_PMDAS_DIR/gluster/Install $ pminfo -fmdtT gluster ''' # volumes and bricks instance domains volumes = {} bricks = {} def runVolumeInfo(self): ''' Execute the gluster volume info command to extract volume names ''' process = subprocess.Popen(self.vol_info, shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE) out, err = process.communicate() # self.log('Info command %s output: %s' % (self.vol_info, out)) return xmltree.fromstring(out) def runVolumeProfileInfo(self, volume): ''' Execute gluster volume profile info command for a given volume ''' command = self.vol_stats % volume process = subprocess.Popen(command, shell = True, stdout = subprocess.PIPE, stderr = subprocess.PIPE) out, err = process.communicate() # self.log('Profile command %s output: %s' % (command, out)) return xmltree.fromstring(out) def parseVolumeInfo(self, xml): ''' Extract the set of volume names from given gluster XML string ''' volumes = [] for volxml in xml.findall('volInfo/volumes'): volname = volxml.find('volume/name').text volumes.append(volname) volume = GlusterVolume() volume.distCount = int(volxml.find('volume/distCount').text) volume.stripeCount = int(volxml.find('volume/stripeCount').text) volume.replicaCount = int(volxml.find('volume/replicaCount').text) volume.fopHitsEnabled = 0 volume.latencyEnabled = 0 for option in volxml.findall('volume/options/option'): name = option.find('name').text value = option.find('value').text if (name == 'diagnostics.count-fop-hits' and value == 'on'): volume.fopHitsEnabled = 1 if (name == 'diagnostics.latency-measurement' and value == 'on'): volume.latencyEnabled = 1 self.volumes[volname] = volume # prepare the volume indom cache return volumes def parseVolumeProfileInfo(self, volume, xml): ''' Extract the metric values from a given gluster profile string ''' for brickxml in xml.findall('volProfile/brick'): brickname = brickxml.find('brickName').text brick = GlusterBrick() for fileop in brickxml.findall('cumulativeStats/fopStats/fop'): name = fileop.find('name').text fop = FILEOPS_INDICES[name] brick.count[fop] = long(fileop.find('hits').text) brick.avgtime[fop] = float(fileop.find('avgLatency').text) brick.mintime[fop] = long(float(fileop.find('minLatency').text)) brick.maxtime[fop] = long(float(fileop.find('maxLatency').text)) brick.read_bytes = long(brickxml.find('cumulativeStats/totalRead').text) brick.write_bytes = long(brickxml.find('cumulativeStats/totalWrite').text) self.bricks[brickname] = brick # prepare the bricks indom cache def gluster_refresh(self): ''' Refresh the values and instances for gluster volumes and bricks ''' xml = self.runVolumeInfo() if (xml != None): for vol in self.parseVolumeInfo(xml): xml = self.runVolumeProfileInfo(vol) if (xml != None): self.parseVolumeProfileInfo(vol, xml) def gluster_instance(self, serial): ''' Called once per "instance request" PDU ''' if (serial == 0 or serial == 1): self.gluster_fetch() def gluster_fetch(self): ''' Called once per "fetch" PDU ''' self.bricks.clear() self.volumes.clear() self.gluster_refresh() self.replace_indom(self.brick_indom, self.bricks) self.replace_indom(self.volume_indom, self.volumes) def gluster_fetch_thruput_callback(self, item, inst): ''' Returns a list of value,status (single pair) for thruput cluster Helper for the fetch callback ''' if (item < 0 or item > 2): return [c_api.PM_ERR_PMID, 0] voidp = self.inst_lookup(self.brick_indom, inst) if (voidp == None): return [c_api.PM_ERR_INST, 0] cache = cast(voidp, POINTER(GlusterBrick)) brick = cache.contents if (item == 0): return [brick.read_bytes, 1] return [brick.write_bytes, 1] def gluster_fetch_latency_callback(self, item, inst): ''' Returns a list of value,status (single pair) for latency cluster Helper for the fetch callback ''' if (item < 0 or item > len(FILEOPS) * 4): return [c_api.PM_ERR_PMID, 0] voidp = self.inst_lookup(self.brick_indom, inst) if (voidp == None): return [c_api.PM_ERR_INST, 0] cache = cast(voidp, POINTER(GlusterBrick)) brick = cache.contents fileop = item / 4 index = item % 4 if (index == 0): return [brick.mintime[fileop], 1] elif (index == 1): return [brick.maxtime[fileop], 1] elif (index == 2): return [brick.avgtime[fileop], 1] return [brick.count[fileop], 1] def gluster_fetch_volumes_callback(self, item, inst): ''' Returns a list of value,status (single pair) for volumes cluster Helper for the fetch callback ''' if (item < 0 or item > 3): return [c_api.PM_ERR_PMID, 0] voidp = self.inst_lookup(self.volume_indom, inst) if (voidp == None): return [c_api.PM_ERR_INST, 0] cached = cast(voidp, POINTER(GlusterVolume)) volume = cached.contents if (item == 0): enabled = volume.fopHitsEnabled if (enabled): enabled = volume.latencyEnabled return [enabled, 1] elif (item == 1): return [volume.distCount, 1] elif (item == 2): return [volume.stripeCount, 1] elif (item == 3): return [volume.replicaCount, 1] return [c_api.PM_ERR_PMID, 0] def gluster_fetch_callback(self, cluster, item, inst): ''' Main fetch callback, defers to helpers for each cluster. Returns a list of value,status (single pair) for requested pmid/inst ''' # self.log("fetch callback for %d.%d[%d]" % (cluster, item, inst)) if (cluster == 0): return self.gluster_fetch_thruput_callback(item, inst) elif (cluster == 1): return self.gluster_fetch_latency_callback(item, inst) elif (cluster == 2): return self.gluster_fetch_volumes_callback(item, inst) return [c_api.PM_ERR_PMID, 0] def gluster_store_volume_callback(self, inst, val): ''' Helper for the store callback, volume profile enabling/disabling ''' sts = 0 name = self.inst_name_lookup(self.volume_indom, inst) if (name == None): sts = c_api.PM_ERR_INST elif (val < 0): sts = c_api.PM_ERR_SIGN elif (val == 0): command = self.vol_stop % name # self.log("Running disable command: %s" % command) subprocess.call(command, shell =True, stdout = subprocess.PIPE, stderr = subprocess.PIPE) else: command = self.vol_start % name # self.log("Running enable command: %s" % command) subprocess.call(command, shell =True, stdout = subprocess.PIPE, stderr = subprocess.PIPE) return sts def gluster_store_callback(self, cluster, item, inst, val): ''' Store callback, executed when a request to write to a metric happens Defers to helpers for each storable metric. Returns a single value. ''' # self.log("store callback for %d.%d[%d]" % (cluster, item, inst)) if (cluster == 2 and item == 0): return self.gluster_store_volume_callback(inst, val) elif (cluster == 0 or cluster == 1): return c_api.PM_ERR_PERMISSION return c_api.PM_ERR_PMID def __init__(self, name, domain): PMDA.__init__(self, name, domain) self.vol_info = getenv('GLUSTER_VOL_INFO', VOL_INFO_COMMAND) self.vol_stop = getenv('GLUSTER_VOL_STOP', VOL_STOP_COMMAND) self.vol_start = getenv('GLUSTER_VOL_START', VOL_START_COMMAND) self.vol_stats = getenv('GLUSTER_VOL_STATS', VOL_STATS_COMMAND) self.volume_indom = self.indom(0) self.add_indom(pmdaIndom(self.volume_indom, self.volumes)) self.brick_indom = self.indom(1) self.add_indom(pmdaIndom(self.brick_indom, self.bricks)) self.add_metric(name + '.brick.read_bytes', pmdaMetric(self.pmid(0, 0), c_api.PM_TYPE_U64, self.brick_indom, c_api.PM_SEM_COUNTER, pmUnits(1, 0, 0, c_api.PM_SPACE_BYTE, 0, 0))) self.add_metric(name + '.brick.write_bytes', pmdaMetric(self.pmid(0, 1), c_api.PM_TYPE_U64, self.brick_indom, c_api.PM_SEM_COUNTER, pmUnits(1, 0, 0, c_api.PM_SPACE_BYTE, 0, 0))) item = 0 for fileop in FILEOPS: metricname = name + '.brick.latency.' + fileop.lower() + '.' self.add_metric(metricname + 'min', pmdaMetric(self.pmid(1, item), c_api.PM_TYPE_U64, self.brick_indom, c_api.PM_SEM_INSTANT, pmUnits(0, 1, 0, 0, c_api.PM_TIME_USEC, 0))) item += 1 self.add_metric(metricname + 'max', pmdaMetric(self.pmid(1, item), c_api.PM_TYPE_U64, self.brick_indom, c_api.PM_SEM_INSTANT, pmUnits(0, 1, 0, 0, c_api.PM_TIME_USEC, 0))) item += 1 self.add_metric(metricname + 'avg', pmdaMetric(self.pmid(1, item), c_api.PM_TYPE_FLOAT, self.brick_indom, c_api.PM_SEM_INSTANT, pmUnits(0, 1, 0, 0, c_api.PM_TIME_USEC, 0))) item += 1 self.add_metric(metricname + 'count', pmdaMetric(self.pmid(1, item), c_api.PM_TYPE_U64, self.brick_indom, c_api.PM_SEM_COUNTER, pmUnits(0, 0, 1, 0, 0, c_api.PM_COUNT_ONE))) item += 1 metricname = name + '.volume.' self.add_metric(metricname + 'profile', pmdaMetric(self.pmid(2, 0), c_api.PM_TYPE_32, self.volume_indom, c_api.PM_SEM_INSTANT, pmUnits(0, 0, 0, 0, 0, 0))) self.add_metric(metricname + 'dist.count', pmdaMetric(self.pmid(2, 1), c_api.PM_TYPE_32, self.volume_indom, c_api.PM_SEM_INSTANT, pmUnits(0, 0, 0, 0, 0, 0))) self.add_metric(metricname + 'stripe.count', pmdaMetric(self.pmid(2, 2), c_api.PM_TYPE_32, self.volume_indom, c_api.PM_SEM_INSTANT, pmUnits(0, 0, 0, 0, 0, 0))) self.add_metric(metricname + 'replica.count', pmdaMetric(self.pmid(2, 3), c_api.PM_TYPE_32, self.volume_indom, c_api.PM_SEM_INSTANT, pmUnits(0, 0, 0, 0, 0, 0))) self.set_fetch(self.gluster_fetch) self.set_instance(self.gluster_instance) self.set_fetch_callback(self.gluster_fetch_callback) self.set_store_callback(self.gluster_store_callback) if __name__ == '__main__': for index in range(0, len(FILEOPS)): fileop = FILEOPS[index] FILEOPS_INDICES[fileop] = index GlusterPMDA('gluster', 118).run() pcp-3.8.12ubuntu1/src/pmdas/gluster/Remove0000664000000000000000000000123512272262501015343 0ustar #! /bin/sh # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the gluster PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=gluster pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/gluster/Install0000664000000000000000000000132412272262501015513 0ustar #! /bin/sh # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the gluster PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=gluster python_opt=true daemon_opt=false forced_restart=true pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/gluster/GNUmakefile0000664000000000000000000000200612272262501016232 0ustar # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = gluster PYSCRIPT = pmda$(IAM).python LSRCFILES = Install Remove $(PYSCRIPT) DOMAIN = GLUSTER PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LDIRT = domain.h $(IAM).log default_pcp default: check_domain include $(BUILDRULES) install_pcp install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 $(PYSCRIPT) $(PMDADIR)/$(PYSCRIPT) check_domain: ../../pmns/stdpmid $(DOMAIN_PYTHONRULE) pcp-3.8.12ubuntu1/src/pmdas/mysql/0000775000000000000000000000000012272262620013644 5ustar pcp-3.8.12ubuntu1/src/pmdas/mysql/pmdamysql.pl0000664000000000000000000027233612272262501016223 0ustar # # Copyright (c) 2012-2013 Chandana De Silva. # Copyright (c) 2012 Red Hat. # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; use DBI; my $database = 'DBI:mysql:mysql'; my $username = 'dbmonitor'; my $password = 'dbmonitor'; # Configuration files for overriding the above settings for my $file ( '/etc/pcpdbi.conf', # system defaults (lowest priority) pmda_config('PCP_PMDAS_DIR') . '/mysql/mysql.conf', './mysql.conf' ) { # current directory (high priority) eval `cat $file` unless ! -f $file; } use vars qw( $pmda %status %variables @processes %slave_status ); use vars qw( $dbh $sth_variables $sth_status $sth_processes $sth_slave_status ); my $process_indom = 0; my @process_instances; # translate yes/no true/false on/off to 1/0 sub mysql_txt2num { my ($value) = lc($_[0]); if (!defined($value)) { return (PM_ERR_AGAIN, 0); } elsif ($value eq "yes" || $value eq "true" || $value eq "on") { return 1; } elsif ($value eq "no" || $value eq "false" || $value eq "off") { return 0; } else { return -1; } } sub mysql_connection_setup { # $pmda->log("mysql_connection_setup\n"); if (!defined($dbh)) { $dbh = DBI->connect($database, $username, $password); if (defined($dbh)) { # set the db handle to undef in case of any failure # this will force a database reconnect $dbh->{HandleError} = sub { $dbh = undef; }; $pmda->log("MySQL connection established\n"); $sth_variables = $dbh->prepare('show variables'); $sth_status = $dbh->prepare('show global status'); $sth_processes = $dbh->prepare('show processlist'); $sth_slave_status = $dbh->prepare('show slave status'); } } } sub mysql_variables_refresh { # $pmda->log("mysql_variables_refresh\n"); %variables = (); # clear any previous contents if (defined($dbh)) { $sth_variables->execute(); my $result = $sth_variables->fetchall_arrayref(); for my $i (0 .. $#{$result}) { $variables{$result->[$i][0]} = $result->[$i][1]; } } } sub mysql_status_refresh { # $pmda->log("mysql_status_refresh\n"); %status = (); # clear any previous contents if (defined($dbh)) { $sth_status->execute(); my $result = $sth_status->fetchall_arrayref(); my $txtnum; my $txtnumvar; for my $i (0 .. $#{$result}) { my $key = lcfirst $result->[$i][0]; $status{$key} = $result->[$i][1]; # if this status value has a yes/no type value, get it translated $txtnum = mysql_txt2num($result->[$i][1]); if ($txtnum ge 0) { $txtnumvar=$key . "_num"; $status{$txtnumvar} = $txtnum; } } } } sub mysql_process_refresh { # $pmda->log("mysql_process_refresh\n"); @processes = (); # clear any previous contents @process_instances = (); # refresh indom too if (defined($dbh)) { $sth_processes->execute(); my $result = $sth_processes->fetchall_arrayref(); for my $i (0 .. $#{$result}) { $process_instances[($i*2)] = $i; $process_instances[($i*2)+1] = "$result->[$i][0]"; $processes[$i] = $result->[$i]; } } $pmda->replace_indom($process_indom, \@process_instances); } sub mysql_slave_status_refresh { # $pmda->log("mysql_slave_status_refresh\n"); %slave_status = (); # clear any previous contents if (defined($dbh)) { $sth_slave_status->execute(); my $result = $sth_slave_status->fetchrow_hashref(); my $txtnum; my $txtnumvar; while ( my ($key, $value) = each(%$result) ) { $slave_status{lc $key} = $value; # if this status value has a yes/no type value, get it translated $txtnum = mysql_txt2num($value); if ($txtnum ge 0) { $txtnumvar=lc($key) . "_num"; $slave_status{$txtnumvar} = $txtnum; } } } } sub mysql_refresh { my ($cluster) = @_; # $pmda->log("mysql_refresh $cluster\n"); if ($cluster == 0) { mysql_status_refresh; } elsif ($cluster == 1) { mysql_variables_refresh; } elsif ($cluster == 2) { mysql_process_refresh; } elsif ($cluster == 3) { mysql_slave_status_refresh; } } sub mysql_fetch_callback { my ($cluster, $item, $inst) = @_; my $metric_name = pmda_pmid_name($cluster, $item); my ($mysql_name, $value, @procs); # $pmda->log("mysql_fetch_callback $metric_name $cluster:$item ($inst)\n"); if (!defined($metric_name)) { return (PM_ERR_PMID, 0); } $mysql_name = $metric_name; if ($cluster == 2) { if ($inst < 0) { return (PM_ERR_INST, 0); } if ($inst > @process_instances) { return (PM_ERR_INST, 0); } $value = $processes[$inst]; if (!defined($value)) { return (PM_ERR_INST, 0); } @procs = @$value; if (!defined($procs[$item]) && $item == 6) { return ("?", 1); } if (!defined($procs[$item])) { return (PM_ERR_APPVERSION, 0); } return ($procs[$item], 1); } if ($inst != PM_IN_NULL) { return (PM_ERR_INST, 0); } if ($cluster == 0) { $mysql_name =~ s/^mysql\.status\.//; $value = $status{$mysql_name}; if (!defined($value)) { return (PM_ERR_APPVERSION, 0); } return ($value, 1); } elsif ($cluster == 1) { $mysql_name =~ s/^mysql\.variables\.//; $value = $variables{$mysql_name}; if (!defined($value)) { return (PM_ERR_APPVERSION, 0); } return ($value, 1); } elsif ($cluster == 3) { $mysql_name =~ s/^mysql\.slave_status\.//; $value = $slave_status{$mysql_name}; if (!defined($value)) { return (PM_ERR_APPVERSION, 0); } return ($value, 1); } return (PM_ERR_PMID, 0); } $pmda = PCP::PMDA->new('mysql', 66); $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.aborted_clients', '', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.aborted_connects', '', ''); $pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.status.binlog_cache_disk_use', '', ''); $pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.status.binlog_cache_use', '', ''); $pmda->add_metric(pmda_pmid(0,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.status.bytes_received', '', ''); $pmda->add_metric(pmda_pmid(0,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.status.bytes_sent', '', ''); $pmda->add_metric(pmda_pmid(0,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_admin_commands', '', ''); $pmda->add_metric(pmda_pmid(0,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_alter_db', '', ''); $pmda->add_metric(pmda_pmid(0,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_alter_table', '', ''); $pmda->add_metric(pmda_pmid(0,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_analyze', '', ''); $pmda->add_metric(pmda_pmid(0,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_backup_table', '', ''); $pmda->add_metric(pmda_pmid(0,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_begin', '', ''); $pmda->add_metric(pmda_pmid(0,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_call_procedure', '', ''); $pmda->add_metric(pmda_pmid(0,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_change_db', '', ''); $pmda->add_metric(pmda_pmid(0,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_change_master', '', ''); $pmda->add_metric(pmda_pmid(0,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_check', '', ''); $pmda->add_metric(pmda_pmid(0,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_checksum', '', ''); $pmda->add_metric(pmda_pmid(0,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_commit', '', ''); $pmda->add_metric(pmda_pmid(0,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_create_db', '', ''); $pmda->add_metric(pmda_pmid(0,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_create_function', '', ''); $pmda->add_metric(pmda_pmid(0,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_create_index', '', ''); $pmda->add_metric(pmda_pmid(0,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_create_table', '', ''); $pmda->add_metric(pmda_pmid(0,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_create_user', '', ''); $pmda->add_metric(pmda_pmid(0,23), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_dealloc_sql', '', ''); $pmda->add_metric(pmda_pmid(0,24), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_delete', '', ''); $pmda->add_metric(pmda_pmid(0,25), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_delete_multi', '', ''); $pmda->add_metric(pmda_pmid(0,26), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_do', '', ''); $pmda->add_metric(pmda_pmid(0,27), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_drop_db', '', ''); $pmda->add_metric(pmda_pmid(0,28), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_drop_function', '', ''); $pmda->add_metric(pmda_pmid(0,29), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_drop_index', '', ''); $pmda->add_metric(pmda_pmid(0,30), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_drop_table', '', ''); $pmda->add_metric(pmda_pmid(0,31), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_drop_user', '', ''); $pmda->add_metric(pmda_pmid(0,32), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_execute_sql', '', ''); $pmda->add_metric(pmda_pmid(0,33), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_flush', '', ''); $pmda->add_metric(pmda_pmid(0,34), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_grant', '', ''); $pmda->add_metric(pmda_pmid(0,35), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_ha_close', '', ''); $pmda->add_metric(pmda_pmid(0,36), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_ha_open', '', ''); $pmda->add_metric(pmda_pmid(0,37), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_ha_read', '', ''); $pmda->add_metric(pmda_pmid(0,38), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_help', '', ''); $pmda->add_metric(pmda_pmid(0,39), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_insert', '', ''); $pmda->add_metric(pmda_pmid(0,40), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_insert_select', '', ''); $pmda->add_metric(pmda_pmid(0,41), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_kill', '', ''); $pmda->add_metric(pmda_pmid(0,42), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_load', '', ''); $pmda->add_metric(pmda_pmid(0,43), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_load_master_data', '', ''); $pmda->add_metric(pmda_pmid(0,44), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_load_master_table', '', ''); $pmda->add_metric(pmda_pmid(0,45), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_lock_tables', '', ''); $pmda->add_metric(pmda_pmid(0,46), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_optimize', '', ''); $pmda->add_metric(pmda_pmid(0,47), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_preload_keys', '', ''); $pmda->add_metric(pmda_pmid(0,48), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_prepare_sql', '', ''); $pmda->add_metric(pmda_pmid(0,49), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_purge', '', ''); $pmda->add_metric(pmda_pmid(0,50), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_purge_before_date', '', ''); $pmda->add_metric(pmda_pmid(0,51), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_rename_table', '', ''); $pmda->add_metric(pmda_pmid(0,52), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_repair', '', ''); $pmda->add_metric(pmda_pmid(0,53), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_replace', '', ''); $pmda->add_metric(pmda_pmid(0,54), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_replace_select', '', ''); $pmda->add_metric(pmda_pmid(0,55), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_reset', '', ''); $pmda->add_metric(pmda_pmid(0,56), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_restore_table', '', ''); $pmda->add_metric(pmda_pmid(0,57), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_revoke', '', ''); $pmda->add_metric(pmda_pmid(0,58), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_revoke_all', '', ''); $pmda->add_metric(pmda_pmid(0,59), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_rollback', '', ''); $pmda->add_metric(pmda_pmid(0,60), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_savepoint', '', ''); $pmda->add_metric(pmda_pmid(0,61), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_select', '', ''); $pmda->add_metric(pmda_pmid(0,62), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_set_option', '', ''); $pmda->add_metric(pmda_pmid(0,63), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_binlog_events', '', ''); $pmda->add_metric(pmda_pmid(0,64), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_binlogs', '', ''); $pmda->add_metric(pmda_pmid(0,65), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_charsets', '', ''); $pmda->add_metric(pmda_pmid(0,66), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_collations', '', ''); $pmda->add_metric(pmda_pmid(0,67), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_column_types', '', ''); $pmda->add_metric(pmda_pmid(0,68), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_create_db', '', ''); $pmda->add_metric(pmda_pmid(0,69), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_create_table', '', ''); $pmda->add_metric(pmda_pmid(0,70), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_databases', '', ''); $pmda->add_metric(pmda_pmid(0,71), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_errors', '', ''); $pmda->add_metric(pmda_pmid(0,72), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_fields', '', ''); $pmda->add_metric(pmda_pmid(0,73), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_grants', '', ''); $pmda->add_metric(pmda_pmid(0,74), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_innodb_status', '', ''); $pmda->add_metric(pmda_pmid(0,75), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_keys', '', ''); $pmda->add_metric(pmda_pmid(0,76), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_logs', '', ''); $pmda->add_metric(pmda_pmid(0,77), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_master_status', '', ''); $pmda->add_metric(pmda_pmid(0,78), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_ndb_status', '', ''); $pmda->add_metric(pmda_pmid(0,79), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_new_master', '', ''); $pmda->add_metric(pmda_pmid(0,80), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_open_tables', '', ''); $pmda->add_metric(pmda_pmid(0,81), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_privileges', '', ''); $pmda->add_metric(pmda_pmid(0,82), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_processlist', '', ''); $pmda->add_metric(pmda_pmid(0,83), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_slave_hosts', '', ''); $pmda->add_metric(pmda_pmid(0,84), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_slave_status', '', ''); $pmda->add_metric(pmda_pmid(0,85), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_status', '', ''); $pmda->add_metric(pmda_pmid(0,86), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_storage_engines', '', ''); $pmda->add_metric(pmda_pmid(0,87), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_tables', '', ''); $pmda->add_metric(pmda_pmid(0,88), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_triggers', '', ''); $pmda->add_metric(pmda_pmid(0,89), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_variables', '', ''); $pmda->add_metric(pmda_pmid(0,90), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_show_warnings', '', ''); $pmda->add_metric(pmda_pmid(0,91), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_slave_start', '', ''); $pmda->add_metric(pmda_pmid(0,92), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_slave_stop', '', ''); $pmda->add_metric(pmda_pmid(0,93), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_stmt_close', '', ''); $pmda->add_metric(pmda_pmid(0,94), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_stmt_execute', '', ''); $pmda->add_metric(pmda_pmid(0,95), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_stmt_fetch', '', ''); $pmda->add_metric(pmda_pmid(0,96), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_stmt_prepare', '', ''); $pmda->add_metric(pmda_pmid(0,97), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_stmt_reset', '', ''); $pmda->add_metric(pmda_pmid(0,98), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_stmt_send_long_data', '', ''); $pmda->add_metric(pmda_pmid(0,99), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_truncate', '', ''); $pmda->add_metric(pmda_pmid(0,100), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_unlock_tables', '', ''); $pmda->add_metric(pmda_pmid(0,101), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_update', '', ''); $pmda->add_metric(pmda_pmid(0,102), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_update_multi', '', ''); $pmda->add_metric(pmda_pmid(0,103), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_xa_commit', '', ''); $pmda->add_metric(pmda_pmid(0,104), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_xa_end', '', ''); $pmda->add_metric(pmda_pmid(0,105), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_xa_prepare', '', ''); $pmda->add_metric(pmda_pmid(0,106), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_xa_recover', '', ''); $pmda->add_metric(pmda_pmid(0,107), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_xa_rollback', '', ''); $pmda->add_metric(pmda_pmid(0,108), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.com_xa_start', '', ''); $pmda->add_metric(pmda_pmid(0,109), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.compression', '', ''); $pmda->add_metric(pmda_pmid(0,110), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.connections', '', ''); $pmda->add_metric(pmda_pmid(0,111), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.created_tmp_disk_tables', '', ''); $pmda->add_metric(pmda_pmid(0,112), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.created_tmp_files', '', ''); $pmda->add_metric(pmda_pmid(0,113), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.created_tmp_tables', '', ''); $pmda->add_metric(pmda_pmid(0,114), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.delayed_errors', '', ''); $pmda->add_metric(pmda_pmid(0,115), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.delayed_insert_threads', '', ''); $pmda->add_metric(pmda_pmid(0,116), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.delayed_writes', '', ''); $pmda->add_metric(pmda_pmid(0,117), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.flush_commands', '', ''); $pmda->add_metric(pmda_pmid(0,118), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_commit', '', ''); $pmda->add_metric(pmda_pmid(0,119), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_delete', '', ''); $pmda->add_metric(pmda_pmid(0,120), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_discover', '', ''); $pmda->add_metric(pmda_pmid(0,121), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_prepare', '', ''); $pmda->add_metric(pmda_pmid(0,122), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_read_first', '', ''); $pmda->add_metric(pmda_pmid(0,123), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_read_key', '', ''); $pmda->add_metric(pmda_pmid(0,124), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_read_next', '', ''); $pmda->add_metric(pmda_pmid(0,125), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_read_prev', '', ''); $pmda->add_metric(pmda_pmid(0,126), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_read_rnd', '', ''); $pmda->add_metric(pmda_pmid(0,127), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_read_rnd_next', '', ''); $pmda->add_metric(pmda_pmid(0,128), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_rollback', '', ''); $pmda->add_metric(pmda_pmid(0,129), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_savepoint', '', ''); $pmda->add_metric(pmda_pmid(0,130), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_savepoint_rollback', '', ''); $pmda->add_metric(pmda_pmid(0,131), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_update', '', ''); $pmda->add_metric(pmda_pmid(0,132), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.handler_write', '', ''); $pmda->add_metric(pmda_pmid(0,133), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_pages_data', '', ''); $pmda->add_metric(pmda_pmid(0,134), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_pages_dirty', '', ''); $pmda->add_metric(pmda_pmid(0,135), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_pages_flushed', '', ''); $pmda->add_metric(pmda_pmid(0,136), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_pages_free', '', ''); $pmda->add_metric(pmda_pmid(0,137), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_pages_latched', '', ''); $pmda->add_metric(pmda_pmid(0,138), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_pages_misc', '', ''); $pmda->add_metric(pmda_pmid(0,139), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_pages_total', '', ''); $pmda->add_metric(pmda_pmid(0,140), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_read_ahead_rnd', '', ''); $pmda->add_metric(pmda_pmid(0,141), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_read_ahead_seq', '', ''); $pmda->add_metric(pmda_pmid(0,142), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_read_requests', '', ''); $pmda->add_metric(pmda_pmid(0,143), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_reads', '', ''); $pmda->add_metric(pmda_pmid(0,144), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_wait_free', '', ''); $pmda->add_metric(pmda_pmid(0,145), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_buffer_pool_write_requests', '', ''); $pmda->add_metric(pmda_pmid(0,146), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_data_fsyncs', '', ''); $pmda->add_metric(pmda_pmid(0,147), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_data_pending_fsyncs', '', ''); $pmda->add_metric(pmda_pmid(0,148), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_data_pending_reads', '', ''); $pmda->add_metric(pmda_pmid(0,149), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_data_pending_writes', '', ''); $pmda->add_metric(pmda_pmid(0,150), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.status.innodb_data_read', '', ''); $pmda->add_metric(pmda_pmid(0,151), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_data_reads', '', ''); $pmda->add_metric(pmda_pmid(0,152), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_data_writes', '', ''); $pmda->add_metric(pmda_pmid(0,153), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.status.innodb_data_written', '', ''); $pmda->add_metric(pmda_pmid(0,154), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_dblwr_pages_written', '', ''); $pmda->add_metric(pmda_pmid(0,155), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_dblwr_writes', '', ''); $pmda->add_metric(pmda_pmid(0,156), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_log_waits', '', ''); $pmda->add_metric(pmda_pmid(0,157), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_log_write_requests', '', ''); $pmda->add_metric(pmda_pmid(0,158), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_log_writes', '', ''); $pmda->add_metric(pmda_pmid(0,159), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_os_log_fsyncs', '', ''); $pmda->add_metric(pmda_pmid(0,160), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_os_log_pending_fsyncs', '', ''); $pmda->add_metric(pmda_pmid(0,161), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_os_log_pending_writes', '', ''); $pmda->add_metric(pmda_pmid(0,162), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.status.innodb_os_log_written', '', ''); $pmda->add_metric(pmda_pmid(0,163), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.status.innodb_page_size', '', ''); $pmda->add_metric(pmda_pmid(0,164), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_pages_created', '', ''); $pmda->add_metric(pmda_pmid(0,165), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_pages_read', '', ''); $pmda->add_metric(pmda_pmid(0,166), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_pages_written', '', ''); $pmda->add_metric(pmda_pmid(0,167), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_row_lock_current_waits', '', ''); $pmda->add_metric(pmda_pmid(0,168), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'mysql.status.innodb_row_lock_time', '', ''); $pmda->add_metric(pmda_pmid(0,169), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'mysql.status.innodb_row_lock_time_avg', '', ''); $pmda->add_metric(pmda_pmid(0,170), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'mysql.status.innodb_row_lock_time_max', '', ''); $pmda->add_metric(pmda_pmid(0,171), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_row_lock_waits', '', ''); $pmda->add_metric(pmda_pmid(0,172), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_rows_deleted', '', ''); $pmda->add_metric(pmda_pmid(0,173), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_rows_inserted', '', ''); $pmda->add_metric(pmda_pmid(0,174), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_rows_read', '', ''); $pmda->add_metric(pmda_pmid(0,175), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.innodb_rows_updated', '', ''); $pmda->add_metric(pmda_pmid(0,176), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.key_blocks_not_flushed', '', ''); $pmda->add_metric(pmda_pmid(0,177), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.key_blocks_unused', '', ''); $pmda->add_metric(pmda_pmid(0,178), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.key_blocks_used', '', ''); $pmda->add_metric(pmda_pmid(0,179), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.key_read_requests', '', ''); $pmda->add_metric(pmda_pmid(0,180), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.key_reads', '', ''); $pmda->add_metric(pmda_pmid(0,181), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.key_write_requests', '', ''); $pmda->add_metric(pmda_pmid(0,182), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.key_writes', '', ''); $pmda->add_metric(pmda_pmid(0,183), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.last_query_cost', '', ''); $pmda->add_metric(pmda_pmid(0,184), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.max_used_connections', '', ''); $pmda->add_metric(pmda_pmid(0,185), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ndb_cluster_node_id', '', ''); $pmda->add_metric(pmda_pmid(0,186), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ndb_config_from_host', '', ''); $pmda->add_metric(pmda_pmid(0,187), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ndb_config_from_port', '', ''); $pmda->add_metric(pmda_pmid(0,188), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ndb_number_of_data_nodes', '', ''); $pmda->add_metric(pmda_pmid(0,189), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.not_flushed_delayed_rows', '', ''); $pmda->add_metric(pmda_pmid(0,190), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.open_files', '', ''); $pmda->add_metric(pmda_pmid(0,191), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.open_streams', '', ''); $pmda->add_metric(pmda_pmid(0,192), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.open_tables', '', ''); $pmda->add_metric(pmda_pmid(0,193), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.opened_tables', '', ''); $pmda->add_metric(pmda_pmid(0,194), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.prepared_stmt_count', '', ''); $pmda->add_metric(pmda_pmid(0,195), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.qcache_free_blocks', '', ''); $pmda->add_metric(pmda_pmid(0,196), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.status.qcache_free_memory', '', ''); $pmda->add_metric(pmda_pmid(0,197), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.qcache_hits', '', ''); $pmda->add_metric(pmda_pmid(0,198), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.qcache_inserts', '', ''); $pmda->add_metric(pmda_pmid(0,199), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.qcache_lowmem_prunes', '', ''); $pmda->add_metric(pmda_pmid(0,200), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.qcache_not_cached', '', ''); $pmda->add_metric(pmda_pmid(0,201), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.qcache_queries_in_cache', '', ''); $pmda->add_metric(pmda_pmid(0,202), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.qcache_total_blocks', '', ''); $pmda->add_metric(pmda_pmid(0,203), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.questions', '', ''); $pmda->add_metric(pmda_pmid(0,204), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.rpl_status', '', ''); $pmda->add_metric(pmda_pmid(0,205), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.select_full_join', '', ''); $pmda->add_metric(pmda_pmid(0,206), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.select_full_range_join', '', ''); $pmda->add_metric(pmda_pmid(0,207), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.select_range', '', ''); $pmda->add_metric(pmda_pmid(0,208), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.select_range_check', '', ''); $pmda->add_metric(pmda_pmid(0,209), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.select_scan', '', ''); $pmda->add_metric(pmda_pmid(0,210), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.slave_open_temp_tables', '', ''); $pmda->add_metric(pmda_pmid(0,211), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.slave_retried_transactions', '', ''); $pmda->add_metric(pmda_pmid(0,212), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.slave_running', '', ''); $pmda->add_metric(pmda_pmid(0,213), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.slow_launch_threads', '', ''); $pmda->add_metric(pmda_pmid(0,214), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.slow_queries', '', ''); $pmda->add_metric(pmda_pmid(0,215), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.sort_merge_passes', '', ''); $pmda->add_metric(pmda_pmid(0,216), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.sort_range', '', ''); $pmda->add_metric(pmda_pmid(0,217), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.sort_rows', '', ''); $pmda->add_metric(pmda_pmid(0,218), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.sort_scan', '', ''); $pmda->add_metric(pmda_pmid(0,219), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ssl_accept_renegotiates', '', ''); $pmda->add_metric(pmda_pmid(0,220), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.ssl_accepts', '', ''); $pmda->add_metric(pmda_pmid(0,221), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.ssl_callback_cache_hits', '', ''); $pmda->add_metric(pmda_pmid(0,222), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ssl_cipher', '', ''); $pmda->add_metric(pmda_pmid(0,223), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ssl_cipher_list', '', ''); $pmda->add_metric(pmda_pmid(0,224), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.ssl_client_connects', '', ''); $pmda->add_metric(pmda_pmid(0,225), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.ssl_connect_renegotiates', '', ''); $pmda->add_metric(pmda_pmid(0,226), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ssl_ctx_verify_depth', '', ''); $pmda->add_metric(pmda_pmid(0,227), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ssl_ctx_verify_mode', '', ''); $pmda->add_metric(pmda_pmid(0,228), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.status.ssl_default_timeout', '', ''); $pmda->add_metric(pmda_pmid(0,229), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.ssl_finished_accepts', '', ''); $pmda->add_metric(pmda_pmid(0,230), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.ssl_finished_connects', '', ''); $pmda->add_metric(pmda_pmid(0,231), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.ssl_session_cache_hits', '', ''); $pmda->add_metric(pmda_pmid(0,232), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.ssl_session_cache_misses', '', ''); $pmda->add_metric(pmda_pmid(0,233), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ssl_session_cache_mode', '', ''); $pmda->add_metric(pmda_pmid(0,234), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.ssl_session_cache_overflows', '', ''); $pmda->add_metric(pmda_pmid(0,235), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ssl_session_cache_size', '', ''); $pmda->add_metric(pmda_pmid(0,236), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.ssl_session_cache_timeouts', '', ''); $pmda->add_metric(pmda_pmid(0,237), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.ssl_sessions_reused', '', ''); $pmda->add_metric(pmda_pmid(0,238), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ssl_used_session_cache_entries', '', ''); $pmda->add_metric(pmda_pmid(0,239), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ssl_verify_depth', '', ''); $pmda->add_metric(pmda_pmid(0,240), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ssl_verify_mode', '', ''); $pmda->add_metric(pmda_pmid(0,241), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.ssl_version', '', ''); $pmda->add_metric(pmda_pmid(0,242), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.table_locks_immediate', '', ''); $pmda->add_metric(pmda_pmid(0,243), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.table_locks_waited', '', ''); $pmda->add_metric(pmda_pmid(0,244), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.tc_log_max_pages_used', '', ''); $pmda->add_metric(pmda_pmid(0,245), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.tc_log_page_size', '', ''); $pmda->add_metric(pmda_pmid(0,246), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.status.tc_log_page_waits', '', ''); $pmda->add_metric(pmda_pmid(0,247), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.threads_cached', '', ''); $pmda->add_metric(pmda_pmid(0,248), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.threads_connected', '', ''); $pmda->add_metric(pmda_pmid(0,249), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.threads_created', '', ''); $pmda->add_metric(pmda_pmid(0,250), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.threads_running', '', ''); $pmda->add_metric(pmda_pmid(0,251), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.status.uptime', '', ''); $pmda->add_metric(pmda_pmid(0,252), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.status.uptime_since_flush_status', '', ''); $pmda->add_metric(pmda_pmid(0,253), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.slave_running_num', '', ''); $pmda->add_metric(pmda_pmid(0,254), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.status.compression_num', '', ''); $pmda->add_metric(pmda_pmid(1,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.auto_increment_increment', '', ''); $pmda->add_metric(pmda_pmid(1,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.auto_increment_offset', '', ''); $pmda->add_metric(pmda_pmid(1,2), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.automatic_sp_privileges', '', ''); $pmda->add_metric(pmda_pmid(1,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.back_log', '', ''); $pmda->add_metric(pmda_pmid(1,4), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.basedir', '', ''); $pmda->add_metric(pmda_pmid(1,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.binlog_cache_size', '', ''); $pmda->add_metric(pmda_pmid(1,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.bulk_insert_buffer_size', '', ''); $pmda->add_metric(pmda_pmid(1,6), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.character_set_client', '', ''); $pmda->add_metric(pmda_pmid(1,7), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.character_set_connection', '', ''); $pmda->add_metric(pmda_pmid(1,8), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.character_set_database', '', ''); $pmda->add_metric(pmda_pmid(1,9), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.character_set_filesystem', '', ''); $pmda->add_metric(pmda_pmid(1,10), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.character_set_results', '', ''); $pmda->add_metric(pmda_pmid(1,11), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.character_set_server', '', ''); $pmda->add_metric(pmda_pmid(1,12), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.character_set_system', '', ''); $pmda->add_metric(pmda_pmid(1,13), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.character_sets_dir', '', ''); $pmda->add_metric(pmda_pmid(1,14), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.collation_connection', '', ''); $pmda->add_metric(pmda_pmid(1,15), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.collation_database', '', ''); $pmda->add_metric(pmda_pmid(1,16), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.collation_server', '', ''); $pmda->add_metric(pmda_pmid(1,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.completion_type', '', ''); $pmda->add_metric(pmda_pmid(1,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.concurrent_insert', '', ''); $pmda->add_metric(pmda_pmid(1,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.variables.connect_timeout', '', ''); $pmda->add_metric(pmda_pmid(1,20), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.datadir', '', ''); $pmda->add_metric(pmda_pmid(1,21), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.date_format', '', ''); $pmda->add_metric(pmda_pmid(1,22), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.datetime_format', '', ''); $pmda->add_metric(pmda_pmid(1,23), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.default_week_format', '', ''); $pmda->add_metric(pmda_pmid(1,24), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.delay_key_write', '', ''); $pmda->add_metric(pmda_pmid(1,25), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.delayed_insert_limit', '', ''); $pmda->add_metric(pmda_pmid(1,26), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.variables.delayed_insert_timeout', '', ''); $pmda->add_metric(pmda_pmid(1,27), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.delayed_queue_size', '', ''); $pmda->add_metric(pmda_pmid(1,28), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.div_precision_increment', '', ''); $pmda->add_metric(pmda_pmid(1,29), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.keep_files_on_create', '', ''); $pmda->add_metric(pmda_pmid(1,30), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.engine_condition_pushdown', '', ''); $pmda->add_metric(pmda_pmid(1,31), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.expire_logs_days', '', ''); $pmda->add_metric(pmda_pmid(1,32), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.flush', '', ''); $pmda->add_metric(pmda_pmid(1,33), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.variables.flush_time', '', ''); $pmda->add_metric(pmda_pmid(1,34), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ft_boolean_syntax', '', ''); $pmda->add_metric(pmda_pmid(1,35), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ft_max_word_len', '', ''); $pmda->add_metric(pmda_pmid(1,35), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ft_min_word_len', '', ''); $pmda->add_metric(pmda_pmid(1,35), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ft_query_expansion_limit', '', ''); $pmda->add_metric(pmda_pmid(1,36), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ft_stopword_file', '', ''); $pmda->add_metric(pmda_pmid(1,37), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.group_concat_max_len', '', ''); $pmda->add_metric(pmda_pmid(1,38), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_archive', '', ''); $pmda->add_metric(pmda_pmid(1,39), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_bdb', '', ''); $pmda->add_metric(pmda_pmid(1,40), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_blackhole_engine', '', ''); $pmda->add_metric(pmda_pmid(1,41), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_compress', '', ''); $pmda->add_metric(pmda_pmid(1,42), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_crypt', '', ''); $pmda->add_metric(pmda_pmid(1,43), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_csv', '', ''); $pmda->add_metric(pmda_pmid(1,44), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_dynamic_loading', '', ''); $pmda->add_metric(pmda_pmid(1,45), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_example_engine', '', ''); $pmda->add_metric(pmda_pmid(1,46), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_federated_engine', '', ''); $pmda->add_metric(pmda_pmid(1,47), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_geometry', '', ''); $pmda->add_metric(pmda_pmid(1,48), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_innodb', '', ''); $pmda->add_metric(pmda_pmid(1,49), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_isam', '', ''); $pmda->add_metric(pmda_pmid(1,50), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_merge_engine', '', ''); $pmda->add_metric(pmda_pmid(1,51), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_ndbcluster', '', ''); $pmda->add_metric(pmda_pmid(1,52), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_openssl', '', ''); $pmda->add_metric(pmda_pmid(1,53), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_ssl', '', ''); $pmda->add_metric(pmda_pmid(1,54), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_query_cache', '', ''); $pmda->add_metric(pmda_pmid(1,55), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_raid', '', ''); $pmda->add_metric(pmda_pmid(1,56), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_rtree_keys', '', ''); $pmda->add_metric(pmda_pmid(1,57), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.have_symlink', '', ''); $pmda->add_metric(pmda_pmid(1,58), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.hostname', '', ''); $pmda->add_metric(pmda_pmid(1,59), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.init_connect', '', ''); $pmda->add_metric(pmda_pmid(1,60), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.init_file', '', ''); $pmda->add_metric(pmda_pmid(1,61), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.init_slave', '', ''); $pmda->add_metric(pmda_pmid(1,63), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_additional_mem_pool_size', '', ''); $pmda->add_metric(pmda_pmid(1,64), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_autoextend_increment', '', ''); $pmda->add_metric(pmda_pmid(1,65), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_MBYTE,0,0), 'mysql.variables.innodb_buffer_pool_awe_mem_mb', '', ''); $pmda->add_metric(pmda_pmid(1,66), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_buffer_pool_size', '', ''); $pmda->add_metric(pmda_pmid(1,67), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_checksums', '', ''); $pmda->add_metric(pmda_pmid(1,68), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_commit_concurrency', '', ''); $pmda->add_metric(pmda_pmid(1,68), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_concurrency_tickets', '', ''); $pmda->add_metric(pmda_pmid(1,69), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_data_file_path', '', ''); $pmda->add_metric(pmda_pmid(1,70), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_data_home_dir', '', ''); $pmda->add_metric(pmda_pmid(1,71), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_doublewrite', '', ''); $pmda->add_metric(pmda_pmid(1,72), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_fast_shutdown', '', ''); $pmda->add_metric(pmda_pmid(1,73), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_file_io_threads', '', ''); $pmda->add_metric(pmda_pmid(1,74), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_file_per_table', '', ''); $pmda->add_metric(pmda_pmid(1,75), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_flush_log_at_trx_commit', '', ''); $pmda->add_metric(pmda_pmid(1,76), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_flush_method', '', ''); $pmda->add_metric(pmda_pmid(1,77), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_force_recovery', '', ''); $pmda->add_metric(pmda_pmid(1,78), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_lock_wait_timeout', '', ''); $pmda->add_metric(pmda_pmid(1,79), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_locks_unsafe_for_binlog', '', ''); $pmda->add_metric(pmda_pmid(1,80), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_log_arch_dir', '', ''); $pmda->add_metric(pmda_pmid(1,81), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_log_archive', '', ''); $pmda->add_metric(pmda_pmid(1,82), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_log_buffer_size', '', ''); $pmda->add_metric(pmda_pmid(1,83), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_log_file_size', '', ''); $pmda->add_metric(pmda_pmid(1,84), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_log_files_in_group', '', ''); $pmda->add_metric(pmda_pmid(1,85), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_log_group_home_dir', '', ''); $pmda->add_metric(pmda_pmid(1,86), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_max_dirty_pages_pct', '', ''); $pmda->add_metric(pmda_pmid(1,87), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_max_purge_lag', '', ''); $pmda->add_metric(pmda_pmid(1,88), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_mirrored_log_groups', '', ''); $pmda->add_metric(pmda_pmid(1,89), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_open_files', '', ''); $pmda->add_metric(pmda_pmid(1,90), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_rollback_on_timeout', '', ''); $pmda->add_metric(pmda_pmid(1,91), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_support_xa', '', ''); $pmda->add_metric(pmda_pmid(1,92), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_sync_spin_loops', '', ''); $pmda->add_metric(pmda_pmid(1,93), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_table_locks', '', ''); $pmda->add_metric(pmda_pmid(1,94), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_thread_concurrency', '', ''); $pmda->add_metric(pmda_pmid(1,95), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.innodb_thread_sleep_delay', '', ''); $pmda->add_metric(pmda_pmid(1,96), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.interactive_timeout', '', ''); $pmda->add_metric(pmda_pmid(1,97), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.join_buffer_size', '', ''); $pmda->add_metric(pmda_pmid(1,98), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.key_buffer_size', '', ''); $pmda->add_metric(pmda_pmid(1,99), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.key_cache_age_threshold', '', ''); $pmda->add_metric(pmda_pmid(1,100), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.key_cache_block_size', '', ''); $pmda->add_metric(pmda_pmid(1,101), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.key_cache_division_limit', '', ''); $pmda->add_metric(pmda_pmid(1,102), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.language', '', ''); $pmda->add_metric(pmda_pmid(1,103), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.large_files_support', '', ''); $pmda->add_metric(pmda_pmid(1,104), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.large_page_size', '', ''); $pmda->add_metric(pmda_pmid(1,105), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.large_pages', '', ''); $pmda->add_metric(pmda_pmid(1,106), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.lc_time_names', '', ''); $pmda->add_metric(pmda_pmid(1,107), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.license', '', ''); $pmda->add_metric(pmda_pmid(1,108), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.local_infile', '', ''); $pmda->add_metric(pmda_pmid(1,109), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.locked_in_memory', '', ''); $pmda->add_metric(pmda_pmid(1,110), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.log', '', ''); $pmda->add_metric(pmda_pmid(1,111), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.log_bin', '', ''); $pmda->add_metric(pmda_pmid(1,112), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.log_bin_trust_function_creators', '', ''); $pmda->add_metric(pmda_pmid(1,113), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.log_error', '', ''); $pmda->add_metric(pmda_pmid(1,114), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.log_queries_not_using_indexes', '', ''); $pmda->add_metric(pmda_pmid(1,115), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.log_slave_updates', '', ''); $pmda->add_metric(pmda_pmid(1,116), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.log_slow_queries', '', ''); $pmda->add_metric(pmda_pmid(1,117), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.log_warnings', '', ''); $pmda->add_metric(pmda_pmid(1,118), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.variables.long_query_time', '', ''); $pmda->add_metric(pmda_pmid(1,119), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.low_priority_updates', '', ''); $pmda->add_metric(pmda_pmid(1,120), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.lower_case_file_system', '', ''); $pmda->add_metric(pmda_pmid(1,121), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.lower_case_table_names', '', ''); $pmda->add_metric(pmda_pmid(1,122), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.max_allowed_packet', '', ''); $pmda->add_metric(pmda_pmid(1,124), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.max_binlog_cache_size', '', ''); $pmda->add_metric(pmda_pmid(1,125), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.max_binlog_size', '', ''); $pmda->add_metric(pmda_pmid(1,126), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_connect_errors', '', ''); $pmda->add_metric(pmda_pmid(1,127), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_connections', '', ''); $pmda->add_metric(pmda_pmid(1,128), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_delayed_threads', '', ''); $pmda->add_metric(pmda_pmid(1,129), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_error_count', '', ''); $pmda->add_metric(pmda_pmid(1,130), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_heap_table_size', '', ''); $pmda->add_metric(pmda_pmid(1,131), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_insert_delayed_threads', '', ''); $pmda->add_metric(pmda_pmid(1,132), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_join_size', '', ''); $pmda->add_metric(pmda_pmid(1,133), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_length_for_sort_data', '', ''); $pmda->add_metric(pmda_pmid(1,134), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_prepared_stmt_count', '', ''); $pmda->add_metric(pmda_pmid(1,135), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_relay_log_size', '', ''); $pmda->add_metric(pmda_pmid(1,136), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_seeks_for_key', '', ''); $pmda->add_metric(pmda_pmid(1,137), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_sort_length', '', ''); $pmda->add_metric(pmda_pmid(1,138), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_sp_recursion_depth', '', ''); $pmda->add_metric(pmda_pmid(1,139), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_tmp_tables', '', ''); $pmda->add_metric(pmda_pmid(1,140), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_user_connections', '', ''); $pmda->add_metric(pmda_pmid(1,141), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.max_write_lock_count', '', ''); $pmda->add_metric(pmda_pmid(1,142), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.multi_range_count', '', ''); $pmda->add_metric(pmda_pmid(1,143), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.myisam_data_pointer_size', '', ''); $pmda->add_metric(pmda_pmid(1,144), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.myisam_max_sort_file_size', '', ''); $pmda->add_metric(pmda_pmid(1,145), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.myisam_recover_options', '', ''); $pmda->add_metric(pmda_pmid(1,146), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.myisam_repair_threads', '', ''); $pmda->add_metric(pmda_pmid(1,147), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.myisam_sort_buffer_size', '', ''); $pmda->add_metric(pmda_pmid(1,148), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.myisam_stats_method', '', ''); $pmda->add_metric(pmda_pmid(1,149), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.ndb_autoincrement_prefetch_sz', '', ''); $pmda->add_metric(pmda_pmid(1,150), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ndb_force_send', '', ''); $pmda->add_metric(pmda_pmid(1,151), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ndb_use_exact_count', '', ''); $pmda->add_metric(pmda_pmid(1,152), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ndb_use_transactions', '', ''); $pmda->add_metric(pmda_pmid(1,153), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.variables.ndb_cache_check_time', '', ''); $pmda->add_metric(pmda_pmid(1,154), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ndb_connectstring', '', ''); $pmda->add_metric(pmda_pmid(1,155), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.net_buffer_length', '', ''); $pmda->add_metric(pmda_pmid(1,156), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.variables.net_read_timeout', '', ''); $pmda->add_metric(pmda_pmid(1,157), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.variables.net_retry_count', '', ''); $pmda->add_metric(pmda_pmid(1,158), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.variables.net_write_timeout', '', ''); $pmda->add_metric(pmda_pmid(1,159), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.new', '', ''); $pmda->add_metric(pmda_pmid(1,159), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.old_passwords', '', ''); $pmda->add_metric(pmda_pmid(1,160), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.open_files_limit', '', ''); $pmda->add_metric(pmda_pmid(1,161), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.optimizer_prune_level', '', ''); $pmda->add_metric(pmda_pmid(1,162), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.optimizer_search_depth', '', ''); $pmda->add_metric(pmda_pmid(1,163), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.pid_file', '', ''); $pmda->add_metric(pmda_pmid(1,164), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.port', '', ''); $pmda->add_metric(pmda_pmid(1,165), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.preload_buffer_size', '', ''); $pmda->add_metric(pmda_pmid(1,166), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.profiling', '', ''); $pmda->add_metric(pmda_pmid(1,167), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.profiling_history_size', '', ''); $pmda->add_metric(pmda_pmid(1,168), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.protocol_version', '', ''); $pmda->add_metric(pmda_pmid(1,169), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.query_alloc_block_size', '', ''); $pmda->add_metric(pmda_pmid(1,170), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.query_cache_limit', '', ''); $pmda->add_metric(pmda_pmid(1,171), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.query_cache_min_res_unit', '', ''); $pmda->add_metric(pmda_pmid(1,172), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.query_cache_size', '', ''); $pmda->add_metric(pmda_pmid(1,173), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.query_cache_type', '', ''); $pmda->add_metric(pmda_pmid(1,174), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.query_cache_wlock_invalidate', '', ''); $pmda->add_metric(pmda_pmid(1,175), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.query_prealloc_size', '', ''); $pmda->add_metric(pmda_pmid(1,176), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.range_alloc_block_size', '', ''); $pmda->add_metric(pmda_pmid(1,177), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.read_buffer_size', '', ''); $pmda->add_metric(pmda_pmid(1,178), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.read_only', '', ''); $pmda->add_metric(pmda_pmid(1,179), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.read_rnd_buffer_size', '', ''); $pmda->add_metric(pmda_pmid(1,180), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.relay_log_purge', '', ''); $pmda->add_metric(pmda_pmid(1,181), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.relay_log_space_limit', '', ''); $pmda->add_metric(pmda_pmid(1,182), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.rpl_recovery_rank', '', ''); $pmda->add_metric(pmda_pmid(1,183), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.secure_auth', '', ''); $pmda->add_metric(pmda_pmid(1,184), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.secure_file_priv', '', ''); $pmda->add_metric(pmda_pmid(1,185), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.server_id', '', ''); $pmda->add_metric(pmda_pmid(1,186), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.skip_external_locking', '', ''); $pmda->add_metric(pmda_pmid(1,187), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.skip_networking', '', ''); $pmda->add_metric(pmda_pmid(1,188), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.skip_show_database', '', ''); $pmda->add_metric(pmda_pmid(1,189), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.slave_compressed_protocol', '', ''); $pmda->add_metric(pmda_pmid(1,190), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.slave_load_tmpdir', '', ''); $pmda->add_metric(pmda_pmid(1,191), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.slave_skip_errors', '', ''); $pmda->add_metric(pmda_pmid(1,192), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.variables.slave_net_timeout', '', ''); $pmda->add_metric(pmda_pmid(1,193), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.slave_transaction_retries', '', ''); $pmda->add_metric(pmda_pmid(1,194), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.variables.slow_launch_time', '', ''); $pmda->add_metric(pmda_pmid(1,195), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.socket', '', ''); $pmda->add_metric(pmda_pmid(1,196), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.sort_buffer_size', '', ''); $pmda->add_metric(pmda_pmid(1,197), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.sql_big_selects', '', ''); $pmda->add_metric(pmda_pmid(1,198), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.sql_mode', '', ''); $pmda->add_metric(pmda_pmid(1,199), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.sql_notes', '', ''); $pmda->add_metric(pmda_pmid(1,200), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.sql_warnings', '', ''); $pmda->add_metric(pmda_pmid(1,201), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ssl_ca', '', ''); $pmda->add_metric(pmda_pmid(1,202), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ssl_capath', '', ''); $pmda->add_metric(pmda_pmid(1,203), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ssl_cert', '', ''); $pmda->add_metric(pmda_pmid(1,204), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ssl_cipher', '', ''); $pmda->add_metric(pmda_pmid(1,205), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.ssl_key', '', ''); $pmda->add_metric(pmda_pmid(1,206), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.storage_engine', '', ''); $pmda->add_metric(pmda_pmid(1,207), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), 'mysql.variables.sync_binlog', '', ''); $pmda->add_metric(pmda_pmid(1,208), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.sync_frm', '', ''); $pmda->add_metric(pmda_pmid(1,209), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.system_time_zone', '', ''); $pmda->add_metric(pmda_pmid(1,210), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.table_cache', '', ''); $pmda->add_metric(pmda_pmid(1,211), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.variables.table_lock_wait_timeout', '', ''); $pmda->add_metric(pmda_pmid(1,212), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.table_type', '', ''); $pmda->add_metric(pmda_pmid(1,211), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.thread_cache_size', '', ''); $pmda->add_metric(pmda_pmid(1,212), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.thread_stack', '', ''); $pmda->add_metric(pmda_pmid(1,213), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.time_format', '', ''); $pmda->add_metric(pmda_pmid(1,214), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.time_zone', '', ''); $pmda->add_metric(pmda_pmid(1,215), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.timed_mutexes', '', ''); $pmda->add_metric(pmda_pmid(1,216), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.variables.tmp_table_size', '', ''); $pmda->add_metric(pmda_pmid(1,217), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.tmpdir', '', ''); $pmda->add_metric(pmda_pmid(1,218), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.transaction_alloc_block_size', '', ''); $pmda->add_metric(pmda_pmid(1,219), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.variables.transaction_prealloc_size', '', ''); $pmda->add_metric(pmda_pmid(1,220), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.tx_isolation', '', ''); $pmda->add_metric(pmda_pmid(1,221), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.updatable_views_with_limit', '', ''); $pmda->add_metric(pmda_pmid(1,222), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.version', '', ''); $pmda->add_metric(pmda_pmid(1,223), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.version_comment', '', ''); $pmda->add_metric(pmda_pmid(1,224), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.version_compile_machine', '', ''); $pmda->add_metric(pmda_pmid(1,225), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.variables.version_compile_os', '', ''); $pmda->add_metric(pmda_pmid(1,226), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.variables.wait_timeout', '', ''); $pmda->add_metric(pmda_pmid(2,0), PM_TYPE_U32, $process_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.processlist.id', '', ''); $pmda->add_metric(pmda_pmid(2,1), PM_TYPE_STRING, $process_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.processlist.user', '', ''); $pmda->add_metric(pmda_pmid(2,2), PM_TYPE_STRING, $process_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.processlist.host', '', ''); $pmda->add_metric(pmda_pmid(2,3), PM_TYPE_STRING, $process_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.processlist.db', '', ''); $pmda->add_metric(pmda_pmid(2,4), PM_TYPE_STRING, $process_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.processlist.command', '', ''); $pmda->add_metric(pmda_pmid(2,5), PM_TYPE_U32, $process_indom, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.processlist.time', '', ''); $pmda->add_metric(pmda_pmid(2,6), PM_TYPE_STRING, $process_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.processlist.state', '', ''); $pmda->add_metric(pmda_pmid(2,7), PM_TYPE_STRING, $process_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.processlist.info', '', ''); $pmda->add_metric(pmda_pmid(3,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.slave_io_state', '', ''); $pmda->add_metric(pmda_pmid(3,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.slave_io_running', '', ''); $pmda->add_metric(pmda_pmid(3,2), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.slave_sql_running', '', ''); $pmda->add_metric(pmda_pmid(3,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.slave_status.seconds_behind_master', '', ''); $pmda->add_metric(pmda_pmid(3,4), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.master_log_file', '', ''); $pmda->add_metric(pmda_pmid(3,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.slave_status.read_master_log_pos', '', ''); $pmda->add_metric(pmda_pmid(3,6), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.relay_master_log_file', '', ''); $pmda->add_metric(pmda_pmid(3,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.slave_status.exec_master_log_pos', '', ''); $pmda->add_metric(pmda_pmid(3,8), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.relay_log_file', '', ''); $pmda->add_metric(pmda_pmid(3,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.slave_status.relay_log_pos', '', ''); $pmda->add_metric(pmda_pmid(3,10), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.until_log_file', '', ''); $pmda->add_metric(pmda_pmid(3,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.slave_status.until_log_pos', '', ''); $pmda->add_metric(pmda_pmid(3,12), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.master_ssl_cipher', '', ''); $pmda->add_metric(pmda_pmid(3,13), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.master_ssl_ca_file', '', ''); $pmda->add_metric(pmda_pmid(3,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'mysql.slave_status.skip_counter', '', ''); $pmda->add_metric(pmda_pmid(3,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0), 'mysql.slave_status.relay_log_space', '', ''); $pmda->add_metric(pmda_pmid(3,16), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.until_condition', '', ''); $pmda->add_metric(pmda_pmid(3,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'mysql.slave_status.connect_retry', '', ''); $pmda->add_metric(pmda_pmid(3,18), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.master_host', '', ''); $pmda->add_metric(pmda_pmid(3,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.last_errno', '', ''); $pmda->add_metric(pmda_pmid(3,20), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.master_ssl_cert', '', ''); $pmda->add_metric(pmda_pmid(3,21), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.replicate_do_db', '', ''); $pmda->add_metric(pmda_pmid(3,22), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.replicate_ignore_db', '', ''); $pmda->add_metric(pmda_pmid(3,23), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.master_user', '', ''); $pmda->add_metric(pmda_pmid(3,24), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.replicate_do_table', '', ''); $pmda->add_metric(pmda_pmid(3,25), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.replicate_wild_do_table', '', ''); $pmda->add_metric(pmda_pmid(3,26), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.replicate_wild_ignore_table', '', ''); $pmda->add_metric(pmda_pmid(3,27), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.replicate_ignore_table', '', ''); $pmda->add_metric(pmda_pmid(3,28), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.master_ssl_allowed', '', ''); $pmda->add_metric(pmda_pmid(3,29), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.master_ssl_ca_path', '', ''); $pmda->add_metric(pmda_pmid(3,30), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.master_port', '', ''); $pmda->add_metric(pmda_pmid(3,31), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.master_ssl_key', '', ''); $pmda->add_metric(pmda_pmid(3,32), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.slave_io_running_num', '', ''); $pmda->add_metric(pmda_pmid(3,33), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.slave_sql_running_num', '', ''); $pmda->add_metric(pmda_pmid(3,34), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, pmda_units(0,0,0,0,0,0), 'mysql.slave_status.master_ssl_allowed_num', '',''); $pmda->add_indom($process_indom, \@process_instances, 'Instance domain exporting each MySQL process', ''); $pmda->set_fetch_callback(\&mysql_fetch_callback); $pmda->set_fetch(\&mysql_connection_setup); $pmda->set_refresh(\&mysql_refresh); $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdamysql - MySQL database PMDA =head1 DESCRIPTION B is a Performance Co-Pilot PMDA which extracts live performance data from a running MySQL database. =head1 INSTALLATION B uses a configuration file from (in this order): =over =item * /etc/pcpdbi.conf =item * $PCP_PMDAS_DIR/mysql/mysql.conf =back This file can contain overridden values (Perl code) for the settings listed at the start of pmdamysql.pl, namely: =over =item * database name (see DBI(3) for details) =item * database user name =item * database pass word =back Once this is setup, you can access the names and values for the mysql performance metrics by doing the following as root: # cd $PCP_PMDAS_DIR/mysql # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/mysql # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 Binary Status values in text Some of the status values are in the form of YES/NO or ON/OFF. Since these cannot be intepreted by tools like PMIE, they have been duplicated with a _num extension and the values of 1 (YES/ON) or 0 (NO/OFF). =head2 Eg: =over =item * mysql.slave_status.slave_io_running =item * mysql.slave_status.slave_io_running_num =back =head1 FILES =over =item /etc/pcpdbi.conf configuration file for all PCP database monitors =item $PCP_PMDAS_DIR/mysql/mysql.conf configuration file for B =item $PCP_PMDAS_DIR/mysql/Install installation script for the B agent =item $PCP_PMDAS_DIR/mysql/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/mysql.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1), pmdadbping.pl(1) and DBI(3). # vi: sw=4 ts=4 et: pcp-3.8.12ubuntu1/src/pmdas/mysql/Remove0000775000000000000000000000160212272262501015024 0ustar #! /bin/sh # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the MySQL PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=mysql pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/mysql/Install0000775000000000000000000000154212272262501015200 0ustar #! /bin/sh # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the MySQL PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=mysql perl_opt=true daemon_opt=false forced_restart=false perl -e "use DBI" 2>/dev/null if test $? -ne 0; then echo "Perl database interface (DBI) is not installed" exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/mysql/pmlogconf.summary0000664000000000000000000000016112272262501017243 0ustar #pmlogconf-setup 2.0 ident mysql summary information probe mysql.status exists ? include : exclude mysql.status pcp-3.8.12ubuntu1/src/pmdas/mysql/GNUmakefile0000664000000000000000000000274712272262501015726 0ustar # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = mysql PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl pmlogconf.summary migrate.conf ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif LDIRT = domain.h root pmns *.log $(MAN_PAGES) default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) $(INSTALL) -m 755 -d $(PCP_VAR_DIR)/config/pmlogconf/$(IAM) $(INSTALL) -m 644 pmlogconf.summary $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)/summary $(INSTALL) -m 644 migrate.conf $(PCP_VAR_DIR)/config/pmlogrewrite/mysql_migrate.conf default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/mysql/migrate.conf0000664000000000000000000000053112272262501016140 0ustar # Copyright 2013 Ken McDonell. All Rights Reserved # # pmlogrewrite configuration for migrating archives containing MySQL metrics # across various changes in the metadata supplied by the PMDA # # was instantaneous, now counter as per commit 1ec908d on 24 Jun 2013 # metric mysql.status.connections { sem -> counter units -> 0,0,1,0,0,ONE } pcp-3.8.12ubuntu1/src/pmdas/infiniband/0000775000000000000000000000000012272262620014600 5ustar pcp-3.8.12ubuntu1/src/pmdas/infiniband/ib.c0000664000000000000000000005715212272262501015346 0ustar /* * Copyright (C) 2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * IB part of the PMDA - initialization, fetching etc. */ #include "ibpmda.h" #include #include #include #define IBPMDA_MAX_HCAS (16) typedef struct local_port_s { /* * Cache the ca_name and portnum to avoid a bug in libibumad that * leaks memory when umad_port_get() is called over and over. * With ca_name and portnum we can safely do umad_port_release() * first and then umad_port_get() without fear that some future * version of release() will deallocate port->ca_name and * port->portnum. */ char ca_name[UMAD_CA_NAME_LEN]; int portnum; umad_port_t *ump; void * hndl; int needsupdate; } local_port_t; /* umad_ca_t starts with a name which is good enough for us to use */ typedef struct hca_state_s { umad_ca_t ca; local_port_t lports[UMAD_CA_MAX_PORTS]; } hca_state_t; /* IB Architecture rel 1.2 demands that performance counters * must plateau once they reach 2^32. This structure is used * to track the counters and reset them when they get close to * the magic boundary */ typedef struct mad_counter_s { uint64_t accum; /* Accumulated value */ uint32_t prev; /* Previous value of the counter */ uint32_t cur; /* Current value, only valid during iteration */ uint32_t isvalid; /* Is current value valid? */ } mad_counter_t; typedef struct mad_cnt_desc_s { enum MAD_FIELDS madid; /* ID for the counter */ char *name; int resetmask; /* Reset mask for port_performance_reset */ uint32_t hiwat; /* If current value is over hiwat mark, reset it */ int multiplier; } mad_cnt_desc_t; #define MADDESC_INIT(id, mask, shft, mul) \ [ IBPMDA_##id ] {IB_PC_##id##_F, #id, (1<= UMAD_CA_MAX_PORTS) || (lport < 0)) { print_parse_err(LOG_ERR, "port number %d is out of bounds for HCA %s\n", lport, local); return; } if (hca->lports[lport].hndl == NULL) { print_parse_err(LOG_ERR, "port %s:%d has failed initialization\n", local, lport); return; } if ((ps = (port_state_t *)calloc(1, sizeof(port_state_t))) == NULL) { __pmNotifyErr (LOG_ERR, "Out of memory to save state for %s\n", name); return; } ps->guid = guid; ps->remport = rport; ps->lport = hca->lports + lport; ps->portid.lid = -1; ps->timeout = 1000; if ((inst = pmdaCacheStore(itab[IB_PORT_INDOM].it_indom, PMDA_CACHE_ADD, name, ps)) < 0) { __pmNotifyErr(LOG_ERR, "Cannot add %s to the cache - %s\n", name, pmErrStr(inst)); free (ps); return; } portcount++; } static int foreachport(hca_state_t *hst, void (*cb)(hca_state_t *, umad_port_t *, void *), void *closure) { int pcnt = hst->ca.numports; int p; int nports = 0; for (p=0; (pcnt >0) && (p < UMAD_CA_MAX_PORTS); p++) { umad_port_t *port = hst->ca.ports[p]; if (port ) { pcnt--; nports++; if (cb) { cb (hst, port, closure); } } } return (nports); } #ifdef HAVE_NETWORK_BYTEORDER #define guid_htonll(a) do { } while (0) /* noop */ #define guid_ntohll(a) do { } while (0) /* noop */ #else static void guid_htonll(char *p) { char c; int i; for (i = 0; i < 4; i++) { c = p[i]; p[i] = p[7-i]; p[7-i] = c; } } #define guid_ntohll(v) guid_htonll(v) #endif static void printportconfig (hca_state_t *hst, umad_port_t *port, void *arg) { uint64_t hguid = port->port_guid; guid_ntohll((char *)&hguid); fprintf (fconf, "%s:%d 0x%llx %d via %s:%d\n", port->ca_name, port->portnum, (unsigned long long)hguid, port->portnum, hst->ca.ca_name, port->portnum); } static void monitorport(hca_state_t *hst, umad_port_t *port, void *arg) { pmdaIndom *itab = arg; uint64_t hguid = port->port_guid; char name[128]; guid_ntohll((char *)&hguid); sprintf(name, "%s:%d", port->ca_name, port->portnum); monitor_guid(itab, name, hguid, port->portnum, port->ca_name, port->portnum); } static int mgmt_classes[] = {IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS, IB_PERFORMANCE_CLASS}; static void openumadport (hca_state_t *hst, umad_port_t *port, void *arg) { void *hndl = arg; local_port_t *lp; if ((hndl = mad_rpc_open_port(port->ca_name, port->portnum, mgmt_classes, ARRAYSZ(mgmt_classes))) == NULL) { __pmNotifyErr(LOG_ERR, "Cannot open port handle for %s:%d\n", port->ca_name, port->portnum); } lp = &hst->lports[port->portnum]; strcpy(lp->ca_name, port->ca_name); lp->portnum = port->portnum; lp->ump = port; lp->hndl = hndl; } static void parse_config(pmdaIndom *itab) { char buffer[2048]; while ((fgets(buffer, sizeof(buffer)-1, fconf)) != NULL) { char *p; lcnt++; /* strip comments */ if ((p = strchr(buffer,'#'))) *p='\0'; for (p = buffer; *p; p++) { if (!isspace (*p)) break; } if (*p != '\0') { char name[128]; long long guid; int rport; char local[128]; int lport; if (sscanf(p, "%[^ \t]%llx%d via %[^:]:%d", name, &guid, &rport, local, &lport) != 5) { __pmNotifyErr (LOG_ERR, "%s(%d): cannot parse the line\n", confpath, lcnt); continue; } monitor_guid(itab, name, guid, rport, local, lport); } } } int ib_load_config(const char *cp, int writeconf, pmdaIndom *itab, unsigned int nindoms) { char hcas[IBPMDA_MAX_HCAS][UMAD_CA_NAME_LEN]; hca_state_t *st = NULL; int i, n; int (*closef)(FILE *) = fclose; if (nindoms <= IB_CNT_INDOM) return -EINVAL; if (umad_init()) { __pmNotifyErr(LOG_ERR, "umad_init() failed. No IB kernel support or incorrect ABI version\n"); return -EIO; } if ((n = umad_get_cas_names(hcas, ARRAYSZ(hcas)))) { if ((st = calloc (n, sizeof(hca_state_t))) == NULL) return -ENOMEM; } else /* No HCAs */ return 0; /* Open config file - if the executable bit is set then assume that * user wants it to be a script and run it, otherwise try loading it. */ strcpy(confpath, cp); if (access(confpath, F_OK) == 0) { if (writeconf) { __pmNotifyErr(LOG_ERR, "Config file exists and writeconf arg was given to pmdaib. Aborting."); exit(1); } if (access(confpath, X_OK)) { /* Not an executable, just read it */ fconf = fopen (confpath, "r"); } else { fconf = popen(confpath, "r"); closef = pclose; } } else if (writeconf) { fconf = fopen(confpath, "w"); } /* else no config file: Just monitor local ports */ for (i=0; i < n; i++) { if (umad_get_ca(hcas[i], &st[i].ca) == 0) { int e = pmdaCacheStore(itab[IB_HCA_INDOM].it_indom, PMDA_CACHE_ADD, st[i].ca.ca_name, &st[i].ca); if (e < 0) { __pmNotifyErr(LOG_ERR, "Cannot add instance for %s to the cache - %s\n", st[i].ca.ca_name, pmErrStr(e)); continue; } foreachport(st+i, openumadport, NULL); if (fconf == NULL) /* No config file - monitor local ports */ foreachport(st+i, monitorport, itab); if (writeconf) foreachport(st+i, printportconfig, fconf); } } if (fconf) { parse_config(itab); (*closef)(fconf); } if (writeconf) /* Config file is now written. Exit. */ exit(0); if (!portcount) { __pmNotifyErr(LOG_INFO, "No IB ports found to monitor"); } itab[IB_CNT_INDOM].it_set = (pmdaInstid *)calloc(ARRAYSZ(mad_cnt_descriptors), sizeof(pmdaInstid)); if (itab[IB_CNT_INDOM].it_set == NULL) { return -ENOMEM; } itab[IB_CNT_INDOM].it_numinst = ARRAYSZ(mad_cnt_descriptors); for (i=0; i < ARRAYSZ(mad_cnt_descriptors); i++) { itab[IB_CNT_INDOM].it_set[i].i_inst = i; itab[IB_CNT_INDOM].it_set[i].i_name = mad_cnt_descriptors[i].name; } return 0; } static char * ib_portcap_to_string(port_state_t *pst) { static struct { int bit; const char *cap; } capdest [] = { {1, "SM"}, {2, "Notice"}, {3, "Trap"}, {5, "AutomaticMigration"}, {6, "SLMapping"}, {7, "MKeyNVRAM"}, {8, "PKeyNVRAM"}, {9, "LedInfo"}, {10, "SMdisabled"}, {11, "SystemImageGUID"}, {12, "PkeySwitchExternalPortTrap"}, {16, "CommunicatonManagement"}, {17, "SNMPTunneling"}, {18, "Reinit"}, {19, "DeviceManagement"}, {20, "VendorClass"}, {21, "DRNotice"}, {22, "CapabilityMaskNotice"}, {23, "BootManagement"}, {24, "IsLinkRoundTripLatency"}, {25, "ClientRegistration"} }; char *comma = ""; int commalen = 0; int i; char *ptr = pst->pcap; uint32_t bsiz = sizeof(pst->pcap); int pcap = mad_get_field(pst->portinfo, 0, IB_PORT_CAPMASK_F); *ptr ='\0'; for (i=0; i < ARRAYSZ(capdest); i++) { if (pcap & (1<pcap); } /* This function can be called multiple times during single * fetch operation so take care to avoid side effects, for example, * if the "previous" value of the counter is above the high * watermark and must be reset, don't change the previous value here - * it could lead to double counting on the second call */ static uint64_t ib_update_perfcnt (port_state_t *pst, int udata, int *rv ) { mad_cnt_desc_t * md = mad_cnt_descriptors + udata; mad_counter_t *mcnt = pst->madcnts + udata; if (!mcnt->isvalid) { uint32_t delta; mcnt->cur = mad_get_field(pst->perfdata, 0, md->madid); mcnt->isvalid = 1; /* If someone resets the counters, then don't update the the * accumulated value because we don't know what was the value before it * was reset. And if the difference between current and previous value * is larger then the high watermark then don't update the accumulated * value either - current value could've pegged because we didn't * fetch often enough */ delta = mcnt->cur - mcnt->prev; if ((mcnt->cur < mcnt->prev) || (delta > md->hiwat)) { mcnt->isvalid = PM_ERR_VALUE; } else { mcnt->accum += delta; } if (mcnt->cur > md->hiwat) { pst->resetmask |= md->resetmask; } } *rv = mcnt->isvalid; return (mcnt->accum * md->multiplier); } static int ib_linkwidth (port_state_t *pst) { int w = mad_get_field(pst->portinfo, 0, IB_PORT_LINK_WIDTH_ACTIVE_F); switch (w) { case 1: return (1); case 2: return (4); case 4: return (8); case 8: return (12); } return (0); } int ib_fetch_val(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmInDom_int *ind = (__pmInDom_int *)&(mdesc->m_desc.indom); __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); int rv = 1; port_state_t *pst = NULL; hca_state_t *hca = NULL; int umask = 1<cluster; int udata = (int)((__psint_t)mdesc->m_user); void *closure = NULL; int st; char *name = NULL; if (inst == PM_INDOM_NULL) { return PM_ERR_INST; } if (ind->serial != IB_CNT_INDOM) { if ((st = pmdaCacheLookup (mdesc->m_desc.indom, inst, &name, &closure)) != PMDA_CACHE_ACTIVE) { if (st == PMDA_CACHE_INACTIVE) st = PM_ERR_INST; __pmNotifyErr (LOG_ERR, "Cannot find instance %d in indom %s: %s\n", inst, pmInDomStr(mdesc->m_desc.indom), pmErrStr(st)); return st; } } /* If fetching from HCA indom, then no refreshing is necessary for the * lifetime of a pmda. Ports could change state, so some update could be * necessary */ switch (ind->serial) { case IB_PORT_INDOM: if (idp->cluster > 2) { return PM_ERR_INST; } pst = closure; if (pst->needupdate & umask) { local_port_t *lp = pst->lport; /* A port state is considered up-to date regardless of any * errors which could happen later - this is used to implement * one shot updates */ pst->needupdate ^= umask; /* The state of the local port used for queries is checked * once per fetch request */ if (lp->needsupdate) { umad_release_port(lp->ump); if (umad_get_port(lp->ca_name, lp->portnum, lp->ump) != 0) { __pmNotifyErr (LOG_ERR, "Cannot get state of the port %s:%d\n", lp->ump->ca_name, lp->ump->portnum); return 0; } lp->needsupdate = 0; } /* If the port which we're supposed to use to query the data * does not have a LID then we don't even try to query anything, * is it going to fail anyway */ if (lp->ump->base_lid == 0) { return 0; /* No values available */ } if (pst->portid.lid < 0) { ib_portid_t sm = {0}; sm.lid = lp->ump->sm_lid; memset (&pst->portid, 0, sizeof (pst->portid)); if (ib_resolve_guid_via (&pst->portid, &pst->guid, &sm, pst->timeout, lp->hndl) < 0) { __pmNotifyErr (LOG_ERR, "Cannot resolve GUID 0x%llx for %s " "via %s:%d\n", (unsigned long long)pst->guid, name, lp->ump->ca_name, lp->ump->portnum); pst->portid.lid = -1; return 0; } } switch (idp->cluster) { case 0: /* port attributes */ memset (pst->portinfo, 0, sizeof(pst->portinfo)); if (!smp_query_via (pst->portinfo, &pst->portid, IB_ATTR_PORT_INFO, 0, pst->timeout, lp->hndl)) { __pmNotifyErr (LOG_ERR, "Cannot get port info for %s via %s:%d\n", name, lp->ump->ca_name, lp->ump->portnum); return 0; } break; case 1: /* performance counters */ /* I thought about updating all accumulating counters * in case port_performance_query() succeeds but * decided not to do it right now - updating all counters * could mean more resets even in case when nobody is * actually looking at the particular counter and I'm * trying to minimize resets. */ memset (pst->perfdata, 0, sizeof (pst->perfdata)); if (!port_perf_query(pst->perfdata, &pst->portid, pst->remport, pst->timeout, lp->hndl)) { __pmNotifyErr (LOG_ERR, "Cannot get performance counters for %s " "via %s:%d\n", name, lp->ump->ca_name, lp->ump->portnum); return 0; } break; } pst->validstate ^= umask; } else if (!(pst->validstate & umask)) { /* We've hit an error on the previous update - continue * reporting no data for this instance */ return (0); } break; case IB_HCA_INDOM: hca = closure; break; case IB_CNT_INDOM: break; default: return (PM_ERR_INST); } switch (idp->cluster) { case 0: /* UMAD data - hca name, fw_version, number of ports etc */ switch(idp->item) { case METRIC_ib_hca_hw_ver: atom->cp = hca->ca.hw_ver; break; case METRIC_ib_hca_system_guid: atom->ull = hca->ca.system_guid; break; case METRIC_ib_hca_node_guid: atom->ull = hca->ca.node_guid; break; case METRIC_ib_hca_numports: atom->l = hca->ca.numports; break; case METRIC_ib_hca_type: if (hca->ca.node_type < ARRAYSZ(node_types)) { atom->cp = node_types[hca->ca.node_type]; } else { __pmNotifyErr (LOG_INFO, "Unknown node type %d for %s\n", hca->ca.node_type, hca->ca.ca_name); atom->cp = "Unknown"; } break; case METRIC_ib_hca_fw_ver: atom->cp = hca->ca.fw_ver; break; case METRIC_ib_port_gid_prefix: atom->ull = mad_get_field64(pst->portinfo, 0, IB_PORT_GID_PREFIX_F); break; case METRIC_ib_port_rate: atom->l = ib_linkwidth(pst) * (5 * mad_get_field (pst->portinfo, 0, IB_PORT_LINK_SPEED_ACTIVE_F))/2; break; case METRIC_ib_port_lid: atom->l = pst->portid.lid; break; case METRIC_ib_port_capabilities: atom->cp = ib_portcap_to_string(pst); break; case METRIC_ib_port_phystate: st = mad_get_field (pst->portinfo, 0, IB_PORT_PHYS_STATE_F); if (st < ARRAYSZ(port_phystates)) { atom->cp = port_phystates[st]; } else { __pmNotifyErr (LOG_INFO, "Unknown port PHY state %d on %s\n", st, name); atom->cp = "Unknown"; } break; case METRIC_ib_port_guid: atom->ull = pst->guid; break; case METRIC_ib_hca_ca_type: atom->cp = hca->ca.ca_type; break; case METRIC_ib_port_state: st = mad_get_field (pst->portinfo, 0, IB_PORT_STATE_F); if (st < ARRAYSZ(port_states)) { atom->cp = port_states[st]; } else { __pmNotifyErr (LOG_INFO, "Unknown port state %d on %s\n", st, name); atom->cp = "Unknown"; } break; case METRIC_ib_port_linkspeed: switch ((st = mad_get_field(pst->portinfo, 0, IB_PORT_LINK_SPEED_ACTIVE_F))) { case 1: atom->cp = "2.5 Gpbs"; break; case 2: atom->cp = "5.0 Gbps"; break; case 4: atom->cp = "10.0 Gbps"; break; default: __pmNotifyErr (LOG_INFO, "Unknown link speed %d on %s\n", st, name); atom->cp = "Unknown"; break; } break; case METRIC_ib_port_linkwidth: atom->l = ib_linkwidth(pst); break; default: rv = PM_ERR_PMID; break; } break; case 1: /* Fetch values from mad rpc response */ if ((udata >= 0) && (udata < ARRAYSZ(mad_cnt_descriptors))) { /* If a metric has udata set then it's one of the "direct" * metrics - just update the accumulated counter * and stuff its value into pmAtomValue */ switch (mdesc->m_desc.type) { case PM_TYPE_32: atom->l = (int32_t)ib_update_perfcnt (pst, udata, &rv); break; case PM_TYPE_64: atom->ll = ib_update_perfcnt (pst, udata, &rv); break; default: rv = PM_ERR_INST; break; } } else { int rv1=0, rv2=0; /* Synthetic metrics */ switch (idp->item) { case METRIC_ib_port_total_bytes: atom->ll = ib_update_perfcnt (pst, IBPMDA_XMT_BYTES, &rv1) + ib_update_perfcnt (pst, IBPMDA_RCV_BYTES, &rv2); break; case METRIC_ib_port_total_packets: atom->ll = ib_update_perfcnt (pst, IBPMDA_XMT_PKTS, &rv1) + ib_update_perfcnt (pst, IBPMDA_RCV_PKTS, &rv2); break; case METRIC_ib_port_total_errors_drop: atom->l = (int)(ib_update_perfcnt (pst, IBPMDA_ERR_SWITCH_REL, &rv1) + ib_update_perfcnt (pst, IBPMDA_XMT_DISCARDS, &rv2)); break; case METRIC_ib_port_total_errors_filter: atom->l = (int)(ib_update_perfcnt (pst, IBPMDA_ERR_XMTCONSTR, &rv1) + ib_update_perfcnt (pst, IBPMDA_ERR_RCVCONSTR, &rv2)); break; default: rv = PM_ERR_PMID; break; } if ((rv1 < 0) || (rv2 < 0)) { rv = (rv1 < 0) ? rv1 : rv2; } } break; case 2: /* Control structures */ switch (idp->item) { case METRIC_ib_control_query_timeout: atom->l = pst->timeout; break; case METRIC_ib_control_hiwat: if (inst < ARRAYSZ(mad_cnt_descriptors)) { atom->ul = mad_cnt_descriptors[inst].hiwat; } else { rv = PM_ERR_INST; } break; default: rv = PM_ERR_PMID; break; } break; default: rv = PM_ERR_PMID; break; } return rv; } /* Walk the instances and arm needupdate flag in each instance's * state. The actuall updating is done in the fetch function */ void ib_rearm_for_update(void *state) { port_state_t *pst = state; pst->lport->needsupdate = 1; pst->needupdate = 3; /* 0x1 for portinfo, 0x2 for perfdata */ pst->validstate = 4; /* 0x4 for timeout which is always valid */ } void ib_reset_perfcounters (void *state) { int m; port_state_t *pst = state; if (pst->resetmask && (pst->portid.lid != 0)) { memset (pst->perfdata, 0, sizeof (pst->perfdata)); if (port_perf_reset(pst->perfdata, &pst->portid, pst->remport, pst->resetmask, pst->timeout, pst->lport->hndl)) { int j; for (j=0; j < ARRAYSZ(mad_cnt_descriptors); j++) { if (pst->resetmask & (1<madcnts[j].prev = 0; pst->madcnts[j].isvalid = 0; } } } } pst->resetmask = 0; for (m=0; m < ARRAYSZ(mad_cnt_descriptors); m++) { if (pst->madcnts[m].isvalid) { pst->madcnts[m].prev = pst->madcnts[m].cur; pst->madcnts[m].isvalid = 0; } } } int ib_store(pmResult *result, pmdaExt *pmda) { int i; for (i = 0; i < result->numpmid ; i++) { pmValueSet *vs = result->vset[i]; __pmID_int *pmidp = (__pmID_int *)&vs->pmid; int inst; if (pmidp->cluster != 2) { return (-EACCES); } if (vs->valfmt != PM_VAL_INSITU) { return (-EINVAL); } for (inst=0; inst < vs->numval; inst++) { int id = vs->vlist[inst].inst; void *closure = NULL; switch (pmidp->item) { case METRIC_ib_control_query_timeout: if (pmdaCacheLookup (pmda->e_indoms[IB_PORT_INDOM].it_indom, id, NULL, &closure) == PMDA_CACHE_ACTIVE) { port_state_t *pst = closure; pst->timeout = vs->vlist[inst].value.lval; } else { return (PM_ERR_INST); } break; case METRIC_ib_control_hiwat: if ((id < 0) || (id > pmda->e_indoms[IB_CNT_INDOM].it_numinst)) { return (PM_ERR_INST); } mad_cnt_descriptors[id].hiwat = (uint32_t)vs->vlist[inst].value.lval; break; default: return (-EACCES); } } } return 0; } pcp-3.8.12ubuntu1/src/pmdas/infiniband/ibpmda.h0000664000000000000000000000744412272262501016214 0ustar /* * Copyright (C) 2013 Red Hat. * Copyright (C) 2007,2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _IBPMDA_H #define _IBPMDA_H #include #include #include #include "domain.h" #ifdef HAVE_PORT_PERFORMANCE_QUERY_VIA #define port_perf_query(data, dst, port, timeout, srcport) \ port_performance_query_via(data, dst, port, timeout, srcport) #define port_perf_reset(data, dst, port, mask, timeout, srcport) \ port_performance_reset_via(data, dst, port, mask, timeout, srcport) #else #define port_perf_query(data, dst, port, timeout, srcport) \ pma_query_via(data, dst, port, timeout, IB_GSI_PORT_COUNTERS, srcport) #define port_perf_reset(data, dst, port, mask, timeout, srcport) \ performance_reset_via(data, dst, port, mask, timeout, IB_GSI_PORT_COUNTERS, srcport) #endif void ibpmda_init (const char *configpath, int, pmdaInterface *); int ib_fetch_val(pmdaMetric *, unsigned int, pmAtomValue *); int ib_load_config(const char *, int, pmdaIndom *, unsigned int); void ib_rearm_for_update(void *); void ib_reset_perfcounters (void *); int ib_store(pmResult *, pmdaExt *); #define IB_HCA_INDOM 0 #define IB_PORT_INDOM 1 #define IB_CNT_INDOM 2 #define ARRAYSZ(a) (sizeof(a)/sizeof(a[0])) #define METRIC_ib_hca_type 0 #define METRIC_ib_hca_ca_type 1 #define METRIC_ib_hca_numports 2 #define METRIC_ib_hca_fw_ver 3 #define METRIC_ib_hca_hw_ver 4 #define METRIC_ib_hca_node_guid 5 #define METRIC_ib_hca_system_guid 6 #define METRIC_ib_port_guid 7 #define METRIC_ib_port_gid_prefix 8 #define METRIC_ib_port_lid 9 #define METRIC_ib_port_state 10 #define METRIC_ib_port_phystate 11 #define METRIC_ib_port_rate 12 #define METRIC_ib_port_capabilities 13 #define METRIC_ib_port_linkspeed 14 #define METRIC_ib_port_linkwidth 15 /* Per-port performance counters, cluster #1 */ #define METRIC_ib_port_in_bytes 0 #define METRIC_ib_port_in_packets 1 #define METRIC_ib_port_out_bytes 2 #define METRIC_ib_port_out_packets 3 #define METRIC_ib_port_in_errors_drop 4 #define METRIC_ib_port_out_errors_drop 5 #define METRIC_ib_port_total_bytes 6 #define METRIC_ib_port_total_packets 7 #define METRIC_ib_port_total_errors_drop 8 #define METRIC_ib_port_in_errors_filter 9 #define METRIC_ib_port_in_errors_local 10 #define METRIC_ib_port_in_errors_remote 11 #define METRIC_ib_port_out_errors_filter 12 #define METRIC_ib_port_total_errors_filter 13 #define METRIC_ib_port_total_errors_link 14 #define METRIC_ib_port_total_errors_recover 15 #define METRIC_ib_port_total_errors_integrity 16 #define METRIC_ib_port_total_errors_vl15 17 #define METRIC_ib_port_total_errors_overrun 18 #define METRIC_ib_port_total_errors_symbol 19 /* Control metrics */ #define METRIC_ib_control_query_timeout 0 #define METRIC_ib_control_hiwat 1 enum ibpmd_cndid { IBPMDA_ERR_SYM = 0, IBPMDA_LINK_RECOVERS, IBPMDA_LINK_DOWNED, IBPMDA_ERR_RCV, IBPMDA_ERR_PHYSRCV, IBPMDA_ERR_SWITCH_REL, IBPMDA_XMT_DISCARDS, IBPMDA_ERR_XMTCONSTR, IBPMDA_ERR_RCVCONSTR, IBPMDA_ERR_LOCALINTEG, IBPMDA_ERR_EXCESS_OVR, IBPMDA_VL15_DROPPED, IBPMDA_XMT_BYTES, IBPMDA_RCV_BYTES, IBPMDA_XMT_PKTS, IBPMDA_RCV_PKTS }; #endif /* _IBPMDA_H */ pcp-3.8.12ubuntu1/src/pmdas/infiniband/Remove0000775000000000000000000000124512272262501015763 0ustar #! /bin/sh # # Copyright (C) 2007,2008 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # . /etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=infiniband pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/infiniband/Install0000775000000000000000000000205212272262501016131 0ustar #! /bin/sh # # Copyright (C) 2013 Red Hat. # Copyright (C) 2007,2008 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # . /etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=infiniband pmda_interface=3 daemon_opt=true dso_opt=false pipe_opt=true socket_opt=false path=/sys/class/infiniband_mad if ! test -d $path; then echo "Kernel lacks Infiniband support - $path directory not found" exit 1 fi __choose_mode() { do_pmda=true } __choose_ipc() { ipc_type=pipe type="pipe binary $PCP_PMDAS_DIR/infiniband/pmdaib" } pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/infiniband/GNUmakefile0000664000000000000000000000263412272262501016655 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2007-2009 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs CMDTARGET = pmdaib$(EXECSUFFIX) CFILES = ib.c pmda.c HFILES = ibpmda.h LSRCFILES = help root pmns Install Remove LLDLIBS = $(IB_LIBS) $(PCP_LIBS) -lpcp_pmda -lpcp IAM = ib DOMAIN = IB PMDADIR = $(PCP_PMDAS_DIR)/infiniband LDIRT = domain.h *.o $(IAM).log $(CMDTARGET) default: build-me include $(BUILDRULES) ifneq "$(PMDA_INFINIBAND)" "" build-me: domain.h $(CMDTARGET) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -S $(PMDADIR) $(PCP_PMDAS_DIR)/$(IAM) $(INSTALL) -m 755 Install Remove $(CMDTARGET) $(PMDADIR) $(INSTALL) -m 644 pmns root help domain.h $(PMDADIR) else build-me: install: endif ib.o: domain.h .NOTPARALLEL: .ORDER: domain.h $(OBJECTS) default_pcp : default install_pcp : install domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/infiniband/root0000664000000000000000000000016612272262501015507 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { infiniband } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/infiniband/pmns0000664000000000000000000000201112272262501015470 0ustar infiniband { hca port control } infiniband.hca { type IB:0:0 ca_type IB:0:1 numports IB:0:2 fw_ver IB:0:3 hw_ver IB:0:4 node_guid IB:0:5 system_guid IB:0:6 } infiniband.port { guid IB:0:7 gid_prefix IB:0:8 lid IB:0:9 state IB:0:10 phystate IB:0:11 rate IB:0:12 capabilities IB:0:13 linkspeed IB:0:14 linkwidth IB:0:15 in out total } infiniband.port.in { bytes IB:1:0 packets IB:1:1 errors } infiniband.port.in.errors { drop IB:1:4 filter IB:1:9 local IB:1:10 remote IB:1:11 } infiniband.port.out { bytes IB:1:2 packets IB:1:3 errors } infiniband.port.out.errors { drop IB:1:5 filter IB:1:12 } infiniband.port.total { bytes IB:1:6 packets IB:1:7 errors } infiniband.port.total.errors { drop IB:1:8 filter IB:1:13 link IB:1:14 recover IB:1:15 integrity IB:1:16 vl15 IB:1:17 overrun IB:1:18 symbol IB:1:19 } infiniband.control { query_timeout IB:2:0 hiwat IB:2:1 } pcp-3.8.12ubuntu1/src/pmdas/infiniband/pmda.c0000664000000000000000000002553112272262501015671 0ustar /* * Copyright (C) 2013 Red Hat. * Copyright (C) 2007,2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "ibpmda.h" /* * Metric Table */ pmdaMetric metrictab[] = { /* infiniband.hca.type */ { NULL, {PMDA_PMID(0,METRIC_ib_hca_type), PM_TYPE_STRING, IB_HCA_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.hca.ca_type */ { NULL, {PMDA_PMID(0,METRIC_ib_hca_ca_type), PM_TYPE_STRING, IB_HCA_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.hca.numports */ { NULL, {PMDA_PMID(0,METRIC_ib_hca_numports), PM_TYPE_32, IB_HCA_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.hca.fw_ver */ { NULL, {PMDA_PMID(0,METRIC_ib_hca_fw_ver), PM_TYPE_STRING, IB_HCA_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.hca.hw_ver */ { NULL, {PMDA_PMID(0,METRIC_ib_hca_hw_ver), PM_TYPE_STRING, IB_HCA_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.hca.node_guid */ { NULL, {PMDA_PMID(0,METRIC_ib_hca_node_guid), PM_TYPE_U64, IB_HCA_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.hca.system_guid */ { NULL, {PMDA_PMID(0,METRIC_ib_hca_system_guid), PM_TYPE_U64, IB_HCA_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.port.guid */ { NULL, {PMDA_PMID(0,METRIC_ib_port_guid), PM_TYPE_U64, IB_PORT_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.port.gid_prefix */ { NULL, {PMDA_PMID(0,METRIC_ib_port_gid_prefix), PM_TYPE_U64, IB_PORT_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.port.lid */ { NULL, {PMDA_PMID(0,METRIC_ib_port_lid), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.port.state */ { NULL, {PMDA_PMID(0,METRIC_ib_port_state), PM_TYPE_STRING, IB_PORT_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.port.phystate */ { NULL, {PMDA_PMID(0,METRIC_ib_port_phystate), PM_TYPE_STRING, IB_PORT_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.port.rate */ { NULL, {PMDA_PMID(0,METRIC_ib_port_rate), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.port.capabilities */ { NULL, {PMDA_PMID(0,METRIC_ib_port_capabilities), PM_TYPE_STRING, IB_PORT_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.port.linkspeed */ { NULL, {PMDA_PMID(0,METRIC_ib_port_linkspeed), PM_TYPE_STRING, IB_PORT_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.port.linkwidth */ { NULL, {PMDA_PMID(0,METRIC_ib_port_linkwidth), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* infiniband.port.in.bytes */ { (void *)IBPMDA_RCV_BYTES, {PMDA_PMID(1,METRIC_ib_port_in_bytes), PM_TYPE_64, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* infiniband.port.in.packets */ { (void *)IBPMDA_RCV_PKTS, {PMDA_PMID(1,METRIC_ib_port_in_packets), PM_TYPE_64, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) }, }, /* infiniband.port.in.errors.drop */ { (void *)IBPMDA_ERR_SWITCH_REL, {PMDA_PMID(1,METRIC_ib_port_in_errors_drop), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.in.errors.filter */ { (void *)IBPMDA_ERR_RCVCONSTR, {PMDA_PMID(1,METRIC_ib_port_in_errors_filter), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.in.errors.local */ { (void *)IBPMDA_ERR_RCV, {PMDA_PMID(1,METRIC_ib_port_in_errors_local), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.in.errors.filter */ { (void *)IBPMDA_ERR_PHYSRCV, {PMDA_PMID(1,METRIC_ib_port_in_errors_remote), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.out.bytes */ { (void *)IBPMDA_XMT_BYTES, {PMDA_PMID(1,METRIC_ib_port_out_bytes), PM_TYPE_64, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* infiniband.port.out.packets */ {(void *)IBPMDA_XMT_PKTS, {PMDA_PMID(1,METRIC_ib_port_out_packets), PM_TYPE_64, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) }, }, /* infiniband.port.out.errors.drop */ { (void *)IBPMDA_XMT_DISCARDS, {PMDA_PMID(1,METRIC_ib_port_out_errors_drop), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.out.errors.filter */ { (void *)IBPMDA_ERR_XMTCONSTR, {PMDA_PMID(1,METRIC_ib_port_out_errors_filter), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.total.bytes */ { (void *)-1, {PMDA_PMID(1,METRIC_ib_port_total_bytes), PM_TYPE_64, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, /* infiniband.port.total.packets */ { (void *)-1, {PMDA_PMID(1,METRIC_ib_port_total_packets), PM_TYPE_64, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.total.errors.drop */ { (void *)-1, {PMDA_PMID(1,METRIC_ib_port_total_errors_drop), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.total.errors.filter */ { (void *)-1, {PMDA_PMID(1,METRIC_ib_port_total_errors_filter), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.total.errors.link */ { (void *)IBPMDA_LINK_DOWNED, {PMDA_PMID(1,METRIC_ib_port_total_errors_link), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.total.errors.recover */ { (void *)IBPMDA_LINK_RECOVERS, {PMDA_PMID(1,METRIC_ib_port_total_errors_recover), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.total.errors.integrity */ { (void *)IBPMDA_ERR_LOCALINTEG, {PMDA_PMID(1,METRIC_ib_port_total_errors_integrity), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.total.errors.vl15 */ { (void *)IBPMDA_VL15_DROPPED, {PMDA_PMID(1,METRIC_ib_port_total_errors_vl15), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.total.errors.overrun */ { (void *)IBPMDA_ERR_EXCESS_OVR, {PMDA_PMID(1,METRIC_ib_port_total_errors_overrun), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.port.total.errors.symbol */ { (void *)IBPMDA_ERR_SYM, {PMDA_PMID(1,METRIC_ib_port_total_errors_symbol), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,0) } }, /* infiniband.control.query_timeout */ { NULL, {PMDA_PMID(2,METRIC_ib_control_query_timeout), PM_TYPE_32, IB_PORT_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* infiniband.control.hiwat */ { NULL, {PMDA_PMID(2,METRIC_ib_control_hiwat), PM_TYPE_U32, IB_CNT_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, }; pmdaIndom indomtab[] = { { IB_HCA_INDOM, 0, NULL }, { IB_PORT_INDOM, 0, NULL }, { IB_CNT_INDOM, 0, NULL }, }; static void foreach_inst(pmInDom indom, void (*cb)(void *state)) { int i; pmdaCacheOp (indom, PMDA_CACHE_WALK_REWIND); while ((i = pmdaCacheOp (indom, PMDA_CACHE_WALK_NEXT)) >= 0) { void *state = NULL; if (pmdaCacheLookup (indom, i, NULL, &state) != PMDA_CACHE_ACTIVE) { abort(); } cb (state); } } int ib_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int rv; foreach_inst (indomtab[IB_PORT_INDOM].it_indom, ib_rearm_for_update); rv = pmdaFetch (numpmid, pmidlist, resp, pmda); foreach_inst (indomtab[IB_PORT_INDOM].it_indom, ib_reset_perfcounters); return (rv); } void ibpmda_init(const char *confpath, int writeconf, pmdaInterface *dp) { char defconf[MAXPATHLEN]; int sep = __pmPathSeparator(); int i; if (dp->status != 0) return; if (confpath == NULL) { snprintf(defconf, sizeof(defconf), "%s%c" "infiniband" "%c" "config", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); confpath = defconf; } for (i=0; i < ARRAYSZ(indomtab); i++) { __pmindom_int(&indomtab[i].it_indom)->domain = dp->domain; if (IB_CNT_INDOM != __pmindom_int(&indomtab[i].it_indom)->serial) { pmdaCacheOp (indomtab[i].it_indom, PMDA_CACHE_LOAD); } } if ((dp->status = ib_load_config(confpath, writeconf, indomtab, ARRAYSZ(indomtab)))) return; for (i=0; i < ARRAYSZ(indomtab); i++) { if (IB_CNT_INDOM != __pmindom_int(&indomtab[i].it_indom)->serial) { pmdaCacheOp (indomtab[i].it_indom, PMDA_CACHE_SAVE); } } dp->version.two.fetch = ib_fetch; dp->version.two.store = ib_store; pmdaSetFetchCallBack(dp, ib_fetch_val); pmdaInit(dp, indomtab, ARRAYSZ(indomtab), metrictab, ARRAYSZ(metrictab)); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -c path to configuration file\n" " -w write the basic configuration file\n", stderr); exit(1); } int main(int argc, char **argv) { int err = 0; int sep = __pmPathSeparator(); pmdaInterface dispatch; char helppath[MAXPATHLEN]; char *confpath = NULL; int opt; int writeconf = 0; __pmSetProgname(argv[0]); snprintf(helppath, sizeof(helppath), "%s%c" "infiniband" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_3, pmProgname, IB, "infiniband.log", helppath); while ((opt = pmdaGetOpt(argc, argv, "D:c:d:l:w?", &dispatch, &err)) != EOF) { switch (opt) { case 'c': confpath = optarg; break; case 'w': writeconf = 1; break; default: err++; } } if (err) { usage(); } if (!writeconf) { /* If writeconf is specified, then errors should go to stdout * since the PMDA daemon will exit immediately after writing * out the default config file */ pmdaOpenLog(&dispatch); } ibpmda_init(confpath, writeconf, &dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/infiniband/help0000664000000000000000000001706612272262501015463 0ustar # # Copyright (c) 2007,2008 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @ infiniband.hca.type Node type Node type: channel adapter (CA), switch, router etc @ infiniband.hca.ca_type HCA type HCA type, e.g. MT23108, @ infiniband.hca.numports Number of ports on HCA Number of ports on HCA @ infiniband.hca.fw_ver Version of HCA firmware Version of HCA firmware @ infiniband.hca.hw_ver Version of HCA hardware Version of HCA hardware @ infiniband.hca.node_guid Node's Global Unique Identifier Node's Global Unique Identifier - 64 bit integer to refer to the node @ infiniband.hca.system_guid System's Global Unique Identifier System's Global Unique Identifier - 64 bit integer to refer to the system @ infiniband.port.guid Port's Global Unique Identifier Port's Global Unique Identifier - 64 bit integer to refer to the port @ infiniband.port.gid_prefix GID prefix GID prefix, assigned by subnet manager @ infiniband.port.lid Port's Local Identifier Port's Local Identifier, assigned by subnet manager @ infiniband.port.state Port's state Port's state - can be Active, Down, NoChange, Armed or Initialize @ infiniband.port.phystate Port's physical state Port's physical state @ infiniband.port.rate Port's Data Rate Port's Data Rate: 2, 5, 10 or 20 Gbps @ infiniband.port.capabilities Port's capabilities Port's capabilities. @ infiniband.port.linkspeed Base link speed of the port. This is a string which represents the base link speed of the port. Multiplying link speed by link width gives port's data rate. @ infiniband.port.linkwidth Port's link width. Number of bi-directional Infiniband links active on the port. Also known as X-factor, as in 1X, 4X, 12X. @ infiniband.port.in.bytes Bytes received Counter of data octets received on all VLs at the port. This includes all octets between (and not including) the start of packet delimiter and the VCRC, and may include packets containing errors. It excludes all link packets. This counter is implemented by sampling underlying saturating PortRcvData counter. When a value of saturated counter reaches predefined threshold, the counter is reset after its value is copied into internal state. @ infiniband.port.in.packets Packets received Counter of data packets received on all VLs at the port. This may include packets containing errors but excludes all link packets. @ infiniband.port.in.errors.drop Packets dropped due to errors Number of packets received on the port that were discarded because they could not be forwarded by the switch relay due to DLID mapping, VL mapping or looping. Implemented by sampling 16 bit PortRcvSwitchRelayErrors counter. @ infiniband.port.in.errors.filter Packets filtered out Number of packets received by the port that were discarded because it was a raw packet and FilterRawInbound is enabled or because PartitionEnforcementInbound is enabled and packet failed partition key check or IP version check. Implemented by sampling 8 bit PortRcvConstraintErrors counter. @ infiniband.port.in.errors.local Packets with errors Counter of packets containing local physical errors, malformed data or link packets or packets discarded due to buffer overrun. Implemented by sampling 16 bit PortRcvErrors counter. @ infiniband.port.in.errors.remote Packets with EBP delimiter. Number of packets marked with End Bad Packet delimited received by the port. Implemented by sampling 16 bit PortRcvRemotePhysicalerrors counter. @ infiniband.port.out.bytes Bytes transmitted Counter of data octets, transmitted on all VLs from the port. This includes all octets between (and not including) the start of packet delimiter and the VCRC, and may include packets containing errors. It excludes all link packets. This counter is implemented by sampling underlying saturating PortXmtData counter. When a value of saturated counter reaches predefined threshold, the counter is reset after its value is copied into internal state. @ infiniband.port.out.packets Packets transmitted Counter of data packets transmitted on all VLs from the port. This may include packets containing errors but excludes all link packets. @ infiniband.port.out.errors.drop Packets dropped without transmitting Number of outbound packets which were droped because port is down or congested. Implemented by sampling 16 bit PortXmtDiscard counter. @ infiniband.port.out.errors.filter Packets filtered out before transmitting Number of packets not transmitted by the port because it was a raw packet and FilterRawInbound is enabled or because PartitionEnforcementInbound is enabled and packet failed partition key check or IP version check. Implemented by sampling 8 bit PortXmitConstraintErrors counter. @ infiniband.port.total.bytes Bytes transmitted and received Cumulative value of infiniband.port.in.bytes and infiniband.port.out.bytes, provided for convenience. @ infiniband.port.total.packets Packets transmitted and received Cumulative value of infiniband.port.in.packets and infiniband.port.out.packets, provided for convenience. @ infiniband.port.total.errors.drop Packet dropped Cumulative counter of infiniband.port.in.errors.drop and infiniband.out.errors.drops. @ infiniband.port.total.errors.filter Packet filtered out Cumulative counter of infiniband.port.in.errors.filter and infiniband.out.errors.filter. @ infiniband.port.total.errors.link Link downed Number of times Port Training state machine has failed to complete link recovery process and downed the link. Implemented by sampling 8 bit LinkDownedCounter. @ infiniband.port.total.errors.recover Successful recoveries Number of times Port Training state machine has managed successfully complete link recovery process. Implemented by sampling 8 bit LinkErrorRecoveryCounter. @ infiniband.port.total.errors.integrity Excessive local physical errors Number of times the count of local physical errors exceeded the threshold. Implemented by sampling 4 bit LocalLinkIntegrityErrors counter. @ infiniband.port.total.errors.vl15 Dropped packets to VL15 Number of times packets to VL15 (management virtual line) was dropped due to resource limitations. Implemented by sampling 16 bit VL15Dropped counter. @ infiniband.port.total.errors.overrun Excessive Buffer Overruns The number of times buffer overrun errors had persisted over multiple flow control update times. Implemented by sampling 4 bit ExcessiveBufferOverrun counter. @ infiniband.port.total.errors.symbol Total number of minor link errors Total number of minor link errors detected on one or more physical lines. Implemented by sampling 16 bit SymbolErrorCounter. @ infiniband.control.query_timeout Timeout for MAD perquery Timeout in milliseconds for MAD rpcs. Default value is 1000 milliseconds. Timeout can be set per port. @ infiniband.control.hiwat Counter threshold values Threshold values for each MAD performance counter. Due to saturating nature of the counters they're reset when value of a particular counter gets above a threshold. Setting threshold to the maximum value disables the reset mechanism. pcp-3.8.12ubuntu1/src/pmdas/mmv/0000775000000000000000000000000012272262620013276 5ustar pcp-3.8.12ubuntu1/src/pmdas/mmv/Makefile.demos0000664000000000000000000000141012272262501016036 0ustar # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # SHELL = /bin/sh CC = cc CFLAGS = -g TARGETS = acme mmvdump default: $(TARGETS) mmvdump: mmvdump.c $(CC) $(CFLAGS) -o $@ $^ -lpcp acme: acme.c $(CC) $(CFLAGS) -o $@ $^ -lpcp_mmv -lpcp clean: rm -f *.o clobber: clean rm -f $(TARGETS) pcp-3.8.12ubuntu1/src/pmdas/mmv/README.demos0000664000000000000000000000176612272262501015274 0ustar sample pcp_mmv applications =========================== acme.c is a sample application that is instrumented with the pcp_mmv interface to generate metrics available from the MMV PMDA (Performance Metrics Domain Agent). It runs without exiting, and continually updates the mmv.acme.* metric values. Detailed discussion about the workings of this application and each of the instrumentation API calls it uses, is available as part of the "Performance Co-Pilot Programmer's Guide". mmvdump.c an example program that dumps the contents of a (memory mapped) mmv(5) format file, as created by the pcp_mmv library and read by the MMV PMDA. The binary is also shipped as part of pcp and can be found installed below ${PCP_PMDAS_DIR}/mmv. All source is shipped as part of pcp as well and is installed in ${PCP_DEMOS_DIR}/mmv. If you have a C toolchain installed, the sources and Makefile in this directory may be used to create the functionally equivalent binaries, by entering the command % make acme mmvdump pcp-3.8.12ubuntu1/src/pmdas/mmv/mmvdump.c0000664000000000000000000002136712272262501015136 0ustar /* * Copyright (C) 2013 Red Hat. * Copyright (C) 2009 Aconex. All Rights Reserved. * Copyright (C) 2001 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include void dump_indoms(void *addr, int idx, long base, __uint64_t offset, __int32_t count) { int i; mmv_disk_string_t * string; mmv_disk_indom_t * indom = (mmv_disk_indom_t *) ((char *)addr + offset); printf("\nTOC[%d]: offset %ld, indoms offset %" PRIu64 " (%d entries)\n", idx, base, offset, count); for (i = 0; i < count; i++) { __uint64_t off = offset + i * sizeof(mmv_disk_indom_t); printf(" [%u/%"PRIi64"] %d instances, starting at offset %"PRIi64"\n", indom[i].serial, off, indom[i].count, indom[i].offset); if (indom[i].shorttext) { string = (mmv_disk_string_t *) ((char *)addr + indom[i].shorttext); printf(" shorttext=%s\n", string->payload); } else printf(" (no shorttext)\n"); if (indom[i].helptext) { string = (mmv_disk_string_t *) ((char *)addr + indom[i].helptext); printf(" helptext=%s\n", string->payload); } else printf(" (no helptext)\n"); } } void dump_insts(void *addr, int idx, long base, __uint64_t offset, __int32_t count) { int i; mmv_disk_instance_t * inst = (mmv_disk_instance_t *) ((char *)addr + offset); printf("\nTOC[%d]: offset %ld, instances offset %"PRIi64" (%d entries)\n", idx, base, offset, count); for (i = 0; i < count; i++) { mmv_disk_indom_t * indom = (mmv_disk_indom_t *) ((char *)addr + inst[i].indom); printf(" [%u/%"PRIi64"] instance = [%d or \"%s\"]\n", indom->serial, (offset + i * sizeof(mmv_disk_instance_t)), inst[i].internal, inst[i].external); } } static char * metrictype(int mtype) { char *type; switch (mtype) { case MMV_TYPE_I32: type = "32-bit int"; break; case MMV_TYPE_U32: type = "32-bit unsigned int"; break; case MMV_TYPE_I64: type = "64-bit int"; break; case MMV_TYPE_U64: type = "64-bit unsigned int"; break; case MMV_TYPE_FLOAT: type = "float"; break; case MMV_TYPE_DOUBLE: type = "double"; break; case MMV_TYPE_STRING: type = "string"; break; case MMV_TYPE_ELAPSED: type = "elapsed"; break; default: type = "?"; break; } return type; } static char * metricsem(int msem) { char *sem; switch (msem) { case PM_SEM_COUNTER: sem = "counter"; break; case PM_SEM_INSTANT: sem = "instant"; break; case PM_SEM_DISCRETE: sem = "discrete"; break; default: sem = "?"; break; } return sem; } void dump_metrics(void *addr, int idx, long base, __uint64_t offset, __int32_t count) { int i; mmv_disk_string_t * string; mmv_disk_metric_t * m = (mmv_disk_metric_t *) ((char *)addr + offset); printf("\nTOC[%d]: toc offset %ld, metrics offset %"PRIi64" (%d entries)\n", idx, base, offset, count); for (i = 0; i < count; i++) { __uint64_t off = offset + i * sizeof(mmv_disk_metric_t); printf(" [%u/%"PRIi64"] %s\n", m[i].item, off, m[i].name); printf(" type=%s (0x%x), sem=%s (0x%x), pad=0x%x\n", metrictype(m[i].type), m[i].type, metricsem(m[i].semantics), m[i].semantics, m[i].padding); printf(" units=%s\n", pmUnitsStr(&m[i].dimension)); if (m[i].indom != PM_INDOM_NULL && m[i].indom != 0) printf(" indom=%d\n", m[i].indom); else printf(" (no indom)\n"); if (m[i].shorttext) { string = (mmv_disk_string_t *) ((char *)addr + m[i].shorttext); printf(" shorttext=%s\n", string->payload); } else printf(" (no shorttext)\n"); if (m[i].helptext) { string = (mmv_disk_string_t *) ((char *)addr + m[i].helptext); printf(" helptext=%s\n", string->payload); } else printf(" (no helptext)\n"); } } void dump_values(void *addr, int idx, long base, __uint64_t offset, __int32_t count) { int i; mmv_disk_value_t * vals = (mmv_disk_value_t *) ((char *)addr + offset); printf("\nTOC[%d]: offset %ld, values offset %"PRIu64" (%d entries)\n", idx, base, offset, count); for (i = 0; i < count; i++) { mmv_disk_string_t * string; mmv_disk_metric_t * m = (mmv_disk_metric_t *) ((char *)addr + vals[i].metric); __uint64_t off = offset + i * sizeof(mmv_disk_value_t); printf(" [%u/%"PRIu64"] %s", m->item, off, m->name); if (m->indom && m->indom != PM_IN_NULL) { mmv_disk_instance_t *indom = (mmv_disk_instance_t *) ((char *)addr + vals[i].instance); printf("[%d or \"%s\"]", indom->internal, indom->external); } switch (m->type) { case MMV_TYPE_I32: printf(" = %d", vals[i].value.l); break; case MMV_TYPE_U32: printf(" = %u", vals[i].value.ul); break; case MMV_TYPE_I64: printf(" = %" PRIi64, vals[i].value.ll); break; case MMV_TYPE_U64: printf(" = %" PRIu64, vals[i].value.ull); break; case MMV_TYPE_FLOAT: printf(" = %f", vals[i].value.f); break; case MMV_TYPE_DOUBLE: printf(" = %lf", vals[i].value.d); break; case MMV_TYPE_STRING: string = (mmv_disk_string_t *)((char *)addr + vals[i].extra); printf(" = \"%s\"", string->payload); break; case MMV_TYPE_ELAPSED: { struct timeval tv; __int64_t t; __pmtimevalNow(&tv); t = vals[i].value.ll; if (vals[i].extra < 0) t += ((tv.tv_sec*1e6 + tv.tv_usec) + vals[i].extra); printf(" = %"PRIi64" (value=%"PRIi64"/extra=%"PRIi64")", t, vals[i].value.ll, vals[i].extra); if (vals[i].extra > 0) printf("Bad ELAPSED 'extra' value found!"); break; } default: printf("Unknown type %d", m->type); } putchar('\n'); } } void dump_strings(void *addr, int idx, long base, __uint64_t offset, __int32_t count) { int i; mmv_disk_string_t * string = (mmv_disk_string_t *) ((char *)addr + offset); printf("\nTOC[%d]: offset %ld, string offset %"PRIu64" (%d entries)\n", idx, base, offset, count); for (i = 0; i < count; i++) { printf(" [%u/%"PRIu64"] %s\n", i+1, offset + i * sizeof(mmv_disk_string_t), string[i].payload); } } int dump(const char *file, void *addr) { int i; mmv_disk_header_t * hdr = (mmv_disk_header_t *) addr; mmv_disk_toc_t * toc = (mmv_disk_toc_t *) ((char *)addr + sizeof(mmv_disk_header_t)); if (strcmp(hdr->magic, "MMV")) { printf("Bad magic: %c%c%c\n", hdr->magic[0], hdr->magic[1], hdr->magic[2]); return 1; } if (hdr->version != MMV_VERSION) { printf("version %d not supported\n", hdr->version); return 1; } printf("MMV file = %s\n", file); printf("Version = %d\n", hdr->version); printf("Generated = %"PRIu64"\n", hdr->g1); if (hdr->g1 != hdr->g2) { printf("Generated2 = %"PRIu64"\n", hdr->g2); printf("Mismatched generation numbers\n"); return 1; } printf("TOC count = %u\n", hdr->tocs); printf("Cluster = %u\n", hdr->cluster); printf("Process = %d\n", hdr->process); printf("Flags = 0x%x\n", hdr->flags); for (i = 0; i < hdr->tocs; i++) { __uint64_t base = ((char *)&toc[i] - (char *)addr); switch (toc[i].type) { case MMV_TOC_INDOMS: dump_indoms(addr, i, base, toc[i].offset, toc[i].count); break; case MMV_TOC_INSTANCES: dump_insts(addr, i, base, toc[i].offset, toc[i].count); break; case MMV_TOC_VALUES: dump_values(addr, i, base, toc[i].offset, toc[i].count); break; case MMV_TOC_METRICS: dump_metrics(addr, i, base, toc[i].offset, toc[i].count); break; case MMV_TOC_STRINGS: dump_strings(addr, i, base, toc[i].offset, toc[i].count); break; default: printf("Unrecognised TOC[%d] type: 0x%x\n", i, toc[i].type); } } return 0; } int main(int argc, char * argv[]) { int fd; char file[MAXPATHLEN]; if (argc > 2) { printf("USAGE: %s \n", argv[0]); exit(1); } if (argc > 1) strncpy(file, argv[1], MAXPATHLEN); else snprintf(file, MAXPATHLEN, "%s%cmmv%ctest", pmGetConfig("PCP_TMP_DIR"), __pmPathSeparator(), __pmPathSeparator()); file[MAXPATHLEN-1] = '\0'; if ((fd = open(file, O_RDONLY)) < 0) perror(file); else { struct stat s; void * addr; if (fstat(fd, &s) < 0) perror(file); else if ((addr = __pmMemoryMap(fd, s.st_size, 0)) != NULL) return dump(file, addr); } return 1; } pcp-3.8.12ubuntu1/src/pmdas/mmv/src/0000775000000000000000000000000012272262620014065 5ustar pcp-3.8.12ubuntu1/src/pmdas/mmv/src/Remove0000775000000000000000000000132512272262501015247 0ustar #! /bin/sh # # Copyright (C) 1997,2009 Silicon Graphics, Inc., All Rights Reserved. # Copyright (C) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=mmv pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/mmv/src/Install0000775000000000000000000000167412272262501015427 0ustar #! /bin/sh # # Copyright (C) 1997,2009 Silicon Graphics, Inc. All Rights Reserved. # Copyright (C) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=mmv dso_opt=true socket_opt=true socket_inet_def=2081 forced_restart=false pmda_interface=4 pmns_source=root_mmv if [ ! -e "$PCP_TMP_DIR/mmv" ] then echo "creating $PCP_TMP_DIR/mmv" mkdir -p -m 1777 "$PCP_TMP_DIR/mmv" fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/mmv/src/GNUmakefile0000664000000000000000000000314612272262501016141 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2009-2010 Aconex. All Rights Reserved. # Copyright (c) 2000-2001,2009 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../../.. include $(TOPDIR)/src/include/builddefs IAM = mmv DOMAIN = MMV CMDTARGET = pmda$(IAM)$(EXECSUFFIX) LIBTARGET = pmda_$(IAM).$(DSOSUFFIX) PMDAINIT = $(IAM)_init TARGETS = $(CMDTARGET) $(LIBTARGET) CFILES = mmv.c VERSION_SCRIPT = exports LSRCFILES = Install Remove root_mmv LLDLIBS = $(PCP_PMDALIB) LCFLAGS = $(INVISIBILITY) LDIRT = domain.h *.log pmns $(VERSION_SCRIPT) PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) default_pcp default: $(TARGETS) pmns include $(BUILDRULES) install_pcp install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 644 domain.h $(PMDADIR)/domain.h $(INSTALL) -m 755 $(TARGETS) Install Remove $(PMDADIR) $(INSTALL) -m 644 pmns $(PMDADIR)/root_mmv $(INSTALL) -m 644 root_mmv $(PCP_VAR_DIR)/pmns/root_mmv $(CMDTARGET): $(OBJECTS) $(IAM).o : domain.h $(LIBTARGET) : $(VERSION_SCRIPT) $(VERSION_SCRIPT): $(VERSION_SCRIPT_MAKERULE) domain.h: ../../../pmns/stdpmid $(DOMAIN_MAKERULE) pmns : $(LN_S) -f root_mmv pmns pcp-3.8.12ubuntu1/src/pmdas/mmv/src/mmv.c0000664000000000000000000005577712272262501015053 0ustar /* * Copyright (c) 2012 Red Hat. * Copyright (c) 2009-2010 Aconex. All Rights Reserved. * Copyright (c) 1995-2000,2009 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * * MMV PMDA * * This PMDA uses specially formatted files in either /var/tmp/mmv or some * other directory, as specified on the command line. Each file represents * a separate "cluster" of values with flat name structure for each cluster. * Names for the metrics are optionally prepended with mmv and then the name * of the file (by default - this can be changed). */ #include "pmapi.h" #include "mmv_stats.h" #include "mmv_dev.h" #include "impl.h" #include "pmda.h" #include "./domain.h" #include #include static int isDSO = 1; static char *username; static pmdaMetric * metrics; static int mcnt; static pmdaIndom * indoms; static int incnt; static int reload; static __pmnsTree * pmns; static time_t statsdir_ts; /* last statsdir timestamp */ static char * prefix = "mmv"; static char * pcptmpdir; /* probably /var/tmp */ static char * pcpvardir; /* probably /var/pcp */ static char * pcppmdasdir; /* probably /var/pcp/pmdas */ static char pmnsdir[MAXPATHLEN]; /* pcpvardir/pmns */ static char statsdir[MAXPATHLEN]; /* pcptmpdir/ */ typedef struct { char * name; /* strdup client name */ void * addr; /* mmap */ mmv_disk_value_t * values; /* values in mmap */ mmv_disk_metric_t * metrics; /* metric descs in mmap */ int vcnt; /* number of values */ int mcnt; /* number of metrics */ pid_t pid; /* process identifier */ int cluster; /* cluster identifier */ __int64_t len; /* mmap region len */ __uint64_t gen; /* generation number on open */ } stats_t; static stats_t * slist; static int scnt; /* * Choose an unused cluster ID while honouring specific requests. * If a specific (non-zero) cluster is requested we always use it. */ static int choose_cluster(int requested, const char *path) { int i; if (!requested) { int next_cluster = 1; for (i = 0; i < scnt; i++) { if (slist[i].cluster == next_cluster) { next_cluster++; i = 0; /* restart, we're filling holes */ } } return next_cluster; } for (i = 0; i < scnt; i++) { if (slist[i].cluster == requested) { if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "MMV: %s: duplicate cluster %d in use", pmProgname, requested); break; } } return requested; } static int create_client_stat(const char *client, const char *path, size_t size) { int fd; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "MMV: create_client_stat: %s, %s", client, path); if ((fd = open(path, O_RDONLY)) >= 0) { void *m = __pmMemoryMap(fd, size, 0); close(fd); if (m != NULL) { mmv_disk_header_t * hdr = (mmv_disk_header_t *)m; int cluster; if (strncmp(hdr->magic, "MMV", 4)) { __pmMemoryUnmap(m, size); return -EINVAL; } if (hdr->version != MMV_VERSION) { __pmNotifyErr(LOG_ERR, "%s: %s client version %d " "not supported (current is %d)", pmProgname, prefix, hdr->version, MMV_VERSION); __pmMemoryUnmap(m, size); return -ENOSYS; } if (!hdr->g1 || hdr->g1 != hdr->g2) { /* still in flux, wait till next time */ __pmMemoryUnmap(m, size); return -EAGAIN; } /* optionally verify the creator PID is running */ if (hdr->process && (hdr->flags & MMV_FLAG_PROCESS) && !__pmProcessExists((pid_t)hdr->process)) { __pmMemoryUnmap(m, size); return -ESRCH; } /* all checks out, we'll use this one */ cluster = choose_cluster(hdr->cluster, path); if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "MMV: %s: loading %s client: %d \"%s\"", pmProgname, prefix, cluster, path); slist = realloc(slist, sizeof(stats_t)*(scnt+1)); if (slist != NULL) { slist[scnt].name = strdup(client); slist[scnt].addr = m; slist[scnt].pid = (pid_t)((hdr->flags & MMV_FLAG_PROCESS)? hdr->process : 0); slist[scnt].cluster = cluster; slist[scnt].mcnt = 0; slist[scnt].gen = hdr->g1; slist[scnt].len = size; scnt++; } else { __pmNotifyErr(LOG_ERR, "%s: client \"%s\" out of memory - %s", pmProgname, client, osstrerror()); __pmMemoryUnmap(m, size); scnt = 0; } } else { __pmNotifyErr(LOG_ERR, "%s: failed to memory map \"%s\" - %s", pmProgname, path, osstrerror()); } } else { __pmNotifyErr(LOG_ERR, "%s: failed to open client file \"%s\" - %s", pmProgname, client, osstrerror()); } return 0; } /* check validity of client metric name, return non-zero if bad or duplicate */ static int verify_metric_name(const char *name, int pos, stats_t *s) { const char *p = name; pmID pmid; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "MMV: verify_metric_name: %s", name); if (p == NULL || *p == '\0' || !isalpha((int)*p)) { __pmNotifyErr(LOG_WARNING, "Invalid metric[%d] name start in %s, ignored", pos, s->name); return -EINVAL; } for (++p; (p != NULL && *p != '\0'); p++) { if (isalnum((int)*p) || *p == '_' || *p == '.') continue; __pmNotifyErr(LOG_WARNING, "invalid metric[%d] name in %s (@%c), ignored", pos, s->name, *p); return -EINVAL; } if (pmdaTreePMID(pmns, name, &pmid) == 0) return -EEXIST; return 0; } /* check client item number validity - must not be too large to fit in PMID! */ static int verify_metric_item(unsigned int item, char *name, stats_t *s) { if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "MMV: verify_metric_item: %u - %s", item, name); if (pmid_item(item) != item) { __pmNotifyErr(LOG_WARNING, "invalid item %u (%s) in %s, ignored", item, name, s->name); return -EINVAL; } return 0; } static int create_metric(pmdaExt *pmda, stats_t *s, mmv_disk_metric_t *m, char *name, pmID pmid) { if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "MMV: create_metric: %s - %s", name, pmIDStr(pmid)); metrics = realloc(metrics, sizeof(pmdaMetric) * (mcnt + 1)); if (metrics == NULL) { __pmNotifyErr(LOG_ERR, "cannot grow MMV metric list: %s", s->name); return -ENOMEM; } metrics[mcnt].m_user = NULL; metrics[mcnt].m_desc.pmid = pmid; if (m->type == MMV_TYPE_ELAPSED) { pmUnits unit = PMDA_PMUNITS(0,1,0,0,PM_TIME_USEC,0); metrics[mcnt].m_desc.sem = PM_SEM_COUNTER; metrics[mcnt].m_desc.type = MMV_TYPE_I64; metrics[mcnt].m_desc.units = unit; } else { if (m->semantics) metrics[mcnt].m_desc.sem = m->semantics; else metrics[mcnt].m_desc.sem = PM_SEM_COUNTER; metrics[mcnt].m_desc.type = m->type; memcpy(&metrics[mcnt].m_desc.units, &m->dimension, sizeof(pmUnits)); } metrics[mcnt].m_desc.indom = (!m->indom || m->indom == PM_INDOM_NULL) ? PM_INDOM_NULL : pmInDom_build(pmda->e_domain, (s->cluster << 11) | m->indom); if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "MMV: map_stats adding metric[%d] %s %s from %s\n", mcnt, name, pmIDStr(pmid), s->name); mcnt++; __pmAddPMNSNode(pmns, pmid, name); return 0; } /* check client serial number validity, and check for a duplicate */ static int verify_indom_serial(pmdaExt *pmda, int serial, stats_t *s, pmInDom *p, pmdaIndom **i) { int index; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "MMV: verify_indom_serial: %u", serial); if (pmInDom_serial(serial) != serial) { __pmNotifyErr(LOG_WARNING, "invalid serial %u in %s, ignored", serial, s->name); return -EINVAL; } *p = pmInDom_build(pmda->e_domain, (s->cluster << 11) | serial); for (index = 0; index < incnt; index++) { *i = &indoms[index]; if (indoms[index].it_indom == *p) return -EEXIST; } *i = NULL; return 0; } static int update_indom(pmdaExt *pmda, stats_t *s, mmv_disk_indom_t *id, pmdaIndom *ip) { int i, j, size, newinsts = 0; mmv_disk_instance_t *in = (mmv_disk_instance_t *)((char *)s->addr + id->offset); if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "MMV: update_indom: %u (%d insts)", id->serial, ip->it_numinst); /* first calculate how many new instances, so we know what to alloc */ for (i = 0; i < id->count; i++) { for (j = 0; j < ip->it_numinst; j++) if (ip->it_set[j].i_inst == in[i].internal) continue; if (j == ip->it_numinst) newinsts++; } if (!newinsts) return 0; /* allocate memory, then append new instances to the known set */ size = sizeof(pmdaInstid) * (ip->it_numinst + newinsts); ip->it_set = (pmdaInstid *)realloc(ip->it_set, size); if (ip->it_set != NULL) { for (i = 0; i < id->count; i++) { for (j = 0; j < ip->it_numinst; j++) if (ip->it_set[j].i_inst == in[j].internal) continue; if (j == ip->it_numinst) { ip->it_set[j].i_inst = in[i].internal; ip->it_set[j].i_name = in[i].external; ip->it_numinst++; } } } else { __pmNotifyErr(LOG_ERR, "%s: cannot get memory for instance list in %s", pmProgname, s->name); ip->it_numinst = 0; return -ENOMEM; } return 0; } static int create_indom(pmdaExt *pmda, stats_t *s, mmv_disk_indom_t *id, pmInDom indom) { int i; pmdaIndom *ip; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "MMV: create_indom: %u", id->serial); indoms = realloc(indoms, sizeof(pmdaIndom) * (incnt + 1)); if (indoms == NULL) { __pmNotifyErr(LOG_ERR, "%s: cannot grow indom list in %s", pmProgname, s->name); return -ENOMEM; } ip = &indoms[incnt++]; ip->it_indom = indom; ip->it_set = (pmdaInstid *)calloc(id->count, sizeof(pmdaInstid)); if (ip->it_set != NULL) { mmv_disk_instance_t * in = (mmv_disk_instance_t *) ((char *)s->addr + id->offset); ip->it_numinst = id->count; for (i = 0; i < ip->it_numinst; i++) { ip->it_set[i].i_inst = in[i].internal; ip->it_set[i].i_name = in[i].external; } } else { __pmNotifyErr(LOG_ERR, "%s: cannot get memory for instance list in %s", pmProgname, s->name); ip->it_numinst = 0; return -ENOMEM; } return 0; } static void map_stats(pmdaExt *pmda) { struct dirent **files; char name[64]; int need_reload = 0; int i, j, k, sts, num; if (pmns) __pmFreePMNS(pmns); if ((sts = __pmNewPMNS(&pmns)) < 0) { __pmNotifyErr(LOG_ERR, "%s: failed to create new pmns: %s\n", pmProgname, pmErrStr(sts)); pmns = NULL; return; } /* hard-coded metrics (not from mmap'd files */ snprintf(name, sizeof(name), "%s.reload", prefix); __pmAddPMNSNode(pmns, pmid_build(pmda->e_domain, 0, 0), name); snprintf(name, sizeof(name), "%s.debug", prefix); __pmAddPMNSNode(pmns, pmid_build(pmda->e_domain, 0, 1), name); mcnt = 2; if (indoms != NULL) { for (i = 0; i < incnt; i++) free(indoms[i].it_set); free(indoms); indoms = NULL; incnt = 0; } if (slist != NULL) { for (i = 0; i < scnt; i++) { free(slist[i].name); __pmMemoryUnmap(slist[i].addr, slist[i].len); } free(slist); slist = NULL; scnt = 0; } num = scandir(statsdir, &files, NULL, NULL); for (i = 0; i < num; i++) { struct stat statbuf; char path[MAXPATHLEN]; char *client; if (files[i]->d_name[0] == '.') continue; client = files[i]->d_name; sprintf(path, "%s%c%s", statsdir, __pmPathSeparator(), client); if (stat(path, &statbuf) >= 0 && S_ISREG(statbuf.st_mode)) if (create_client_stat(client, path, statbuf.st_size) == -EAGAIN) need_reload = 1; } for (i = 0; i < num; i++) free(files[i]); if (num > 0) free(files); for (i = 0; slist && i < scnt; i++) { stats_t * s = slist + i; mmv_disk_header_t * hdr = (mmv_disk_header_t *)s->addr; mmv_disk_toc_t * toc = (mmv_disk_toc_t *) ((char *)s->addr + sizeof(mmv_disk_header_t)); for (j = 0; j < hdr->tocs; j++) { switch (toc[j].type) { case MMV_TOC_METRICS: { mmv_disk_metric_t *ml = (mmv_disk_metric_t *) ((char *)s->addr + toc[j].offset); s->metrics = ml; s->mcnt = toc[j].count; for (k = 0; k < toc[j].count; k++) { char name[MAXPATHLEN]; pmID pmid; /* build name, check its legitimate and unique */ if (hdr->flags & MMV_FLAG_NOPREFIX) sprintf(name, "%s.", prefix); else sprintf(name, "%s.%s.", prefix, s->name); strcat(name, ml[k].name); if (verify_metric_name(name, k, s) != 0) continue; if (verify_metric_item(ml[k].item, name, s) != 0) continue; pmid = pmid_build(pmda->e_domain, s->cluster, ml[k].item); create_metric(pmda, s, &ml[k], name, pmid); } break; } case MMV_TOC_INDOMS: { mmv_disk_indom_t * id = (mmv_disk_indom_t *) ((char *)s->addr + toc[j].offset); for (k = 0; k < toc[j].count; k++) { int sts, serial = id[k].serial; pmInDom pmindom; pmdaIndom *ip; sts = verify_indom_serial(pmda, serial, s, &pmindom, &ip); if (sts == -EINVAL) continue; else if (sts == -EEXIST) /* see if we have new instances to add here */ update_indom(pmda, s, &id[k], ip); else /* first time we've observed this indom */ create_indom(pmda, s, &id[k], pmindom); } break; } case MMV_TOC_VALUES: { s->vcnt = toc[j].count; s->values = (mmv_disk_value_t *) ((char *)s->addr + toc[j].offset); break; } default: break; } } } pmdaTreeRebuildHash(pmns, mcnt); /* for reverse (pmid->name) lookups */ reload = need_reload; } static int mmv_lookup_stat_metric_value(pmID pmid, unsigned int inst, stats_t **sout, mmv_disk_metric_t **mout, mmv_disk_value_t **vout) { __pmID_int * id = (__pmID_int *)&pmid; mmv_disk_metric_t * m; mmv_disk_value_t * v; stats_t * s; int si, mi, vi; int sts = PM_ERR_PMID; for (si = 0; si < scnt; si++) { s = &slist[si]; if (s->cluster != id->cluster) continue; m = s->metrics; for (mi = 0; mi < s->mcnt; mi++) { if (m[mi].item != id->item) continue; sts = PM_ERR_INST; v = s->values; for (vi = 0; vi < s->vcnt; vi++) { mmv_disk_metric_t * mt = (mmv_disk_metric_t *) ((char *)s->addr + v[vi].metric); mmv_disk_instance_t * is = (mmv_disk_instance_t *) ((char *)s->addr + v[vi].instance); if ((mt == &m[mi]) && (mt->indom == PM_INDOM_NULL || mt->indom == 0 || inst == PM_IN_NULL || is->internal == inst)) { *sout = s; *mout = &m[mi]; *vout = &v[vi]; return 0; } } } } return sts; } /* * callback provided to pmdaFetch */ static int mmv_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int * id = (__pmID_int *)&(mdesc->m_desc.pmid); if (id->cluster == 0) { if (id->item == 0) { atom->l = reload; return 1; } if (id->item == 1) { atom->l = pmDebug; return 1; } return PM_ERR_PMID; } else if (scnt > 0) { /* We have at least one source of metrics */ mmv_disk_string_t * str; mmv_disk_metric_t * m; mmv_disk_value_t * v; stats_t * s; int rv; rv = mmv_lookup_stat_metric_value(mdesc->m_desc.pmid, inst, &s, &m, &v); if (rv < 0) return rv; switch (m->type) { case MMV_TYPE_I32: case MMV_TYPE_U32: case MMV_TYPE_I64: case MMV_TYPE_U64: case MMV_TYPE_FLOAT: case MMV_TYPE_DOUBLE: memcpy(atom, &v->value, sizeof(pmAtomValue)); break; case MMV_TYPE_ELAPSED: { atom->ll = v->value.ll; if (v->extra < 0) { /* inside a timed section */ struct timeval tv; __pmtimevalNow(&tv); atom->ll += (tv.tv_sec * 1e6 + tv.tv_usec) + v->extra; } break; } case MMV_TYPE_STRING: { str = (mmv_disk_string_t *)((char *)s->addr + v->extra); atom->cp = str->payload; break; } case MMV_TYPE_NOSUPPORT: return PM_ERR_APPVERSION; } return 1; } return 0; } static void mmv_reload_maybe(pmdaExt *pmda) { int i; struct stat s; int need_reload = reload; /* check if generation numbers changed or monitored process exited */ for (i = 0; i < scnt; i++) { mmv_disk_header_t *hdr = (mmv_disk_header_t *)slist[i].addr; if (hdr->g1 != slist[i].gen || hdr->g2 != slist[i].gen) { need_reload++; break; } if (slist[i].pid && !__pmProcessExists(slist[i].pid)) { need_reload++; break; } } /* check if the directory has been modified */ if (stat(statsdir, &s) >= 0 && s.st_mtime != statsdir_ts) { need_reload++; statsdir_ts = s.st_mtime; } if (need_reload) { if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "MMV: %s: reloading", pmProgname); map_stats(pmda); pmda->e_indoms = indoms; pmda->e_nindoms = incnt; pmdaRehash(pmda, metrics, mcnt); if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "MMV: %s: %d metrics and %d indoms after reload", pmProgname, mcnt, incnt); } } /* Intercept request for descriptor and check if we'd have to reload */ static int mmv_desc(pmID pmid, pmDesc *desc, pmdaExt *ep) { mmv_reload_maybe(ep); return pmdaDesc(pmid, desc, ep); } static int mmv_text(int ident, int type, char **buffer, pmdaExt *ep) { if (type & PM_TEXT_INDOM) return PM_ERR_TEXT; mmv_reload_maybe(ep); if (pmid_cluster(ident) == 0) { if (pmid_item(ident) == 0) { static char reloadoneline[] = "Control maps reloading"; static char reloadtext[] = "Writing anything other then 0 to this metric will result in\n" "re-reading directory and re-mapping files.\n"; *buffer = (type & PM_TEXT_ONELINE) ? reloadoneline : reloadtext; return 0; } else if (pmid_item(ident) == 1) { static char debugoneline[] = "Debug flag"; static char debugtext[] = "See pmdbg(1). pmstore into this metric to change the debug value.\n"; *buffer = (type & PM_TEXT_ONELINE) ? debugoneline : debugtext; return 0; } else return PM_ERR_PMID; } else { mmv_disk_string_t * str; mmv_disk_metric_t * m; mmv_disk_value_t * v; stats_t * s; if (mmv_lookup_stat_metric_value(ident, PM_IN_NULL, &s, &m, &v) != 0) return PM_ERR_PMID; if ((type & PM_TEXT_ONELINE) && m->shorttext) { str = (mmv_disk_string_t *)((char *)s->addr + m->shorttext); *buffer = str->payload; return 0; } if ((type & PM_TEXT_HELP) && m->helptext) { str = (mmv_disk_string_t *)((char *)s->addr + m->helptext); *buffer = str->payload; return 0; } } return PM_ERR_TEXT; } static int mmv_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *ep) { mmv_reload_maybe(ep); return pmdaInstance(indom, inst, name, result, ep); } static int mmv_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { mmv_reload_maybe(pmda); return pmdaFetch(numpmid, pmidlist, resp, pmda); } static int mmv_store(pmResult *result, pmdaExt *ep) { int i, m; mmv_reload_maybe(ep); for (i = 0; i < result->numpmid; i++) { pmValueSet * vsp = result->vset[i]; __pmID_int * id = (__pmID_int *)&vsp->pmid; if (id->cluster == 0) { for (m = 0; m < mcnt; m++) { __pmID_int * mid = (__pmID_int *)&(metrics[m].m_desc.pmid); if (mid->cluster == 0 && mid->item == id->item) { pmAtomValue atom; int sts; if (vsp->numval != 1 ) return PM_ERR_CONV; if ((sts = pmExtractValue(vsp->valfmt, &vsp->vlist[0], PM_TYPE_32, &atom, PM_TYPE_32)) < 0) return sts; if (id->item == 0) reload = atom.l; else if (id->item == 1) pmDebug = atom.l; else return PM_ERR_PERMISSION; } } } else return PM_ERR_PERMISSION; } return 0; } static int mmv_pmid(const char *name, pmID *pmid, pmdaExt *pmda) { mmv_reload_maybe(pmda); return pmdaTreePMID(pmns, name, pmid); } static int mmv_name(pmID pmid, char ***nameset, pmdaExt *pmda) { mmv_reload_maybe(pmda); return pmdaTreeName(pmns, pmid, nameset); } static int mmv_children(const char *name, int traverse, char ***kids, int **sts, pmdaExt *pmda) { mmv_reload_maybe(pmda); return pmdaTreeChildren(pmns, name, traverse, kids, sts); } void __PMDA_INIT_CALL mmv_init(pmdaInterface *dp) { int m; int sep = __pmPathSeparator(); if (isDSO) { pmdaDSO(dp, PMDA_INTERFACE_4, "mmv", NULL); } else { __pmSetProcessIdentity(username); } pcptmpdir = pmGetConfig("PCP_TMP_DIR"); pcpvardir = pmGetConfig("PCP_VAR_DIR"); pcppmdasdir = pmGetConfig("PCP_PMDAS_DIR"); snprintf(statsdir, sizeof(statsdir), "%s%c%s", pcptmpdir, sep, prefix); snprintf(pmnsdir, sizeof(pmnsdir), "%s%c" "pmns", pcpvardir, sep); statsdir[sizeof(statsdir)-1] = '\0'; pmnsdir[sizeof(pmnsdir)-1] = '\0'; /* Initialize internal dispatch table */ if (dp->status == 0) { /* * number of hard-coded metrics here has to match initializer * cases below, and pmns initialization in map_stats() */ mcnt = 2; if ((metrics = malloc(mcnt*sizeof(pmdaMetric))) != NULL) { /* * all the hard-coded metrics have the same semantics */ for (m = 0; m < mcnt; m++) { if (m == 0) metrics[m].m_user = &reload; else if (m == 1) metrics[m].m_user = &pmDebug; metrics[m].m_desc.pmid = pmid_build(dp->domain, 0, m); metrics[m].m_desc.type = PM_TYPE_32; metrics[m].m_desc.indom = PM_INDOM_NULL; metrics[m].m_desc.sem = PM_SEM_INSTANT; memset(&metrics[m].m_desc.units, 0, sizeof(pmUnits)); } } else { __pmNotifyErr(LOG_ERR, "%s: pmdaInit - out of memory\n", pmProgname); if (isDSO) return; exit(0); } dp->version.four.fetch = mmv_fetch; dp->version.four.store = mmv_store; dp->version.four.desc = mmv_desc; dp->version.four.text = mmv_text; dp->version.four.instance = mmv_instance; dp->version.four.pmid = mmv_pmid; dp->version.four.name = mmv_name; dp->version.four.children = mmv_children; pmdaSetFetchCallBack(dp, mmv_fetchCallBack); pmdaSetFlags(dp, PMDA_EXT_FLAG_HASHED); pmdaInit(dp, indoms, incnt, metrics, mcnt); } } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } int main(int argc, char **argv) { int c, err = 0; char logfile[32]; pmdaInterface dispatch = { 0 }; isDSO = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); if (strncmp(pmProgname, "pmda", 4) == 0 && strlen(pmProgname) > 4) prefix = pmProgname + 4; snprintf(logfile, sizeof(logfile), "%s.log", prefix); pmdaDaemon(&dispatch, PMDA_INTERFACE_4, pmProgname, MMV, logfile, NULL); while ((c = pmdaGetOpt(argc, argv, "D:d:l:U:?", &dispatch, &err)) != EOF) { switch(c) { case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&dispatch); mmv_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/mmv/src/root_mmv0000664000000000000000000000014712272262501015652 0ustar /* * MMV metrics name space */ #ifndef MMV #define MMV 70 #endif root { mmv MMV:*:* } #undef MMV pcp-3.8.12ubuntu1/src/pmdas/mmv/GNUmakefile0000664000000000000000000000344212272262501015351 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2009-2010 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = mmv TARGET = mmvdump$(EXECSUFFIX) CFILES = mmvdump.c SUBDIRS = src LCFILES = acme.c LTARGET = acme$(EXECSUFFIX) LSRCFILES = $(LCFILES) README.demos Makefile.demos TARGETS = $(TARGET) $(LTARGET) LLDFLAGS = -L$(TOPDIR)/src/libpcp_mmv/src -L$(TOPDIR)/src/libpcp/src LLDLIBS = -lpcp_mmv $(PCPLIB) PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) DEMODIR = $(PCP_DEMOS_DIR)/$(IAM) DEMOFILES = README.demos Makefile.demos CONF_LINE = "mmv 70 dso mmv_init $(PCP_PMDAS_DIR)/mmv/pmda_mmv.$(DSOSUFFIX)" default_pcp default :: $(TARGETS) default_pcp default :: $(SUBDIRS) $(SUBDIRS_MAKERULE) @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi include $(BUILDRULES) install_pcp install :: $(SUBDIRS) $(SUBDIRS_MAKERULE) install_pcp install :: $(SUBDIRS) $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(TARGET) $(PMDADIR)/$(TARGET) $(INSTALL) -m 755 -d $(DEMODIR) $(INSTALL) -m 644 Makefile.demos $(DEMODIR)/Makefile $(INSTALL) -m 644 README.demos $(DEMODIR)/README $(INSTALL) -m 644 $(CFILES) $(LCFILES) $(DEMODIR) # check-build only, binary not installed (but source is) $(LTARGET): acme.c $(CCF) -o $@ $^ $(LDFLAGS) $(LDLIBS) pcp-3.8.12ubuntu1/src/pmdas/mmv/acme.c0000664000000000000000000001044712272262501014353 0ustar /* * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include static mmv_instances_t products[] = { { .internal = 0, .external = "Anvils" }, { .internal = 1, .external = "Rockets" }, { .internal = 2, .external = "Giant_Rubber_Bands" }, }; #define ACME_PRODUCTS_INDOM 61 #define ACME_PRODUCTS_COUNT (sizeof(products)/sizeof(products[0])) static mmv_indom_t indoms[] = { { .serial = ACME_PRODUCTS_INDOM, .count = ACME_PRODUCTS_COUNT, .instances = products, .shorttext = "Acme products", .helptext = "Most popular products produced by the Acme Corporation", }, }; static mmv_metric_t metrics[] = { { .name = "products.count", .item = 7, .type = MMV_TYPE_U64, .semantics = MMV_SEM_COUNTER, .dimension = MMV_UNITS(0,0,1,0,0,PM_COUNT_ONE), .indom = ACME_PRODUCTS_INDOM, .shorttext = "Acme factory product throughput", .helptext = "Monotonic increasing counter of products produced in the Acme Corporation\n" "factory since starting the Acme production application. Quality guaranteed.", }, { .name = "products.time", .item = 8, .type = MMV_TYPE_U64, .semantics = MMV_SEM_COUNTER, .dimension = MMV_UNITS(0,1,0,0,PM_TIME_USEC,0), .indom = ACME_PRODUCTS_INDOM, .shorttext = "Machine time spent producing Acme products", .helptext = "Machine time spent producing Acme Corporation products. Does not include\n" "time in queues waiting for production machinery.", }, { .name = "products.queuetime", .item = 10, .type = MMV_TYPE_U64, .semantics = MMV_SEM_COUNTER, .dimension = MMV_UNITS(0,1,0,0,PM_TIME_USEC,0), .indom = ACME_PRODUCTS_INDOM, .shorttext = "Queued time while producing Acme products", .helptext = "Time spent in the queue waiting to build Acme Corporation products,\n" "while some other Acme product was being built instead of this one.", }, }; #define INDOM_COUNT (sizeof(indoms)/sizeof(indoms[0])) #define METRIC_COUNT (sizeof(metrics)/sizeof(metrics[0])) #define ACME_CLUSTER 321 /* PMID cluster identifier */ int main(int argc, char * argv[]) { void *base; pmAtomValue *count[ACME_PRODUCTS_COUNT]; pmAtomValue *machine[ACME_PRODUCTS_COUNT]; pmAtomValue *inqueue[ACME_PRODUCTS_COUNT]; unsigned int working; unsigned int product; unsigned int i; base = mmv_stats_init("acme", ACME_CLUSTER, 0, metrics, METRIC_COUNT, indoms, INDOM_COUNT); if (!base) { perror("mmv_stats_init"); return 1; } for (i = 0; i < ACME_PRODUCTS_COUNT; i++) { count[i] = mmv_lookup_value_desc(base, "products.count", products[i].external); machine[i] = mmv_lookup_value_desc(base, "products.time", products[i].external); inqueue[i] = mmv_lookup_value_desc(base, "products.queuetime", products[i].external); } while (1) { /* choose a random number between 0-N -> product */ product = rand() % ACME_PRODUCTS_COUNT; /* assign a time spent "working" on this product */ working = rand() % 50000; /* pretend to "work" so process doesn't burn CPU */ usleep(working); /* update the memory mapped values for this one: */ /* one more product produced and work time spent */ mmv_inc_value(base, machine[product], working); /* API */ count[product]->ull += 1; /* or direct mmap update */ /* all other products are "queued" for this time */ for (i = 0; i < ACME_PRODUCTS_COUNT; i++) if (i != product) mmv_inc_value(base, inqueue[i], working); } mmv_stats_stop("acme", base); return 0; } pcp-3.8.12ubuntu1/src/pmdas/rsyslog/0000775000000000000000000000000012272262620014201 5ustar pcp-3.8.12ubuntu1/src/pmdas/rsyslog/pmdarsyslog.pl0000664000000000000000000002265712272262501017114 0ustar # # Copyright (c) 2012-2013 Red Hat. # Copyright (c) 2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; my $pmda = PCP::PMDA->new('rsyslog', 107); my $statsfile = pmda_config('PCP_LOG_DIR') . '/rsyslog/stats'; my ($es_connfail, $es_submits, $es_failed, $es_success) = (0,0,0,0); my ($ux_submitted, $ux_discarded, $ux_ratelimiters) = (0,0,0); my ($interval, $lasttime) = (0,0); my $queue_indom = 0; my @queue_insts = (); use vars qw(%queue_ids %queue_values); # .* rsyslogd-pstats: # imuxsock: submitted=37 ratelimit.discarded=0 ratelimit.numratelimiters=22 # elasticsearch: connfail=0 submits=0 failed=0 success=0 # [main Q]: size=1 enqueued=1436 full=0 maxqsize=3 sub rsyslog_parser { ( undef, $_ ) = @_; #$pmda->log("rsyslog_parser got line: $_"); if (m|rsyslogd-pstats:|) { my $timenow = time; if ($lasttime != 0) { if ($timenow > $lasttime) { $interval = $timenow - $lasttime; $lasttime = $timenow; } } else { $lasttime = $timenow; } } if (m|imuxsock: submitted=(\d+) ratelimit.discarded=(\d+) ratelimit.numratelimiters=(\d+)|) { ($ux_submitted, $ux_discarded, $ux_ratelimiters) = ($1,$2,$3); } elsif (m|elasticsearch: connfail=(\d+) submits=(\d+) failed=(\d+) success=(\d+)|) { ($es_connfail, $es_submits, $es_failed, $es_success) = ($1,$2,$3,$4); } elsif (m|stats: (.+): size=(\d+) enqueued=(\d+) full=(\d+) maxqsize=(\d+)|) { my ($qname, $qid) = ($1, undef); if (!defined($queue_ids{$qname})) { $qid = @queue_insts / 2; $queue_ids{$qname} = $qid; push @queue_insts, ($qid, $qname); $pmda->replace_indom($queue_indom, \@queue_insts); } $queue_values{$qname} = [ $2, $3, $4, $5 ]; } } sub rsyslog_fetch_callback { my ($cluster, $item, $inst) = @_; #$pmda->log("rsyslog_fetch_callback for PMID: $cluster.$item ($inst)"); return (PM_ERR_AGAIN,0) unless ($interval != 0); if ($cluster == 0) { return (PM_ERR_INST, 0) unless ($inst == PM_IN_NULL); if ($item == 0) { return ($interval, 1); } if ($item == 1) { return ($ux_submitted, 1); } if ($item == 2) { return ($ux_discarded, 1); } if ($item == 3) { return ($ux_ratelimiters, 1); } if ($item == 8) { return ($es_connfail, 1); } if ($item == 9) { return ($es_submits, 1); } if ($item == 10){ return ($es_failed, 1); } if ($item == 11){ return ($es_success, 1); } } elsif ($cluster == 1) { # queues return (PM_ERR_INST, 0) unless ($inst != PM_IN_NULL); return (PM_ERR_INST, 0) unless ($inst <= @queue_insts); my $qname = $queue_insts[$inst * 2 + 1]; my $qvref = $queue_values{$qname}; my @qvals; return (PM_ERR_INST, 0) unless defined ($qvref); @qvals = @$qvref; if ($item == 0) { return ($qvals[0], 1); } if ($item == 1) { return ($qvals[1], 1); } if ($item == 2) { return ($qvals[2], 1); } if ($item == 3) { return ($qvals[3], 1); } } return (PM_ERR_PMID, 0); } die "Cannot find a valid rsyslog statistics named pipe\n" unless -p $statsfile; $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'rsyslog.interval', 'Time interval observed between samples', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'rsyslog.imuxsock.submitted', 'Cumulative count of unix domain socket input messages queued', "Cumulative count of messages successfully queued to the rsyslog\n" . "main message queueing core that arrived on unix domain sockets."); $pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'rsyslog.imuxsock.discarded', 'Count of unix domain socket messages discarded due to rate limiting', "Cumulative count of messages that are were discarded due to their\n" . "priority being at or below rate-limit-severity and their sending\n" . "process being deemed to be sending messages too quickly (refer to\n" . "parameters ratelimitburst, ratelimitinterval and ratelimitseverity"); $pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), 'rsyslog.imuxsock.numratelimiters', 'Count of messages received that could be subject to rate limiting', "Cumulative count of messages that rsyslog received and performed a\n" . "credentials (PID) lookup for subsequent rate limiting decisions.\n" . "The message would have to be at rate-limit-severity or lower, with\n" . "rate limiting enabled, in order for this count to be incremented."); $pmda->add_metric(pmda_pmid(0,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'rsyslog.elasticsearch.connfail', 'Count of failed connections while attempting to send events', ''); $pmda->add_metric(pmda_pmid(0,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'rsyslog.elasticsearch.submits', 'Count of valid submissions of events to elasticsearch indexer', ''); $pmda->add_metric(pmda_pmid(0,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'rsyslog.elasticsearch.failed', 'Count of failed attempts to send events to elasticsearch', 'This count is often a good indicator of malformed JSON messages'); $pmda->add_metric(pmda_pmid(0,11), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'rsyslog.elasticsearch.success', 'Count of successfully acknowledged events from elasticsearch', ''); $pmda->add_metric(pmda_pmid(1,0), PM_TYPE_U64, $queue_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'rsyslog.queues.size', 'Current queue depth for each rsyslog queue', "As messages arrive they are enqueued to the main message queue\n" . "(for example) -this counter is incremented for each such message."); $pmda->add_metric(pmda_pmid(1,1), PM_TYPE_U64, $queue_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'rsyslog.queues.enqueued', 'Cumulative count of nessages enqueued to individual queues', "As messages arrive they are added to the main message processing\n" . "queue, either individually or in batches in the case of messages\n" . "arriving on the network."); $pmda->add_metric(pmda_pmid(1,2), PM_TYPE_U64, $queue_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'rsyslog.queues.full', 'Cumulative count of message arrivals with a full queue', "When messages are enqueued, a check is first made to ensure the\n" . "queue is not full. If it is, this counter is incremented. The\n" . "full-queue-handling logic will wait for a configurable time for\n" . "the queue congestion to ease, failing which the message will be\n" . "discarded. Worth keeping an eye on this metric, as it indicates\n" . "rsyslog is not able to process messages quickly enough given the\n" . "current arrival rate."); $pmda->add_metric(pmda_pmid(1,3), PM_TYPE_U64, $queue_indom, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'rsyslog.queues.maxsize', 'Maximum depth reached by an individual queue', "When messages arrive (for example) they are enqueued to the main\n" . "message queue - if the queue length on arrival is now greater than\n" . "ever before observed, we set this value to the current queue size"); $pmda->add_indom($queue_indom, \@queue_insts, 'Instance domain exporting each rsyslog queue', ''); $pmda->add_tail($statsfile, \&rsyslog_parser, 0); $pmda->set_fetch_callback(\&rsyslog_fetch_callback); $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdarsyslog - rsyslog (reliable and extended syslog) PMDA =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from the rsyslogd(8) server. Further details about rsyslog can be found at http://www.rsyslog.com/. =head1 INSTALLATION If you want access to the names and values for the rsyslog performance metrics, do the following as root: # cd $PCP_PMDAS_DIR/rsyslog # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/rsyslog # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. In order to use this agent, rsyslog stats gathering must be enabled. This is done by adding the lines: $ModLoad impstats $PStatsInterval 5 # log every 5 seconds syslog.info |/var/log/pcp/rsyslog/stats to your rsyslog.conf(5) configuration file after installing the PMDA. Take care to ensure the syslog.info messages do not get logged in any other file, as this could unexpectedly fill your filesystem. Syntax useful for this is syslog.!=info for explicitly excluding these. =head1 FILES =over =item /var/log/pcp/rsyslog/stats named pipe containing statistics exported from rsyslog, usually created by the PMDA Install script. =item $PCP_PMDAS_DIR/rsyslog/Install installation script for the B agent =item $PCP_PMDAS_DIR/rsyslog/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/rsyslog.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1), rsyslog.conf(5), rsyslogd(8). pcp-3.8.12ubuntu1/src/pmdas/rsyslog/Remove0000775000000000000000000000126112272262501015362 0ustar #!/bin/sh # # Copyright (c) 2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the rsyslog PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=rsyslog pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/rsyslog/Install0000775000000000000000000000216112272262501015533 0ustar #!/bin/sh # # Copyright (c) 2012 Red Hat. # Copyright (c) 2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the rsyslog PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=rsyslog perl_opt=true daemon_opt=false forced_restart=false statsfile="$PCP_LOG_DIR/rsyslog/stats" statsdir=`dirname "$statsfile"` if ! test -d "$statsdir"; then echo "Creating rsyslog statistics file directory: $statsdir" mkdir "$statsdir" [ $? -eq 0 ] || exit 1 fi if ! test -p "$statsfile"; then echo "Creating rsyslog statistics file: $statsfile" mkfifo "$statsfile" [ $? -eq 0 ] || exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/rsyslog/GNUmakefile0000664000000000000000000000235012272262501016251 0ustar #!gmake # # Copyright (c) 2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = rsyslog PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/darwin/0000775000000000000000000000000012272262620013763 5ustar pcp-3.8.12ubuntu1/src/pmdas/darwin/network.c0000664000000000000000000001222512272262501015620 0ustar /* * Copyright (c) 2004,2006 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "network.h" extern char *pmProgname; extern mach_port_t mach_master_port; void init_network(void) { } /* * Ensure we have space for the next interface in our pre-allocated * interface stats pool. If not, make some or pass on the error. */ static int check_stats_size(struct netstats *stats, int count) { if (count > stats->highwater) { stats->highwater++; stats->interfaces = realloc(stats->interfaces, stats->highwater * sizeof(struct ifacestat)); if (!stats->interfaces) { stats->highwater = 0; return -ENOMEM; } } return 0; } /* * Insert all interfaces into the global network instance domain. */ static int update_network_indom(struct netstats *all, int count, pmdaIndom *indom) { int i; if (count > 0 && count != indom->it_numinst) { i = sizeof(pmdaInstid) * count; if ((indom->it_set = realloc(indom->it_set, i)) == NULL) { indom->it_numinst = 0; return -ENOMEM; } } for (i = 0; i < count; i++) { indom->it_set[i].i_name = all->interfaces[i].name; indom->it_set[i].i_inst = i; } indom->it_numinst = count; return 0; } int refresh_network(struct netstats *stats, pmdaIndom *indom) { int i = 0, status = 0; size_t n; char *new_buf, *next, *end; struct sockaddr_dl *sdl; static char *buf=NULL; static size_t buf_len=0; #ifdef RTM_IFINFO2 struct if_msghdr2 *ifm; int mib[6] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0}; #else struct if_msghdr *ifm; int mib[6] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0}; #endif if( sysctl( mib, 6, NULL, &n, NULL, 0 ) < 0 ) { /* unable to query buffer size */ fprintf( stderr, "%s: get net mib buf len failed\n", pmProgname ); return -ENXIO; } if( n > buf_len ) { if( (new_buf = malloc(n)) == NULL ) { /* unable to malloc buf */ fprintf( stderr, "%s: net mib buf malloc failed\n", pmProgname ); return -ENXIO; } else { if( buf != NULL ) free( buf ); buf = new_buf; buf_len = n; } } if( sysctl( mib, 6, buf, &n, NULL, 0 ) < 0 ) { /* unable to copy-in buffer */ fprintf( stderr, "%s: net mib buf read failed\n", pmProgname ); return -ENXIO; } for( next = buf, i=0, end = buf + n; next < end; ) { #ifdef RTM_IFINFO2 ifm = (struct if_msghdr2 *)next; next += ifm->ifm_msglen; if( ifm->ifm_type == RTM_IFINFO2 ) { #else ifm = (struct if_msghdr *)next; next += ifm->ifm_msglen; if( ifm->ifm_type == RTM_IFINFO ) { #endif status = check_stats_size(stats, i + 1); if (status < 0) break; sdl = (struct sockaddr_dl *)(ifm + 1); n = sdl->sdl_nlen < IFNAMEMAX ? sdl->sdl_nlen : IFNAMEMAX; strncpy( stats->interfaces[i].name, sdl->sdl_data, n ); stats->interfaces[i].name[n] = 0; stats->interfaces[i].mtu = ifm->ifm_data.ifi_mtu; stats->interfaces[i].baudrate = ifm->ifm_data.ifi_baudrate; stats->interfaces[i].ipackets = ifm->ifm_data.ifi_ipackets; stats->interfaces[i].ierrors = ifm->ifm_data.ifi_ierrors; stats->interfaces[i].opackets = ifm->ifm_data.ifi_opackets; stats->interfaces[i].oerrors = ifm->ifm_data.ifi_oerrors; stats->interfaces[i].collisions = ifm->ifm_data.ifi_collisions; stats->interfaces[i].ibytes = ifm->ifm_data.ifi_ibytes; stats->interfaces[i].obytes = ifm->ifm_data.ifi_obytes; stats->interfaces[i].imcasts = ifm->ifm_data.ifi_imcasts; stats->interfaces[i].omcasts = ifm->ifm_data.ifi_omcasts; stats->interfaces[i].iqdrops = ifm->ifm_data.ifi_iqdrops; i++; } } if (!status) update_network_indom(stats, i, indom); return status; } int refresh_nfs(struct nfsstats *stats) { int name[3]; size_t length = sizeof(struct nfsstats); static int nfstype = -1; if (nfstype == -1) { struct vfsconf vfsconf; if (getvfsbyname("nfs", &vfsconf) == -1) return -oserror(); nfstype = vfsconf.vfc_typenum; } name[0] = CTL_VFS; name[1] = nfstype; name[0] = NFS_NFSSTATS; if (sysctl(name, 3, stats, &length, NULL, 0) == -1) return -oserror(); stats->biocache_reads -= stats->read_bios; stats->biocache_writes -= stats->write_bios; stats->biocache_readlinks -= stats->readlink_bios; stats->biocache_readdirs -= stats->readdir_bios; return 0; } pcp-3.8.12ubuntu1/src/pmdas/darwin/disk.h0000664000000000000000000000333012272262501015063 0ustar /* * Disk statistics types * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define DEVNAMEMAX 255 /* largest device name we allow */ /* * Per-device statistics */ typedef struct diskstat { __uint64_t read; __uint64_t write; __uint64_t read_bytes; __uint64_t write_bytes; __uint64_t read_time; __uint64_t write_time; __uint64_t blocksize; char name[DEVNAMEMAX + 1]; } diskstat_t; /* * Global statistics. * * We avoid continually realloc'ing memory by keeping track * of the maximum number of devices we've allocated space for * so far, and only realloc new space if we go beyond that. */ typedef struct diskstats { __uint64_t read; __uint64_t write; __uint64_t read_bytes; __uint64_t write_bytes; __uint64_t blkread; __uint64_t blkwrite; __uint64_t read_time; __uint64_t write_time; int highwater; /* largest number of devices seen so far */ diskstat_t *disks; /* space for highwater number of devices */ } diskstats_t; pcp-3.8.12ubuntu1/src/pmdas/darwin/GNUmakefile0000664000000000000000000000370712272262501016042 0ustar # # Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = darwin DOMAIN = DARWIN CMDTARGET = pmdadarwin LIBTARGET = pmda_darwin.dylib PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) CONF_LINE = "darwin 78 dso darwin_init $(PMDADIR)/$(LIBTARGET)" CFILES = pmda.c kernel.c disk.c network.c HFILES = disk.h network.h LSRCFILES = help root pmns FRAMEWORKS = -framework CoreFoundation -framework IOKit LLDLIBS = $(PCP_PMDALIB) $(FRAMEWORKS) LDIRT = *.log *.dir *.pag root_darwin domain.h default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "darwin" build-me: root_darwin domain.h $(LIBTARGET) $(CMDTARGET) help.dir help.pag @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi install: build-me $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 644 domain.h help.dir help.pag $(PMDADIR) $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(PMDADIR) $(INSTALL) -m 644 root_darwin $(PCP_VAR_DIR)/pmns/root_darwin else build-me: install: endif default_pcp : default install_pcp : install help.dir help.pag: help root_darwin $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_darwin -v 2 -o help < help root_darwin: ../../pmns/stdpmid root pmns rm -f root_darwin sed -e 's;;"../../pmns/stdpmid";' root_darwin domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/darwin/root0000664000000000000000000000020612272262501014665 0ustar #include root { kernel pmda mem hinv filesys disk network nfs3 rpc } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/darwin/pmns0000664000000000000000000001007212272262501014661 0ustar hinv { physmem DARWIN:1:2 pagesize DARWIN:0:0 ncpu DARWIN:8:71 nfilesys DARWIN:5:31 ndisk DARWIN:7:46 } pmda { uname DARWIN:2:28 version DARWIN:2:29 } kernel { uname all percpu } kernel.uname { release DARWIN:2:23 version DARWIN:2:24 sysname DARWIN:2:25 machine DARWIN:2:26 nodename DARWIN:2:27 } kernel.all { cpu load DARWIN:3:30 uptime DARWIN:9:76 hz DARWIN:0:1 } kernel.all.cpu { user DARWIN:6:42 nice DARWIN:6:43 sys DARWIN:6:44 idle DARWIN:6:45 } kernel.percpu { cpu } kernel.percpu.cpu { user DARWIN:8:72 nice DARWIN:8:73 sys DARWIN:8:74 idle DARWIN:8:75 } mem { physmem DARWIN:1:3 freemem DARWIN:1:4 active DARWIN:1:5 inactive DARWIN:1:6 pages pageins DARWIN:1:15 pageouts DARWIN:1:16 cache_hits DARWIN:1:17 cache_lookups DARWIN:1:18 util } mem.pages { freemem DARWIN:1:7 active DARWIN:1:8 inactive DARWIN:1:9 reactivated DARWIN:1:10 wired DARWIN:1:11 faults DARWIN:1:12 cow_faults DARWIN:1:13 zero_filled DARWIN:1:14 } mem.util { wired DARWIN:1:19 active DARWIN:1:20 inactive DARWIN:1:21 free DARWIN:1:22 } filesys { capacity DARWIN:5:32 used DARWIN:5:33 free DARWIN:5:34 maxfiles DARWIN:5:129 usedfiles DARWIN:5:35 freefiles DARWIN:5:36 mountdir DARWIN:5:37 full DARWIN:5:38 blocksize DARWIN:5:39 avail DARWIN:5:40 type DARWIN:5:41 } disk { dev all } disk.dev { read DARWIN:7:47 write DARWIN:7:48 total DARWIN:7:49 read_bytes DARWIN:7:50 write_bytes DARWIN:7:51 total_bytes DARWIN:7:52 blkread DARWIN:7:53 blkwrite DARWIN:7:54 blktotal DARWIN:7:55 read_time DARWIN:7:56 write_time DARWIN:7:57 total_time DARWIN:7:58 } disk.all { read DARWIN:7:59 write DARWIN:7:60 total DARWIN:7:61 read_bytes DARWIN:7:62 write_bytes DARWIN:7:63 total_bytes DARWIN:7:64 blkread DARWIN:7:65 blkwrite DARWIN:7:66 blktotal DARWIN:7:67 read_time DARWIN:7:68 write_time DARWIN:7:69 total_time DARWIN:7:70 } network { interface } network.interface { in out collisions DARWIN:10:86 mtu DARWIN:10:87 baudrate DARWIN:10:88 total } network.interface.in { bytes DARWIN:10:77 packets DARWIN:10:78 errors DARWIN:10:79 drops DARWIN:10:80 mcasts DARWIN:10:81 } network.interface.out { bytes DARWIN:10:82 packets DARWIN:10:83 errors DARWIN:10:84 mcasts DARWIN:10:85 } network.interface.total { bytes DARWIN:10:89 packets DARWIN:10:90 errors DARWIN:10:91 drops DARWIN:10:92 mcasts DARWIN:10:93 } nfs3 { client server } nfs3.client { calls DARWIN:11:94 reqs DARWIN:11:95 } nfs3.server { calls DARWIN:11:96 reqs DARWIN:11:97 } rpc { client server } rpc.client { rpccnt DARWIN:11:98 rpcretrans DARWIN:11:99 rpctimeouts DARWIN:11:100 rpcinvalid DARWIN:11:101 rpcunexpected DARWIN:11:102 attrcache lookupcache biocache direofcache } rpc.client.attrcache { hits DARWIN:11:103 misses DARWIN:11:104 } rpc.client.lookupcache { hits DARWIN:11:105 misses DARWIN:11:106 } rpc.client.biocache { read write readlink readdir } rpc.client.biocache.read { hits DARWIN:11:107 misses DARWIN:11:108 } rpc.client.biocache.write { hits DARWIN:11:109 misses DARWIN:11:110 } rpc.client.biocache.readlink { hits DARWIN:11:111 misses DARWIN:11:112 } rpc.client.biocache.readdir { hits DARWIN:11:113 misses DARWIN:11:114 } rpc.client.direofcache { hits DARWIN:11:115 misses DARWIN:11:116 } rpc.server { retfailed DARWIN:11:117 faults DARWIN:11:118 cache vopwrites DARWIN:11:126 pageins DARWIN:11:127 pageouts DARWIN:11:128 } rpc.server.cache { inprog DARWIN:11:119 nonidem DARWIN:11:120 idem DARWIN:11:121 misses DARWIN:11:122 } pcp-3.8.12ubuntu1/src/pmdas/darwin/kernel.c0000664000000000000000000001146512272262501015414 0ustar /* * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" extern mach_port_t mach_host; extern int mach_hertz; int refresh_vmstat(struct vm_statistics *vmstat) { int error, info = HOST_VM_INFO; natural_t count = HOST_VM_INFO_COUNT; error = host_statistics(mach_host, info, (host_info_t)vmstat, &count); return (error != KERN_SUCCESS) ? -oserror() : 0; } int refresh_cpuload(struct host_cpu_load_info *cpuload) { int error, info = HOST_CPU_LOAD_INFO; natural_t count = HOST_CPU_LOAD_INFO_COUNT; error = host_statistics(mach_host, info, (host_info_t)cpuload, &count); return (error != KERN_SUCCESS) ? -oserror() : 0; } int refresh_uname(struct utsname *utsname) { return (uname(utsname) == -1) ? -oserror() : 0; } int refresh_hertz(unsigned int *hertz) { int mib[2] = { CTL_KERN, KERN_CLOCKRATE }; size_t size = sizeof(struct clockinfo); struct clockinfo clockrate; if (sysctl(mib, 2, &clockrate, &size, NULL, 0) == -1) return -oserror(); *hertz = clockrate.hz; return 0; } int refresh_loadavg(float *loadavg) { int mib[2] = { CTL_VM, VM_LOADAVG }; size_t size = sizeof(struct loadavg); struct loadavg loadavgs; if (sysctl(mib, 2, &loadavgs, &size, NULL, 0) == -1) return -oserror(); loadavg[0] = (float)loadavgs.ldavg[0] / (float)loadavgs.fscale; loadavg[1] = (float)loadavgs.ldavg[1] / (float)loadavgs.fscale; loadavg[2] = (float)loadavgs.ldavg[2] / (float)loadavgs.fscale; return 0; } int refresh_uptime(unsigned int *uptime) { static struct timeval boottime; struct timeval timediff; if (!boottime.tv_sec) { int mib[2] = { CTL_KERN, KERN_BOOTTIME }; size_t size = sizeof(struct timeval); if (sysctl(mib, 2, &boottime, &size, NULL, 0) == -1) return -oserror(); } __pmtimevalNow(&timediff); timediff.tv_usec -= boottime.tv_usec; if (timediff.tv_usec < 0) { timediff.tv_usec += 1000000; timediff.tv_sec--; } timediff.tv_sec -= boottime.tv_sec; *uptime = timediff.tv_sec; return 0; } int refresh_cpus(struct processor_cpu_load_info **cpuload, pmdaIndom *indom) { natural_t ncpu, icount; processor_info_array_t iarray; struct processor_cpu_load_info *cpuinfo; int error, i, info = PROCESSOR_CPU_LOAD_INFO; error = host_processor_info(mach_host, info, &ncpu, &iarray, &icount); if (error != KERN_SUCCESS) return -oserror(); cpuinfo = (struct processor_cpu_load_info *)iarray; if (ncpu != indom->it_numinst) { char name[16]; /* 8 is real max atm, but be conservative */ error = -ENOMEM; i = sizeof(unsigned long) * CPU_STATE_MAX * ncpu; if ((*cpuload = realloc(*cpuload, i)) == NULL) goto vmdealloc; i = sizeof(pmdaInstid) * ncpu; if ((indom->it_set = realloc(indom->it_set, i)) == NULL) { free(*cpuload); *cpuload = NULL; indom->it_numinst = 0; goto vmdealloc; } for (i = 0; i < ncpu; i++) { snprintf(name, sizeof(name), "cpu%d", i); indom->it_set[i].i_name = strdup(name); indom->it_set[i].i_inst = i; } indom->it_numinst = ncpu; } error = 0; for (i = 0; i < ncpu; i++) memcpy(&(*cpuload)[i], &cpuinfo[i], sizeof(unsigned long) * CPU_STATE_MAX); vmdealloc: vm_deallocate(mach_host, (vm_address_t)iarray, icount); return error; } int refresh_filesys(struct statfs **filesys, pmdaIndom *indom) { int i, count = getmntinfo(filesys, MNT_NOWAIT); if (count < 0) { indom->it_numinst = 0; indom->it_set = NULL; return -oserror(); } if (count > 0 && count != indom->it_numinst) { i = sizeof(pmdaInstid) * count; if ((indom->it_set = realloc(indom->it_set, i)) == NULL) { indom->it_numinst = 0; return -ENOMEM; } } for (i = 0; i < count; i++) { indom->it_set[i].i_name = (*filesys)[i].f_mntfromname; indom->it_set[i].i_inst = i; } indom->it_numinst = count; return 0; } #if 0 int refresh_hinv() { sysctl... hw.machine = Power Macintosh hw.model = PowerMac4,2 hw.busfrequency = 99837332 hw.cpufrequency = 700000000 hw.cachelinesize = 32 hw.l1icachesize = 32768 hw.l1dcachesize = 32768 hw.l2settings = 2147483648 hw.l2cachesize = 262144 } #endif pcp-3.8.12ubuntu1/src/pmdas/darwin/pmda.c0000664000000000000000000013065212272262501015055 0ustar /* * MacOS X kernel PMDA * "darwin" is easier to type than "macosx", especially for Aussies. ;-) * * Copyright (c) 2012 Red Hat. * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include "disk.h" #include "network.h" #define page_count_to_kb(x) (((__uint64_t)(x) << mach_page_shift) >> 10) #define page_count_to_mb(x) (((__uint64_t)(x) << mach_page_shift) >> 20) static pmdaInterface dispatch; static int _isDSO = 1; /* =0 I am a daemon */ static char *username; mach_port_t mach_host = 0; vm_size_t mach_page_size = 0; unsigned int mach_page_shift = 0; unsigned int mach_hertz = 0; extern int refresh_hertz(unsigned int *); int mach_uname_error = 0; struct utsname mach_uname = { { 0 } }; extern int refresh_uname(struct utsname *); int mach_loadavg_error = 0; float mach_loadavg[3] = { 0,0,0 }; extern int refresh_loadavg(float *); int mach_cpuload_error = 0; struct host_cpu_load_info mach_cpuload = { { 0 } }; extern int refresh_cpuload(struct host_cpu_load_info *); int mach_vmstat_error = 0; struct vm_statistics mach_vmstat = { 0 }; extern int refresh_vmstat(struct vm_statistics *); int mach_fs_error = 0; struct statfs *mach_fs = NULL; extern int refresh_filesys(struct statfs **, pmdaIndom *); int mach_disk_error = 0; struct diskstats mach_disk = { 0 }; extern int refresh_disks(struct diskstats *, pmdaIndom *); int mach_cpu_error = 0; struct processor_cpu_load_info *mach_cpu = NULL; extern int refresh_cpus(struct processor_cpu_load_info **, pmdaIndom *); int mach_uptime_error = 0; unsigned int mach_uptime = 0; extern int refresh_uptime(unsigned int *); int mach_net_error = 0; struct netstats mach_net = { 0 }; extern int refresh_network(struct netstats *, pmdaIndom *); extern void init_network(void); int mach_nfs_error = 0; struct nfsstats mach_nfs = { 0 }; extern int refresh_nfs(struct nfsstats *); /* * Metric Instance Domains (statically initialized ones only) */ static pmdaInstid loadavg_indom_id[] = { { 1, "1 minute" }, { 5, "5 minute" }, { 15, "15 minute" } }; #define LOADAVG_COUNT (sizeof(loadavg_indom_id)/sizeof(pmdaInstid)) static pmdaInstid nfs3_indom_id[] = { { 0, "null" }, { 1, "getattr" }, { 2, "setattr" }, { 3, "lookup" }, { 4, "access" }, { 5, "readlink" }, { 6, "read" }, { 7, "write" }, { 8, "create" }, { 9, "mkdir" }, { 10, "symlink" }, { 11, "mknod" }, { 12, "remove" }, { 13, "rmdir" }, { 14, "rename" }, { 15, "link" }, { 16, "readdir" }, { 17, "readdir+" }, { 18, "statfs" }, { 19, "fsinfo" }, { 20, "pathconf" }, { 21, "commit" }, { 22, "getlease" }, { 23, "vacate" }, { 24, "evict" } }; #define NFS3_RPC_COUNT (sizeof(nfs3_indom_id)/sizeof(pmdaInstid)) /* * Metric Instance Domain table */ enum { LOADAVG_INDOM, /* 0 - 1, 5, 15 minute run queue averages */ FILESYS_INDOM, /* 1 - set of all mounted filesystems */ DISK_INDOM, /* 2 - set of all disk devices */ CPU_INDOM, /* 3 - set of all processors */ NETWORK_INDOM, /* 4 - set of all network interfaces */ NFS3_INDOM, /* 6 - nfs v3 operations */ NUM_INDOMS /* total number of instance domains */ }; static pmdaIndom indomtab[] = { { LOADAVG_INDOM, 3, loadavg_indom_id }, { FILESYS_INDOM, 0, NULL }, { DISK_INDOM, 0, NULL }, { CPU_INDOM, 0, NULL }, { NETWORK_INDOM, 0, NULL }, { NFS3_INDOM, NFS3_RPC_COUNT, nfs3_indom_id }, }; /* * Fetch clusters and metric table */ enum { CLUSTER_INIT = 0, /* 0 = values we know at startup */ CLUSTER_VMSTAT, /* 1 = mach memory statistics */ CLUSTER_KERNEL_UNAME, /* 2 = utsname information */ CLUSTER_LOADAVG, /* 3 = run queue averages */ CLUSTER_HINV, /* 4 = hardware inventory */ CLUSTER_FILESYS, /* 5 = mounted filesystems */ CLUSTER_CPULOAD, /* 6 = number of ticks in state */ CLUSTER_DISK, /* 7 = disk device statistics */ CLUSTER_CPU, /* 8 = per-cpu statistics */ CLUSTER_UPTIME, /* 9 = system uptime in seconds */ CLUSTER_NETWORK, /* 10 = networking statistics */ CLUSTER_NFS, /* 11 = nfs filesystem statistics */ NUM_CLUSTERS /* total number of clusters */ }; static pmdaMetric metrictab[] = { /* hinv.pagesize */ { &mach_page_size, { PMDA_PMID(CLUSTER_INIT,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* kernel.all.hz */ { &mach_hertz, { PMDA_PMID(CLUSTER_INIT,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE) }, }, /* hinv.physmem */ { NULL, { PMDA_PMID(CLUSTER_VMSTAT,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_MBYTE,0,0) }, }, /* mem.physmem */ { NULL, { PMDA_PMID(CLUSTER_VMSTAT,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.freemem */ { NULL, { PMDA_PMID(CLUSTER_VMSTAT,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.active */ { NULL, { PMDA_PMID(CLUSTER_VMSTAT,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.inactive */ { NULL, { PMDA_PMID(CLUSTER_VMSTAT,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.pages.free */ { &mach_vmstat.free_count, { PMDA_PMID(CLUSTER_VMSTAT,7), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.pages.active */ { &mach_vmstat.active_count, { PMDA_PMID(CLUSTER_VMSTAT,8), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.pages.inactive */ { &mach_vmstat.inactive_count, { PMDA_PMID(CLUSTER_VMSTAT,9), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.pages.reactivated */ { &mach_vmstat.reactivations, { PMDA_PMID(CLUSTER_VMSTAT,10), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.pages.wired */ { &mach_vmstat.wire_count, { PMDA_PMID(CLUSTER_VMSTAT,11), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.pages.faults */ { &mach_vmstat.faults, { PMDA_PMID(CLUSTER_VMSTAT,12), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.pages.cow_faults */ { &mach_vmstat.cow_faults, { PMDA_PMID(CLUSTER_VMSTAT,13), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.pages.zero_filled */ { &mach_vmstat.zero_fill_count, { PMDA_PMID(CLUSTER_VMSTAT,14), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.pageins */ { &mach_vmstat.pageins, { PMDA_PMID(CLUSTER_VMSTAT,15), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.pageouts */ { &mach_vmstat.pageouts, { PMDA_PMID(CLUSTER_VMSTAT,16), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.cache_hits */ { &mach_vmstat.hits, { PMDA_PMID(CLUSTER_VMSTAT,17), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.cache_lookups */ { &mach_vmstat.lookups, { PMDA_PMID(CLUSTER_VMSTAT,18), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.util.wired */ { NULL, { PMDA_PMID(CLUSTER_VMSTAT,19), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.active */ { NULL, { PMDA_PMID(CLUSTER_VMSTAT,20), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.inactive */ { NULL, { PMDA_PMID(CLUSTER_VMSTAT,21), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.free */ { NULL, { PMDA_PMID(CLUSTER_VMSTAT,22), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* kernel.uname.release */ { mach_uname.release, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 23), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* kernel.uname.version */ { mach_uname.version, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 24), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* kernel.uname.sysname */ { mach_uname.sysname, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 25), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* kernel.uname.machine */ { mach_uname.machine, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 26), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* kernel.uname.nodename */ { mach_uname.nodename, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 27), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* pmda.uname */ { NULL, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 28), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* pmda.version */ { NULL, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 29), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* kernel.all.load */ { NULL, { PMDA_PMID(CLUSTER_LOADAVG,30), PM_TYPE_FLOAT, LOADAVG_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* hinv.nfilesys */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,31), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* filesys.capacity */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,32), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* filesys.used */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,33), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* filesys.free */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,34), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* filesys.usedfiles */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,35), PM_TYPE_U32, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* filesys.freefiles */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,36), PM_TYPE_U32, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* filesys.mountdir */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,37), PM_TYPE_STRING, FILESYS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* filesys.full */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,38), PM_TYPE_DOUBLE, FILESYS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* filesys.blocksize */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,39), PM_TYPE_U32, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* filesys.avail */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,40), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* filesys.type */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,41), PM_TYPE_STRING, FILESYS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* kernel.all.cpu.user */ { NULL, { PMDA_PMID(CLUSTER_CPULOAD,42), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.nice */ { NULL, { PMDA_PMID(CLUSTER_CPULOAD,43), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.sys */ { NULL, { PMDA_PMID(CLUSTER_CPULOAD,44), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.idle */ { NULL, { PMDA_PMID(CLUSTER_CPULOAD,45), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* hinv.ndisk */ { NULL, { PMDA_PMID(CLUSTER_DISK,46), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* disk.dev.read */ { NULL, { PMDA_PMID(CLUSTER_DISK,47), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.write */ { NULL, { PMDA_PMID(CLUSTER_DISK,48), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.total */ { NULL, { PMDA_PMID(CLUSTER_DISK,49), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.read_bytes */ { NULL, { PMDA_PMID(CLUSTER_DISK,50), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.dev.write_bytes */ { NULL, { PMDA_PMID(CLUSTER_DISK,51), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.dev.total_bytes */ { NULL, { PMDA_PMID(CLUSTER_DISK,52), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.dev.blkread */ { NULL, { PMDA_PMID(CLUSTER_DISK,53), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.blkwrite */ { NULL, { PMDA_PMID(CLUSTER_DISK,54), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.blktotal */ { NULL, { PMDA_PMID(CLUSTER_DISK,55), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.read_time */ { NULL, { PMDA_PMID(CLUSTER_DISK,56), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, /* disk.dev.write_time */ { NULL, { PMDA_PMID(CLUSTER_DISK,57), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, /* disk.dev.total_time */ { NULL, { PMDA_PMID(CLUSTER_DISK,58), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, /* disk.all.read */ { NULL, { PMDA_PMID(CLUSTER_DISK,59), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.write */ { NULL, { PMDA_PMID(CLUSTER_DISK,60), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.total */ { NULL, { PMDA_PMID(CLUSTER_DISK,61), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.read_bytes */ { NULL, { PMDA_PMID(CLUSTER_DISK,62), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.all.write_bytes */ { NULL, { PMDA_PMID(CLUSTER_DISK,63), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.all.total_bytes */ { NULL, { PMDA_PMID(CLUSTER_DISK,64), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.all.blkread */ { NULL, { PMDA_PMID(CLUSTER_DISK,65), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.blkwrite */ { NULL, { PMDA_PMID(CLUSTER_DISK,66), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.blktotal */ { NULL, { PMDA_PMID(CLUSTER_DISK,67), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.read_time */ { NULL, { PMDA_PMID(CLUSTER_DISK,68), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, /* disk.all.write_time */ { NULL, { PMDA_PMID(CLUSTER_DISK,69), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, /* disk.all.total_time */ { NULL, { PMDA_PMID(CLUSTER_DISK,70), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_NSEC,0) }, }, /* hinv.ncpu */ { NULL, { PMDA_PMID(CLUSTER_CPU,71), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* kernel.percpu.cpu.user */ { NULL, { PMDA_PMID(CLUSTER_CPU,72), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.nice */ { NULL, { PMDA_PMID(CLUSTER_CPU,73), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.sys */ { NULL, { PMDA_PMID(CLUSTER_CPU,74), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.idle */ { NULL, { PMDA_PMID(CLUSTER_CPU,75), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.uptime */ { &mach_uptime, { PMDA_PMID(CLUSTER_UPTIME,76), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,1,0,PM_TIME_SEC,PM_COUNT_ONE) }, }, /* network.interface.in.bytes */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,77), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* network.interface.in.packets */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,78), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.in.errors */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,79), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.in.drops */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,80), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.in.mcasts */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,81), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.out.bytes */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,82), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,0,PM_SPACE_BYTE,0) }, }, /* network.interface.out.packets */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,83), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.out.errors */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,84), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.out.mcasts */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,85), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.collisions */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,86), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.mtu */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,87), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,0,PM_SPACE_BYTE,0) }, }, /* network.interface.baudrate */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,88), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,0,PM_SPACE_BYTE,0) }, }, /* network.interface.total.bytes */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,89), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,0,PM_SPACE_BYTE,0) }, }, /* network.interface.total.packets */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,90), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.total.errors */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,91), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.total.drops */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,92), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.total.mcasts */ { NULL, { PMDA_PMID(CLUSTER_NETWORK,93), PM_TYPE_U64, NETWORK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* nfs3.client.calls */ { NULL, { PMDA_PMID(CLUSTER_NFS,94), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* nfs3.client.reqs */ { NULL, { PMDA_PMID(CLUSTER_NFS,95), PM_TYPE_32, NFS3_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* nfs3.server.calls */ { NULL, { PMDA_PMID(CLUSTER_NFS,96), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* nfs3.server.reqs */ { NULL, { PMDA_PMID(CLUSTER_NFS,97), PM_TYPE_32, NFS3_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.rpccnt */ { &mach_nfs.rpcrequests, { PMDA_PMID(CLUSTER_NFS,98), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.rpcretrans */ { &mach_nfs.rpcretries, { PMDA_PMID(CLUSTER_NFS,99), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.rpctimeouts */ { &mach_nfs.rpctimeouts, { PMDA_PMID(CLUSTER_NFS,100), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.rpcinvalid */ { &mach_nfs.rpcinvalid, { PMDA_PMID(CLUSTER_NFS,101), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.rpcunexpected */ { &mach_nfs.rpcunexpected, { PMDA_PMID(CLUSTER_NFS,102), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.attrcache.hits */ { &mach_nfs.attrcache_hits, { PMDA_PMID(CLUSTER_NFS,103), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.attrcache.misses */ { &mach_nfs.attrcache_misses, { PMDA_PMID(CLUSTER_NFS,104), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.lookupcache.hits */ { &mach_nfs.lookupcache_hits, { PMDA_PMID(CLUSTER_NFS,105), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.lookupcache.misses */ { &mach_nfs.lookupcache_misses, { PMDA_PMID(CLUSTER_NFS,106), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.biocache.read.hits */ { &mach_nfs.read_bios, { PMDA_PMID(CLUSTER_NFS,107), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.biocache.read.misses */ { &mach_nfs.biocache_reads, { PMDA_PMID(CLUSTER_NFS,108), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.biocache.write.hits */ { &mach_nfs.write_bios, { PMDA_PMID(CLUSTER_NFS,109), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.biocache.write.misses */ { &mach_nfs.biocache_writes, { PMDA_PMID(CLUSTER_NFS,110), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.biocache.readlink.hits */ { &mach_nfs.readlink_bios, { PMDA_PMID(CLUSTER_NFS,111), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.biocache.readlink.misses */ { &mach_nfs.biocache_readlinks, { PMDA_PMID(CLUSTER_NFS,112), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.biocache.readdir.hits */ { &mach_nfs.readdir_bios, { PMDA_PMID(CLUSTER_NFS,113), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.biocache.readdir.misses */ { &mach_nfs.biocache_readdirs, { PMDA_PMID(CLUSTER_NFS,114), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.direofcache.hits */ { &mach_nfs.direofcache_hits, { PMDA_PMID(CLUSTER_NFS,115), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.client.direofcache.misses */ { &mach_nfs.direofcache_misses, { PMDA_PMID(CLUSTER_NFS,116), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.server.retfailed */ { &mach_nfs.srvrpc_errs, { PMDA_PMID(CLUSTER_NFS,117), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.server.faults */ { &mach_nfs.srvrpc_errs, { PMDA_PMID(CLUSTER_NFS,118), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.server.cache.inprog */ { &mach_nfs.srvcache_inproghits, { PMDA_PMID(CLUSTER_NFS,119), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.server.cache.nonidem */ { &mach_nfs.srvcache_nonidemdonehits, { PMDA_PMID(CLUSTER_NFS,120), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.server.cache.idem */ { &mach_nfs.srvcache_idemdonehits, { PMDA_PMID(CLUSTER_NFS,121), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.server.cache.misses */ { &mach_nfs.srvcache_misses, { PMDA_PMID(CLUSTER_NFS,122), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.server.nqnfs.leases -- deprecated */ { NULL, { PMDA_PMID(CLUSTER_NFS,123), PM_TYPE_NOSUPPORT, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.server.nqnfs.maxleases -- deprecated */ { NULL, { PMDA_PMID(CLUSTER_NFS,124), PM_TYPE_NOSUPPORT, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.server.nqnfs.getleases -- deprecated */ { NULL, { PMDA_PMID(CLUSTER_NFS,125), PM_TYPE_NOSUPPORT, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.server.vopwrites */ { &mach_nfs.srvvop_writes, { PMDA_PMID(CLUSTER_NFS,126), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.server.pageins */ { &mach_nfs.pageins, { PMDA_PMID(CLUSTER_NFS,127), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* rpc.server.pageouts */ { &mach_nfs.pageouts, { PMDA_PMID(CLUSTER_NFS,128), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* filesys.maxfiles */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,129), PM_TYPE_U32, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, }; static void darwin_refresh(int *need_refresh) { if (need_refresh[CLUSTER_LOADAVG]) mach_loadavg_error = refresh_loadavg(mach_loadavg); if (need_refresh[CLUSTER_CPULOAD]) mach_cpuload_error = refresh_cpuload(&mach_cpuload); if (need_refresh[CLUSTER_VMSTAT]) mach_vmstat_error = refresh_vmstat(&mach_vmstat); if (need_refresh[CLUSTER_KERNEL_UNAME]) mach_uname_error = refresh_uname(&mach_uname); if (need_refresh[CLUSTER_FILESYS]) mach_fs_error = refresh_filesys(&mach_fs, &indomtab[FILESYS_INDOM]); if (need_refresh[CLUSTER_DISK]) mach_disk_error = refresh_disks(&mach_disk, &indomtab[DISK_INDOM]); if (need_refresh[CLUSTER_CPU]) mach_cpu_error = refresh_cpus(&mach_cpu, &indomtab[CPU_INDOM]); if (need_refresh[CLUSTER_UPTIME]) mach_uptime_error = refresh_uptime(&mach_uptime); if (need_refresh[CLUSTER_NETWORK]) mach_net_error = refresh_network(&mach_net, &indomtab[NETWORK_INDOM]); if (need_refresh[CLUSTER_NFS]) mach_nfs_error = refresh_nfs(&mach_nfs); } static inline int fetch_loadavg(unsigned int item, unsigned int inst, pmAtomValue *atom) { if (mach_loadavg_error) return mach_loadavg_error; switch (item) { case 30: /* kernel.all.load */ if (inst == 1) atom->f = mach_loadavg[0]; else if (inst == 5) atom->f = mach_loadavg[1]; else if (inst == 15) atom->f = mach_loadavg[2]; else return PM_ERR_INST; return 1; } return PM_ERR_PMID; } static inline int fetch_cpuload(unsigned int item, pmAtomValue *atom) { if (mach_cpuload_error) return mach_cpuload_error; switch (item) { case 42: /* kernel.all.cpu.user */ atom->ull = LOAD_SCALE * (double) mach_cpuload.cpu_ticks[CPU_STATE_USER] / mach_hertz; return 1; case 43: /* kernel.all.cpu.nice */ atom->ull = LOAD_SCALE * (double) mach_cpuload.cpu_ticks[CPU_STATE_NICE] / mach_hertz; return 1; case 44: /* kernel.all.cpu.sys */ atom->ull = LOAD_SCALE * (double) mach_cpuload.cpu_ticks[CPU_STATE_SYSTEM] / mach_hertz; return 1; case 45: /* kernel.all.cpu.idle */ atom->ull = LOAD_SCALE * (double) mach_cpuload.cpu_ticks[CPU_STATE_IDLE] / mach_hertz; return 1; } return PM_ERR_PMID; } static inline int fetch_vmstat(unsigned int item, unsigned int inst, pmAtomValue *atom) { if (mach_vmstat_error) return mach_vmstat_error; switch (item) { case 2: /* hinv.physmem */ atom->ul = (__uint32_t)page_count_to_mb( mach_vmstat.free_count + mach_vmstat.wire_count + mach_vmstat.active_count + mach_vmstat.inactive_count); return 1; case 3: /* mem.physmem */ atom->ull = page_count_to_kb( mach_vmstat.free_count + mach_vmstat.wire_count + mach_vmstat.active_count + mach_vmstat.inactive_count); return 1; case 4: /* mem.freemem */ atom->ull = page_count_to_kb(mach_vmstat.free_count); return 1; case 5: /* mem.active */ atom->ull = page_count_to_kb(mach_vmstat.active_count); return 1; case 6: /* mem.inactive */ atom->ull = page_count_to_kb(mach_vmstat.inactive_count); return 1; case 19: /* mem.util.wired */ atom->ull = page_count_to_kb(mach_vmstat.wire_count); return 1; case 20: /* mem.util.active */ atom->ull = page_count_to_kb(mach_vmstat.active_count); return 1; case 21: /* mem.util.inactive */ atom->ull = page_count_to_kb(mach_vmstat.inactive_count); return 1; case 22: /* mem.util.free */ atom->ull = page_count_to_kb(mach_vmstat.free_count); return 1; } return PM_ERR_PMID; } static inline int fetch_uname(unsigned int item, pmAtomValue *atom) { static char mach_uname_all[(_SYS_NAMELEN*5)+8]; if (mach_uname_error) return mach_uname_error; switch (item) { case 28: /* pmda.uname */ snprintf(mach_uname_all, sizeof(mach_uname_all), "%s %s %s %s %s", mach_uname.sysname, mach_uname.nodename, mach_uname.release, mach_uname.version, mach_uname.machine); atom->cp = mach_uname_all; return 1; case 29: /* pmda.version */ atom->cp = pmGetConfig("PCP_VERSION"); return 1; } return PM_ERR_PMID; } static inline int fetch_filesys(unsigned int item, unsigned int inst, pmAtomValue *atom) { __uint64_t ull, used; if (mach_fs_error) return mach_fs_error; if (item == 31) { /* hinv.nfilesys */ atom->ul = indomtab[FILESYS_INDOM].it_numinst; return 1; } if (indomtab[FILESYS_INDOM].it_numinst == 0) return 0; /* no values available */ if (inst < 0 || inst >= indomtab[FILESYS_INDOM].it_numinst) return PM_ERR_INST; switch (item) { case 32: /* filesys.capacity */ ull = (__uint64_t)mach_fs[inst].f_blocks; atom->ull = ull * mach_fs[inst].f_bsize >> 10; return 1; case 33: /* filesys.used */ used = (__uint64_t)(mach_fs[inst].f_blocks - mach_fs[inst].f_bfree); atom->ull = used * mach_fs[inst].f_bsize >> 10; return 1; case 34: /* filesys.free */ ull = (__uint64_t)mach_fs[inst].f_bfree; atom->ull = ull * mach_fs[inst].f_bsize >> 10; return 1; case 129: /* filesys.maxfiles */ atom->ul = mach_fs[inst].f_files; return 1; case 35: /* filesys.usedfiles */ atom->ul = mach_fs[inst].f_files - mach_fs[inst].f_ffree; return 1; case 36: /* filesys.freefiles */ atom->ul = mach_fs[inst].f_ffree; return 1; case 37: /* filesys.mountdir */ atom->cp = mach_fs[inst].f_mntonname; return 1; case 38: /* filesys.full */ used = (__uint64_t)(mach_fs[inst].f_blocks - mach_fs[inst].f_bfree); ull = used + (__uint64_t)mach_fs[inst].f_bavail; atom->d = (100.0 * (double)used) / (double)ull; return 1; case 39: /* filesys.blocksize */ atom->ul = mach_fs[inst].f_bsize; return 1; case 40: /* filesys.avail */ ull = (__uint64_t)mach_fs[inst].f_bavail; atom->ull = ull * mach_fs[inst].f_bsize >> 10; return 1; case 41: /* filesys.type */ atom->cp = mach_fs[inst].f_fstypename; return 1; } return PM_ERR_PMID; } static inline int fetch_disk(unsigned int item, unsigned int inst, pmAtomValue *atom) { if (mach_disk_error) return mach_disk_error; if (item == 46) { /* hinv.ndisk */ atom->ul = indomtab[DISK_INDOM].it_numinst; return 1; } if (indomtab[DISK_INDOM].it_numinst == 0) return 0; /* no values available */ if (item < 59 && (inst < 0 || inst >= indomtab[DISK_INDOM].it_numinst)) return PM_ERR_INST; switch (item) { case 47: /* disk.dev.read */ atom->ull = mach_disk.disks[inst].read; return 1; case 48: /* disk.dev.write */ atom->ull = mach_disk.disks[inst].write; return 1; case 49: /* disk.dev.total */ atom->ull = mach_disk.disks[inst].read + mach_disk.disks[inst].write; return 1; case 50: /* disk.dev.read_bytes */ atom->ull = mach_disk.disks[inst].read_bytes >> 10; return 1; case 51: /* disk.dev.write_bytes */ atom->ull = mach_disk.disks[inst].write_bytes >> 10; return 1; case 52: /* disk.dev.total_bytes */ atom->ull = (mach_disk.disks[inst].read_bytes + mach_disk.disks[inst].write_bytes) >> 10; return 1; case 53: /* disk.dev.blkread */ atom->ull = mach_disk.disks[inst].read_bytes / mach_disk.disks[inst].blocksize; return 1; case 54: /* disk.dev.blkwrite */ atom->ull = mach_disk.disks[inst].write_bytes / mach_disk.disks[inst].blocksize; return 1; case 55: /* disk.dev.blktotal */ atom->ull = (mach_disk.disks[inst].read_bytes + mach_disk.disks[inst].write_bytes) / mach_disk.disks[inst].blocksize; return 1; case 56: /* disk.dev.read_time */ atom->ull = mach_disk.disks[inst].read_time; return 1; case 57: /* disk.dev.write_time */ atom->ull = mach_disk.disks[inst].write_time; return 1; case 58: /* disk.dev.total_time */ atom->ull = mach_disk.disks[inst].read_time + mach_disk.disks[inst].write_time; return 1; case 59: /* disk.all.read */ atom->ull = mach_disk.read; return 1; case 60: /* disk.all.write */ atom->ull = mach_disk.write; return 1; case 61: /* disk.all.total */ atom->ull = mach_disk.read + mach_disk.write; return 1; case 62: /* disk.all.read_bytes */ atom->ull = mach_disk.read_bytes >> 10; return 1; case 63: /* disk.all.write_bytes */ atom->ull = mach_disk.write_bytes >> 10; return 1; case 64: /* disk.all.total_bytes */ atom->ull = (mach_disk.read_bytes + mach_disk.write_bytes) >> 10; return 1; case 65: /* disk.all.blkread */ atom->ull = mach_disk.blkread; return 1; case 66: /* disk.all.blkwrite */ atom->ull = mach_disk.blkwrite; return 1; case 67: /* disk.all.blktotal */ atom->ull = mach_disk.blkread + mach_disk.blkwrite; return 1; case 68: /* disk.all.read_time */ atom->ull = mach_disk.read_time; return 1; case 69: /* disk.all.write_time */ atom->ull = mach_disk.write_time; return 1; case 70: /* disk.all.total_time */ atom->ull = mach_disk.read_time + mach_disk.write_time; return 1; } return PM_ERR_PMID; } static inline int fetch_cpu(unsigned int item, unsigned int inst, pmAtomValue *atom) { if (mach_cpu_error) return mach_cpu_error; if (item == 71) { /* hinv.ncpu */ atom->ul = indomtab[CPU_INDOM].it_numinst; return 1; } if (indomtab[CPU_INDOM].it_numinst == 0) /* uh-huh. */ return 0; /* no values available */ if (inst < 0 || inst >= indomtab[CPU_INDOM].it_numinst) return PM_ERR_INST; switch (item) { case 72: /* kernel.percpu.cpu.user */ atom->ull = LOAD_SCALE * (double) mach_cpu[inst].cpu_ticks[CPU_STATE_USER] / mach_hertz; return 1; case 73: /* kernel.percpu.cpu.nice */ atom->ull = LOAD_SCALE * (double) mach_cpu[inst].cpu_ticks[CPU_STATE_NICE] / mach_hertz; return 1; case 74: /* kernel.percpu.cpu.sys */ atom->ull = LOAD_SCALE * (double) mach_cpu[inst].cpu_ticks[CPU_STATE_SYSTEM] / mach_hertz; return 1; case 75: /* kernel.percpu.cpu.idle */ atom->ull = LOAD_SCALE * (double) mach_cpu[inst].cpu_ticks[CPU_STATE_IDLE] / mach_hertz; return 1; } return PM_ERR_PMID; } static inline int fetch_network(unsigned int item, unsigned int inst, pmAtomValue *atom) { if (mach_net_error) return mach_net_error; if (indomtab[NETWORK_INDOM].it_numinst == 0) return 0; /* no values available */ if (inst < 0 || inst >= indomtab[NETWORK_INDOM].it_numinst) return PM_ERR_INST; switch (item) { case 77: /* network.interface.in.bytes */ atom->ull = mach_net.interfaces[inst].ibytes; return 1; case 78: /* network.interface.in.packets */ atom->ull = mach_net.interfaces[inst].ipackets; return 1; case 79: /* network.interface.in.errors */ atom->ull = mach_net.interfaces[inst].ierrors; return 1; case 80: /* network.interface.in.drops */ atom->ull = mach_net.interfaces[inst].iqdrops; return 1; case 81: /* network.interface.in.mcasts */ atom->ull = mach_net.interfaces[inst].imcasts; return 1; case 82: /* network.interface.out.bytes */ atom->ull = mach_net.interfaces[inst].obytes; return 1; case 83: /* network.interface.out.packets */ atom->ull = mach_net.interfaces[inst].opackets; return 1; case 84: /* network.interface.out.errors */ atom->ull = mach_net.interfaces[inst].oerrors; return 1; case 85: /* network.interface.out.mcasts */ atom->ull = mach_net.interfaces[inst].omcasts; return 1; case 86: /* network.interface.collisions */ atom->ull = mach_net.interfaces[inst].collisions; return 1; case 87: /* network.interface.mtu */ atom->ull = mach_net.interfaces[inst].mtu; return 1; case 88: /* network.interface.baudrate */ atom->ull = mach_net.interfaces[inst].baudrate; return 1; case 89: /* network.interface.total.bytes */ atom->ull = mach_net.interfaces[inst].ibytes + mach_net.interfaces[inst].obytes; return 1; case 90: /* network.interface.total.packets */ atom->ull = mach_net.interfaces[inst].ipackets + mach_net.interfaces[inst].opackets; return 1; case 91: /* network.interface.total.errors */ atom->ull = mach_net.interfaces[inst].ierrors + mach_net.interfaces[inst].oerrors; return 1; case 92: /* network.interface.total.drops */ atom->ull = mach_net.interfaces[inst].iqdrops; return 1; case 93: /* network.interface.total.mcasts */ atom->ull = mach_net.interfaces[inst].imcasts + mach_net.interfaces[inst].omcasts; return 1; } return PM_ERR_PMID; } static inline int fetch_nfs(unsigned int item, unsigned int inst, pmAtomValue *atom) { if (mach_net_error) return mach_net_error; switch (item) { case 94: /* nfs3.client.calls */ for (atom->l = 0, inst = 0; inst < NFS3_RPC_COUNT; inst++) atom->l += mach_nfs.rpccnt[inst]; return 1; case 95: /* nfs3.client.reqs */ if (inst < 0 || inst >= NFS3_RPC_COUNT) return PM_ERR_INST; atom->l = mach_nfs.rpccnt[inst]; return 1; case 96: /* nfs3.server.calls */ for (atom->l = 0, inst = 0; inst < NFS3_RPC_COUNT; inst++) atom->l += mach_nfs.srvrpccnt[inst]; return 1; case 97: /* nfs3.server.reqs */ if (inst < 0 || inst >= NFS3_RPC_COUNT) return PM_ERR_INST; atom->l = mach_nfs.srvrpccnt[inst]; return 1; case 123: /* rpc.server.nqnfs.leases -- deprecated */ case 124: /* rpc.server.nqnfs.maxleases -- deprecated */ case 125: /* rpc.server.nqnfs.getleases -- deprecated */ return PM_ERR_APPVERSION; } return PM_ERR_PMID; } static int darwin_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); if (mdesc->m_user) { /* * The metric value is extracted directly via the address specified * in metrictab. Note: not all metrics support this - those that * don't have NULL for the m_user field in their respective * metrictab slot. */ switch (mdesc->m_desc.type) { case PM_TYPE_32: atom->l = *(__int32_t *)mdesc->m_user; break; case PM_TYPE_U32: atom->ul = *(__uint32_t *)mdesc->m_user; break; case PM_TYPE_64: atom->ll = *(__int64_t *)mdesc->m_user; break; case PM_TYPE_U64: atom->ull = *(__uint64_t *)mdesc->m_user; break; case PM_TYPE_FLOAT: atom->f = *(float *)mdesc->m_user; break; case PM_TYPE_DOUBLE: atom->d = *(double *)mdesc->m_user; break; case PM_TYPE_STRING: atom->cp = (char *)mdesc->m_user; break; case PM_TYPE_NOSUPPORT: return 0; default: fprintf(stderr, "Error in fetchCallBack: unsupported metric type %s\n", pmTypeStr(mdesc->m_desc.type)); return 0; } return 1; } switch (idp->cluster) { case CLUSTER_LOADAVG: return fetch_loadavg(idp->item, inst, atom); case CLUSTER_CPULOAD: return fetch_cpuload(idp->item, atom); case CLUSTER_VMSTAT: return fetch_vmstat(idp->item, inst, atom); case CLUSTER_KERNEL_UNAME: return fetch_uname(idp->item, atom); case CLUSTER_FILESYS: return fetch_filesys(idp->item, inst, atom); case CLUSTER_DISK: return fetch_disk(idp->item, inst, atom); case CLUSTER_CPU: return fetch_cpu(idp->item, inst, atom); case CLUSTER_NETWORK: return fetch_network(idp->item, inst, atom); case CLUSTER_NFS: return fetch_nfs(idp->item, inst, atom); } return 0; } static int darwin_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) { __pmInDom_int *indomp = (__pmInDom_int *)&indom; int need_refresh[NUM_CLUSTERS] = { 0 }; switch (indomp->serial) { case FILESYS_INDOM: need_refresh[CLUSTER_FILESYS]++; break; case DISK_INDOM: need_refresh[CLUSTER_DISK]++; break; case CPU_INDOM: need_refresh[CLUSTER_CPU]++; break; case NETWORK_INDOM: need_refresh[CLUSTER_NETWORK]++; break; } darwin_refresh(need_refresh); return pmdaInstance(indom, inst, name, result, pmda); } static int darwin_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i, need_refresh[NUM_CLUSTERS] = { 0 }; for (i = 0; i < numpmid; i++) { __pmID_int *idp = (__pmID_int *)&(pmidlist[i]); if (idp->cluster >= 0 && idp->cluster < NUM_CLUSTERS) need_refresh[idp->cluster]++; } darwin_refresh(need_refresh); return pmdaFetch(numpmid, pmidlist, resp, pmda); } void darwin_init(pmdaInterface *dp) { if (_isDSO) { int sep = __pmPathSeparator(); char helppath[MAXPATHLEN]; sprintf(helppath, "%s%c" "darwin" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_3, "darwin DSO", helppath); } else { __pmSetProcessIdentity(username); } if (dp->status != 0) return; dp->version.two.instance = darwin_instance; dp->version.two.fetch = darwin_fetch; pmdaSetFetchCallBack(dp, darwin_fetchCallBack); pmdaSetFlags(dp, PMDA_EXT_FLAG_DIRECT); pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), metrictab, sizeof(metrictab)/sizeof(metrictab[0])); mach_host = mach_host_self(); host_page_size(mach_host, &mach_page_size); mach_page_shift = ffs(mach_page_size) - 1; if (refresh_hertz(&mach_hertz) != 0) mach_hertz = 100; init_network(); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n" "\nExactly one of the following options may appear:\n" " -i port expect PMCD to connect on given inet port (number or name)\n" " -p expect PMCD to supply stdin/stdout (pipe)\n" " -u socket expect PMCD to connect on given unix domain socket\n" " -6 port expect PMCD to connect on given ipv6 port (number or name)\n", stderr); exit(1); } int main(int argc, char **argv) { int c, sep = __pmPathSeparator(); int errflag = 0; char helppath[MAXPATHLEN]; _isDSO = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); sprintf(helppath, "%s%c" "darwin" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_3, pmProgname, DARWIN, "darwin.log", helppath); while ((c = pmdaGetOpt(argc, argv, "D:d:i:l:pu:U:6:?", &dispatch, &errflag)) != EOF) { switch(c) { case 'U': username = optarg; break; default: errflag++; } } if (errflag) usage(); pmdaOpenLog(&dispatch); darwin_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/darwin/disk.c0000664000000000000000000001671612272262501015072 0ustar /* * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #define IOKIT 1 #include #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "disk.h" /* * Ensure we have space for the next device in our pre-allocated * device pool. If not, make some or pass on the error. */ static int check_stats_size(struct diskstats *stats, int count) { if (count > stats->highwater) { stats->highwater++; stats->disks = realloc(stats->disks, stats->highwater * sizeof(struct diskstat)); if (!stats->disks) { stats->highwater = 0; return -ENOMEM; } } return 0; } /* * Insert all disks into the global disk instance domain. */ static int update_disk_indom(struct diskstats *all, int count, pmdaIndom *indom) { int i; if (count > 0 && count != indom->it_numinst) { i = sizeof(pmdaInstid) * count; if ((indom->it_set = realloc(indom->it_set, i)) == NULL) { indom->it_numinst = 0; return -ENOMEM; } } for (i = 0; i < count; i++) { indom->it_set[i].i_name = all->disks[i].name; indom->it_set[i].i_inst = i; } indom->it_numinst = count; return 0; } /* * Update the global counters with values from one disk. */ static void update_disk_totals(struct diskstats *all, struct diskstat *disk) { all->read += disk->read; all->write += disk->write; all->read_bytes += disk->read_bytes; all->write_bytes += disk->write_bytes; all->blkread += disk->read_bytes / disk->blocksize; all->blkwrite += disk->write_bytes / disk->blocksize; all->read_time += disk->read_time; all->write_time += disk->write_time; } static void clear_disk_totals(struct diskstats *all) { all->read = 0; all->write = 0; all->read_bytes = 0; all->write_bytes = 0; all->blkread = 0; all->blkwrite = 0; all->read_time = 0; all->write_time = 0; } /* * Update the counters associated with a single disk. */ static void update_disk_stats(struct diskstat *disk, CFDictionaryRef pproperties, CFDictionaryRef properties) { CFDictionaryRef statistics; CFStringRef name; CFNumberRef number; memset(disk, 0, sizeof(struct diskstat)); /* Get name from the drive properties */ name = (CFStringRef) CFDictionaryGetValue(pproperties, CFSTR(kIOBSDNameKey)); if(name == NULL) return; /* Not much we can do with no name */ CFStringGetCString(name, disk->name, DEVNAMEMAX, CFStringGetSystemEncoding()); /* Get the blocksize from the drive properties */ number = (CFNumberRef) CFDictionaryGetValue(pproperties, CFSTR(kIOMediaPreferredBlockSizeKey)); if(number == NULL) return; /* Not much we can do with no number */ CFNumberGetValue(number, kCFNumberSInt64Type, &disk->blocksize); /* Get the statistics from the device properties. */ statistics = (CFDictionaryRef) CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey)); if (statistics) { number = (CFNumberRef) CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsReadsKey)); if (number) CFNumberGetValue(number, kCFNumberSInt64Type, &disk->read); number = (CFNumberRef) CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsWritesKey)); if (number) CFNumberGetValue(number, kCFNumberSInt64Type, &disk->write); number = (CFNumberRef) CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)); if (number) CFNumberGetValue(number, kCFNumberSInt64Type, &disk->read_bytes); number = (CFNumberRef) CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)); if (number) CFNumberGetValue(number, kCFNumberSInt64Type, &disk->write_bytes); number = (CFNumberRef) CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentReadTimeKey)); if (number) CFNumberGetValue(number, kCFNumberSInt64Type, &disk->read_time); number = (CFNumberRef) CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentWriteTimeKey)); if (number) CFNumberGetValue(number, kCFNumberSInt64Type, &disk->write_time); } } static int update_disk(diskstats_t *stats, io_registry_entry_t drive, int index) { io_registry_entry_t device; CFDictionaryRef pproperties, properties; int status; /* Get the drives parent, from which we get statistics. */ status = IORegistryEntryGetParentEntry(drive, kIOServicePlane, &device); if (status != KERN_SUCCESS) return -oserror(); if (!IOObjectConformsTo(device, "IOBlockStorageDriver")) { IOObjectRelease(device); return 0; } /* Obtain the drive properties. */ pproperties = 0; status = IORegistryEntryCreateCFProperties(drive, (CFMutableDictionaryRef *)&pproperties, kCFAllocatorDefault, kNilOptions); if (status != KERN_SUCCESS) { IOObjectRelease(device); return -oserror(); } /* Obtain the device properties. */ properties = 0; status = IORegistryEntryCreateCFProperties(device, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, kNilOptions); if (status != KERN_SUCCESS) { IOObjectRelease(device); return -oserror(); } /* Make space to store the actual values, then go get them. */ status = check_stats_size(stats, index + 1); if (status < 0) { IOObjectRelease(device); } else { update_disk_stats(&stats->disks[index], pproperties, properties); update_disk_totals(stats, &stats->disks[index]); } CFRelease(pproperties); CFRelease(properties); return status; } int refresh_disks(struct diskstats *stats, pmdaIndom *indom) { io_registry_entry_t drive; CFMutableDictionaryRef match; int i, status; static int inited = 0; static mach_port_t mach_master_port; static io_iterator_t mach_device_list; if (!inited) { /* Get ports and services for device statistics. */ if (IOMasterPort(bootstrap_port, &mach_master_port)) { fprintf(stderr, "%s: IOMasterPort error\n", __FUNCTION__); return -oserror(); } memset(stats, 0, sizeof(struct diskstats)); inited = 1; } /* Get an interator for IOMedia objects (drives). */ match = IOServiceMatching("IOMedia"); CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue); status = IOServiceGetMatchingServices(mach_master_port, match, &mach_device_list); if (status != KERN_SUCCESS) { fprintf(stderr, "%s: IOServiceGetMatchingServices error\n", __FUNCTION__); return -oserror(); } indom->it_numinst = 0; clear_disk_totals(stats); for (i = 0; (drive = IOIteratorNext(mach_device_list)) != 0; i++) { status = update_disk(stats, drive, i); if (status) break; IOObjectRelease(drive); } IOIteratorReset(mach_device_list); if (!status) status = update_disk_indom(stats, i, indom); return status; } pcp-3.8.12ubuntu1/src/pmdas/darwin/help0000664000000000000000000002132712272262501014641 0ustar # # Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # MacOS X PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ kernel.uname.release release level of the running kernel @ kernel.uname.version version level (build number) and build date of the running kernel @ kernel.uname.sysname name of the implementation of the operating system @ kernel.uname.machine name of the hardware type the system is running on @ kernel.uname.nodename host name of this node on the network @ kernel.all.cpu.user total user time for all processors @ kernel.all.cpu.nice total nice time for all processors @ kernel.all.cpu.sys total system time for all processors @ kernel.all.cpu.idle total idle time for all processors @ kernel.all.load 1, 5 and 15 minute load average @ kernel.all.uptime time the current kernel has been running @ kernel.all.hz value of HZ (jiffies/second) for the currently running kernel @ hinv.ncpu number of processors @ kernel.percpu.cpu.user percpu user processor time metric @ kernel.percpu.cpu.nice percpu nice user processor time metric @ kernel.percpu.cpu.sys percpu system processor time metric @ kernel.percpu.cpu.idle percpu idle processor time metric @ hinv.physmem total system memory @ hinv.pagesize system memory page size @ mem.physmem total system memory metric @ mem.freemem total pages free in the system @ mem.active the total pages currently in use and pageable @ mem.inactive the total pages on the inactive list @ mem.pages.freemem total number of free pages in the system @ mem.pages.active the number of pages currently in use and pageable @ mem.pages.inactive the number of pages on the inactive list @ mem.pages.reactivated the number of pages that have been moved from inactive to active list @ mem.pages.wired the total number of pages wired down (cannot be paged out) @ mem.pages.faults the number of times the "vm_fault" routine has been called @ mem.pages.cow_faults the number of faults that caused a page to be copied @ mem.pages.zero_filled the number of pages that have been zero-filled on demand @ mem.pageins the number of requests for pages from a pager @ mem.pageouts the number of pages that have been paged out @ mem.cache_hits the number of object cache hits @ mem.cache_lookups the number of object cache lookups @ mem.util.wired wired memory @ mem.util.active active memory @ mem.util.inactive inactive memory @ mem.util.free free memory @ hinv.nfilesys number of file systems currently mounted @ filesys.capacity total capacity of mounted filesystem (Kbytes) @ filesys.used total space used on mounted filesystem (Kbytes) @ filesys.free total space free on mounted filesystem (Kbytes) @ filesys.usedfiles number of inodes allocated on mounted filesystem @ filesys.freefiles number of unallocated inodes on mounted filesystem @ filesys.mountdir file system mount point @ filesys.full percentage of filesystem in use @ filesys.blocksize size of each block on mounted filesystem (Bytes) @ filesys.avail total space free to non-superusers on mounted filesystem (Kbytes) @ filesys.type filesystem type name for each mounted filesystem @ hinv.ndisk number of disks in the system @ disk.dev.read per-disk read operations Cumulative number of disk read operations since system boot time (subject to counter wrap). @ disk.dev.write per-disk write operations Cumulative number of disk write operations since system boot time (subject to counter wrap). @ disk.dev.total per-disk total (read+write) operations Cumulative number of disk read and write operations since system boot time (subject to counter wrap). @ disk.dev.read_bytes per-disk count of bytes read @ disk.dev.write_bytes per-disk count of bytes written @ disk.dev.total_bytes per-disk count bytes read and written @ disk.dev.blkread per-disk block read operations Cumulative number of disk block read operations since system boot time (subject to counter wrap). @ disk.dev.blkwrite per-disk block write operations Cumulative number of disk block write operations since system boot time (subject to counter wrap). @ disk.dev.blktotal per-disk total (read+write) block operations Cumulative number of disk block read and write operations since system boot time (subject to counter wrap). @ disk.dev.read_time i dunno either @ disk.dev.write_time i dunno either @ disk.dev.total_time i dunno either @ disk.all.read_time i dunno either @ disk.all.write_time i dunno either @ disk.all.total_time i dunno either @ disk.all.read total read operations, summed for all disks Cumulative number of disk read operations since system boot time (subject to counter wrap), summed over all disk devices. @ disk.all.write total write operations, summed for all disks Cumulative number of disk read operations since system boot time (subject to counter wrap), summed over all disk devices. @ disk.all.total total read and write operations, summed for all disks Cumulative number of disk read and write operations since system boot time (subject to counter wrap), summed over all disk devices. @ disk.all.blkread block read operations, summed for all disks Cumulative number of disk block read operations since system boot time (subject to counter wrap), summed over all disk devices. @ disk.all.blkwrite block write operations, summed for all disks Cumulative number of disk block write operations since system boot time (subject to counter wrap), summed over all disk devices. @ disk.all.blktotal total (read+write) block operations, summed for all disks Cumulative number of disk block read and write operations since system boot time (subject to counter wrap), summed over all disk devices. @ disk.all.read_bytes count of bytes read for all disk devices @ disk.all.write_bytes count of bytes written for all disk devices @ disk.all.total_bytes count of bytes read and written for all disk devices @ network.interface.in.bytes network receive read bytes @ network.interface.in.packets network receive read packets @ network.interface.in.errors network receive read errors @ network.interface.in.drops connections dropped on input @ network.interface.in.mcasts network receive multicasts @ network.interface.out.bytes network send write bytes @ network.interface.out.packets network send write packets @ network.interface.out.errors network send write errors @ network.interface.out.mcasts network send multicasts @ network.interface.collisions network send collisions for CDMA interfaces @ network.interface.mtu maximum transmission size for network interfaces @ network.interface.baudrate line speed for network interfaces @ network.interface.total.bytes total network bytes received and sent @ network.interface.total.packets total network packets received and sent @ network.interface.total.errors total network errors on receive and send @ network.interface.total.drops total network connections dropped @ network.interface.total.mcasts total network multicasts @ nfs3.client.calls @ nfs3.client.reqs @ nfs3.server.calls @ nfs3.server.reqs @ rpc.client.rpccnt @ rpc.client.rpcretrans @ rpc.client.rpctimeouts @ rpc.client.rpcinvalid @ rpc.client.rpcunexpected @ rpc.client.attrcache.hits @ rpc.client.attrcache.misses @ rpc.client.lookupcache.hits @ rpc.client.lookupcache.misses @ rpc.client.biocache.read.hits @ rpc.client.biocache.read.misses @ rpc.client.biocache.write.hits @ rpc.client.biocache.write.misses @ rpc.client.biocache.readlink.hits @ rpc.client.biocache.readlink.misses @ rpc.client.biocache.readdir.hits @ rpc.client.biocache.readdir.misses @ rpc.client.direofcache.hits @ rpc.client.direofcache.misses @ rpc.server.retfailed @ rpc.server.faults @ rpc.server.cache.inprog @ rpc.server.cache.nonidem @ rpc.server.cache.idem @ rpc.server.cache.misses @ rpc.server.vopwrites @ rpc.server.pageins @ rpc.server.pageouts pcp-3.8.12ubuntu1/src/pmdas/darwin/network.h0000664000000000000000000000423012272262501015622 0ustar /* * Network interface statistics types * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #define IFNAMEMAX 16 /* largest interface name we allow */ /* * Per-interface statistics */ typedef struct ifacestat { __uint64_t mtu; /* maximum transmission unit */ __uint64_t baudrate; /* linespeed */ __uint64_t ipackets; /* packets received on interface */ __uint64_t ierrors; /* input errors on interface */ __uint64_t opackets; /* packets sent on interface */ __uint64_t oerrors; /* output errors on interface */ __uint64_t collisions; /* collisions on csma interfaces */ __uint64_t ibytes; /* total number of octets received */ __uint64_t obytes; /* total number of octets sent */ __uint64_t imcasts; /* packets received via multicast */ __uint64_t omcasts; /* packets sent via multicast */ __uint64_t iqdrops; /* dropped on input, this interface */ char name[IFNAMEMAX + 1]; } ifacestat_t; /* * Global statistics. * * We avoid continually realloc'ing memory by keeping track * of the maximum number of interfaces we've allocated space * for so far, and only realloc new space if we go beyond that. */ typedef struct netstats { int highwater; /* largest number of interfaces seen so far */ ifacestat_t *interfaces; /* space for highwater number of interfaces */ } netstats_t; pcp-3.8.12ubuntu1/src/pmdas/rpm/0000775000000000000000000000000012272262620013275 5ustar pcp-3.8.12ubuntu1/src/pmdas/rpm/Remove0000664000000000000000000000122512272262501014453 0ustar #! /bin/sh # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the rpm PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=rpm pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/rpm/Install0000664000000000000000000000135112272262501014624 0ustar #! /bin/sh # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the rpm PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=rpm pmda_interface=5 forced_restart=false dso_opt=true pipe_opt=true daemon_opt=true pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/rpm/GNUmakefile0000664000000000000000000000304012272262501015342 0ustar # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = rpm DOMAIN = RPM CMDTARGET = pmda$(IAM)$(EXECSUFFIX) LIBTARGET = pmda_$(IAM).$(DSOSUFFIX) PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) PMDAINIT = $(IAM)_init HFILES = rpm.h timer.h CFILES = rpm.c timer.c SCRIPTS = Install Remove VERSION_SCRIPT = exports LSRCFILES = Install Remove pmns root help LDIRT = domain.h $(IAM).log $(VERSION_SCRIPT) LIB_FOR_RPM = -lrpm LLDLIBS = $(PCP_PMDALIB) $(LIB_FOR_RPM) $(LIB_FOR_PTHREADS) LCFLAGS = $(INVISIBILITY) default: build-me include $(BUILDRULES) ifeq ($(HAVE_RPMLIB),1) build-me: domain.h $(CMDTARGET) $(LIBTARGET) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 644 root pmns domain.h help $(PMDADIR) $(INSTALL) -m 755 $(CMDTARGET) $(LIBTARGET) $(SCRIPTS) $(PMDADIR) else build-me: install: endif default_pcp : default install_pcp : install $(VERSION_SCRIPT): $(VERSION_SCRIPT_MAKERULE) domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) rpm.o: rpm.h rpm.o timer.o: timer.h rpm.o: $(VERSION_SCRIPT) pcp-3.8.12ubuntu1/src/pmdas/rpm/root0000664000000000000000000000016012272262501014176 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { rpm } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/rpm/pmns0000664000000000000000000000112112272262521014170 0ustar rpm { arch RPM:1:0 buildhost RPM:1:1 buildtime RPM:1:2 description RPM:1:3 epoch RPM:1:4 group RPM:1:5 installtime RPM:1:6 license RPM:1:7 packager RPM:1:8 release RPM:1:9 size RPM:1:10 sourcerpm RPM:1:11 summary RPM:1:12 url RPM:1:13 vendor RPM:1:14 version RPM:1:15 name RPM:1:16 refresh datasize RPM:0:4 total } rpm.refresh { count RPM:0:0 time } rpm.refresh.time { user RPM:0:1 sys RPM:0:2 elapsed RPM:0:3 } rpm.total { count RPM:2:0 bytes RPM:2:1 } pcp-3.8.12ubuntu1/src/pmdas/rpm/rpm.h0000664000000000000000000000535712272262521014256 0ustar /* * Copyright (c) 2013-2014 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef RPM_H #define RPM_H /* * Instance domain handling */ enum { RPM_INDOM = 0, /* active RPM packages */ CACHE_INDOM = 1, /* pseudo-indom for refreshing */ STRINGS_INDOM = 2, /* pseudo-indom for string sharing */ }; /* * Metrics describing internals of pmdarpm operation (Cluster 0) */ enum { REFRESH_COUNT_ID = 0, REFRESH_TIME_USER_ID = 1, REFRESH_TIME_KERNEL_ID = 2, REFRESH_TIME_ELAPSED_ID = 3, DATASIZE_ID = 4, }; /* * List of metrics corresponding to rpm --querytags (Cluster 1) */ enum { ARCH_ID = 0, BUILDHOST_ID = 1, BUILDTIME_ID = 2, DESCRIPTION_ID = 3, EPOCH_ID = 4, GROUP_ID = 5, INSTALLTIME_ID = 6, LICENSE_ID = 7, PACKAGER_ID = 8, RELEASE_ID = 9, SIZE_ID = 10, SOURCERPM_ID = 11, SUMMARY_ID = 12, URL_ID = 13, VENDOR_ID = 14, VERSION_ID = 15, NAME_ID = 16, }; /* * Metrics describing cumulative pmdarpm totals (Cluster 2) */ enum { TOTAL_COUNT_ID = 0, TOTAL_BYTES_ID = 1, }; /* * Package metadata stored for each installed RPM * * A "refresh" count is stored to indicate whether this entry * is out of date with respect to the global "refresh" count. * If its value is greater-than-or-equal-to a global refresh * count, the entry is current - otherwise it is out-of-date * and must not be reported in the active instance domain. * * Note that many of the structure entries (below) are string * dictionary keys (int), allowing sharing of the memory used * to hold the values. It also further reduces the footprint * on 64 bit systems, instead of storing 64bit pointers. */ typedef struct metadata { int name; int arch; int buildhost; __uint32_t buildtime; int description; __uint32_t epoch; int group; __uint32_t installtime; int license; int packager; int release; __uint32_t size; int sourcerpm; int summary; int url; int vendor; int version; } metadata; typedef struct package { __uint64_t refresh; metadata values; } package; #define EVENT_SIZE ( sizeof (struct inotify_event) ) #define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) #endif /* RPM_H */ pcp-3.8.12ubuntu1/src/pmdas/rpm/rpm.c0000664000000000000000000004407612272262521014252 0ustar /* * RPM Package Manager PMDA * * Copyright (c) 2013-2014 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include "domain.h" #include "timer.h" #include "rpm.h" static pmdaIndom indomtab[] = { {RPM_INDOM, 0, NULL}, {CACHE_INDOM, 1, NULL}, {STRINGS_INDOM, 2, NULL}, }; static pmdaMetric metrictab[] = { /* PMDA internals metrics - timing, count of refreshes, memory */ { NULL, { PMDA_PMID(0, REFRESH_COUNT_ID), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, { NULL, { PMDA_PMID(0, REFRESH_TIME_USER_ID), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0)}}, { NULL, { PMDA_PMID(0, REFRESH_TIME_KERNEL_ID), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0)}}, { NULL, { PMDA_PMID(0, REFRESH_TIME_ELAPSED_ID), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0)}}, { NULL, { PMDA_PMID(0, DATASIZE_ID), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0)}}, /* rpm package metrics */ { NULL, { PMDA_PMID(1, ARCH_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, BUILDHOST_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, BUILDTIME_ID), PM_TYPE_U32, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0)}}, { NULL, { PMDA_PMID(1, DESCRIPTION_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, EPOCH_ID), PM_TYPE_U32, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, GROUP_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, INSTALLTIME_ID), PM_TYPE_U32, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0)}}, { NULL, { PMDA_PMID(1, LICENSE_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, PACKAGER_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, RELEASE_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, SIZE_ID), PM_TYPE_U32, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0)}}, { NULL, { PMDA_PMID(1, SOURCERPM_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, SUMMARY_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, URL_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, VENDOR_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, VERSION_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, { NULL, { PMDA_PMID(1, NAME_ID), PM_TYPE_STRING, RPM_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* cumulative rpm metrics - total package count, size */ { NULL, { PMDA_PMID(2, TOTAL_COUNT_ID), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE)}}, { NULL, { PMDA_PMID(2, TOTAL_BYTES_ID), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0)}}, }; static pthread_t indom_thread; /* load the instances initially */ static pthread_t inotify_thread; /* runs when the rpmdb changes */ static unsigned long long numrefresh; /* updated by background thread */ static unsigned long long packagesize; /* sum of sizes of all packages */ static unsigned long numpackages; /* total count for all packages */ static pthread_mutex_t indom_mutex; static int isDSO = 1; /* invoked as shlib or daemon */ static char *username; static char *dbpath = "/var/lib/rpm/Packages"; static pmInDom INDOM(int serial) { return indomtab[serial].it_indom; } static char * dict_lookup(int index) { char *value; pmInDom dict = INDOM(STRINGS_INDOM); if (pmdaCacheLookup(dict, index, &value, NULL) == PMDA_CACHE_ACTIVE) return value; return ""; } static int dict_insert(const char *string) { pmInDom dict = INDOM(STRINGS_INDOM); if (!string) string = ""; return pmdaCacheStore(dict, PMDA_CACHE_ADD, string, NULL); } static int rpm_fetch_pmda(int item, pmAtomValue *atom) { int sts = PMDA_FETCH_STATIC; unsigned long datasize; switch (item) { case REFRESH_COUNT_ID: /* rpm.refresh.count */ atom->ull = numrefresh; break; case REFRESH_TIME_USER_ID: /* rpm.refresh.time.user */ atom->d = get_user_timer(); break; case REFRESH_TIME_KERNEL_ID: /* rpm.refresh.time.kernel */ atom->d = get_kernel_timer(); break; case REFRESH_TIME_ELAPSED_ID: /* rpm.refresh.time.elapsed */ atom->d = get_elapsed_timer(); break; case DATASIZE_ID: /* rpm.datasize */ __pmProcessDataSize(&datasize); atom->ul = datasize; break; default: sts = PM_ERR_PMID; break; } return sts; } static int rpm_fetch_package(int item, unsigned int inst, pmAtomValue *atom) { package *p; char *name; int sts; sts = pmdaCacheLookup(INDOM(RPM_INDOM), inst, &name, (void **)&p); if (sts < 0 || sts == PMDA_CACHE_INACTIVE) return PM_ERR_INST; sts = PMDA_FETCH_STATIC; switch (item) { case ARCH_ID: atom->cp = dict_lookup(p->values.arch); break; case BUILDHOST_ID: atom->cp = dict_lookup(p->values.buildhost); break; case BUILDTIME_ID: atom->ul = p->values.buildtime; break; case DESCRIPTION_ID: atom->cp = dict_lookup(p->values.description); break; case EPOCH_ID: atom->ul = p->values.epoch; break; case GROUP_ID: atom->cp = dict_lookup(p->values.group); break; case INSTALLTIME_ID: atom->ul = p->values.installtime; break; case LICENSE_ID: atom->cp = dict_lookup(p->values.license); break; case PACKAGER_ID: atom->cp = dict_lookup(p->values.packager); break; case RELEASE_ID: atom->cp = dict_lookup(p->values.release); break; case SIZE_ID: atom->ul = p->values.size; break; case SOURCERPM_ID: atom->cp = dict_lookup(p->values.sourcerpm); break; case SUMMARY_ID: atom->cp = dict_lookup(p->values.summary); break; case URL_ID: atom->cp = dict_lookup(p->values.url); break; case VENDOR_ID: atom->cp = dict_lookup(p->values.vendor); break; case VERSION_ID: atom->cp = dict_lookup(p->values.version); break; case NAME_ID: atom->cp = dict_lookup(p->values.name); break; default: sts = PM_ERR_PMID; break; } return sts; } static int rpm_fetch_totals(int item, pmAtomValue *atom) { int sts = PMDA_FETCH_STATIC; switch (item) { case TOTAL_COUNT_ID: /* rpm.total.count */ atom->ul = numpackages; break; case TOTAL_BYTES_ID: /* rpm.total.bytes */ atom->ull = packagesize; break; default: sts = PM_ERR_PMID; break; } return sts; } static int rpm_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *) &mdesc->m_desc.pmid; int sts; pthread_mutex_lock(&indom_mutex); switch (idp->cluster) { case 0: if (inst != PM_IN_NULL) sts = PM_ERR_INST; else sts = rpm_fetch_pmda(idp->item, atom); break; case 1: sts = rpm_fetch_package(idp->item, inst, atom); break; case 2: sts = rpm_fetch_totals(idp->item, atom); break; default: sts = PM_ERR_PMID; break; } pthread_mutex_unlock(&indom_mutex); return sts; } /* * Sync the active rpm package instances with the reference database * maintained by the background threads. */ static void rpm_indom_refresh(unsigned long long refresh) { pmInDom rpmdb, cache; package *p; char *name; int sts; rpmdb = INDOM(RPM_INDOM); cache = INDOM(CACHE_INDOM); pmdaCacheOp(rpmdb, PMDA_CACHE_INACTIVE); pthread_mutex_lock(&indom_mutex); for (pmdaCacheOp(cache, PMDA_CACHE_WALK_REWIND);;) { if ((sts = pmdaCacheOp(cache, PMDA_CACHE_WALK_NEXT)) < 0) break; if ((pmdaCacheLookup(cache, sts, &name, (void **)&p) < 0) || !p) continue; if (p->refresh < refresh) continue; pmdaCacheStore(rpmdb, PMDA_CACHE_ADD, name, (void *)p); } pthread_mutex_unlock(&indom_mutex); } /* * Sync up with the (initial) indom loading thread */ static int notready(pmdaExt *pmda) { __pmSendError(pmda->e_outfd, FROM_ANON, PM_ERR_PMDANOTREADY); pthread_join(indom_thread, NULL); return PM_ERR_PMDAREADY; } /* * Called once for each pmFetch(3) operation */ static int rpm_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { unsigned long long refresh; pthread_mutex_lock(&indom_mutex); refresh = numrefresh; pthread_mutex_unlock(&indom_mutex); if (refresh == 0) return notready(pmda); rpm_indom_refresh(refresh); return pmdaFetch(numpmid, pmidlist, resp, pmda); } /* * Called once for each pmGetInDom(3) operation */ static int rpm_instance(pmInDom id, int i, char *name, __pmInResult **in, pmdaExt *pmda) { unsigned long long refresh; pthread_mutex_lock(&indom_mutex); refresh = numrefresh; pthread_mutex_unlock(&indom_mutex); if (refresh == 0) return notready(pmda); rpm_indom_refresh(refresh); return pmdaInstance(id, i, name, in, pmda); } static const char * rpm_extract_string(rpmtd td, Header h, int tag) { headerGet(h, tag, td, HEADERGET_EXT | HEADERGET_MINMEM); /* * RPM_STRING_ARRAY_TYPE being the alternative, e.g. filenames * (which we never expect to see, for the metrics we export). */ if (td->type == RPM_STRING_ARRAY_TYPE) __pmNotifyErr(LOG_ERR, "rpm_extract_string: unexpected string array: %d", tag); return rpmtdGetString(td); } static __uint32_t rpm_extract_value(rpmtd td, Header h, int tag) { __uint32_t value; headerGet(h, tag, td, HEADERGET_EXT | HEADERGET_MINMEM); switch (td->type) { case RPM_INT8_TYPE: value = ((char *)(td->data))[0]; break; case RPM_INT16_TYPE: value = ((short *)(td->data))[0]; break; case RPM_INT32_TYPE: value = ((int *)(td->data))[0]; break; case RPM_INT64_TYPE: value = ((long long *)(td->data))[0]; break; default: value = 0; break; } return value; } static void rpm_extract_metadata(const char *name, rpmtd td, Header h, metadata *m) { if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_INFO, "updating package %s metadata", name); m->name = dict_insert(rpm_extract_string(td, h, RPMTAG_NAME)); m->arch = dict_insert(rpm_extract_string(td, h, RPMTAG_ARCH)); m->buildhost = dict_insert(rpm_extract_string(td, h, RPMTAG_BUILDHOST)); m->buildtime = rpm_extract_value(td, h, RPMTAG_BUILDTIME); m->description = dict_insert(rpm_extract_string(td, h, RPMTAG_DESCRIPTION)); m->epoch = rpm_extract_value(td, h, RPMTAG_EPOCH); m->group = dict_insert(rpm_extract_string(td, h, RPMTAG_GROUP)); m->installtime = rpm_extract_value(td, h, RPMTAG_INSTALLTIME); m->license = dict_insert(rpm_extract_string(td, h, RPMTAG_LICENSE)); m->packager = dict_insert(rpm_extract_string(td, h, RPMTAG_PACKAGER)); m->release = dict_insert(rpm_extract_string(td, h, RPMTAG_RELEASE)); m->size = rpm_extract_value(td, h, RPMTAG_SIZE); m->sourcerpm = dict_insert(rpm_extract_string(td, h, RPMTAG_SOURCERPM)); m->summary = dict_insert(rpm_extract_string(td, h, RPMTAG_SUMMARY)); m->url = dict_insert(rpm_extract_string(td, h, RPMTAG_URL)); m->vendor = dict_insert(rpm_extract_string(td, h, RPMTAG_VENDOR)); m->version = dict_insert(rpm_extract_string(td, h, RPMTAG_VERSION)); } /* * Refresh the RPM package names and values in the cache */ void * rpm_update_cache(void *ptr) { rpmtd td; rpmts ts; Header h; rpmdbMatchIterator mi; unsigned long long refresh; unsigned long long totalsize = 0; unsigned long packages = 0; static int cache_err = 0; pthread_mutex_lock(&indom_mutex); start_timing(); refresh = numrefresh + 1; /* current iteration */ pthread_mutex_unlock(&indom_mutex); td = rpmtdNew(); ts = rpmtsCreate(); rpmReadConfigFiles(NULL, NULL); /* Iterate through the entire list of RPMs, extract names and values */ mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0); while ((h = rpmdbNextIterator(mi)) != NULL) { headerGet(h, RPMTAG_NEVRA, td, HEADERGET_EXT | HEADERGET_MINMEM); const char *name = rpmtdGetString(td); metadata meta; package *pp = NULL; int sts, err = 0; /* extract an on-stack copy of the package metadata, may do I/O */ rpm_extract_metadata(name, td, h, &meta); /* update cumulative counts */ totalsize += meta.size; packages++; /* we now have our data and cannot need more I/O; lock and load */ pthread_mutex_lock(&indom_mutex); sts = pmdaCacheLookupName(INDOM(CACHE_INDOM), name, NULL, (void **)&pp); if (sts == PM_ERR_INST || (sts >= 0 && pp == NULL)) { /* allocate space for new package entry for the cache */ if ((pp = calloc(1, sizeof(package))) == NULL) err = 1; } else if (sts < 0) { err = 1; } if (!err) { /* update values in cache entry for this package (locked) */ pp->refresh = refresh; memcpy(&pp->values, &meta, sizeof(metadata)); pmdaCacheStore(INDOM(CACHE_INDOM), PMDA_CACHE_ADD, name, (void *)pp); } else { /* ensure the logfile isn't spammed over and over */ if (cache_err++ < 10) { fprintf(stderr, "rpm_refresh_cache: " "pmdaCacheLookupName(%s, %s, ... %p) failed: %s\n", pmInDomStr(INDOM(CACHE_INDOM)), name, pp, pmErrStr(sts)); } } pthread_mutex_unlock(&indom_mutex); } rpmdbFreeIterator(mi); rpmtsFree(ts); pthread_mutex_lock(&indom_mutex); stop_timing(); numrefresh = refresh; /* current iteration complete */ packagesize = totalsize; numpackages = packages; pthread_mutex_unlock(&indom_mutex); return NULL; } /* * Notice when the rpm database changes and reload the instances. */ void * rpm_inotify(void *ptr) { char buffer[EVENT_BUF_LEN]; int fd; fd = inotify_init(); inotify_add_watch(fd, dbpath, IN_CLOSE_WRITE); while (1) { int i = 0; int read_count; int need_refresh = 0; /* Wait for changes in the rpm database */ read_count = read(fd, buffer, EVENT_BUF_LEN); if (pmDebug & DBG_TRACE_APPL1) __pmNotifyErr(LOG_INFO, "rpm_inotify: read_count=%d", read_count); while (i < read_count) { struct inotify_event *event = (struct inotify_event *) &buffer[i]; if (event->mask & IN_CLOSE_WRITE) need_refresh++; i++; } if (pmDebug & DBG_TRACE_APPL1) __pmNotifyErr(LOG_INFO, "rpm_inotify: need_refresh=%d", need_refresh); if (!need_refresh) continue; rpm_update_cache(ptr); if (pmDebug & DBG_TRACE_APPL1) __pmNotifyErr(LOG_INFO, "rpm_inotify: refresh done"); } return NULL; } /* * Initialize the daemon/.so agent. */ void __PMDA_INIT_CALL rpm_init(pmdaInterface * dp) { if (isDSO) { int sep = __pmPathSeparator(); char helppath[MAXPATHLEN]; snprintf(helppath, sizeof(helppath), "%s%c" "rpm" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_5, "rpm DSO", helppath); } else { __pmSetProcessIdentity(username); } if (dp->status != 0) return; dp->version.any.fetch = rpm_fetch; dp->version.any.instance = rpm_instance; pmdaSetFetchCallBack(dp, rpm_fetchCallBack); pmdaInit(dp, indomtab, sizeof(indomtab) / sizeof(indomtab[0]), metrictab, sizeof(metrictab) / sizeof(metrictab[0])); pmdaCacheOp(INDOM(STRINGS_INDOM), PMDA_CACHE_STRINGS); pthread_mutex_init(&indom_mutex, NULL); /* Load rpms into instance table */ pthread_create(&indom_thread, NULL, rpm_update_cache, NULL); /* Note changes to the rpm database */ pthread_create(&inotify_thread, NULL, rpm_inotify, NULL); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fprintf(stderr, "Options:\n" " -C parse the RPM database, and exit\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -r path path to directory containing RPM database (default %s)\n" " -U username user account to run under (default \"pcp\")\n" "\nExactly one of the following options may appear:\n" " -i port expect PMCD to connect on given inet port (number or name)\n" " -p expect PMCD to supply stdin/stdout (pipe)\n" " -u socket expect PMCD to connect on given unix domain socket\n" " -6 port expect PMCD to connect on given ipv6 port (number or name)\n", dbpath); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int c, err = 0; int Cflag = 0, sep = __pmPathSeparator(); pmdaInterface dispatch; char helppath[MAXPATHLEN]; isDSO = 0; __pmSetProgname(argv[0]); __pmProcessDataSize(NULL); __pmGetUsername(&username); snprintf(helppath, sizeof(helppath), "%s%c" "rpm" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_5, pmProgname, RPM, "rpm.log", helppath); while ((c = pmdaGetOpt(argc, argv, "CD:d:i:l:pr:u:6:U:?", &dispatch, &err)) != EOF) { switch (c) { case 'C': Cflag++; break; case 'U': username = optarg; break; case 'r': dbpath = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&dispatch); rpm_init(&dispatch); if (Cflag) { rpm_update_cache(NULL); exit(0); } pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/rpm/timer.c0000664000000000000000000000250712272262501014563 0ustar /* * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include static struct rusage start_rsrc, final_rsrc; static struct timeval start_time, final_time; static double user, kernel, elapsed; double get_user_timer() { return user; } double get_kernel_timer() { return kernel; } double get_elapsed_timer() { return elapsed; } void start_timing(void) { getrusage(RUSAGE_SELF, &start_rsrc); gettimeofday(&start_time, NULL); } void stop_timing(void) { gettimeofday(&final_time, NULL); getrusage(RUSAGE_SELF, &final_rsrc); /* accumulate the totals as we go */ user += __pmtimevalSub(&final_rsrc.ru_utime, &start_rsrc.ru_utime); kernel += __pmtimevalSub(&final_rsrc.ru_stime, &start_rsrc.ru_stime); elapsed += __pmtimevalSub(&final_time, &start_time); } pcp-3.8.12ubuntu1/src/pmdas/rpm/timer.h0000664000000000000000000000141012272262501014560 0ustar /* * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef TIMER_H #define TIMER_H extern void start_timing(void); extern void stop_timing(void); extern double get_user_timer(void); extern double get_kernel_timer(void); extern double get_elapsed_timer(void); #endif /* TIMER_H */ pcp-3.8.12ubuntu1/src/pmdas/rpm/help0000664000000000000000000000430012272262521014145 0ustar # # Copyright (c) 2013-2014 Red Hat, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # rpm PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ rpm.arch package architecture @ rpm.buildhost package build host @ rpm.buildtime package buildtime @ rpm.description package description @ rpm.epoch package install epoch @ rpm.group group of the package @ rpm.installtime package install time @ rpm.license package license @ rpm.packager entity responsible for packaging @ rpm.release release list of the package @ rpm.size size of the package in bytes @ rpm.sourcerpm package source rpm @ rpm.summary summary of the package @ rpm.url url of the package @ rpm.vendor package vendor @ rpm.version package version @ rpm.name package name @ rpm.refresh.count Cumulative count of rpmdb scans performed @ rpm.refresh.time.user Cumulative count of user mode scan time @ rpm.refresh.time.sys Cumulative count of kernel mode scan time @ rpm.refresh.time.elapsed Cumulative count of elapsed scan time @ rpm.datasize Space allocated for pmdarpms data segment (K) This metric returns the amount of memory in kilobytes allocated for the data segment of pmdarpm. This is handy for tracking memory utilization. @ rpm.total.count Count of packages returned in last rpmdb scan @ rpm.total.bytes Size of all packages from the last rpmdb scan pcp-3.8.12ubuntu1/src/pmdas/linux/0000775000000000000000000000000012272262620013636 5ustar pcp-3.8.12ubuntu1/src/pmdas/linux/proc_net_rpc.h0000664000000000000000000000637012272262501016470 0ustar /* * Linux /proc/net/rpc metrics cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define NR_RPC_COUNTERS 18 #define NR_RPC3_COUNTERS 22 #define NR_RPC4_CLI_COUNTERS 35 #define NR_RPC4_SVR_COUNTERS 41 typedef struct { struct { int errcode; /* error from last refresh */ /* /proc/net/rpc/nfs "net" */ unsigned int netcnt; unsigned int netudpcnt; unsigned int nettcpcnt; unsigned int nettcpconn; /* /proc/net/rpc/nfs "rpc" */ unsigned int rpccnt; unsigned int rpcretrans; unsigned int rpcauthrefresh; /* /proc/net/rpc/nfs "proc2" */ unsigned int reqcounts[NR_RPC_COUNTERS]; /* /proc/net/rpc/nfs "proc3" */ unsigned int reqcounts3[NR_RPC3_COUNTERS]; /* /proc/net/rpc/nfs "proc4" */ unsigned int reqcounts4[NR_RPC4_CLI_COUNTERS]; } client; struct { int errcode; /* error from last refresh */ /* /proc/net/rpc/nfsd "rc" and "fh" */ unsigned int rchits; /* repcache hits */ unsigned int rcmisses; /* repcache hits */ unsigned int rcnocache; /* uncached reqs */ unsigned int fh_cached; /* dentry cached */ unsigned int fh_valid; /* dentry validated */ unsigned int fh_fixup; /* dentry fixup validated */ unsigned int fh_lookup; /* new lookup required */ unsigned int fh_stale; /* FH stale error */ unsigned int fh_concurrent; /* concurrent request */ unsigned int fh_anon; /* anon file dentry returned */ unsigned int fh_nocache_dir; /* dir filehandle not found in dcache */ unsigned int fh_nocache_nondir; /* nondir filehandle not in dcache */ /* /proc/net/rpc/nfsd "io" */ unsigned int io_read; /* bytes returned to read requests */ unsigned int io_write; /* bytes passed in write requests */ /* /proc/net/rpc/nfsd "th" */ unsigned int th_cnt; /* available nfsd threads */ unsigned int th_fullcnt; /* times last free thread used */ /* /proc/net/rpc/nfsd "net" */ unsigned int netcnt; unsigned int netudpcnt; unsigned int nettcpcnt; unsigned int nettcpconn; /* /proc/net/rpc/nfsd "rpc" */ unsigned int rpccnt; unsigned int rpcerr; unsigned int rpcbadfmt; unsigned int rpcbadauth; unsigned int rpcbadclnt; /* /proc/net/rpc/nfsd "proc2" */ unsigned int reqcounts[NR_RPC_COUNTERS]; /* /proc/net/rpc/nfsd "proc3" */ unsigned int reqcounts3[NR_RPC3_COUNTERS]; /* /proc/net/rpc/nfsd "proc4" & "proc4ops" */ unsigned int reqcounts4[NR_RPC4_SVR_COUNTERS]; } server; } proc_net_rpc_t; extern int refresh_proc_net_rpc(proc_net_rpc_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/sysfs_kernel.h0000664000000000000000000000232612272262501016517 0ustar /* * Linux sysfs_kernel cluster * * Copyright (c) 2009, Red Hat, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef _SYSFS_KERNEL_H #define _SYSFS_KERNEL_H #include "pmapi.h" #include "impl.h" #include "pmda.h" #include typedef struct { int valid_uevent_seqnum; uint64_t uevent_seqnum; /* /sys/kernel/uevent_seqnum */ /* TODO queue length, event type counters and other metrics */ } sysfs_kernel_t; /* refresh sysfs_kernel */ extern int refresh_sysfs_kernel(sysfs_kernel_t *); #endif /* _SYSFS_KERNEL_H */ pcp-3.8.12ubuntu1/src/pmdas/linux/sem_limits.c0000664000000000000000000000272112272262501016147 0ustar /* * Copyright (c) International Business Machines Corp., 2002 * This code contributed by Mike Mason * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #define __USE_GNU 1 /* required for IPC_INFO define */ #include #include #include "pmapi.h" #include "sem_limits.h" int refresh_sem_limits(sem_limits_t *sem_limits) { static int started; static struct seminfo seminfo; static union semun arg; if (!started) { started = 1; memset(sem_limits, 0, sizeof(sem_limits_t)); arg.array = (unsigned short *) &seminfo; } if (semctl(0, 0, IPC_INFO, arg) < 0) { return -oserror(); } sem_limits->semmap = seminfo.semmap; sem_limits->semmni = seminfo.semmni; sem_limits->semmns = seminfo.semmns; sem_limits->semmnu = seminfo.semmnu; sem_limits->semmsl = seminfo.semmsl; sem_limits->semopm = seminfo.semopm; sem_limits->semume = seminfo.semume; sem_limits->semusz = seminfo.semusz; sem_limits->semvmx = seminfo.semvmx; sem_limits->semaem = seminfo.semaem; return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_net_snmp.c0000664000000000000000000003370612272262521016661 0ustar /* * Copyright (c) 2013-2014 Red Hat. * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "indom.h" #include "proc_net_snmp.h" extern proc_net_snmp_t _pm_proc_net_snmp; extern pmdaInstid _pm_proc_net_snmp_indom_id[]; static char *proc_net_snmp_icmpmsg_names; typedef struct { const char *field; __uint64_t *offset; } snmp_fields_t; snmp_fields_t ip_fields[] = { { .field = "Forwarding", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_FORWARDING] }, { .field = "DefaultTTL", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_DEFAULTTTL] }, { .field = "InReceives", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_INRECEIVES] }, { .field = "InHdrErrors", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_INHDRERRORS] }, { .field = "InAddrErrors", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_INADDRERRORS] }, { .field = "ForwDatagrams", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_FORWDATAGRAMS] }, { .field = "InUnknownProtos", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_INUNKNOWNPROTOS] }, { .field = "InDiscards", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_INDISCARDS] }, { .field = "InDelivers", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_INDELIVERS] }, { .field = "OutRequests", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_OUTREQUESTS] }, { .field = "OutDiscards", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_OUTDISCARDS] }, { .field = "OutNoRoutes", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_OUTNOROUTES] }, { .field = "ReasmTimeout", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_REASMTIMEOUT] }, { .field = "ReasmReqds", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_REASMREQDS] }, { .field = "ReasmOKs", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_REASMOKS] }, { .field = "ReasmFails", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_REASMFAILS] }, { .field = "FragOKs", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_FRAGOKS] }, { .field = "FragFails", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_FRAGFAILS] }, { .field = "FragCreates", .offset = &_pm_proc_net_snmp.ip[_PM_SNMP_IP_FRAGCREATES] }, { .field = NULL, .offset = NULL } }; snmp_fields_t icmp_fields[] = { { .field = "InMsgs", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INMSGS] }, { .field = "InErrors", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INERRORS] }, { .field = "InCsumErrors", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INCSUMERRORS] }, { .field = "InDestUnreachs", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INDESTUNREACHS] }, { .field = "InTimeExcds", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INTIMEEXCDS] }, { .field = "InParmProbs", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INPARMPROBS] }, { .field = "InSrcQuenchs", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INSRCQUENCHS] }, { .field = "InRedirects", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INREDIRECTS] }, { .field = "InEchos", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INECHOS] }, { .field = "InEchoReps", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INECHOREPS] }, { .field = "InTimestamps", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INTIMESTAMPS] }, { .field = "InTimestampReps", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INTIMESTAMPREPS] }, { .field = "InAddrMasks", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INADDRMASKS] }, { .field = "InAddrMaskReps", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INADDRMASKREPS] }, { .field = "OutMsgs", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTMSGS] }, { .field = "OutErrors", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTERRORS] }, { .field = "OutDestUnreachs", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTDESTUNREACHS] }, { .field = "OutTimeExcds", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTTIMEEXCDS] }, { .field = "OutParmProbs", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTPARMPROBS] }, { .field = "OutSrcQuenchs", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTSRCQUENCHS] }, { .field = "OutRedirects", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTREDIRECTS] }, { .field = "OutEchos", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTECHOS] }, { .field = "OutEchoReps", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTECHOREPS] }, { .field = "OutTimestamps", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTTIMESTAMPS] }, { .field = "OutTimestampReps", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTTIMESTAMPREPS] }, { .field = "OutAddrMasks", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTADDRMASKS] }, { .field = "OutAddrMaskReps", .offset = &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTADDRMASKREPS] }, { .field = NULL, .offset = NULL } }; snmp_fields_t icmpmsg_fields[] = { { .field = "InType%u", .offset = &_pm_proc_net_snmp.icmpmsg[_PM_SNMP_ICMPMSG_INTYPE] }, { .field = "OutType%u", .offset = &_pm_proc_net_snmp.icmpmsg[_PM_SNMP_ICMPMSG_OUTTYPE] }, { .field = NULL, .offset = NULL } }; snmp_fields_t tcp_fields[] = { { .field = "RtoAlgorithm", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_RTOALGORITHM] }, { .field = "RtoMin", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_RTOMIN] }, { .field = "RtoMax", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_RTOMAX] }, { .field = "MaxConn", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_MAXCONN] }, { .field = "ActiveOpens", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_ACTIVEOPENS] }, { .field = "PassiveOpens", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_PASSIVEOPENS] }, { .field = "AttemptFails", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_ATTEMPTFAILS] }, { .field = "EstabResets", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_ESTABRESETS] }, { .field = "CurrEstab", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_CURRESTAB] }, { .field = "InSegs", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_INSEGS] }, { .field = "OutSegs", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_OUTSEGS] }, { .field = "RetransSegs", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_RETRANSSEGS] }, { .field = "InErrs", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_INERRS] }, { .field = "OutRsts", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_OUTRSTS] }, { .field = "InCsumErrors", .offset = &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_INCSUMERRORS] }, { .field = NULL, .offset = NULL } }; snmp_fields_t udp_fields[] = { { .field = "InDatagrams", .offset = &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_INDATAGRAMS] }, { .field = "NoPorts", .offset = &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_NOPORTS] }, { .field = "InErrors", .offset = &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_INERRORS] }, { .field = "OutDatagrams", .offset = &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_OUTDATAGRAMS] }, { .field = "RcvbufErrors", .offset = &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_RECVBUFERRORS] }, { .field = "SndbufErrors", .offset = &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_SNDBUFERRORS] }, { .field = "InCsumErrors", .offset = &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_INCSUMERRORS] }, { .field = NULL, .offset = NULL } }; snmp_fields_t udplite_fields[] = { { .field = "InDatagrams", .offset = &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_INDATAGRAMS] }, { .field = "NoPorts", .offset = &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_NOPORTS] }, { .field = "InErrors", .offset = &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_INERRORS] }, { .field = "OutDatagrams", .offset = &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_OUTDATAGRAMS] }, { .field = "RcvbufErrors", .offset = &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_RECVBUFERRORS] }, { .field = "SndbufErrors", .offset = &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_SNDBUFERRORS] }, { .field = "InCsumErrors", .offset = &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_INCSUMERRORS] }, { .field = NULL, .offset = NULL } }; static void get_fields(snmp_fields_t *fields, char *header, char *buffer) { int i, j, count; char *p, *indices[SNMP_MAX_COLUMNS]; /* first get pointers to each of the column headings */ strtok(header, " "); for (i = 0; i < SNMP_MAX_COLUMNS; i++) { if ((p = strtok(NULL, " \n")) == NULL) break; indices[i] = p; } count = i; /* * Extract values via back-referencing column headings. * "i" is the last found index, which we use for a bit * of optimisation for the (common) in-order maps case * (where "in order" means in the order defined by the * passed in "fields" table which typically matches the * kernel - but may be out-of-order for older kernels). */ strtok(buffer, " "); for (i = j = 0; j < count && fields[i].field; j++, i++) { if ((p = strtok(NULL, " \n")) == NULL) break; if (strcmp(fields[i].field, indices[j]) == 0) { *fields[i].offset = strtoull(p, NULL, 10); } else { for (i = 0; fields[i].field; i++) { if (strcmp(fields[i].field, indices[j]) != 0) continue; *fields[i].offset = strtoull(p, NULL, 10); break; } if (fields[i].field == NULL) /* not found, ignore */ i = 0; } } } static void get_ordinal_fields(snmp_fields_t *fields, char *header, char *buffer, unsigned limit) { int i, j, count; unsigned int inst; char *p, *indices[SNMP_MAX_COLUMNS]; strtok(header, " "); for (i = 0; i < SNMP_MAX_COLUMNS; i++) { if ((p = strtok(NULL, " \n")) == NULL) break; indices[i] = p; } count = i; strtok(buffer, " "); for (j = 0; j < count; j++) { if ((p = strtok(NULL, " \n")) == NULL) break; for (i = 0; fields[i].field; i++) { if (sscanf(indices[j], fields[i].field, &inst) != 1) continue; if (inst >= limit) continue; *(fields[i].offset + inst) = strtoull(p, NULL, 10); break; } } } #define SNMP_IP_OFFSET(ii, pp) (int64_t *)((char *)pp + \ (__psint_t)ip_fields[ii].offset - (__psint_t)&_pm_proc_net_snmp.ip) #define SNMP_ICMP_OFFSET(ii, pp) (int64_t *)((char *)pp + \ (__psint_t)icmp_fields[ii].offset - (__psint_t)&_pm_proc_net_snmp.icmp) #define SNMP_ICMPMSG_OFFSET(ii, nn, pp) (int64_t *)((char *)pp + \ (__psint_t)(icmpmsg_fields[ii].offset + nn) - (__psint_t)&_pm_proc_net_snmp.icmpmsg) #define SNMP_TCP_OFFSET(ii, pp) (int64_t *)((char *)pp + \ (__psint_t)tcp_fields[ii].offset - (__psint_t)&_pm_proc_net_snmp.tcp) #define SNMP_UDP_OFFSET(ii, pp) (int64_t *)((char *)pp + \ (__psint_t)udp_fields[ii].offset - (__psint_t)&_pm_proc_net_snmp.udp) #define SNMP_UDPLITE_OFFSET(ii, pp) (int64_t *)((char *)pp + \ (__psint_t)udplite_fields[ii].offset - (__psint_t)&_pm_proc_net_snmp.udplite) static void init_refresh_proc_net_snmp(proc_net_snmp_t *snmp) { pmdaIndom *idp; char *s; int i, n; /* initially, all marked as "no value available" */ for (i = 0; ip_fields[i].field != NULL; i++) *(SNMP_IP_OFFSET(i, snmp->ip)) = -1; for (i = 0; icmp_fields[i].field != NULL; i++) *(SNMP_ICMP_OFFSET(i, snmp->icmp)) = -1; for (i = 0; tcp_fields[i].field != NULL; i++) *(SNMP_TCP_OFFSET(i, snmp->tcp)) = -1; for (i = 0; udp_fields[i].field != NULL; i++) *(SNMP_UDP_OFFSET(i, snmp->udp)) = -1; for (i = 0; udplite_fields[i].field != NULL; i++) *(SNMP_UDPLITE_OFFSET(i, snmp->udplite)) = -1; for (i = 0; icmpmsg_fields[i].field != NULL; i++) for (n = 0; n < NR_ICMPMSG_COUNTERS; n++) *(SNMP_ICMPMSG_OFFSET(i, n, snmp->icmpmsg)) = -1; /* only need to allocate and setup the names once */ if (proc_net_snmp_icmpmsg_names) return; i = NR_ICMPMSG_COUNTERS * SNMP_MAX_ICMPMSG_TYPESTR; proc_net_snmp_icmpmsg_names = malloc(i); if (!proc_net_snmp_icmpmsg_names) return; s = proc_net_snmp_icmpmsg_names; for (n = 0; n < NR_ICMPMSG_COUNTERS; n++) { sprintf(s, "Type%u", n); _pm_proc_net_snmp_indom_id[n].i_name = s; _pm_proc_net_snmp_indom_id[n].i_inst = n; s += SNMP_MAX_ICMPMSG_TYPESTR; } idp = PMDAINDOM(ICMPMSG_INDOM); idp->it_numinst = NR_ICMPMSG_COUNTERS; idp->it_set = _pm_proc_net_snmp_indom_id; } int refresh_proc_net_snmp(proc_net_snmp_t *snmp) { char header[1024]; char values[1024]; FILE *fp; init_refresh_proc_net_snmp(snmp); if ((fp = fopen("/proc/net/snmp", "r")) == NULL) return -oserror(); while (fgets(header, sizeof(header), fp) != NULL) { if (fgets(values, sizeof(values), fp) != NULL) { if (strncmp(values, "Ip:", 3) == 0) get_fields(ip_fields, header, values); else if (strncmp(values, "Icmp:", 5) == 0) get_fields(icmp_fields, header, values); else if (strncmp(values, "IcmpMsg:", 8) == 0) get_ordinal_fields(icmpmsg_fields, header, values, NR_ICMPMSG_COUNTERS); else if (strncmp(values, "Tcp:", 4) == 0) get_fields(tcp_fields, header, values); else if (strncmp(values, "Udp:", 4) == 0) get_fields(udp_fields, header, values); else if (strncmp(values, "UdpLite:", 8) == 0) get_fields(udplite_fields, header, values); else fprintf(stderr, "Error: " "Unrecognised /proc/net/snmp row: %s", values); } } fclose(fp); return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/filesys.c0000664000000000000000000000627612272262501015471 0ustar /* * Linux Filesystem Cluster * * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "filesys.h" char * scan_filesys_options(const char *options, const char *option) { static char buffer[128]; char *s; strncpy(buffer, options, sizeof(buffer)); buffer[sizeof(buffer)-1] = '\0'; s = strtok(buffer, ","); while (s) { if (strcmp(s, option) == 0) return s; s = strtok(NULL, ","); } return NULL; } int refresh_filesys(pmInDom filesys_indom, pmInDom tmpfs_indom) { char buf[MAXPATHLEN]; char realdevice[MAXPATHLEN]; filesys_t *fs; pmInDom indom; FILE *fp; char *path, *device, *type, *options; int sts; pmdaCacheOp(tmpfs_indom, PMDA_CACHE_INACTIVE); pmdaCacheOp(filesys_indom, PMDA_CACHE_INACTIVE); if ((fp = fopen("/proc/mounts", "r")) == (FILE *)NULL) return -oserror(); while (fgets(buf, sizeof(buf), fp) != NULL) { if ((device = strtok(buf, " ")) == 0) continue; path = strtok(NULL, " "); type = strtok(NULL, " "); options = strtok(NULL, " "); if (strcmp(type, "proc") == 0 || strcmp(type, "nfs") == 0 || strcmp(type, "devfs") == 0 || strcmp(type, "devpts") == 0 || strcmp(type, "cgroup") == 0 || strncmp(type, "auto", 4) == 0) continue; indom = filesys_indom; if (strcmp(type, "tmpfs") == 0) { indom = tmpfs_indom; device = path; } else if (strncmp(device, "/dev", 4) != 0) continue; if (realpath(device, realdevice) != NULL) device = realdevice; sts = pmdaCacheLookupName(indom, device, NULL, (void **)&fs); if (sts == PMDA_CACHE_ACTIVE) /* repeated line in /proc/mounts? */ continue; if (sts == PMDA_CACHE_INACTIVE) { /* re-activate an old mount */ pmdaCacheStore(indom, PMDA_CACHE_ADD, device, fs); if (strcmp(path, fs->path) != 0) { /* old device, new path */ free(fs->path); fs->path = strdup(path); } if (strcmp(options, fs->options) != 0) { /* old device, new opts */ free(fs->options); fs->options = strdup(options); } } else { /* new mount */ if ((fs = malloc(sizeof(filesys_t))) == NULL) continue; fs->device = strdup(device); fs->path = strdup(path); fs->options = strdup(options); #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { fprintf(stderr, "refresh_filesys: add \"%s\" \"%s\"\n", fs->path, device); } #endif pmdaCacheStore(indom, PMDA_CACHE_ADD, device, fs); } fs->flags = 0; } /* * success * Note: we do not call statfs() here since only some instances * may be requested (rather, we do it in linux_fetch, see pmda.c). */ fclose(fp); return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/shm_limits.h0000664000000000000000000000236112272262501016157 0ustar /* * Copyright (c) International Business Machines Corp., 2002 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * This code contributed by Mike Mason (mmlnx@us.ibm.com) */ typedef struct { unsigned int shmmax; /* maximum shared segment size (bytes) */ unsigned int shmmin; /* minimum shared segment size (bytes) */ unsigned int shmmni; /* maximum number of segments system wide */ unsigned int shmseg; /* maximum shared segments per process */ unsigned int shmall; /* maximum shared memory system wide (pages) */ } shm_limits_t; extern int refresh_shm_limits(shm_limits_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/linux_table.h0000664000000000000000000000355012272262501016316 0ustar /* * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _LINUX_TABLE_H #define _LINUX_TABLE_H /* * scans linux style /proc tables, e.g. : * * numa_hit 266809 * numa_miss 0 * numa_foreign 0 * interleave_hit 0 * local_node 265680 * other_node 1129 * * Value is a counter that wraps at maxval, * unless maxval is 0, in which case the * value is treated as instantaneous and no * wrap detection is attempted. * * Tables are typically declared as a static array, and * then allocated dynamically with linux_table_clone(). * e.g. : * * static struct linux_table numa_meminfo_table[] = { * { "numa_hit", 0xffffffffffffffff }, * { "numa_miss", 0xffffffffffffffff }, * { "numa_foreign", 0xffffffffffffffff }, * { "interleave_hit", 0xffffffffffffffff }, * { "local_node", 0xffffffffffffffff }, * { "other_node", 0xffffffffffffffff }, * { NULL }; * }; */ enum { LINUX_TABLE_INVALID, LINUX_TABLE_VALID }; struct linux_table { char *field; uint64_t maxval; uint64_t val; uint64_t this; uint64_t prev; int field_len; int valid; }; extern int linux_table_lookup(const char *field, struct linux_table *table, uint64_t *val); extern struct linux_table *linux_table_clone(struct linux_table *table); extern int linux_table_scan(FILE *fp, struct linux_table *table); #endif /* _LINUX_TABLE_H */ pcp-3.8.12ubuntu1/src/pmdas/linux/proc_net_tcp.c0000664000000000000000000000325612272262501016465 0ustar /* * Copyright (c) 1999,2004 Silicon Graphics, Inc. All Rights Reserved. * This code contributed by Michal Kara (lemming@arthur.plbohnice.cz) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "proc_net_tcp.h" #define MYBUFSZ (1<<14) /*16k*/ int refresh_proc_net_tcp(proc_net_tcp_t *proc_net_tcp) { FILE *fp; char buf[MYBUFSZ]; char *p = buf; char *q; unsigned int n; ssize_t got = 0; ptrdiff_t remnant = 0; memset(proc_net_tcp, 0, sizeof(*proc_net_tcp)); if ((fp = fopen("/proc/net/tcp", "r")) == NULL) { return -oserror(); } /* skip header */ if (fgets(buf, sizeof(buf), fp) == NULL) { /* oops, no header! */ fclose(fp); return -oserror(); } for (buf[0]='\0';;) { q = strchrnul(p, '\n'); if (*q == '\n') { if (1 == sscanf(p, " %*s %*s %*s %x", &n) && n < _PM_TCP_LAST) { proc_net_tcp->stat[n]++; } p = q + 1; continue; } remnant = (q - p); if (remnant > 0 && p != buf) memmove(buf, p, remnant); got = read(fileno(fp), buf + remnant, MYBUFSZ - remnant - 1); if (got <= 0) break; buf[remnant + got] = '\0'; p = buf; } fclose(fp); /* success */ return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/devmapper.h0000664000000000000000000000153312272262501015772 0ustar /* * Linux /dev/mapper metrics cluster * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ typedef struct { int id; /* internal instance id */ char *dev_name; char *lv_name; } lv_entry_t; typedef struct { int nlv; lv_entry_t *lv; pmdaIndom *lv_indom; } dev_mapper_t; extern int refresh_dev_mapper(dev_mapper_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/numa_meminfo.h0000664000000000000000000000176412272262501016467 0ustar /* * Linux NUMA meminfo metrics cluster from sysfs * * Copyright (c) 2012 Red Hat. * Copyright (c) 2009 Silicon Graphics Inc., All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * Information from /sys/devices/node/node[0-9]+/meminfo and numastat */ typedef struct { struct linux_table *meminfo; struct linux_table *memstat; } nodeinfo_t; typedef struct { nodeinfo_t *node_info; pmdaIndom *node_indom; } numa_meminfo_t; extern int refresh_numa_meminfo(numa_meminfo_t *, proc_cpuinfo_t *, proc_stat_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/interrupts.h0000664000000000000000000000136712272262501016233 0ustar /* * Copyright (c) 2011 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ extern unsigned int irq_err_count; extern void interrupts_init(pmdaMetric *, int); extern int refresh_interrupt_values(void); extern int interrupts_fetch(int, int, unsigned int, pmAtomValue *); pcp-3.8.12ubuntu1/src/pmdas/linux/proc_loadavg.c0000664000000000000000000000273712272262501016451 0ustar /* * Linux /proc/loadavg metrics cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "proc_loadavg.h" int refresh_proc_loadavg(proc_loadavg_t *proc_loadavg) { char fmt[64]; int fd; int n; static int started; static char buf[1024]; if (!started) { started = 1; memset(proc_loadavg, 0, sizeof(proc_loadavg_t)); } if ((fd = open("/proc/loadavg", O_RDONLY)) < 0) return -oserror(); n = read(fd, buf, sizeof(buf)); close(fd); if (n < 0) return -oserror(); buf[sizeof(buf)-1] = '\0'; /* * 0.00 0.00 0.05 1/67 17563 * Lastpid added by Mike Mason */ strcpy(fmt, "%f %f %f %u/%u %u"); sscanf((const char *)buf, fmt, &proc_loadavg->loadavg[0], &proc_loadavg->loadavg[1], &proc_loadavg->loadavg[2], &proc_loadavg->runnable, &proc_loadavg->nprocs, &proc_loadavg->lastpid); /* success */ return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_slabinfo.c0000664000000000000000000001451112272262501016622 0ustar /* * Linux Memory Slab Cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "proc_slabinfo.h" int refresh_proc_slabinfo(proc_slabinfo_t *slabinfo) { char buf[1024]; slab_cache_t sbuf; slab_cache_t *s; FILE *fp; int i, n; int instcount; char *w, *p; int old_cache; int err = 0; static int next_id = -1; static int major_version = -1; static int minor_version = 0; if (next_id < 0) { /* one trip initialization */ next_id = 0; slabinfo->ncaches = 0; slabinfo->caches = (slab_cache_t *)malloc(sizeof(slab_cache_t)); slabinfo->indom->it_numinst = 0; slabinfo->indom->it_set = (pmdaInstid *)malloc(sizeof(pmdaInstid)); } if ((fp = fopen("/proc/slabinfo", "r")) == (FILE *)NULL) return -oserror(); for (i=0; i < slabinfo->ncaches; i++) { slabinfo->caches[i].seen = 0; } /* skip header */ if (fgets(buf, sizeof(buf), fp) == NULL) { /* oops, no header! */ err = -oserror(); goto out; } if (major_version < 0) { major_version = minor_version = 0; if (strstr(buf, "slabinfo - version:")) { char *p; for (p=buf; *p; p++) { if (isdigit((int)*p)) { sscanf(p, "%d.%d", &major_version, &minor_version); break; } } } } while (fgets(buf, sizeof(buf), fp) != NULL) { /* try to convert whitespace in cache names to underscores, */ /* by looking for alphabetic chars which follow whitespace. */ if (buf[0] == '#') continue; for (w = NULL, p = buf; *p != '\0'; p++) { if (isspace((int)*p)) w = p; else if (isdigit((int)*p)) break; else if (isalpha((int)*p) && w) { for (; w && w != p; w++) *w = '_'; w = NULL; } } memset(&sbuf, 0, sizeof(slab_cache_t)); if (major_version == 1 && minor_version == 0) { /* * * (generally 2.2 kernels) */ n = sscanf(buf, "%s %lu %lu", sbuf.name, (unsigned long *)&sbuf.num_active_objs, (unsigned long *)&sbuf.total_objs); if (n != 3) { err = PM_ERR_APPVERSION; goto out; } } else if (major_version == 1 && minor_version == 1) { /* * * (generally 2.4 kernels) */ n = sscanf(buf, "%s %lu %lu %u %u %u %u", sbuf.name, (unsigned long *)&sbuf.num_active_objs, (unsigned long *)&sbuf.total_objs, &sbuf.object_size, &sbuf.num_active_slabs, &sbuf.total_slabs, &sbuf.pages_per_slab); if (n != 7) { err = PM_ERR_APPVERSION; goto out; } sbuf.total_size = sbuf.pages_per_slab * sbuf.num_active_slabs * _pm_system_pagesize; } else if (major_version == 2 && minor_version >= 0 && minor_version <= 1) { /* * .. and more * (generally for kernels up to at least 2.6.11) */ n = sscanf(buf, "%s %lu %lu %u %u %u", sbuf.name, (unsigned long *)&sbuf.num_active_objs, (unsigned long *)&sbuf.total_objs, &sbuf.object_size, &sbuf.objects_per_slab, &sbuf.pages_per_slab); if (n != 6) { err = PM_ERR_APPVERSION; goto out; } sbuf.total_size = sbuf.pages_per_slab * sbuf.num_active_objs * _pm_system_pagesize / sbuf.objects_per_slab; } else { /* no support */ err = PM_ERR_APPVERSION; goto out; } old_cache = -1; for (i=0; i < slabinfo->ncaches; i++) { if (strcmp(slabinfo->caches[i].name, sbuf.name) == 0) { if (slabinfo->caches[i].valid) break; else old_cache = i; } } if (i == slabinfo->ncaches) { /* new cache has appeared */ if (old_cache >= 0) { /* same cache as last time : reuse the id */ i = old_cache; } else { slabinfo->ncaches++; slabinfo->caches = (slab_cache_t *)realloc(slabinfo->caches, slabinfo->ncaches * sizeof(slab_cache_t)); slabinfo->caches[i].id = next_id++; } slabinfo->caches[i].valid = 1; #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { fprintf(stderr, "refresh_slabinfo: add \"%s\"\n", sbuf.name); } #endif } s = &slabinfo->caches[i]; strcpy(s->name, sbuf.name); s->num_active_objs = sbuf.num_active_objs; s->total_objs = sbuf.total_objs; s->object_size = sbuf.object_size; s->num_active_slabs = sbuf.num_active_slabs; s->total_slabs = sbuf.total_slabs; s->pages_per_slab = sbuf.pages_per_slab; s->objects_per_slab = sbuf.objects_per_slab; s->total_size = sbuf.total_size; s->seen = major_version * 10 + minor_version; } /* check for caches that have been deleted (eg. by rmmod) */ for (i=0, instcount=0; i < slabinfo->ncaches; i++) { if (slabinfo->caches[i].valid) { if (slabinfo->caches[i].seen == 0) { slabinfo->caches[i].valid = 0; #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { fprintf(stderr, "refresh_slabinfo: drop \"%s\"\n", slabinfo->caches[i].name); } #endif } else { instcount++; } } } /* refresh slabinfo indom */ if (slabinfo->indom->it_numinst != instcount) { slabinfo->indom->it_numinst = instcount; slabinfo->indom->it_set = (pmdaInstid *)realloc(slabinfo->indom->it_set, instcount * sizeof(pmdaInstid)); memset(slabinfo->indom->it_set, 0, instcount * sizeof(pmdaInstid)); } for (n=0, i=0; i < slabinfo->ncaches; i++) { if (slabinfo->caches[i].valid) { slabinfo->indom->it_set[n].i_inst = slabinfo->caches[i].id; slabinfo->indom->it_set[n].i_name = slabinfo->caches[i].name; #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { fprintf(stderr, "refresh_slabinfo: cache[%d] = \"%s\"\n", n, slabinfo->indom->it_set[n].i_name); } #endif n++; } } /* * success */ out: fclose(fp); return err; } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_partitions.c0000664000000000000000000004434612272262501017232 0ustar /* * Linux Partitions (disk and disk partition IO stats) Cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "convert.h" #include "clusters.h" #include "indom.h" #include "proc_partitions.h" extern int _pm_numdisks; /* * _pm_ispartition : return true if arg is a partition name * return false if arg is a disk name * ide disks are named e.g. hda * ide partitions are named e.g. hda1 * * scsi disks are named e.g. sda * scsi partitions are named e.g. sda1 * * devfs scsi disks are named e.g. scsi/host0/bus0/target1/lun0/disc * devfs scsi partitions are named e.g. scsi/host0/bus0/target1/lun0/part1 * * Mylex raid disks are named e.g. rd/c0d0 or dac960/c0d0 * Mylex raid partitions are named e.g. rd/c0d0p1 or dac960/c0d0p1 * * What this now tries to do is be a bit smarter, and guess that names * with slashes that end in the form .../c0t0d0[p0], and ones without * are good old 19th century device names like xx0 or xx0a. */ static int _pm_isloop(char *dname) { return strncmp(dname, "loop", 4) == 0; } static int _pm_isramdisk(char *dname) { return strncmp(dname, "ram", 3) == 0; } static int _pm_ismmcdisk(char *dname) { if (strncmp(dname, "mmcblk", 6) != 0) return 0; /* * Are we a disk or a partition of the disk? If there is a "p" * assume it is a partition - e.g. mmcblk0p6. */ return (strchr(dname + 6, 'p') == NULL); } /* * slight improvement to heuristic suggested by * Tim Bradshaw on 29 Dec 2003 */ int _pm_ispartition(char *dname) { int p, m = strlen(dname) - 1; /* * looking at something like foo/x, and we hope x ends p, for * a partition, or not for a disk. */ if (strchr(dname, '/')) { for (p = m; p > 0 && isdigit((int)dname[p]); p--) ; if (p == m) /* name had no trailing digits. Wildly guess a disk. */ return 1; else /* * ends with digits, if preceding character is a 'p' punt * on a partition */ return (dname[p] == 'p'? 1 : 0); } else { /* * default test : partition names end in a digit do not * look like loopback devices. Handle other special-cases * here - mostly seems to be RAM-type disk drivers that're * choosing to end device names with numbers. */ return isdigit((int)dname[m]) && !_pm_isloop(dname) && !_pm_isramdisk(dname) && !_pm_ismmcdisk(dname); } } /* * return true is arg is an xvm volume name */ static int _pm_isxvmvol(char *dname) { return strstr(dname, "xvm") != NULL; } /* * return true is arg is a disk name */ static int _pm_isdisk(char *dname) { return !_pm_isloop(dname) && !_pm_isramdisk(dname) && !_pm_ispartition(dname) && !_pm_isxvmvol(dname); } static void refresh_udev(pmInDom disk_indom, pmInDom partitions_indom) { char buf[MAXNAMELEN]; char realname[MAXNAMELEN]; char *shortname; char *p; char *udevname; FILE *pfp; partitions_entry_t *entry; int indom; int inst; if (access("/dev/xscsi", R_OK) != 0) return; if (!(pfp = popen("find /dev/xscsi -name disc -o -name part[0-9]*", "r"))) return; while (fgets(buf, sizeof(buf), pfp)) { if ((p = strrchr(buf, '\n')) != NULL) *p = '\0'; if (realpath(buf, realname)) { udevname = buf + 5; /* /dev/xscsi/.... */ if ((shortname = strrchr(realname, '/')) != NULL) { shortname++; indom = _pm_ispartition(shortname) ? partitions_indom : disk_indom; if (pmdaCacheLookupName(indom, shortname, &inst, (void **)&entry) != PMDA_CACHE_ACTIVE) continue; entry->udevnamebuf = strdup(udevname); pmdaCacheStore(indom, PMDA_CACHE_HIDE, shortname, entry); /* inactive */ pmdaCacheStore(indom, PMDA_CACHE_ADD, udevname, entry); /* active */ } } } pclose(pfp); } int refresh_proc_partitions(pmInDom disk_indom, pmInDom partitions_indom) { char buf[1024]; char namebuf[1024]; FILE *fp; int devmin; int devmaj; int n; int indom; int have_proc_diskstats; int inst; unsigned long long blocks; partitions_entry_t *p; int indom_changes = 0; static int first = 1; if (first) { /* initialize the instance domain caches */ pmdaCacheOp(disk_indom, PMDA_CACHE_LOAD); pmdaCacheOp(partitions_indom, PMDA_CACHE_LOAD); first = 0; indom_changes = 1; } pmdaCacheOp(disk_indom, PMDA_CACHE_INACTIVE); pmdaCacheOp(partitions_indom, PMDA_CACHE_INACTIVE); if ((fp = fopen("/proc/diskstats", "r")) != (FILE *)NULL) /* 2.6 style disk stats */ have_proc_diskstats = 1; else { if ((fp = fopen("/proc/partitions", "r")) != (FILE *)NULL) have_proc_diskstats = 0; else return -oserror(); } while (fgets(buf, sizeof(buf), fp) != NULL) { if (buf[0] != ' ' || buf[0] == '\n') { /* skip heading */ continue; } if (have_proc_diskstats) { if ((n = sscanf(buf, "%d %d %s", &devmaj, &devmin, namebuf)) != 3) continue; } else { /* /proc/partitions */ if ((n = sscanf(buf, "%d %d %llu %s", &devmaj, &devmin, &blocks, namebuf)) != 4) continue; } if (_pm_ispartition(namebuf)) indom = partitions_indom; else if (_pm_isdisk(namebuf)) indom = disk_indom; else continue; p = NULL; if (pmdaCacheLookupName(indom, namebuf, &inst, (void **)&p) < 0 || !p) { /* not found: allocate and add a new entry */ p = (partitions_entry_t *)malloc(sizeof(partitions_entry_t)); memset(p, 0, sizeof(partitions_entry_t)); indom_changes++; } /* activate this entry */ if (p->udevnamebuf) /* long xscsi name */ inst = pmdaCacheStore(indom, PMDA_CACHE_ADD, p->udevnamebuf, p); else /* short /proc/diskstats or /proc/partitions name */ inst = pmdaCacheStore(indom, PMDA_CACHE_ADD, namebuf, p); if (have_proc_diskstats) { /* 2.6 style /proc/diskstats */ p->nr_blocks = 0; namebuf[0] = '\0'; /* Linux source: block/genhd.c::diskstats_show(1) */ n = sscanf(buf, "%u %u %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u", &p->major, &p->minor, namebuf, &p->rd_ios, &p->rd_merges, &p->rd_sectors, &p->rd_ticks, &p->wr_ios, &p->wr_merges, &p->wr_sectors, &p->wr_ticks, &p->ios_in_flight, &p->io_ticks, &p->aveq); if (n != 14) { p->rd_merges = p->wr_merges = p->wr_ticks = p->ios_in_flight = p->io_ticks = p->aveq = 0; /* Linux source: block/genhd.c::diskstats_show(2) */ n = sscanf(buf, "%u %u %s %u %u %u %u\n", &p->major, &p->minor, namebuf, (unsigned int *)&p->rd_ios, (unsigned int *)&p->rd_sectors, (unsigned int *)&p->wr_ios, (unsigned int *)&p->wr_sectors); } } else { /* 2.4 style /proc/partitions */ namebuf[0] = '\0'; n = sscanf(buf, "%u %u %lu %s %lu %lu %llu %u %lu %lu %llu %u %u %u %u", &p->major, &p->minor, &p->nr_blocks, namebuf, &p->rd_ios, &p->rd_merges, &p->rd_sectors, &p->rd_ticks, &p->wr_ios, &p->wr_merges, &p->wr_sectors, &p->wr_ticks, &p->ios_in_flight, &p->io_ticks, &p->aveq); } if (!p->namebuf) p->namebuf = strdup(namebuf); else if (strcmp(namebuf, p->namebuf) != 0) { free(p->namebuf); p->namebuf = strdup(namebuf); } } /* * If any new disks or partitions have appeared then we * we need to remap the long device names (if /dev/xscsi * exists) and then flush the pmda cache. * * We just let inactive instances rot in the inactive state * (this doesn't happen very often, so is only a minor leak). */ if (indom_changes) { refresh_udev(disk_indom, partitions_indom); pmdaCacheOp(disk_indom, PMDA_CACHE_SAVE); pmdaCacheOp(partitions_indom, PMDA_CACHE_SAVE); } /* * success */ if (fp) fclose(fp); return 0; } /* * This table must always match the definitions in root_linux * and metrictab[] in pmda.c */ static pmID disk_metric_table[] = { /* disk.dev.read */ PMDA_PMID(CLUSTER_STAT,4), /* disk.dev.write */ PMDA_PMID(CLUSTER_STAT,5), /* disk.dev.total */ PMDA_PMID(CLUSTER_STAT,28), /* disk.dev.blkread */ PMDA_PMID(CLUSTER_STAT,6), /* disk.dev.blkwrite */ PMDA_PMID(CLUSTER_STAT,7), /* disk.dev.blktotal */ PMDA_PMID(CLUSTER_STAT,36), /* disk.dev.read_bytes */ PMDA_PMID(CLUSTER_STAT,38), /* disk.dev.write_bytes */ PMDA_PMID(CLUSTER_STAT,39), /* disk.dev.total_bytes */ PMDA_PMID(CLUSTER_STAT,40), /* disk.dev.read_merge */ PMDA_PMID(CLUSTER_STAT,49), /* disk.dev.write_merge */ PMDA_PMID(CLUSTER_STAT,50), /* disk.dev.avactive */ PMDA_PMID(CLUSTER_STAT,46), /* disk.dev.aveq */ PMDA_PMID(CLUSTER_STAT,47), /* disk.dev.scheduler */ PMDA_PMID(CLUSTER_STAT,59), /* disk.dev.read_rawactive */ PMDA_PMID(CLUSTER_STAT,72), /* disk.dev.write_rawactive */ PMDA_PMID(CLUSTER_STAT,73), /* disk.all.read */ PMDA_PMID(CLUSTER_STAT,24), /* disk.all.write */ PMDA_PMID(CLUSTER_STAT,25), /* disk.all.total */ PMDA_PMID(CLUSTER_STAT,29), /* disk.all.blkread */ PMDA_PMID(CLUSTER_STAT,26), /* disk.all.blkwrite */ PMDA_PMID(CLUSTER_STAT,27), /* disk.all.blktotal */ PMDA_PMID(CLUSTER_STAT,37), /* disk.all.read_bytes */ PMDA_PMID(CLUSTER_STAT,41), /* disk.all.write_bytes */ PMDA_PMID(CLUSTER_STAT,42), /* disk.all.total_bytes */ PMDA_PMID(CLUSTER_STAT,43), /* disk.all.read_merge */ PMDA_PMID(CLUSTER_STAT,51), /* disk.all.write_merge */ PMDA_PMID(CLUSTER_STAT,52), /* disk.all.avactive */ PMDA_PMID(CLUSTER_STAT,44), /* disk.all.aveq */ PMDA_PMID(CLUSTER_STAT,45), /* disk.all.read_rawactive */ PMDA_PMID(CLUSTER_STAT,74), /* disk.all.write_rawactive */ PMDA_PMID(CLUSTER_STAT,75), /* disk.partitions.read */ PMDA_PMID(CLUSTER_PARTITIONS,0), /* disk.partitions.write */ PMDA_PMID(CLUSTER_PARTITIONS,1), /* disk.partitions.total */ PMDA_PMID(CLUSTER_PARTITIONS,2), /* disk.partitions.blkread */ PMDA_PMID(CLUSTER_PARTITIONS,3), /* disk.partitions.blkwrite */ PMDA_PMID(CLUSTER_PARTITIONS,4), /* disk.partitions.blktotal */ PMDA_PMID(CLUSTER_PARTITIONS,5), /* disk.partitions.read_bytes */ PMDA_PMID(CLUSTER_PARTITIONS,6), /* disk.partitions.write_bytes */PMDA_PMID(CLUSTER_PARTITIONS,7), /* disk.partitions.total_bytes */PMDA_PMID(CLUSTER_PARTITIONS,8), /* hinv.ndisk */ PMDA_PMID(CLUSTER_STAT,33), }; int is_partitions_metric(pmID full_pmid) { int i; static pmID *p = NULL; __pmID_int *idp = (__pmID_int *)&(full_pmid); pmID pmid = PMDA_PMID(idp->cluster, idp->item); int n = sizeof(disk_metric_table) / sizeof(disk_metric_table[0]); if (p && *p == PMDA_PMID(idp->cluster, idp->item)) return 1; for (p = disk_metric_table, i=0; i < n; i++, p++) { if (*p == pmid) return 1; } return 0; } char * _pm_ioscheduler(const char *device) { FILE *fp; char *p, *q; static char buf[1024]; char path[MAXNAMELEN]; /* * Extract scheduler from /sys/block//queue/scheduler. * File format: "noop anticipatory [deadline] cfq" * In older kernels (incl. RHEL5 and SLES10) this doesn't exist, * but we can still look in /sys/block//queue/iosched to * intuit the ones we know about (cfq, deadline, as, noop) based * on the different status files they create. */ sprintf(path, "/sys/block/%s/queue/scheduler", device); if ((fp = fopen(path, "r")) != NULL) { p = fgets(buf, sizeof(buf), fp); fclose(fp); if (!p) goto unknown; for (p = q = buf; p && *p && *p != ']'; p++) { if (*p == '[') q = p+1; } if (q == buf) goto unknown; if (*p != ']') goto unknown; *p = '\0'; return q; } else { /* sniff around, maybe we'll get lucky and find something */ sprintf(path, "/sys/block/%s/queue/iosched/quantum", device); if (access(path, F_OK) == 0) return "cfq"; sprintf(path, "/sys/block/%s/queue/iosched/fifo_batch", device); if (access(path, F_OK) == 0) return "deadline"; sprintf(path, "/sys/block/%s/queue/iosched/antic_expire", device); if (access(path, F_OK) == 0) return "anticipatory"; /* punt. noop has no files to match on ... */ sprintf(path, "/sys/block/%s/queue/iosched", device); if (access(path, F_OK) == 0) return "noop"; /* else fall though ... */ } unknown: return "unknown"; } int proc_partitions_fetch(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); int i; partitions_entry_t *p = NULL; if (inst != PM_IN_NULL) { if (pmdaCacheLookup(mdesc->m_desc.indom, inst, NULL, (void **)&p) < 0) return PM_ERR_INST; } switch (idp->cluster) { case CLUSTER_STAT: /* * disk.{dev,all} remain in CLUSTER_STAT for backward compatibility */ switch(idp->item) { case 4: /* disk.dev.read */ if (p == NULL) return PM_ERR_INST; _pm_assign_ulong(atom, p->rd_ios); break; case 5: /* disk.dev.write */ if (p == NULL) return PM_ERR_INST; _pm_assign_ulong(atom, p->wr_ios); break; case 6: /* disk.dev.blkread */ if (p == NULL) return PM_ERR_INST; atom->ull = p->rd_sectors; break; case 7: /* disk.dev.blkwrite */ if (p == NULL) return PM_ERR_INST; atom->ull = p->wr_sectors; break; case 28: /* disk.dev.total */ if (p == NULL) return PM_ERR_INST; atom->ull = p->rd_ios + p->wr_ios; break; case 36: /* disk.dev.blktotal */ if (p == NULL) return PM_ERR_INST; atom->ull = p->rd_sectors + p->wr_sectors; break; case 38: /* disk.dev.read_bytes */ if (p == NULL) return PM_ERR_INST; atom->ull = p->rd_sectors / 2; break; case 39: /* disk.dev.write_bytes */ if (p == NULL) return PM_ERR_INST; atom->ull = p->wr_sectors / 2; break; case 40: /* disk.dev.total_bytes */ if (p == NULL) return PM_ERR_INST; atom->ull = (p->rd_sectors + p->wr_sectors) / 2; break; case 46: /* disk.dev.avactive ... already msec from /proc/diskstats */ if (p == NULL) return PM_ERR_INST; atom->ul = p->io_ticks; break; case 47: /* disk.dev.aveq ... already msec from /proc/diskstats */ if (p == NULL) return PM_ERR_INST; atom->ul = p->aveq; break; case 49: /* disk.dev.read_merge */ if (p == NULL) return PM_ERR_INST; _pm_assign_ulong(atom, p->rd_merges); break; case 50: /* disk.dev.write_merge */ if (p == NULL) return PM_ERR_INST; _pm_assign_ulong(atom, p->wr_merges); break; case 59: /* disk.dev.scheduler */ if (p == NULL) return PM_ERR_INST; atom->cp = _pm_ioscheduler(p->namebuf); break; case 72: /* disk.dev.read_rawactive already ms from /proc/diskstats */ if (p == NULL) return PM_ERR_INST; atom->ul = p->rd_ticks; break; case 73: /* disk.dev.write_rawactive already ms from /proc/diskstats */ if (p == NULL) return PM_ERR_INST; atom->ul = p->wr_ticks; break; default: /* disk.all.* is a singular instance domain */ atom->ull = 0; for (pmdaCacheOp(INDOM(DISK_INDOM), PMDA_CACHE_WALK_REWIND);;) { if ((i = pmdaCacheOp(INDOM(DISK_INDOM), PMDA_CACHE_WALK_NEXT)) < 0) break; if (!pmdaCacheLookup(INDOM(DISK_INDOM), i, NULL, (void **)&p) || !p) continue; switch (idp->item) { case 24: /* disk.all.read */ atom->ull += p->rd_ios; break; case 25: /* disk.all.write */ atom->ull += p->wr_ios; break; case 26: /* disk.all.blkread */ atom->ull += p->rd_sectors; break; case 27: /* disk.all.blkwrite */ atom->ull += p->wr_sectors; break; case 29: /* disk.all.total */ atom->ull += p->rd_ios + p->wr_ios; break; case 37: /* disk.all.blktotal */ atom->ull += p->rd_sectors + p->wr_sectors; break; case 41: /* disk.all.read_bytes */ atom->ull += p->rd_sectors / 2; break; case 42: /* disk.all.write_bytes */ atom->ull += p->wr_sectors / 2; break; case 43: /* disk.all.total_bytes */ atom->ull += (p->rd_sectors + p->wr_sectors) / 2; break; case 44: /* disk.all.avactive ... already msec from /proc/diskstats */ atom->ull += p->io_ticks; break; case 45: /* disk.all.aveq ... already msec from /proc/diskstats */ atom->ull += p->aveq; break; case 51: /* disk.all.read_merge */ atom->ull += p->rd_merges; break; case 52: /* disk.all.write_merge */ atom->ull += p->wr_merges; break; case 74: /* disk.all.read_rawactive ... already msec from /proc/diskstats */ atom->ull += p->rd_ticks; break; case 75: /* disk.all.write_rawactive ... already msec from /proc/diskstats */ atom->ull += p->wr_ticks; break; default: return PM_ERR_PMID; } } /* loop */ } break; case CLUSTER_PARTITIONS: if (p == NULL) return PM_ERR_INST; switch(idp->item) { /* disk.partitions */ case 0: /* disk.partitions.read */ atom->ul = p->rd_ios; break; case 1: /* disk.partitions.write */ atom->ul = p->wr_ios; break; case 2: /* disk.partitions.total */ atom->ul = p->wr_ios + p->rd_ios; break; case 3: /* disk.partitions.blkread */ atom->ul = p->rd_sectors; break; case 4: /* disk.partitions.blkwrite */ atom->ul = p->wr_sectors; break; case 5: /* disk.partitions.blktotal */ atom->ul = p->rd_sectors + p->wr_sectors; break; case 6: /* disk.partitions.read_bytes */ atom->ul = p->rd_sectors / 2; break; case 7: /* disk.partitions.write_bytes */ atom->ul = p->wr_sectors / 2; break; case 8: /* disk.partitions.total_bytes */ atom->ul = (p->rd_sectors + p->wr_sectors) / 2; break; default: return PM_ERR_PMID; } break; default: /* switch cluster */ return PM_ERR_PMID; } return 1; } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_cpuinfo.h0000664000000000000000000000304712272262501016477 0ustar /* * Linux /proc/cpuinfo metrics cluster * * Copyright (c) 2013 Red Hat. * Copyright (c) 2001 Gilly Ran (gilly@exanet.com) for the * portions of the code supporting the Alpha platform. * All rights reserved. * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifdef __alpha__ #define HAVE_ALPHA_LINUX #endif typedef struct { int cpu_num; int node; char *name; float clock; float bogomips; int sapic; /* strings dictionary hash key */ int vendor; /* strings dictionary hash key */ int model; /* strings dictionary hash key */ int model_name; /* strings dictionary hash key */ int stepping; /* strings dictionary hash key */ int flags; /* strings dictionary hash key */ unsigned int cache; unsigned int cache_align; } cpuinfo_t; typedef struct { char *machine; cpuinfo_t *cpuinfo; pmdaIndom *cpuindom; pmdaIndom *node_indom; } proc_cpuinfo_t; extern int refresh_proc_cpuinfo(proc_cpuinfo_t *); extern char *cpu_name(proc_cpuinfo_t *, int); pcp-3.8.12ubuntu1/src/pmdas/linux/proc_loadavg.h0000664000000000000000000000204312272262501016444 0ustar /* * Linux /proc/stat metrics cluster * * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ typedef struct { float loadavg[3]; /* 1, 5 and 15 min load average */ unsigned int runnable; unsigned int nprocs; unsigned int lastpid; } proc_loadavg_t; extern int refresh_proc_loadavg(proc_loadavg_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/proc_net_dev.h0000664000000000000000000000542412272262501016461 0ustar /* * Linux /proc/net/dev metrics cluster * * Copyright (c) 2013 Red Hat. * Copyright (c) 1995,2005 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ typedef struct { uint32_t mtu; uint32_t speed; uint8_t duplex; uint8_t linkup; uint8_t running; uint8_t pad; } net_dev_t; #define HWADDRSTRLEN 64 typedef struct { int has_inet : 1; int has_ipv6 : 1; int has_hw : 1; int padding : 13; uint16_t ipv6scope; char inet[INET_ADDRSTRLEN]; char ipv6[INET6_ADDRSTRLEN+16]; /* extra for /plen */ char hw_addr[HWADDRSTRLEN]; } net_addr_t; #define PROC_DEV_COUNTERS_PER_LINE 16 typedef struct { uint64_t last_gen; uint64_t last_counters[PROC_DEV_COUNTERS_PER_LINE]; uint64_t counters[PROC_DEV_COUNTERS_PER_LINE]; net_dev_t ioc; } net_interface_t; #ifndef ETHTOOL_GSET #define ETHTOOL_GSET 0x1 #endif #ifndef SIOCGIFCONF #define SIOCGIFCONF 0x8912 #endif #ifndef SIOCGIFFLAGS #define SIOCGIFFLAGS 0x8913 #endif #ifndef SIOCGIFADDR #define SIOCGIFADDR 0x8915 #endif #ifndef SIOCGIFMTU #define SIOCGIFMTU 0x8921 #endif #ifndef SIOCETHTOOL #define SIOCETHTOOL 0x8946 #endif /* ioctl(SIOCIFETHTOOL) GSET ("get settings") structure */ struct ethtool_cmd { uint32_t cmd; uint32_t supported; /* Features this interface supports */ uint32_t advertising; /* Features this interface advertises */ uint16_t speed; /* The forced speed, 10Mb, 100Mb, gigabit */ uint8_t duplex; /* Duplex, half or full */ uint8_t port; /* Which connector port */ uint8_t phy_address; uint8_t transceiver; /* Which tranceiver to use */ uint8_t autoneg; /* Enable or disable autonegotiation */ uint32_t maxtxpkt; /* Tx pkts before generating tx int */ uint32_t maxrxpkt; /* Rx pkts before generating rx int */ uint32_t reserved[4]; }; #define IPV6_ADDR_ANY 0x0000U #define IPV6_ADDR_UNICAST 0x0001U #define IPV6_ADDR_MULTICAST 0x0002U #define IPV6_ADDR_ANYCAST 0x0004U #define IPV6_ADDR_LOOPBACK 0x0010U #define IPV6_ADDR_LINKLOCAL 0x0020U #define IPV6_ADDR_SITELOCAL 0x0040U #define IPV6_ADDR_COMPATv4 0x0080U extern int refresh_proc_net_dev(pmInDom); extern int refresh_net_dev_addr(pmInDom); extern char *lookup_ipv6_scope(int); pcp-3.8.12ubuntu1/src/pmdas/linux/proc_uptime.c0000664000000000000000000000235312272262501016331 0ustar /* * Copyright (c) International Business Machines Corp., 2002 * This code contributed by Mike Mason * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "proc_uptime.h" int refresh_proc_uptime(proc_uptime_t *proc_uptime) { char buf[80]; int fd, n; float uptime = 0.0, idletime = 0.0; memset(proc_uptime, 0, sizeof(proc_uptime_t)); if ((fd = open("/proc/uptime", O_RDONLY)) < 0) return -oserror(); n = read(fd, buf, sizeof(buf)); close(fd); if (n < 0) return -oserror(); else if (n > 0) n--; buf[n] = '\0'; sscanf((const char *)buf, "%f %f", &uptime, &idletime); proc_uptime->uptime = (unsigned long) uptime; proc_uptime->idletime = (unsigned long) idletime; return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_cpuinfo.c0000664000000000000000000001527512272262501016500 0ustar /* * Linux /proc/cpuinfo metrics cluster * * Copyright (c) 2013 Red Hat. * Copyright (c) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. * Portions Copyright (c) 2001 Gilly Ran (gilly@exanet.com) - for the * portions supporting the Alpha platform. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "indom.h" #include "proc_cpuinfo.h" static void decode_map(proc_cpuinfo_t *proc_cpuinfo, char *cp, int node, int offset) { uint32_t map = strtoul(cp, NULL, 16); while (map) { int i; if ((i = ffsl(map))) { /* the kernel returns 32bit words in the map file */ int cpu = i - 1 + 32*offset; proc_cpuinfo->cpuinfo[cpu].node = node; if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "cpu %d -> node %d\n", cpu, node); } map &= ~(1 << (i-1)); } } } static void map_cpu_nodes(proc_cpuinfo_t *proc_cpuinfo) { int i, j; char *node_path = "/sys/devices/system/node"; char path[1024]; char cpumap[4096]; DIR *nodes; FILE *f; struct dirent *de; int node, max_node = -1; char *cp; pmdaIndom *idp = PMDAINDOM(NODE_INDOM); for (i = 0; i < proc_cpuinfo->cpuindom->it_numinst; i++) proc_cpuinfo->cpuinfo[i].node = -1; if ((nodes = opendir(node_path)) == NULL) return; while ((de = readdir(nodes)) != NULL) { if (sscanf(de->d_name, "node%d", &node) != 1) continue; if (node > max_node) max_node = node; sprintf(path, "%s/%s/cpumap", node_path, de->d_name); if ((f = fopen(path, "r")) == NULL) continue; i = fscanf(f, "%s", cpumap); fclose(f); if (i != 1) continue; for (j = 0; (cp = strrchr(cpumap, ',')); j++) { decode_map(proc_cpuinfo, cp+1, node, j); *cp = '\0'; } decode_map(proc_cpuinfo, cpumap, node, j); } closedir(nodes); /* initialize node indom */ idp->it_numinst = max_node + 1; idp->it_set = calloc(max_node + 1, sizeof(pmdaInstid)); for (i = 0; i <= max_node; i++) { char node_name[256]; sprintf(node_name, "node%d", i); idp->it_set[i].i_inst = i; idp->it_set[i].i_name = strdup(node_name); } proc_cpuinfo->node_indom = idp; } char * cpu_name(proc_cpuinfo_t *proc_cpuinfo, int c) { char name[1024]; char *p; FILE *f; static int started = 0; if (!started) { refresh_proc_cpuinfo(proc_cpuinfo); proc_cpuinfo->machine = NULL; if ((f = fopen("/proc/sgi_prominfo/node0/version", "r")) != NULL) { while (fgets(name, sizeof(name), f)) { if (strncmp(name, "SGI", 3) == 0) { if ((p = strstr(name, " IP")) != NULL) proc_cpuinfo->machine = strndup(p+1, 4); break; } } fclose(f); } if (proc_cpuinfo->machine == NULL) proc_cpuinfo->machine = strdup("linux"); started = 1; } snprintf(name, sizeof(name), "cpu%d", c); return strdup(name); } int refresh_proc_cpuinfo(proc_cpuinfo_t *proc_cpuinfo) { char buf[4096]; FILE *fp; int cpunum; cpuinfo_t *info; char *val; char *p; static int started = 0; if (!started) { int need = proc_cpuinfo->cpuindom->it_numinst * sizeof(cpuinfo_t); proc_cpuinfo->cpuinfo = (cpuinfo_t *)calloc(1, need); for (cpunum=0; cpunum < proc_cpuinfo->cpuindom->it_numinst; cpunum++) { proc_cpuinfo->cpuinfo[cpunum].sapic = -1; proc_cpuinfo->cpuinfo[cpunum].vendor = -1; proc_cpuinfo->cpuinfo[cpunum].model = -1; proc_cpuinfo->cpuinfo[cpunum].model_name = -1; proc_cpuinfo->cpuinfo[cpunum].stepping = -1; proc_cpuinfo->cpuinfo[cpunum].flags = -1; } started = 1; } if ((fp = fopen("/proc/cpuinfo", "r")) == (FILE *)NULL) return -oserror(); #if defined(HAVE_ALPHA_LINUX) cpunum = 0; #else //intel cpunum = -1; #endif while (fgets(buf, sizeof(buf), fp) != NULL) { if ((val = strrchr(buf, '\n')) != NULL) *val = '\0'; if ((val = strchr(buf, ':')) == NULL) continue; val += 2; #if !defined(HAVE_ALPHA_LINUX) if (strncmp(buf, "processor", 9) == 0) { cpunum++; proc_cpuinfo->cpuinfo[cpunum].cpu_num = atoi(val); continue; } #endif info = &proc_cpuinfo->cpuinfo[cpunum]; /* note: order is important due to strNcmp comparisons */ if (info->sapic < 0 && strncasecmp(buf, "sapic", 5) == 0) info->sapic = linux_strings_insert(val); else if (info->model_name < 0 && strncasecmp(buf, "model name", 10) == 0) info->model_name = linux_strings_insert(val); else if (info->model < 0 && strncasecmp(buf, "model", 5) == 0) info->model = linux_strings_insert(val); else if (info->model < 0 && strncasecmp(buf, "cpu model", 9) == 0) info->model = linux_strings_insert(val); else if (info->vendor < 0 && strncasecmp(buf, "vendor", 6) == 0) info->vendor = linux_strings_insert(val); else if (info->stepping < 0 && strncasecmp(buf, "step", 4) == 0) info->stepping = linux_strings_insert(val); else if (info->stepping < 0 && strncasecmp(buf, "revision", 8) == 0) info->stepping = linux_strings_insert(val); else if (info->stepping < 0 && strncasecmp(buf, "cpu revision", 12) == 0) info->stepping = linux_strings_insert(val); else if (info->flags < 0 && strncasecmp(buf, "flags", 5) == 0) info->flags = linux_strings_insert(val); else if (info->flags < 0 && strncasecmp(buf, "features", 8) == 0) info->flags = linux_strings_insert(val); else if (info->cache == 0 && strncasecmp(buf, "cache size", 10) == 0) info->cache = atoi(val); else if (info->cache_align == 0 && strncasecmp(buf, "cache_align", 11) == 0) info->cache_align = atoi(val); else if (info->bogomips == 0.0 && strncasecmp(buf, "bogo", 4) == 0) info->bogomips = atof(val); else if (info->clock == 0.0 && strncasecmp(buf, "cpu MHz", 7) == 0) info->clock = atof(val); else if (info->clock == 0.0 && strncasecmp(buf, "cycle frequency", 15) == 0) { if ((p = strchr(val, ' ')) != NULL) *p = '\0'; info->clock = (atof(val))/1000000; } } fclose(fp); #if defined(HAVE_ALPHA_LINUX) /* all processors are identical, therefore duplicate it to all the instances */ for (cpunum=1; cpunum < proc_cpuinfo->cpuindom->it_numinst; cpunum++) memcpy(&proc_cpuinfo->cpuinfo[cpunum], info, sizeof(cpuinfo_t)); #endif map_cpu_nodes(proc_cpuinfo); /* success */ return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_slabinfo.h0000664000000000000000000000322112272262501016623 0ustar /* * Linux /proc/slabinfo metrics cluster * * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /*** version 1.1 "cache-name" num-active-objs total-objs object-size num-active-slabs \ total-slabs num-pages-per-slab + further values (not exported) on SMP and with statistics enabled *** version 1.0 "cache-name" num-active-objs total-objs ***/ typedef struct { int id; int seen; /* have seen this time, and num values seen */ int valid; char name[64]; __uint64_t num_active_objs; __uint64_t total_objs; __uint32_t object_size; __uint64_t total_size; __uint32_t num_active_slabs; __uint32_t objects_per_slab; __uint32_t total_slabs; __uint32_t pages_per_slab; } slab_cache_t; typedef struct { int ncaches; slab_cache_t *caches; pmdaIndom *indom; } proc_slabinfo_t; extern size_t _pm_system_pagesize; extern int refresh_proc_slabinfo(proc_slabinfo_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/proc_stat.c0000664000000000000000000002077712272262501016013 0ustar /* * Linux /proc/stat metrics cluster * * Copyright (c) 2012 Red Hat. * Copyright (c) 2008-2009 Aconex. All Rights Reserved. * Copyright (c) 2000,2004-2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "indom.h" #include #include #include #include #include "proc_cpuinfo.h" #include "proc_stat.h" int refresh_proc_stat(proc_cpuinfo_t *proc_cpuinfo, proc_stat_t *proc_stat) { pmdaIndom *idp = PMDAINDOM(CPU_INDOM); char fmt[64]; static int fd = -1; /* kept open until exit() */ static int started; static char *statbuf; static int maxstatbuf; static char **bufindex; static int nbufindex; static int maxbufindex; int n; int i; int j; if (fd >= 0) lseek(fd, 0, SEEK_SET); else if ((fd = open("/proc/stat", O_RDONLY)) < 0) return -oserror(); for (n=0;;) { if (n >= maxstatbuf) { maxstatbuf += 512; statbuf = (char *)realloc(statbuf, maxstatbuf * sizeof(char)); } if ((i = read(fd, statbuf+n, 512)) > 0) n += i; else break; } statbuf[n] = '\0'; if (bufindex == NULL) { maxbufindex = 4; bufindex = (char **)malloc(maxbufindex * sizeof(char *)); } nbufindex = 0; bufindex[nbufindex++] = statbuf; for (i=0; i < n; i++) { if (statbuf[i] == '\n') { statbuf[i] = '\0'; if (nbufindex >= maxbufindex) { maxbufindex += 4; bufindex = (char **)realloc(bufindex, maxbufindex * sizeof(char *)); } bufindex[nbufindex++] = statbuf + i + 1; } } if (!started) { started = 1; memset(proc_stat, 0, sizeof(*proc_stat)); /* hz of running kernel */ proc_stat->hz = sysconf(_SC_CLK_TCK); /* scan ncpus */ for (i=0; i < nbufindex; i++) { if (strncmp("cpu", bufindex[i], 3) == 0 && isdigit((int)bufindex[i][3])) proc_stat->ncpu++; } if (proc_stat->ncpu == 0) proc_stat->ncpu = 1; /* non-SMP kernel? */ proc_stat->cpu_indom = idp; proc_stat->cpu_indom->it_numinst = proc_stat->ncpu; proc_stat->cpu_indom->it_set = (pmdaInstid *)malloc( proc_stat->ncpu * sizeof(pmdaInstid)); /* * Map out the CPU instance domain. * * The first call to cpu_name() does initialization on the * proc_cpuinfo structure. */ for (i=0; i < proc_stat->ncpu; i++) { proc_stat->cpu_indom->it_set[i].i_inst = i; proc_stat->cpu_indom->it_set[i].i_name = cpu_name(proc_cpuinfo, i); } n = proc_stat->ncpu * sizeof(unsigned long long); proc_stat->p_user = (unsigned long long *)calloc(1, n); proc_stat->p_nice = (unsigned long long *)calloc(1, n); proc_stat->p_sys = (unsigned long long *)calloc(1, n); proc_stat->p_idle = (unsigned long long *)calloc(1, n); proc_stat->p_wait = (unsigned long long *)calloc(1, n); proc_stat->p_irq = (unsigned long long *)calloc(1, n); proc_stat->p_sirq = (unsigned long long *)calloc(1, n); proc_stat->p_steal = (unsigned long long *)calloc(1, n); proc_stat->p_guest = (unsigned long long *)calloc(1, n); n = proc_cpuinfo->node_indom->it_numinst * sizeof(unsigned long long); proc_stat->n_user = calloc(1, n); proc_stat->n_nice = calloc(1, n); proc_stat->n_sys = calloc(1, n); proc_stat->n_idle = calloc(1, n); proc_stat->n_wait = calloc(1, n); proc_stat->n_irq = calloc(1, n); proc_stat->n_sirq = calloc(1, n); proc_stat->n_steal = calloc(1, n); proc_stat->n_guest = calloc(1, n); } /* reset per-node stats */ n = proc_cpuinfo->node_indom->it_numinst * sizeof(unsigned long long); memset(proc_stat->n_user, 0, n); memset(proc_stat->n_nice, 0, n); memset(proc_stat->n_sys, 0, n); memset(proc_stat->n_idle, 0, n); memset(proc_stat->n_wait, 0, n); memset(proc_stat->n_irq, 0, n); memset(proc_stat->n_sirq, 0, n); memset(proc_stat->n_steal, 0, n); memset(proc_stat->n_guest, 0, n); /* * cpu 95379 4 20053 6502503 * 2.6 kernels have 3 additional fields * for wait, irq and soft_irq. */ strcpy(fmt, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu"); n = sscanf((const char *)bufindex[0], fmt, &proc_stat->user, &proc_stat->nice, &proc_stat->sys, &proc_stat->idle, &proc_stat->wait, &proc_stat->irq, &proc_stat->sirq, &proc_stat->steal, &proc_stat->guest); /* * per-cpu stats * e.g. cpu0 95379 4 20053 6502503 * 2.6 kernels have 3 additional fields for wait, irq and soft_irq. * More recent (2008) 2.6 kernels have an extra field for guest. */ if (proc_stat->ncpu == 1) { /* * Don't bother scanning - the counters are the same * as for "all" cpus, as already scanned above. * This also handles the non-SMP code where * there is no line starting with "cpu0". */ proc_stat->p_user[0] = proc_stat->user; proc_stat->p_nice[0] = proc_stat->nice; proc_stat->p_sys[0] = proc_stat->sys; proc_stat->p_idle[0] = proc_stat->idle; proc_stat->p_wait[0] = proc_stat->wait; proc_stat->p_irq[0] = proc_stat->irq; proc_stat->p_sirq[0] = proc_stat->sirq; proc_stat->p_steal[0] = proc_stat->steal; proc_stat->p_guest[0] = proc_stat->guest; } else { strcpy(fmt, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu"); for (i=0; i < proc_stat->ncpu; i++) { for (j=0; j < nbufindex; j++) { if (strncmp("cpu", bufindex[j], 3) == 0 && isdigit((int)bufindex[j][3])) { int c; int cpunum = atoi(&bufindex[j][3]); int node; if (cpunum >= 0 && cpunum < proc_stat->ncpu) { n = sscanf(bufindex[j], fmt, &c, &proc_stat->p_user[cpunum], &proc_stat->p_nice[cpunum], &proc_stat->p_sys[cpunum], &proc_stat->p_idle[cpunum], &proc_stat->p_wait[cpunum], &proc_stat->p_irq[cpunum], &proc_stat->p_sirq[cpunum], &proc_stat->p_steal[cpunum], &proc_stat->p_guest[cpunum]); if ((node = proc_cpuinfo->cpuinfo[cpunum].node) != -1) { proc_stat->n_user[node] += proc_stat->p_user[cpunum]; proc_stat->n_nice[node] += proc_stat->p_nice[cpunum]; proc_stat->n_sys[node] += proc_stat->p_sys[cpunum]; proc_stat->n_idle[node] += proc_stat->p_idle[cpunum]; proc_stat->n_wait[node] += proc_stat->p_wait[cpunum]; proc_stat->n_irq[node] += proc_stat->p_irq[cpunum]; proc_stat->n_sirq[node] += proc_stat->p_sirq[cpunum]; proc_stat->n_steal[node] += proc_stat->p_steal[cpunum]; proc_stat->n_guest[node] += proc_stat->p_guest[cpunum]; } } } } if (j == nbufindex) break; } } /* * page 59739 34786 * Note: this has moved to /proc/vmstat in 2.6 kernels */ strcpy(fmt, "page %u %u"); for (j=0; j < nbufindex; j++) { if (strncmp(fmt, bufindex[j], 5) == 0) { sscanf((const char *)bufindex[j], fmt, &proc_stat->page[0], &proc_stat->page[1]); break; } } /* * swap 0 1 * Note: this has moved to /proc/vmstat in 2.6 kernels */ strcpy(fmt, "swap %u %u"); for (j=0; j < nbufindex; j++) { if (strncmp(fmt, bufindex[j], 5) == 0) { sscanf((const char *)bufindex[j], fmt, &proc_stat->swap[0], &proc_stat->swap[1]); break; } } /* * intr 32845463 24099228 2049 0 2 .... * (just export the first number, which is total interrupts) */ strcpy(fmt, "intr %llu"); for (j=0; j < nbufindex; j++) { if (strncmp(fmt, bufindex[j], 5) == 0) { sscanf((const char *)bufindex[j], fmt, &proc_stat->intr); break; } } /* * ctxt 1733480 */ strcpy(fmt, "ctxt %llu"); for (j=0; j < nbufindex; j++) { if (strncmp(fmt, bufindex[j], 5) == 0) { sscanf((const char *)bufindex[j], fmt, &proc_stat->ctxt); break; } } /* * btime 1733480 */ strcpy(fmt, "btime %lu"); for (j=0; j < nbufindex; j++) { if (strncmp(fmt, bufindex[j], 6) == 0) { sscanf((const char *)bufindex[j], fmt, &proc_stat->btime); break; } } /* * processes 2213 */ strcpy(fmt, "processes %lu"); for (j=0; j < nbufindex; j++) { if (strncmp(fmt, bufindex[j], 10) == 0) { sscanf((const char *)bufindex[j], fmt, &proc_stat->processes); break; } } /* success */ return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/sem_limits.h0000664000000000000000000000335512272262501016160 0ustar /* * Copyright (c) International Business Machines Corp., 2002 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * This code contributed by Mike Mason (mmlnx@us.ibm.com) */ #ifdef _SEM_SEMUN_UNDEFINED /* glibc 2.1 no longer defines semun, instead it defines * _SEM_SEMUN_UNDEFINED so users can define semun on their own. */ union semun { int val; struct semid_ds *buf; unsigned short int *array; struct seminfo *__buf; }; #endif typedef struct { unsigned int semmap; /* # of entries in semaphore map */ unsigned int semmni; /* max # of semaphore identifiers */ unsigned int semmns; /* max # of semaphores in system */ unsigned int semmnu; /* num of undo structures system wide */ unsigned int semmsl; /* max num of semaphores per id */ unsigned int semopm; /* max num of ops per semop call */ unsigned int semume; /* max num of undo entries per process */ unsigned int semusz; /* sizeof struct sem_undo */ unsigned int semvmx; /* semaphore maximum value */ unsigned int semaem; /* adjust on exit max value */ } sem_limits_t; extern int refresh_sem_limits(sem_limits_t*); pcp-3.8.12ubuntu1/src/pmdas/linux/proc_net_sockstat.c0000664000000000000000000000447712272262501017540 0ustar /* * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "proc_net_sockstat.h" int refresh_proc_net_sockstat(proc_net_sockstat_t *proc_net_sockstat) { static int started; char buf[1024]; char fmt[64]; FILE *fp; if (!started) { started = 1; memset(proc_net_sockstat, 0, sizeof(*proc_net_sockstat)); } if ((fp = fopen("/proc/net/sockstat", "r")) == NULL) { return -oserror(); } while (fgets(buf, sizeof(buf), fp) != NULL) { if (strncmp(buf, "TCP:", 4) == 0) { sscanf(buf, "%s %s %d %s %d", fmt, fmt, &proc_net_sockstat->tcp[_PM_SOCKSTAT_INUSE], fmt, &proc_net_sockstat->tcp[_PM_SOCKSTAT_HIGHEST]); proc_net_sockstat->tcp[_PM_SOCKSTAT_UTIL] = proc_net_sockstat->tcp[_PM_SOCKSTAT_HIGHEST] != 0 ? 100 * proc_net_sockstat->tcp[_PM_SOCKSTAT_INUSE] / proc_net_sockstat->tcp[_PM_SOCKSTAT_HIGHEST] : 0; } else if (strncmp(buf, "UDP:", 4) == 0) { sscanf(buf, "%s %s %d %s %d", fmt, fmt, &proc_net_sockstat->udp[_PM_SOCKSTAT_INUSE], fmt, &proc_net_sockstat->udp[_PM_SOCKSTAT_HIGHEST]); proc_net_sockstat->udp[_PM_SOCKSTAT_UTIL] = proc_net_sockstat->udp[_PM_SOCKSTAT_HIGHEST] != 0 ? 100 * proc_net_sockstat->udp[_PM_SOCKSTAT_INUSE] / proc_net_sockstat->udp[_PM_SOCKSTAT_HIGHEST] : 0; } else if (strncmp(buf, "RAW:", 4) == 0) { sscanf(buf, "%s %s %d %s %d", fmt, fmt, &proc_net_sockstat->raw[_PM_SOCKSTAT_INUSE], fmt, &proc_net_sockstat->raw[_PM_SOCKSTAT_HIGHEST]); proc_net_sockstat->raw[_PM_SOCKSTAT_UTIL] = proc_net_sockstat->raw[_PM_SOCKSTAT_HIGHEST] != 0 ? 100 * proc_net_sockstat->raw[_PM_SOCKSTAT_INUSE] / proc_net_sockstat->raw[_PM_SOCKSTAT_HIGHEST] : 0; } } fclose(fp); /* success */ return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/shm_limits.c0000664000000000000000000000234112272262501016150 0ustar /* * Copyright (c) International Business Machines Corp., 2002 * This code contributed by Mike Mason * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #define __USE_GNU 1 /* required for IPC_INFO define */ #include #include #include "pmapi.h" #include "shm_limits.h" int refresh_shm_limits(shm_limits_t *shm_limits) { static int started; static struct shminfo shminfo; if (!started) { started = 1; memset(shm_limits, 0, sizeof(shm_limits_t)); } if (shmctl(0, IPC_INFO, (struct shmid_ds *) &shminfo) < 0) return -oserror(); shm_limits->shmmax = shminfo.shmmax; shm_limits->shmmin = shminfo.shmmin; shm_limits->shmmni = shminfo.shmmni; shm_limits->shmseg = shminfo.shmseg; shm_limits->shmall = shminfo.shmall; return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/swapdev.h0000664000000000000000000000174012272262501015460 0ustar /* * Linux swap device Cluster * * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ typedef struct swapdev { char *path; unsigned int size; unsigned int used; int priority; } swapdev_t; extern int refresh_swapdev(pmInDom); pcp-3.8.12ubuntu1/src/pmdas/linux/GNUmakefile0000664000000000000000000001010112272262501015677 0ustar # # Copyright (c) 2000,2003,2004,2008 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2007-2010 Aconex. All Rights Reserved. # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = linux DOMAIN = LINUX CMDTARGET = pmdalinux LIBTARGET = pmda_linux.so PMDAINIT = linux_init PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LOGREWRITEDIR = $(PCP_VAR_DIR)/config/pmlogrewrite CONF_LINE = "linux 60 dso $(PMDAINIT) $(PMDADIR)/$(LIBTARGET)" CFILES = pmda.c \ proc_stat.c proc_meminfo.c proc_loadavg.c \ proc_net_dev.c interrupts.c filesys.c \ swapdev.c devmapper.c proc_net_rpc.c proc_partitions.c \ getinfo.c proc_net_sockstat.c proc_net_snmp.c \ proc_scsi.c proc_cpuinfo.c proc_net_tcp.c \ proc_slabinfo.c sem_limits.c msg_limits.c shm_limits.c \ proc_uptime.c proc_sys_fs.c proc_vmstat.c \ sysfs_kernel.c linux_table.c numa_meminfo.c HFILES = clusters.h indom.h convert.h \ proc_stat.h proc_meminfo.h proc_loadavg.h \ proc_net_dev.h interrupts.h filesys.h \ swapdev.h devmapper.h proc_net_rpc.h proc_partitions.h \ getinfo.h proc_net_sockstat.h proc_net_snmp.h \ proc_scsi.h proc_cpuinfo.h proc_net_tcp.h \ proc_slabinfo.h sem_limits.h msg_limits.h shm_limits.h \ proc_uptime.h proc_sys_fs.h proc_vmstat.h \ sysfs_kernel.h linux_table.h numa_meminfo.h VERSION_SCRIPT = exports HELPTARGETS = help.dir help.pag LSRCFILES = help root_linux proc_net_snmp_migrate.conf LDIRT = $(HELPTARGETS) domain.h $(VERSION_SCRIPT) LLDLIBS = $(PCP_PMDALIB) LCFLAGS = $(INVISIBILITY) # Uncomment these flags for profiling # LCFLAGS += -pg # LLDFLAGS += -pg default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "linux" build-me: domain.h $(LIBTARGET) $(CMDTARGET) $(HELPTARGETS) @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 644 domain.h help $(HELPTARGETS) $(PMDADIR) $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(PMDADIR) $(INSTALL) -m 644 root_linux $(PCP_VAR_DIR)/pmns/root_linux $(INSTALL) -m 644 proc_net_snmp_migrate.conf $(LOGREWRITEDIR)/linux_proc_net_snmp_migrate.conf else build-me: install: endif default_pcp : default install_pcp : install $(HELPTARGETS) : help $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_linux -v 2 -o help < help $(VERSION_SCRIPT): $(VERSION_SCRIPT_MAKERULE) domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) interrupts.o pmda.o proc_partitions.o: clusters.h pmda.o proc_partitions.o: convert.h pmda.o: domain.h filesys.o interrupts.o pmda.o: filesys.h pmda.o: getinfo.h pmda.o devmapper.o: devmapper.h numa_meminfo.o pmda.o proc_cpuinfo.o proc_partitions.o proc_stat.o: indom.h interrupts.o pmda.o: interrupts.h linux_table.o numa_meminfo.o pmda.o: linux_table.h msg_limits.o pmda.o: msg_limits.h numa_meminfo.o pmda.o: numa_meminfo.h pmda.o proc_cpuinfo.o proc_stat.o: proc_cpuinfo.h pmda.o proc_loadavg.o: proc_loadavg.h pmda.o proc_meminfo.o: proc_meminfo.h pmda.o proc_net_dev.o: proc_net_dev.h pmda.o proc_net_rpc.o: proc_net_rpc.h pmda.o proc_net_snmp.o: proc_net_snmp.h pmda.o proc_net_sockstat.o: proc_net_sockstat.h pmda.o proc_net_tcp.o: proc_net_tcp.h pmda.o proc_partitions.o: proc_partitions.h pmda.o proc_scsi.o: proc_scsi.h pmda.o proc_slabinfo.o: proc_slabinfo.h pmda.o proc_stat.o: proc_stat.h pmda.o proc_sys_fs.o: proc_sys_fs.h pmda.o proc_uptime.o: proc_uptime.h pmda.o proc_vmstat.o: proc_vmstat.h pmda.o sem_limits.o: sem_limits.h pmda.o shm_limits.o: shm_limits.h pmda.o swapdev.o: swapdev.h pmda.o sysfs_kernel.o: sysfs_kernel.h pmda.o: $(VERSION_SCRIPT) pcp-3.8.12ubuntu1/src/pmdas/linux/proc_net_dev.c0000664000000000000000000002731312272262501016455 0ustar /* * Linux /proc/net_dev metrics cluster * * Copyright (c) 2013 Red Hat. * Copyright (c) 1995,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include #include #include #include #include #include "proc_net_dev.h" static int refresh_inet_socket() { static int netfd = -1; if (netfd < 0) netfd = socket(AF_INET, SOCK_DGRAM, 0); return netfd; } static int refresh_net_dev_ioctl(char *name, net_interface_t *netip) { struct ethtool_cmd ecmd; struct ifreq ifr; int fd; if ((fd = refresh_inet_socket()) < 0) return 0; ecmd.cmd = ETHTOOL_GSET; ifr.ifr_data = (caddr_t)&ecmd; strncpy(ifr.ifr_name, name, IF_NAMESIZE); ifr.ifr_name[IF_NAMESIZE-1] = '\0'; if (!(ioctl(fd, SIOCGIFMTU, &ifr) < 0)) netip->ioc.mtu = ifr.ifr_mtu; ecmd.cmd = ETHTOOL_GSET; ifr.ifr_data = (caddr_t)&ecmd; strncpy(ifr.ifr_name, name, IF_NAMESIZE); ifr.ifr_name[IF_NAMESIZE-1] = '\0'; if (!(ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)) { netip->ioc.linkup = !!(ifr.ifr_flags & IFF_UP); netip->ioc.running = !!(ifr.ifr_flags & IFF_RUNNING); } /* ETHTOOL ioctl -> non-root permissions issues for old kernels */ ecmd.cmd = ETHTOOL_GSET; ifr.ifr_data = (caddr_t)&ecmd; strncpy(ifr.ifr_name, name, IF_NAMESIZE); ifr.ifr_name[IF_NAMESIZE-1] = '\0'; if (!(ioctl(fd, SIOCETHTOOL, &ifr) < 0)) { /* * speed is defined in ethtool.h and returns the speed in * Mbps, so 100 for 100Mbps, 1000 for 1Gbps, etc */ netip->ioc.speed = ecmd.speed; netip->ioc.duplex = ecmd.duplex + 1; return 0; } return -ENOSYS; /* caller should try ioctl alternatives */ } static void refresh_net_ipv4_addr(char *name, net_addr_t *addr) { struct ifreq ifr; int fd; if ((fd = refresh_inet_socket()) < 0) return; strncpy(ifr.ifr_name, name, IF_NAMESIZE); ifr.ifr_name[IF_NAMESIZE-1] = '\0'; ifr.ifr_addr.sa_family = AF_INET; if (ioctl(fd, SIOCGIFADDR, &ifr) >= 0) { struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; if (inet_ntop(AF_INET, &sin->sin_addr, addr->inet, INET_ADDRSTRLEN)) addr->has_inet = 1; } } /* * No ioctl support or no permissions (more likely), so we * fall back to grovelling about in /sys/class/net in a last * ditch attempt to find the ethtool interface data (duplex * and speed). */ static char * read_oneline(const char *path, char *buffer) { FILE *fp = fopen(path, "r"); if (fp) { int i = fscanf(fp, "%63s", buffer); fclose(fp); if (i == 1) return buffer; } return ""; } static void refresh_net_dev_sysfs(char *name, net_interface_t *netip) { char path[256]; char line[64]; char *duplex; snprintf(path, sizeof(path), "/sys/class/net/%s/speed", name); path[sizeof(path)-1] = '\0'; netip->ioc.speed = atoi(read_oneline(path, line)); snprintf(path, sizeof(path), "/sys/class/net/%s/duplex", name); path[sizeof(path)-1] = '\0'; duplex = read_oneline(path, line); if (strcmp(duplex, "full") == 0) netip->ioc.duplex = 2; else if (strcmp(duplex, "half") == 0) netip->ioc.duplex = 1; else /* eh? */ netip->ioc.duplex = 0; } static void refresh_net_hw_addr(char *name, net_addr_t *netip) { char path[256]; char line[64]; char *value; snprintf(path, sizeof(path), "/sys/class/net/%s/address", name); path[sizeof(path)-1] = '\0'; value = read_oneline(path, line); if (value[0] != '\0') netip->has_hw = 1; strncpy(netip->hw_addr, value, sizeof(netip->hw_addr)); netip->hw_addr[sizeof(netip->hw_addr)-1] = '\0'; } int refresh_proc_net_dev(pmInDom indom) { char buf[1024]; FILE *fp; unsigned long long llval; char *p, *v; int j, sts; net_interface_t *netip; static uint64_t gen; /* refresh generation number */ static uint32_t cache_err; if ((fp = fopen("/proc/net/dev", "r")) == (FILE *)0) return -oserror(); if (gen == 0) { /* * first time, reload cache from external file, and force any * subsequent changes to be saved */ pmdaCacheOp(indom, PMDA_CACHE_LOAD); } gen++; /* Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed lo: 4060748 39057 0 0 0 0 0 0 4060748 39057 0 0 0 0 0 0 eth0: 0 337614 0 0 0 0 0 0 0 267537 0 0 0 27346 62 0 */ pmdaCacheOp(indom, PMDA_CACHE_INACTIVE); while (fgets(buf, sizeof(buf), fp) != NULL) { if ((p = v = strchr(buf, ':')) == NULL) continue; *p = '\0'; for (p=buf; *p && isspace((int)*p); p++) {;} sts = pmdaCacheLookupName(indom, p, NULL, (void **)&netip); if (sts == PM_ERR_INST || (sts >= 0 && netip == NULL)) { /* first time since re-loaded, else new one */ netip = (net_interface_t *)calloc(1, sizeof(net_interface_t)); #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { fprintf(stderr, "refresh_proc_net_dev: initialize \"%s\"\n", p); } #endif } else if (sts < 0) { if (cache_err++ < 10) { fprintf(stderr, "refresh_proc_net_dev: pmdaCacheLookupName(%s, %s, ...) failed: %s\n", pmInDomStr(indom), p, pmErrStr(sts)); } continue; } if (netip->last_gen != gen-1) { /* * rediscovered one that went away and has returned * * kernel counters are reset, so clear last_counters to * avoid false overflows */ for (j=0; j < PROC_DEV_COUNTERS_PER_LINE; j++) { netip->last_counters[j] = 0; } } netip->last_gen = gen; if ((sts = pmdaCacheStore(indom, PMDA_CACHE_ADD, p, (void *)netip)) < 0) { if (cache_err++ < 10) { fprintf(stderr, "refresh_proc_net_dev: pmdaCacheStore(%s, PMDA_CACHE_ADD, %s, " PRINTF_P_PFX "%p) failed: %s\n", pmInDomStr(indom), p, netip, pmErrStr(sts)); } continue; } /* Issue ioctls for remaining data, not exported through proc */ memset(&netip->ioc, 0, sizeof(netip->ioc)); if (refresh_net_dev_ioctl(p, netip) < 0) refresh_net_dev_sysfs(p, netip); for (p=v, j=0; j < PROC_DEV_COUNTERS_PER_LINE; j++) { for (; !isdigit((int)*p); p++) {;} sscanf(p, "%llu", &llval); if (llval >= netip->last_counters[j]) { netip->counters[j] += llval - netip->last_counters[j]; } else { /* 32bit counter has wrapped */ netip->counters[j] += llval + (UINT_MAX - netip->last_counters[j]); } netip->last_counters[j] = llval; for (; !isspace((int)*p); p++) {;} } } pmdaCacheOp(indom, PMDA_CACHE_SAVE); /* success */ fclose(fp); return 0; } static int refresh_net_dev_ipv4_addr(pmInDom indom) { int n, fd, sts, numreqs = 30; struct ifconf ifc; struct ifreq *ifr; net_addr_t *netip; static uint32_t cache_err; if ((fd = refresh_inet_socket()) < 0) return fd; ifc.ifc_buf = NULL; for (;;) { ifc.ifc_len = sizeof(struct ifreq) * numreqs; ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len); if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { free(ifc.ifc_buf); return -oserror(); } if (ifc.ifc_len == sizeof(struct ifreq) * numreqs) { /* assume it overflowed and try again */ numreqs *= 2; continue; } break; } for (n = 0, ifr = ifc.ifc_req; n < ifc.ifc_len; n += sizeof(struct ifreq), ifr++) { sts = pmdaCacheLookupName(indom, ifr->ifr_name, NULL, (void **)&netip); if (sts == PM_ERR_INST || (sts >= 0 && netip == NULL)) { /* first time since re-loaded, else new one */ netip = (net_addr_t *)calloc(1, sizeof(net_addr_t)); } else if (sts < 0) { if (cache_err++ < 10) { fprintf(stderr, "refresh_net_dev_ipv4_addr: " "pmdaCacheLookupName(%s, %s, ...) failed: %s\n", pmInDomStr(indom), ifr->ifr_name, pmErrStr(sts)); } continue; } if ((sts = pmdaCacheStore(indom, PMDA_CACHE_ADD, ifr->ifr_name, (void *)netip)) < 0) { if (cache_err++ < 10) { fprintf(stderr, "refresh_net_dev_ipv4_addr: " "pmdaCacheStore(%s, PMDA_CACHE_ADD, %s, " PRINTF_P_PFX "%p) failed: %s\n", pmInDomStr(indom), ifr->ifr_name, netip, pmErrStr(sts)); } continue; } refresh_net_ipv4_addr(ifr->ifr_name, netip); refresh_net_hw_addr(ifr->ifr_name, netip); } free(ifc.ifc_buf); return 0; } static int refresh_net_dev_ipv6_addr(pmInDom indom) { FILE *fp; char addr6p[8][5]; char addr6[40], devname[20+1]; char addr[INET6_ADDRSTRLEN]; struct sockaddr_in6 sin6; int sts, plen, scope, dad_status, if_idx; net_addr_t *netip; static uint32_t cache_err; if ((fp = fopen("/proc/net/if_inet6", "r")) == NULL) return 0; while (fscanf(fp, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7], &if_idx, &plen, &scope, &dad_status, devname) != EOF) { sts = pmdaCacheLookupName(indom, devname, NULL, (void **)&netip); if (sts == PM_ERR_INST || (sts >= 0 && netip == NULL)) { /* first time since re-loaded, else new one */ netip = (net_addr_t *)calloc(1, sizeof(net_addr_t)); } else if (sts < 0) { if (cache_err++ < 10) { fprintf(stderr, "refresh_net_dev_ipv6_addr: " "pmdaCacheLookupName(%s, %s, ...) failed: %s\n", pmInDomStr(indom), devname, pmErrStr(sts)); } continue; } if ((sts = pmdaCacheStore(indom, PMDA_CACHE_ADD, devname, (void *)netip)) < 0) { if (cache_err++ < 10) { fprintf(stderr, "refresh_net_dev_ipv6_addr: " "pmdaCacheStore(%s, PMDA_CACHE_ADD, %s, " PRINTF_P_PFX "%p) failed: %s\n", pmInDomStr(indom), devname, netip, pmErrStr(sts)); } continue; } sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], addr6p[5], addr6p[6], addr6p[7]); if (inet_pton(AF_INET6, addr6, sin6.sin6_addr.s6_addr) != 1) continue; sin6.sin6_family = AF_INET6; sin6.sin6_port = 0; if (!inet_ntop(AF_INET6, &sin6.sin6_addr, addr, INET6_ADDRSTRLEN)) continue; snprintf(netip->ipv6, sizeof(netip->ipv6), "%s/%d", addr, plen); netip->ipv6scope = (uint16_t)scope; netip->has_ipv6 = 1; refresh_net_hw_addr(devname, netip); } fclose(fp); return 0; } /* * This separate indom provides the addresses for all interfaces including * aliases (e.g. eth0, eth0:0, eth0:1, etc) - this is what ifconfig does. */ int refresh_net_dev_addr(pmInDom indom) { int sts = 0; net_addr_t*p; for (pmdaCacheOp(indom, PMDA_CACHE_WALK_REWIND);;) { if ((sts = pmdaCacheOp(indom, PMDA_CACHE_WALK_NEXT)) < 0) break; if (!pmdaCacheLookup(indom, sts, NULL, (void **)&p) || !p) continue; p->has_inet = 0; p->has_ipv6 = 0; p->has_hw = 0; } pmdaCacheOp(indom, PMDA_CACHE_INACTIVE); sts |= refresh_net_dev_ipv4_addr(indom); sts |= refresh_net_dev_ipv6_addr(indom); pmdaCacheOp(indom, PMDA_CACHE_SAVE); return sts; } char * lookup_ipv6_scope(int scope) { switch (scope) { case IPV6_ADDR_ANY: return "Global"; case IPV6_ADDR_LINKLOCAL: return "Link"; case IPV6_ADDR_SITELOCAL: return "Site"; case IPV6_ADDR_COMPATv4: return "Compat"; case IPV6_ADDR_LOOPBACK: return "Host"; } return "Unknown"; } pcp-3.8.12ubuntu1/src/pmdas/linux/convert.h0000664000000000000000000000344512272262501015473 0ustar /* * Size conversion for different sized types extracted from the * kernel on different platforms, particularly where the sizeof * "long" differs. * * Copyright (c) 2007-2008 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Some metrics are exported by the kernel as "unsigned long". * On most 64bit platforms this is not the same size as an * "unsigned int". */ #if defined(HAVE_64BIT_LONG) #define KERNEL_ULONG PM_TYPE_U64 #define _pm_assign_ulong(atomp, val) do { (atomp)->ull = (val); } while (0) #else #define KERNEL_ULONG PM_TYPE_U32 #define _pm_assign_ulong(atomp, val) do { (atomp)->ul = (val); } while (0) #endif /* * Some metrics need to have their type set at runtime, based on the * running kernel version (not simply a 64 vs 32 bit machine issue). */ #define KERNEL_UTYPE PM_TYPE_NOSUPPORT /* set to real type at runtime */ #define _pm_metric_type(type, size) \ do { \ (type) = ((size)==8 ? PM_TYPE_U64 : PM_TYPE_U32); \ } while (0) #define _pm_assign_utype(size, atomp, val) \ do { \ if ((size)==8) { (atomp)->ull = (val); } else { (atomp)->ul = (val); } \ } while (0) pcp-3.8.12ubuntu1/src/pmdas/linux/msg_limits.c0000664000000000000000000000255012272262501016151 0ustar /* * Copyright (c) International Business Machines Corp., 2002 * This code contributed by Mike Mason * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #define __USE_GNU 1 /* required for IPC_INFO define */ #include #include #include "pmapi.h" #include "msg_limits.h" int refresh_msg_limits(msg_limits_t *msg_limits) { static struct msginfo msginfo; static int started; if (!started) { started = 1; memset(msg_limits, 0, sizeof(msg_limits_t)); } if (msgctl(0, IPC_INFO, (struct msqid_ds *) &msginfo) < 0) { return -oserror(); } msg_limits->msgpool = msginfo.msgpool; msg_limits->msgmap = msginfo.msgmap; msg_limits->msgmax = msginfo.msgmax; msg_limits->msgmnb = msginfo.msgmnb; msg_limits->msgmni = msginfo.msgmni; msg_limits->msgssz = msginfo.msgssz; msg_limits->msgtql = msginfo.msgtql; msg_limits->msgseg = msginfo.msgseg; /* success */ return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/swapdev.c0000664000000000000000000000403312272262501015451 0ustar /* * Linux Swap Device Cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "swapdev.h" int refresh_swapdev(pmInDom swapdev_indom) { char buf[MAXPATHLEN]; swapdev_t *swap; FILE *fp; char *path; char *size; char *used; char *priority; int sts; pmdaCacheOp(swapdev_indom, PMDA_CACHE_INACTIVE); if ((fp = fopen("/proc/swaps", "r")) == (FILE *)NULL) return -oserror(); while (fgets(buf, sizeof(buf), fp) != NULL) { if (buf[0] != '/') continue; if ((path = strtok(buf, " \t")) == 0) continue; if ((/*type: */ strtok(NULL, " \t")) == NULL || (size = strtok(NULL, " \t")) == NULL || (used = strtok(NULL, " \t")) == NULL || (priority = strtok(NULL, " \t")) == NULL) continue; sts = pmdaCacheLookupName(swapdev_indom, path, NULL, (void **)&swap); if (sts == PMDA_CACHE_ACTIVE) /* repeated line in /proc/swaps? */ continue; if (sts == PMDA_CACHE_INACTIVE) { /* re-activate an old swap device */ pmdaCacheStore(swapdev_indom, PMDA_CACHE_ADD, path, swap); } else { /* new swap device */ if ((swap = malloc(sizeof(swapdev_t))) == NULL) continue; #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) fprintf(stderr, "refresh_swapdev: add \"%s\"\n", path); #endif pmdaCacheStore(swapdev_indom, PMDA_CACHE_ADD, path, swap); } sscanf(size, "%u", &swap->size); sscanf(used, "%u", &swap->used); sscanf(priority, "%d", &swap->priority); } fclose(fp); return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/sysfs_kernel.c0000664000000000000000000000210212272262501016502 0ustar /* * Linux sysfs_kernel cluster * * Copyright (c) 2009, Red Hat, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "sysfs_kernel.h" int refresh_sysfs_kernel(sysfs_kernel_t *sk) { char buf[64]; int fd, n; if ((fd = open("/sys/kernel/uevent_seqnum", O_RDONLY)) < 0) { sk->valid_uevent_seqnum = 0; return -oserror(); } if ((n = read(fd, buf, sizeof(buf))) <= 0) sk->valid_uevent_seqnum = 0; else { buf[n-1] = '\0'; sscanf(buf, "%llu", (long long unsigned int *)&sk->uevent_seqnum); sk->valid_uevent_seqnum = 1; } close(fd); return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_meminfo.c0000664000000000000000000001006012272262501016452 0ustar /* * Linux /proc/meminfo metrics cluster * * Copyright (c) 2013 Red Hat. * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include "pmapi.h" #include "proc_meminfo.h" static proc_meminfo_t moff; static struct { char *field; int64_t *offset; } meminfo_fields[] = { { "MemTotal", &moff.MemTotal }, { "MemFree", &moff.MemFree }, { "MemShared", &moff.MemShared }, { "Buffers", &moff.Buffers }, { "Cached", &moff.Cached }, { "SwapCached", &moff.SwapCached }, { "Active", &moff.Active }, { "Inactive", &moff.Inactive }, { "Active(anon)", &moff.Active_anon }, { "Inactive(anon)", &moff.Inactive_anon }, { "Active(file)", &moff.Active_file }, { "Inactive(file)", &moff.Inactive_file }, { "Unevictable", &moff.Unevictable }, { "Mlocked", &moff.Mlocked }, { "HighTotal", &moff.HighTotal }, { "HighFree", &moff.HighFree }, { "LowTotal", &moff.LowTotal }, { "LowFree", &moff.LowFree }, { "MmapCopy", &moff.MmapCopy }, { "SwapTotal", &moff.SwapTotal }, { "SwapFree", &moff.SwapFree }, { "Dirty", &moff.Dirty }, { "Writeback", &moff.Writeback }, { "AnonPages", &moff.AnonPages }, { "Mapped", &moff.Mapped }, { "Shmem", &moff.Shmem }, { "Slab", &moff.Slab }, { "SReclaimable", &moff.SlabReclaimable }, { "SUnreclaim", &moff.SlabUnreclaimable }, { "KernelStack", &moff.KernelStack }, { "PageTables", &moff.PageTables }, { "Quicklists", &moff.Quicklists }, { "NFS_Unstable", &moff.NFS_Unstable }, { "Bounce", &moff.Bounce }, { "WritebackTmp", &moff.WritebackTmp }, { "CommitLimit", &moff.CommitLimit }, { "Committed_AS", &moff.Committed_AS }, { "VmallocTotal", &moff.VmallocTotal }, { "VmallocUsed", &moff.VmallocUsed }, { "VmallocChunk", &moff.VmallocChunk }, { "HardwareCorrupted", &moff.HardwareCorrupted }, { "AnonHugePages", &moff.AnonHugePages }, /* vendor kernel patches, some outdated now */ { "MemShared", &moff.MemShared }, { "ReverseMaps", &moff.ReverseMaps }, { "HugePages_Total", &moff.HugepagesTotal }, { "HugePages_Free", &moff.HugepagesFree }, { "HugePages_Rsvd", &moff.HugepagesRsvd }, { "HugePages_Surp", &moff.HugepagesSurp }, { "DirectMap4k", &moff.directMap4k }, { "DirectMap2M", &moff.directMap2M }, { "DirectMap1G", &moff.directMap1G }, { NULL, NULL } }; #define MOFFSET(ii, pp) (int64_t *)((char *)pp + \ (__psint_t)meminfo_fields[ii].offset - (__psint_t)&moff) int refresh_proc_meminfo(proc_meminfo_t *proc_meminfo) { static int started; char buf[1024]; char *bufp; int64_t *p; int i; FILE *fp; if (!started) { started = 1; memset(proc_meminfo, 0, sizeof(*proc_meminfo)); } for (i=0; meminfo_fields[i].field != NULL; i++) { p = MOFFSET(i, proc_meminfo); *p = -1; /* marked as "no value available" */ } if ((fp = fopen("/proc/meminfo", "r")) == (FILE *)0) return -oserror(); while (fgets(buf, sizeof(buf), fp) != NULL) { if ((bufp = strchr(buf, ':')) == NULL) continue; *bufp = '\0'; for (i=0; meminfo_fields[i].field != NULL; i++) { if (strcmp(buf, meminfo_fields[i].field) != 0) continue; p = MOFFSET(i, proc_meminfo); for (bufp++; *bufp; bufp++) { if (isdigit((int)*bufp)) { sscanf(bufp, "%llu", (unsigned long long *)p); *p *= 1024; /* kbytes -> bytes */ break; } } } } fclose(fp); /* success */ return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/interrupts.c0000664000000000000000000002417312272262501016226 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2011 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "filesys.h" #include "clusters.h" #include "interrupts.h" #include #ifdef HAVE_STRINGS_H #include #endif #include typedef struct { unsigned int id; /* becomes PMID item number */ char *name; /* becomes PMNS sub-component */ char *text; /* one-line metric help text */ unsigned long long *values; /* per-CPU values for this counter */ } interrupt_t; static unsigned int cpu_count; static int *online_cpumap; /* maps input columns to CPU IDs */ static unsigned int lines_count; static interrupt_t *interrupt_lines; static unsigned int other_count; static interrupt_t *interrupt_other; static __pmnsTree *interrupt_tree; unsigned int irq_err_count; static void update_lines_pmns(int domain, unsigned int item, unsigned int id) { char entry[128]; pmID pmid = pmid_build(domain, CLUSTER_INTERRUPT_LINES, item); snprintf(entry, sizeof(entry), "kernel.percpu.interrupts.line%d", id); __pmAddPMNSNode(interrupt_tree, pmid, entry); } static void update_other_pmns(int domain, unsigned int item, const char *name) { char entry[128]; pmID pmid = pmid_build(domain, CLUSTER_INTERRUPT_OTHER, item); snprintf(entry, sizeof(entry), "kernel.percpu.interrupts.%s", name); __pmAddPMNSNode(interrupt_tree, pmid, entry); } static int map_online_cpus(char *buffer) { unsigned long i = 0, cpuid; char *s, *end; for (s = buffer; *s != '\0'; s++) { if (!isdigit((int)*s)) continue; cpuid = strtoul(s, &end, 10); if (end == s) break; online_cpumap[i++] = cpuid; s = end; } return i; } static int column_to_cpuid(int column) { int i; if (online_cpumap[column] == column) return column; for (i = 0; i < cpu_count; i++) if (online_cpumap[i] == column) return i; return 0; } static char * extract_values(char *buffer, unsigned long long *values, int ncolumns) { unsigned long i, value, cpuid; char *s = buffer, *end = NULL; for (i = 0; i < ncolumns; i++) { value = strtoul(s, &end, 10); if (*end != ' ') return NULL; s = end; cpuid = column_to_cpuid(i); values[cpuid] = value; } return end; } /* Create oneline help text - remove duplicates and end-of-line marker */ static char * oneline_reformat(char *buf) { char *result, *start, *end; /* position end marker, and skip over whitespace at the start */ for (start = end = buf; *end != '\n' && *end != '\0'; end++) if (isspace((int)*start) && isspace((int)*end)) start = end+1; *end = '\0'; /* squash duplicate whitespace and remove trailing whitespace */ for (result = start; *result != '\0'; result++) { if (isspace((int)result[0]) && (isspace((int)result[1]) || result[1] == '\0')) { memmove(&result[0], &result[1], end - &result[0]); result--; } } return start; } static void initialise_interrupt(interrupt_t *ip, unsigned int id, char *s, char *end) { ip->id = id; ip->name = strdup(s); if (end) ip->text = strdup(oneline_reformat(end)); } static int extend_interrupts(interrupt_t **interp, unsigned int *countp) { int cnt = cpu_count * sizeof(unsigned long long); unsigned long long *values = malloc(cnt); interrupt_t *interrupt = *interp; int count = *countp + 1; if (!values) return 0; interrupt = realloc(interrupt, count * sizeof(interrupt_t)); if (!interrupt) { free(values); return 0; } interrupt[count-1].values = values; *interp = interrupt; *countp = count; return 1; } static char * extract_interrupt_name(char *buffer, char **suffix) { char *s = buffer, *end; while (isspace((int)*s)) /* find start of name */ s++; for (end = s; *end && isalnum((int)*end); end++) { } *end = '\0'; /* mark end of name */ *suffix = end + 1; /* mark values start */ return s; } static int extract_interrupt_lines(char *buffer, int ncolumns, int nlines) { unsigned long id; char *name, *end, *values; int resize = (nlines >= lines_count); name = extract_interrupt_name(buffer, &values); id = strtoul(name, &end, 10); if (*end != '\0') return 0; if (resize && !extend_interrupts(&interrupt_lines, &lines_count)) return 0; end = extract_values(values, interrupt_lines[nlines].values, ncolumns); if (resize) initialise_interrupt(&interrupt_lines[nlines], id, name, end); return 1; } static int extract_interrupt_errors(char *buffer) { return (sscanf(buffer, " ERR: %u", &irq_err_count) == 1 || sscanf(buffer, "Err: %u", &irq_err_count) == 1 || sscanf(buffer, "BAD: %u", &irq_err_count) == 1); } static int extract_interrupt_misses(char *buffer) { unsigned int irq_mis_count; /* not exported */ return sscanf(buffer, " MIS: %u", &irq_mis_count) == 1; } static int extract_interrupt_other(char *buffer, int ncolumns, int nlines) { char *name, *end, *values; int resize = (nlines >= other_count); name = extract_interrupt_name(buffer, &values); if (resize && !extend_interrupts(&interrupt_other, &other_count)) return 0; end = extract_values(values, interrupt_other[nlines].values, ncolumns); if (resize) initialise_interrupt(&interrupt_other[nlines], nlines, name, end); return 1; } int refresh_interrupt_values(void) { FILE *fp; char buf[4096]; int i, ncolumns; if (cpu_count == 0) { long ncpus = sysconf(_SC_NPROCESSORS_CONF); online_cpumap = malloc(ncpus * sizeof(int)); if (!online_cpumap) return -oserror(); cpu_count = ncpus; } memset(online_cpumap, 0, cpu_count * sizeof(int)); if ((fp = fopen("/proc/interrupts", "r")) == NULL) return -oserror(); /* first parse header, which maps online CPU number to column number */ if (fgets(buf, sizeof(buf), fp)) { ncolumns = map_online_cpus(buf); } else { fclose(fp); return -EINVAL; /* unrecognised file format */ } /* next we parse each interrupt line row (starting with a digit) */ i = 0; while (fgets(buf, sizeof(buf), fp)) if (!extract_interrupt_lines(buf, ncolumns, i++)) break; /* parse other per-CPU interrupt counter rows (starts non-digit) */ i = 0; while (fgets(buf, sizeof(buf), fp) != NULL) { if (extract_interrupt_errors(buf)) continue; if (extract_interrupt_misses(buf)) continue; if (!extract_interrupt_other(buf, ncolumns, i++)) break; } fclose(fp); return 0; } static int refresh_interrupts(pmdaExt *pmda, __pmnsTree **tree) { int i, sts, dom = pmda->e_domain; if (interrupt_tree) { *tree = interrupt_tree; } else if ((sts = __pmNewPMNS(&interrupt_tree)) < 0) { __pmNotifyErr(LOG_ERR, "%s: failed to create interrupt names: %s\n", pmProgname, pmErrStr(sts)); *tree = NULL; } else if ((sts = refresh_interrupt_values()) < 0) { __pmNotifyErr(LOG_ERR, "%s: failed to update interrupt values: %s\n", pmProgname, pmErrStr(sts)); *tree = NULL; } else { for (i = 0; i < lines_count; i++) update_lines_pmns(dom, i, interrupt_lines[i].id); for (i = 0; i < other_count; i++) update_other_pmns(dom, i, interrupt_other[i].name); *tree = interrupt_tree; return 1; } return 0; } int interrupts_fetch(int cluster, int item, unsigned int inst, pmAtomValue *atom) { if (inst >= cpu_count) return PM_ERR_INST; switch (cluster) { case CLUSTER_INTERRUPT_LINES: if (item > lines_count) return PM_ERR_PMID; atom->ull = interrupt_lines[item].values[inst]; return 1; case CLUSTER_INTERRUPT_OTHER: if (item > other_count) return PM_ERR_PMID; atom->ull = interrupt_other[item].values[inst]; return 1; } return PM_ERR_PMID; } /* * Create a new metric table entry based on an existing one. */ static void refresh_metrictable(pmdaMetric *source, pmdaMetric *dest, int id) { int domain = pmid_domain(source->m_desc.pmid); int cluster = pmid_cluster(source->m_desc.pmid); memcpy(dest, source, sizeof(pmdaMetric)); dest->m_desc.pmid = pmid_build(domain, cluster, id); if (pmDebug & DBG_TRACE_LIBPMDA) fprintf(stderr, "interrupts refresh_metrictable: (%p -> %p) " "metric ID dup: %d.%d.%d -> %d.%d.%d\n", source, dest, domain, cluster, pmid_item(source->m_desc.pmid), domain, cluster, id); } /* * Needs to answer the question: how much extra space needs to be * allocated in the metric table for (dynamic) interrupt metrics"? * Return value is the number of additional entries/trees needed. */ static void size_metrictable(int *total, int *trees) { *total = 2; /* lines and other */ *trees = lines_count > other_count ? lines_count : other_count; if (pmDebug & DBG_TRACE_LIBPMDA) fprintf(stderr, "interrupts size_metrictable: %d total x %d trees\n", *total, *trees); } static int interrupts_text(pmdaExt *pmda, pmID pmid, int type, char **buf) { int item = pmid_item(pmid); int cluster = pmid_cluster(pmid); switch (cluster) { case CLUSTER_INTERRUPT_LINES: if (item > lines_count) return PM_ERR_PMID; if (interrupt_lines[item].text == NULL) return PM_ERR_TEXT; *buf = interrupt_lines[item].text; return 0; case CLUSTER_INTERRUPT_OTHER: if (item > other_count) return PM_ERR_PMID; if (interrupt_other[item].text == NULL) return PM_ERR_TEXT; *buf = interrupt_other[item].text; return 0; } return PM_ERR_PMID; } void interrupts_init(pmdaMetric *metrictable, int nmetrics) { int set[] = { CLUSTER_INTERRUPT_LINES, CLUSTER_INTERRUPT_OTHER }; pmdaDynamicPMNS("kernel.percpu.interrupts", set, sizeof(set)/sizeof(int), refresh_interrupts, interrupts_text, refresh_metrictable, size_metrictable, metrictable, nmetrics); } pcp-3.8.12ubuntu1/src/pmdas/linux/filesys.h0000664000000000000000000000173012272262501015464 0ustar /* * Linux Filesystem Cluster * * Copyright (c) 2000,2004,2007 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include /* Values for flags in filesys_t */ #define FSF_FETCHED (1U << 0) typedef struct filesys { int id; unsigned int flags; char *device; char *path; char *options; struct statfs stats; } filesys_t; extern int refresh_filesys(pmInDom, pmInDom); extern char *scan_filesys_options(const char *, const char *); pcp-3.8.12ubuntu1/src/pmdas/linux/proc_net_sockstat.h0000664000000000000000000000202112272262501017524 0ustar /* * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #define _PM_SOCKSTAT_INUSE 0 #define _PM_SOCKSTAT_HIGHEST 1 #define _PM_SOCKSTAT_UTIL 2 typedef struct { int tcp[3]; int udp[3]; int raw[3]; } proc_net_sockstat_t; extern int refresh_proc_net_sockstat(proc_net_sockstat_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/linux_table.c0000664000000000000000000000551112272262501016310 0ustar /* * Copyright (c) 2012 Red Hat. * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include "linux_table.h" extern int linux_table_lookup(const char *field, struct linux_table *table, uint64_t *val); extern struct linux_table *linux_table_clone(struct linux_table *table); extern int linux_table_scan(FILE *fp, struct linux_table *table); inline int linux_table_lookup(const char *field, struct linux_table *table, uint64_t *val) { struct linux_table *t; for (t=table; t && t->field; t++) { if (strncmp(field, t->field, t->field_len) == 0) { if (t->valid) { *val = t->val; return 1; } /* Invalid */ return 0; } } fprintf(stderr, "Warning: linux_table_lookup failed for \"%s\"\n", field); return 0; } inline struct linux_table * linux_table_clone(struct linux_table *table) { struct linux_table *ret; struct linux_table *t; int len; if (!table) return NULL; for (len=1, t=table; t->field; t++) len++; ret = (struct linux_table *)malloc(len * sizeof(struct linux_table)); if (!ret) return NULL; memcpy(ret, table, len * sizeof(struct linux_table)); /* Initialize the table */ for (t=ret; t && t->field; t++) { if (!t->field_len) t->field_len = strlen(t->field); t->valid = LINUX_TABLE_INVALID; } return ret; } inline int linux_table_scan(FILE *fp, struct linux_table *table) { char *p; struct linux_table *t; char buf[1024]; int ret = 0; while(fgets(buf, sizeof(buf), fp) != NULL) { for (t=table; t && t->field; t++) { if ((p = strstr(buf, t->field)) != NULL) { /* first digit after the matched field */ for (p += t->field_len; *p; p++) { if (isdigit((int)*p)) break; } if (isdigit((int)*p)) { t->this = strtoul(p, NULL, 10); t->valid = LINUX_TABLE_VALID; ret++; break; } } } } /* calculate current value, accounting for counter wrap */ for (t=table; t && t->field; t++) { if (t->maxval == 0) /* instantaneous value */ t->val = t->this; else { /* counter value */ if (t->this >= t->prev) t->val += t->this - t->prev; else t->val += t->this + (t->maxval - t->prev); t->prev = t->this; } } return ret; } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_vmstat.h0000664000000000000000000000764412272262501016361 0ustar /* * Linux /proc/vmstat metrics cluster * * Copyright (c) 2013 Red Hat. * Copyright (c) 2007,2011 Aconex. All Rights Reserved. * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * All fields (sorted!) in /proc/vmstat for 2.6.x */ typedef struct { /* sorted by name to make maintenance easier */ __uint64_t allocstall; __uint64_t compact_blocks_moved; __uint64_t compact_fail; __uint64_t compact_pagemigrate_failed; __uint64_t compact_pages_moved; __uint64_t compact_stall; __uint64_t compact_success; __uint64_t htlb_buddy_alloc_fail; __uint64_t htlb_buddy_alloc_success; __uint64_t kswapd_high_wmark_hit_quickly; __uint64_t kswapd_inodesteal; __uint64_t kswapd_low_wmark_hit_quickly; __uint64_t kswapd_skip_congestion_wait; __uint64_t kswapd_steal; __uint64_t nr_active_anon; __uint64_t nr_active_file; __uint64_t nr_anon_pages; __uint64_t nr_anon_transparent_hugepages; __uint64_t nr_bounce; __uint64_t nr_dirtied; __uint64_t nr_dirty; __uint64_t nr_dirty_threshold; __uint64_t nr_dirty_background_threshold; __uint64_t nr_file_pages; __uint64_t nr_free_pages; __uint64_t nr_inactive_anon; __uint64_t nr_inactive_file; __uint64_t nr_isolated_anon; __uint64_t nr_isolated_file; __uint64_t nr_kernel_stack; __uint64_t nr_mapped; __uint64_t nr_mlock; __uint64_t nr_page_table_pages; __uint64_t nr_shmem; __uint64_t nr_slab; /* not in later kernels */ __uint64_t nr_slab_reclaimable; __uint64_t nr_slab_unreclaimable; __uint64_t nr_unevictable; __uint64_t nr_unstable; __uint64_t nr_vmscan_write; __uint64_t nr_writeback; __uint64_t nr_writeback_temp; __uint64_t nr_written; __uint64_t numa_foreign; __uint64_t numa_hit; __uint64_t numa_interleave; __uint64_t numa_local; __uint64_t numa_miss; __uint64_t numa_other; __uint64_t pageoutrun; __uint64_t pgactivate; __uint64_t pgalloc_dma; __uint64_t pgalloc_dma32; __uint64_t pgalloc_movable; __uint64_t pgalloc_high; __uint64_t pgalloc_normal; __uint64_t pgdeactivate; __uint64_t pgfault; __uint64_t pgfree; __uint64_t pginodesteal; __uint64_t pgmajfault; __uint64_t pgpgin; __uint64_t pgpgout; __uint64_t pgrefill_dma; __uint64_t pgrefill_dma32; __uint64_t pgrefill_high; __uint64_t pgrefill_movable; __uint64_t pgrefill_normal; __uint64_t pgrotated; __uint64_t pgscan_direct_dma; __uint64_t pgscan_direct_dma32; __uint64_t pgscan_direct_high; __uint64_t pgscan_direct_movable; __uint64_t pgscan_direct_normal; __uint64_t pgscan_kswapd_dma; __uint64_t pgscan_kswapd_dma32; __uint64_t pgscan_kswapd_high; __uint64_t pgscan_kswapd_movable; __uint64_t pgscan_kswapd_normal; __uint64_t pgsteal_dma; __uint64_t pgsteal_dma32; __uint64_t pgsteal_high; __uint64_t pgsteal_movable; __uint64_t pgsteal_normal; __uint64_t pswpin; __uint64_t pswpout; __uint64_t slabs_scanned; __uint64_t thp_fault_alloc; __uint64_t thp_fault_fallback; __uint64_t thp_collapse_alloc; __uint64_t thp_collapse_alloc_failed; __uint64_t thp_split; __uint64_t unevictable_pgs_cleared; __uint64_t unevictable_pgs_culled; __uint64_t unevictable_pgs_mlocked; __uint64_t unevictable_pgs_mlockfreed; __uint64_t unevictable_pgs_munlocked; __uint64_t unevictable_pgs_rescued; __uint64_t unevictable_pgs_scanned; __uint64_t unevictable_pgs_stranded; __uint64_t zone_reclaim_failed; } proc_vmstat_t; extern void proc_vmstat_init(void); extern int refresh_proc_vmstat(proc_vmstat_t *); extern int _pm_have_proc_vmstat; extern proc_vmstat_t _pm_proc_vmstat; pcp-3.8.12ubuntu1/src/pmdas/linux/indom.h0000664000000000000000000000437712272262501015126 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 2010 Aconex. All Rights Reserved. * Copyright (c) 2005,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _INDOM_H #define _INDOM_H enum { CPU_INDOM = 0, /* 0 - percpu */ DISK_INDOM, /* 1 - disks */ LOADAVG_INDOM, /* 2 - 1, 5, 15 minute load averages */ NET_DEV_INDOM, /* 3 - network interfaces */ PROC_INTERRUPTS_INDOM, /* 4 - interrupt lines -> proc PMDA */ FILESYS_INDOM, /* 5 - mounted bdev filesystems */ SWAPDEV_INDOM, /* 6 - swap devices */ NFS_INDOM, /* 7 - nfs operations */ NFS3_INDOM, /* 8 - nfs v3 operations */ PROC_PROC_INDOM, /* 9 - processes */ PARTITIONS_INDOM, /* 10 - disk partitions */ SCSI_INDOM, /* 11 - scsi devices */ SLAB_INDOM, /* 12 - kernel slabs */ STRINGS_INDOM, /* 13 - string dictionary */ NFS4_CLI_INDOM, /* 14 - nfs v4 client operations */ NFS4_SVR_INDOM, /* 15 - nfs n4 server operations */ QUOTA_PRJ_INDOM, /* 16 - project quota -> xfs PMDA */ NET_ADDR_INDOM, /* 17 - inet/ipv6 addresses */ TMPFS_INDOM, /* 18 - tmpfs mounts */ NODE_INDOM, /* 19 - NUMA nodes */ PROC_CGROUP_SUBSYS_INDOM, /* 20 - control group subsystems -> proc PMDA */ PROC_CGROUP_MOUNTS_INDOM, /* 21 - control group mounts -> proc PMDA */ LV_INDOM, /* 22 - lvm devices */ ICMPMSG_INDOM, /* 23 - icmp message types */ NUM_INDOMS /* one more than highest numbered cluster */ }; extern pmInDom linux_indom(int); #define INDOM(i) linux_indom(i) extern pmdaIndom *linux_pmda_indom(int); #define PMDAINDOM(i) linux_pmda_indom(i) /* * static string dictionary - one copy of oft-repeated strings; * implemented using STRINGS_INDOM and pmdaCache(3) routines. */ char *linux_strings_lookup(int); int linux_strings_insert(const char *); #endif /* _INDOM_H */ pcp-3.8.12ubuntu1/src/pmdas/linux/proc_vmstat.c0000664000000000000000000002624212272262501016347 0ustar /* * Linux /proc/vmstat metrics cluster * * Copyright (c) 2013 Red Hat. * Copyright (c) 2007,2011 Aconex. All Rights Reserved. * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "proc_vmstat.h" static struct { const char *field; __uint64_t *offset; } vmstat_fields[] = { /* sorted by name to make maintenance easier */ { .field = "allocstall", .offset = &_pm_proc_vmstat.allocstall }, { .field = "compact_blocks_moved", .offset = &_pm_proc_vmstat.compact_blocks_moved }, { .field = "compact_fail", .offset = &_pm_proc_vmstat.compact_fail }, { .field = "compact_pagemigrate_failed", .offset = &_pm_proc_vmstat.compact_pagemigrate_failed }, { .field = "compact_pages_moved", .offset = &_pm_proc_vmstat.compact_pages_moved }, { .field = "compact_stall", .offset = &_pm_proc_vmstat.compact_stall }, { .field = "compact_success", .offset = &_pm_proc_vmstat.compact_success }, { .field = "htlb_buddy_alloc_fail", .offset = &_pm_proc_vmstat.htlb_buddy_alloc_fail }, { .field = "htlb_buddy_alloc_success", .offset = &_pm_proc_vmstat.htlb_buddy_alloc_success }, { .field = "kswapd_inodesteal", .offset = &_pm_proc_vmstat.kswapd_inodesteal }, { .field = "kswapd_low_wmark_hit_quickly", .offset = &_pm_proc_vmstat.kswapd_low_wmark_hit_quickly }, { .field = "kswapd_high_wmark_hit_quickly", .offset = &_pm_proc_vmstat.kswapd_high_wmark_hit_quickly }, { .field = "kswapd_skip_congestion_wait", .offset = &_pm_proc_vmstat.kswapd_skip_congestion_wait }, { .field = "kswapd_steal", .offset = &_pm_proc_vmstat.kswapd_steal }, { .field = "nr_active_anon", .offset = &_pm_proc_vmstat.nr_active_anon }, { .field = "nr_active_file", .offset = &_pm_proc_vmstat.nr_active_file }, { .field = "nr_anon_pages", .offset = &_pm_proc_vmstat.nr_anon_pages }, { .field = "nr_anon_transparent_hugepages", .offset = &_pm_proc_vmstat.nr_anon_transparent_hugepages }, { .field = "nr_bounce", .offset = &_pm_proc_vmstat.nr_bounce }, { .field = "nr_dirty", .offset = &_pm_proc_vmstat.nr_dirty }, { .field = "nr_dirtied", .offset = &_pm_proc_vmstat.nr_dirtied }, { .field = "nr_dirty_threshold", .offset = &_pm_proc_vmstat.nr_dirty_threshold }, { .field = "nr_dirty_background_threshold", .offset = &_pm_proc_vmstat.nr_dirty_background_threshold }, { .field = "nr_file_pages", .offset = &_pm_proc_vmstat.nr_file_pages }, { .field = "nr_free_pages", .offset = &_pm_proc_vmstat.nr_free_pages }, { .field = "nr_inactive_anon", .offset = &_pm_proc_vmstat.nr_inactive_anon }, { .field = "nr_inactive_file", .offset = &_pm_proc_vmstat.nr_inactive_file }, { .field = "nr_isolated_anon", .offset = &_pm_proc_vmstat.nr_isolated_anon }, { .field = "nr_isolated_file", .offset = &_pm_proc_vmstat.nr_isolated_file }, { .field = "nr_kernel_stack", .offset = &_pm_proc_vmstat.nr_kernel_stack }, { .field = "nr_mapped", .offset = &_pm_proc_vmstat.nr_mapped }, { .field = "nr_mlock", .offset = &_pm_proc_vmstat.nr_mlock }, { .field = "nr_page_table_pages", .offset = &_pm_proc_vmstat.nr_page_table_pages }, { .field = "nr_shmem", .offset = &_pm_proc_vmstat.nr_shmem }, { .field = "nr_slab_reclaimable", .offset = &_pm_proc_vmstat.nr_slab_reclaimable }, { .field = "nr_slab_unreclaimable", .offset = &_pm_proc_vmstat.nr_slab_unreclaimable }, { .field = "nr_slab", .offset = &_pm_proc_vmstat.nr_slab }, /* not in later kernels */ { .field = "nr_unevictable", .offset = &_pm_proc_vmstat.nr_unevictable }, { .field = "nr_unstable", .offset = &_pm_proc_vmstat.nr_unstable }, { .field = "nr_vmscan_write", .offset = &_pm_proc_vmstat.nr_vmscan_write }, { .field = "nr_writeback", .offset = &_pm_proc_vmstat.nr_writeback }, { .field = "nr_writeback_temp", .offset = &_pm_proc_vmstat.nr_writeback_temp }, { .field = "nr_written", .offset = &_pm_proc_vmstat.nr_written }, { .field = "numa_hit", .offset = &_pm_proc_vmstat.numa_hit }, { .field = "numa_miss", .offset = &_pm_proc_vmstat.numa_miss }, { .field = "numa_foreign", .offset = &_pm_proc_vmstat.numa_foreign }, { .field = "numa_interleave", .offset = &_pm_proc_vmstat.numa_interleave }, { .field = "numa_local", .offset = &_pm_proc_vmstat.numa_local }, { .field = "numa_other", .offset = &_pm_proc_vmstat.numa_other }, { .field = "pageoutrun", .offset = &_pm_proc_vmstat.pageoutrun }, { .field = "pgactivate", .offset = &_pm_proc_vmstat.pgactivate }, { .field = "pgalloc_dma", .offset = &_pm_proc_vmstat.pgalloc_dma }, { .field = "pgalloc_dma32", .offset = &_pm_proc_vmstat.pgalloc_dma32 }, { .field = "pgalloc_high", .offset = &_pm_proc_vmstat.pgalloc_high }, { .field = "pgalloc_movable", .offset = &_pm_proc_vmstat.pgalloc_movable }, { .field = "pgalloc_normal", .offset = &_pm_proc_vmstat.pgalloc_normal }, { .field = "pgdeactivate", .offset = &_pm_proc_vmstat.pgdeactivate }, { .field = "pgfault", .offset = &_pm_proc_vmstat.pgfault }, { .field = "pgfree", .offset = &_pm_proc_vmstat.pgfree }, { .field = "pginodesteal", .offset = &_pm_proc_vmstat.pginodesteal }, { .field = "pgmajfault", .offset = &_pm_proc_vmstat.pgmajfault }, { .field = "pgpgin", .offset = &_pm_proc_vmstat.pgpgin }, { .field = "pgpgout", .offset = &_pm_proc_vmstat.pgpgout }, { .field = "pgrefill_dma", .offset = &_pm_proc_vmstat.pgrefill_dma }, { .field = "pgrefill_dma32", .offset = &_pm_proc_vmstat.pgrefill_dma32 }, { .field = "pgrefill_high", .offset = &_pm_proc_vmstat.pgrefill_high }, { .field = "pgrefill_movable", .offset = &_pm_proc_vmstat.pgrefill_movable }, { .field = "pgrefill_normal", .offset = &_pm_proc_vmstat.pgrefill_normal }, { .field = "pgrotated", .offset = &_pm_proc_vmstat.pgrotated }, { .field = "pgscan_direct_dma", .offset = &_pm_proc_vmstat.pgscan_direct_dma }, { .field = "pgscan_direct_dma32", .offset = &_pm_proc_vmstat.pgscan_direct_dma32 }, { .field = "pgscan_direct_high", .offset = &_pm_proc_vmstat.pgscan_direct_high }, { .field = "pgscan_direct_movable", .offset = &_pm_proc_vmstat.pgscan_direct_movable }, { .field = "pgscan_direct_normal", .offset = &_pm_proc_vmstat.pgscan_direct_normal }, { .field = "pgscan_kswapd_dma", .offset = &_pm_proc_vmstat.pgscan_kswapd_dma }, { .field = "pgscan_kswapd_dma32", .offset = &_pm_proc_vmstat.pgscan_kswapd_dma32 }, { .field = "pgscan_kswapd_high", .offset = &_pm_proc_vmstat.pgscan_kswapd_high }, { .field = "pgscan_kswapd_movable", .offset = &_pm_proc_vmstat.pgscan_kswapd_movable }, { .field = "pgscan_kswapd_normal", .offset = &_pm_proc_vmstat.pgscan_kswapd_normal }, { .field = "pgsteal_dma", .offset = &_pm_proc_vmstat.pgsteal_dma }, { .field = "pgsteal_dma32", .offset = &_pm_proc_vmstat.pgsteal_dma32 }, { .field = "pgsteal_high", .offset = &_pm_proc_vmstat.pgsteal_high }, { .field = "pgsteal_movable", .offset = &_pm_proc_vmstat.pgsteal_movable }, { .field = "pgsteal_normal", .offset = &_pm_proc_vmstat.pgsteal_normal }, { .field = "pswpin", .offset = &_pm_proc_vmstat.pswpin }, { .field = "pswpout", .offset = &_pm_proc_vmstat.pswpout }, { .field = "slabs_scanned", .offset = &_pm_proc_vmstat.slabs_scanned }, { .field = "thp_collapse_alloc", .offset = &_pm_proc_vmstat.thp_collapse_alloc }, { .field = "thp_collapse_alloc_failed", .offset = &_pm_proc_vmstat.thp_collapse_alloc_failed }, { .field = "thp_fault_alloc", .offset = &_pm_proc_vmstat.thp_fault_alloc }, { .field = "thp_fault_fallback", .offset = &_pm_proc_vmstat.thp_fault_fallback }, { .field = "thp_split", .offset = &_pm_proc_vmstat.thp_split }, { .field = "unevictable_pgs_cleared", .offset = &_pm_proc_vmstat.unevictable_pgs_cleared }, { .field = "unevictable_pgs_culled", .offset = &_pm_proc_vmstat.unevictable_pgs_culled }, { .field = "unevictable_pgs_mlocked", .offset = &_pm_proc_vmstat.unevictable_pgs_mlocked }, { .field = "unevictable_pgs_mlockfreed", .offset = &_pm_proc_vmstat.unevictable_pgs_mlockfreed }, { .field = "unevictable_pgs_munlocked", .offset = &_pm_proc_vmstat.unevictable_pgs_munlocked }, { .field = "unevictable_pgs_rescued", .offset = &_pm_proc_vmstat.unevictable_pgs_rescued }, { .field = "unevictable_pgs_scanned", .offset = &_pm_proc_vmstat.unevictable_pgs_scanned }, { .field = "unevictable_pgs_stranded", .offset = &_pm_proc_vmstat.unevictable_pgs_stranded }, { .field = "zone_reclaim_failed", .offset = &_pm_proc_vmstat.zone_reclaim_failed }, { .field = NULL, .offset = NULL } }; #define VMSTAT_OFFSET(ii, pp) (int64_t *)((char *)pp + \ (__psint_t)vmstat_fields[ii].offset - (__psint_t)&_pm_proc_vmstat) void proc_vmstat_init(void) { /* * The swap metrics moved from /proc/stat to /proc/vmstat early in 2.6. * In addition, the swap operation count was removed; the fetch routine * needs to deal with these quirks and return something sensible based * (initially) on whether the vmstat file exists. * * We'll re-evaluate this on each fetch of the mem.vmstat metrics, but * that is not a problem. This routine makes sure any swap.xxx metric * fetch without a preceding mem.vmstat fetch has the correct state. */ _pm_have_proc_vmstat = (access("/proc/vmstat", R_OK) == 0); } int refresh_proc_vmstat(proc_vmstat_t *proc_vmstat) { char buf[1024]; char *bufp; int64_t *p; int i; FILE *fp; for (i = 0; vmstat_fields[i].field != NULL; i++) { p = VMSTAT_OFFSET(i, proc_vmstat); *p = -1; /* marked as "no value available" */ } if ((fp = fopen("/proc/vmstat", "r")) == NULL) return -oserror(); _pm_have_proc_vmstat = 1; while (fgets(buf, sizeof(buf), fp) != NULL) { if ((bufp = strchr(buf, ' ')) == NULL) continue; *bufp = '\0'; for (i = 0; vmstat_fields[i].field != NULL; i++) { if (strcmp(buf, vmstat_fields[i].field) != 0) continue; p = VMSTAT_OFFSET(i, proc_vmstat); for (bufp++; *bufp; bufp++) { if (isdigit((int)*bufp)) { sscanf(bufp, "%llu", (unsigned long long *)p); break; } } } } fclose(fp); if (proc_vmstat->nr_slab == -1) /* split apart in 2.6.18 */ proc_vmstat->nr_slab = proc_vmstat->nr_slab_reclaimable + proc_vmstat->nr_slab_unreclaimable; /* success */ return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_net_tcp.h0000664000000000000000000000232512272262501016466 0ustar /* * Copyright (c) 1999,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * This code contributed by Michal Kara (lemming@arthur.plbohnice.cz) */ enum { _PM_TCP_ESTABLISHED = 1, _PM_TCP_SYN_SENT, _PM_TCP_SYN_RECV, _PM_TCP_FIN_WAIT1, _PM_TCP_FIN_WAIT2, _PM_TCP_TIME_WAIT, _PM_TCP_CLOSE, _PM_TCP_CLOSE_WAIT, _PM_TCP_LAST_ACK, _PM_TCP_LISTEN, _PM_TCP_CLOSING, _PM_TCP_LAST }; typedef struct { int stat[_PM_TCP_LAST]; } proc_net_tcp_t; extern int refresh_proc_net_tcp(proc_net_tcp_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/clusters.h0000664000000000000000000000734412272262501015661 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 2005,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _CLUSTERS_H #define _CLUSTERS_H /* * fetch cluster numbers */ enum { CLUSTER_STAT = 0, /* 0 /proc/stat */ CLUSTER_MEMINFO, /* 1 /proc/meminfo */ CLUSTER_LOADAVG, /* 2 /proc/loadavg */ CLUSTER_NET_DEV, /* 3 /proc/net/dev */ CLUSTER_INTERRUPTS, /* 4 /proc/interrupts */ CLUSTER_FILESYS, /* 5 /proc/mounts + statfs */ CLUSTER_SWAPDEV, /* 6 /proc/swaps */ CLUSTER_NET_NFS, /* 7 /proc/net/rpc/nfs + /proc/net/rpc/nfsd */ PROC_PID_STAT, /* 8 /proc//stat -> proc PMDA */ PROC_PID_STATM, /* 9 /proc//statm + /proc//maps -> proc PMDA */ CLUSTER_PARTITIONS, /* 10 /proc/partitions */ CLUSTER_NET_SOCKSTAT, /* 11 /proc/net/sockstat */ CLUSTER_KERNEL_UNAME, /* 12 uname() system call */ PROC_PROC_RUNQ, /* 13 number of processes in various states -> proc PMDA */ CLUSTER_NET_SNMP, /* 14 /proc/net/snmp */ CLUSTER_SCSI, /* 15 /proc/scsi/scsi */ CLUSTER_XFS, /* 16 /proc/fs/xfs/stat -> xfs PMDA */ CLUSTER_XFSBUF, /* 17 /proc/fs/pagebuf/stat -> xfs PMDA */ CLUSTER_CPUINFO, /* 18 /proc/cpuinfo */ CLUSTER_NET_TCP, /* 19 /proc/net/tcp */ CLUSTER_SLAB, /* 20 /proc/slabinfo */ CLUSTER_SEM_LIMITS, /* 21 semctl(IPC_INFO) system call */ CLUSTER_MSG_LIMITS, /* 22 msgctl(IPC_INFO) system call */ CLUSTER_SHM_LIMITS, /* 23 shmctl(IPC_INFO) system call */ PROC_PID_STATUS, /* 24 /proc//status -> proc PMDA */ CLUSTER_NUSERS, /* 25 number of users */ CLUSTER_UPTIME, /* 26 /proc/uptime */ CLUSTER_VFS, /* 27 /proc/sys/fs */ CLUSTER_VMSTAT, /* 28 /proc/vmstat */ CLUSTER_IB, /* deprecated: do not re-use 29 infiniband */ CLUSTER_QUOTA, /* 30 quotactl() -> xfs PMDA */ PROC_PID_SCHEDSTAT, /* 31 /proc//schedstat -> proc PMDA */ PROC_PID_IO, /* 32 /proc//io -> proc PMDA */ CLUSTER_NET_ADDR, /* 33 /proc/net/dev and ioctl(SIOCGIFCONF) */ CLUSTER_TMPFS, /* 34 /proc/mounts + statfs (tmpfs only) */ CLUSTER_SYSFS_KERNEL, /* 35 /sys/kernel metrics */ CLUSTER_NUMA_MEMINFO, /* 36 /sys/devices/system/node* NUMA memory */ PROC_CGROUP_SUBSYS, /* 37 /proc/cgroups control group subsystems -> proc PMDA */ PROC_CGROUP_MOUNTS, /* 38 /proc/mounts active control groups -> proc PMDA */ PROC_CPUSET_GROUPS, /* 39 cpuset control groups -> proc PMDA */ PROC_CPUSET_PROCS, /* 40 cpuset control group processes -> proc PMDA */ PROC_CPUACCT_GROUPS, /* 41 cpu accounting control groups -> proc PMDA */ PROC_CPUACCT_PROCS, /* 42 cpu accounting group processes -> proc PMDA */ PROC_CPUSCHED_GROUPS, /* 43 scheduler control groups -> proc PMDA */ PROC_CPUSCHED_PROCS, /* 44 scheduler group processes -> proc PMDA */ PROC_MEMORY_GROUPS, /* 45 memory control groups -> proc PMDA */ PROC_MEMORY_PROCS, /* 46 memory group processes -> proc PMDA */ PROC_NET_CLS_GROUPS, /* 47 network classification control groups -> proc PMDA */ PROC_NET_CLS_PROCS, /* 48 network classification group processes -> proc PMDA */ CLUSTER_INTERRUPT_LINES,/* 49 /proc/interrupts percpu interrupts */ CLUSTER_INTERRUPT_OTHER,/* 50 /proc/interrupts percpu interrupts */ PROC_PID_FD, /* 51 /proc//fd -> proc PMDA */ CLUSTER_LV, /* 52 /dev/mapper */ NUM_CLUSTERS /* one more than highest numbered cluster */ }; #endif /* _CLUSTERS_H */ pcp-3.8.12ubuntu1/src/pmdas/linux/proc_meminfo.h0000664000000000000000000000374012272262501016466 0ustar /* * Linux /proc/meminfo metrics cluster * * Copyright (c) 2013 Red Hat. * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * All fields in /proc/meminfo */ typedef struct { int64_t MemTotal; int64_t MemFree; int64_t MemShared; int64_t Buffers; int64_t Cached; int64_t SwapCached; int64_t Active; int64_t Inactive; int64_t Active_anon; int64_t Inactive_anon; int64_t Active_file; int64_t Inactive_file; int64_t Unevictable; int64_t Mlocked; int64_t HighTotal; int64_t HighFree; int64_t LowTotal; int64_t LowFree; int64_t MmapCopy; int64_t SwapTotal; int64_t SwapFree; int64_t SwapUsed; /* computed */ int64_t Dirty; int64_t Writeback; int64_t Mapped; int64_t Shmem; int64_t Slab; int64_t SlabReclaimable; int64_t SlabUnreclaimable; int64_t KernelStack; int64_t CommitLimit; int64_t Committed_AS; int64_t PageTables; int64_t Quicklists; int64_t ReverseMaps; int64_t AnonPages; int64_t Bounce; int64_t NFS_Unstable; int64_t WritebackTmp; int64_t VmallocTotal; int64_t VmallocUsed; int64_t VmallocChunk; int64_t HardwareCorrupted; int64_t AnonHugePages; int64_t HugepagesTotal; int64_t HugepagesFree; int64_t HugepagesRsvd; int64_t HugepagesSurp; int64_t directMap4k; int64_t directMap2M; int64_t directMap1G; } proc_meminfo_t; extern int refresh_proc_meminfo(proc_meminfo_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/proc_uptime.h0000664000000000000000000000173312272262501016337 0ustar /* * Copyright (c) International Business Machines Corp., 2002 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * This code contributed by Mike Mason */ typedef struct { unsigned long uptime; unsigned long idletime; } proc_uptime_t; extern int refresh_proc_uptime(proc_uptime_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/getinfo.c0000664000000000000000000000466412272262501015445 0ustar /* * Copyright (c) 2010 Aconex. All Rights Reserved. * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include "pmapi.h" char * get_distro_info(void) { /* * Heuristic guesswork ... add code here as we learn * more about how to identify each Linux distribution. */ static char *distro_name; struct stat sbuf; int r, sts, fd = -1, len = 0; char prefix[16]; enum { /* rfiles array offsets */ DEB_VERSION = 0, LSB_RELEASE = 5, }; char *rfiles[] = { "/etc/debian_version", "/etc/oracle-release", "/etc/fedora-release", "/etc/redhat-release", "/etc/slackware-version", "/etc/SuSE-release", "/etc/lsb-release", NULL }; if (distro_name) return distro_name; for (r = 0; rfiles[r] != NULL; r++) { if (stat(rfiles[r], &sbuf) == 0 && S_ISREG(sbuf.st_mode)) { fd = open(rfiles[r], O_RDONLY); break; } } if (fd != -1) { if (r == DEB_VERSION) { /* Debian, needs a prefix */ strncpy(prefix, "Debian ", sizeof(prefix)); len = 7; } /* * at this point, assume sbuf is good and file contains * the string we want, probably with a \n terminator */ distro_name = (char *)malloc(len + (int)sbuf.st_size + 1); if (distro_name != NULL) { if (len) strncpy(distro_name, prefix, len); sts = read(fd, distro_name + len, (int)sbuf.st_size); if (sts <= 0) { free(distro_name); distro_name = NULL; } else { char *nl; if (r == LSB_RELEASE) { /* may be Ubuntu */ if (!strncmp(distro_name, "DISTRIB_ID = ", 13)) distro_name += 13; /* ick */ if (!strncmp(distro_name, "DISTRIB_ID=", 11)) distro_name += 11; /* more ick */ } distro_name[sts + len] = '\0'; if ((nl = strchr(distro_name, '\n')) != NULL) *nl = '\0'; } } close(fd); } if (distro_name == NULL) distro_name = "?"; return distro_name; } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_partitions.h0000664000000000000000000000312512272262501017225 0ustar /* * Linux /proc/partitions metrics cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ typedef struct { int id; unsigned int major; unsigned int minor; unsigned long nr_blocks; char *namebuf; /* from /proc/{partitions,diskstats} */ char *udevnamebuf; /* from udev if we have it, else NULL */ unsigned long rd_ios; unsigned long rd_merges; unsigned long long rd_sectors; unsigned int rd_ticks; unsigned long wr_ios; unsigned long wr_merges; unsigned long long wr_sectors; unsigned int wr_ticks; unsigned int ios_in_flight; unsigned int io_ticks; unsigned int aveq; } partitions_entry_t; extern int refresh_proc_partitions(pmInDom disk_indom, pmInDom partitions_indom); extern int is_partitions_metric(pmID); extern int proc_partitions_fetch(pmdaMetric *, unsigned int, pmAtomValue *); pcp-3.8.12ubuntu1/src/pmdas/linux/root_linux0000664000000000000000000003631212272262501015766 0ustar /* * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * Portions Copyright (c) International Business Machines Corp., 2002 * Portions Copyright (c) 2007-2009 Aconex. All Rights Reserved. * Portions Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ root { hinv kernel mem swap network disk filesys swapdev rpc nfs nfs3 nfs4 pmda ipc vfs tmpfs sysfs } hinv { physmem 60:1:9 pagesize 60:1:11 ncpu 60:0:32 ndisk 60:0:33 nfilesys 60:5:0 ninterface 60:3:27 nlv 60:52:1 nnode 60:0:19 machine 60:18:7 map cpu } hinv.map { scsi 60:15:0 cpu_num 60:18:6 cpu_node 60:18:8 lvname 60:52:0 } hinv.cpu { clock 60:18:0 vendor 60:18:1 model 60:18:2 stepping 60:18:3 cache 60:18:4 bogomips 60:18:5 model_name 60:18:9 flags 60:18:10 cache_alignment 60:18:11 } kernel { all percpu pernode uname } kernel.all { cpu load 60:2:0 intr 60:0:12 pswitch 60:0:13 sysfork 60:0:14 hz 60:0:48 uptime 60:26:0 idletime 60:26:1 nusers 60:25:0 lastpid 60:2:1 runnable 60:2:2 nprocs 60:2:3 interrupts } kernel.all.interrupts { errors 60:4:3 } kernel.all.cpu { user 60:0:20 nice 60:0:21 sys 60:0:22 idle 60:0:23 intr 60:0:34 wait irq steal 60:0:55 guest 60:0:60 vuser 60:0:78 } kernel.all.cpu.wait { total 60:0:35 } kernel.all.cpu.irq { soft 60:0:53 hard 60:0:54 } kernel.percpu { interrupts 60:*:* cpu } kernel.percpu.cpu { user 60:0:0 nice 60:0:1 sys 60:0:2 idle 60:0:3 intr 60:0:31 wait irq steal 60:0:58 guest 60:0:61 vuser 60:0:76 } kernel.percpu.cpu.wait { total 60:0:30 } kernel.percpu.cpu.irq { soft 60:0:56 hard 60:0:57 } kernel.pernode { cpu } kernel.pernode.cpu { user 60:0:62 nice 60:0:63 sys 60:0:64 idle 60:0:65 intr 60:0:66 wait irq steal 60:0:67 guest 60:0:68 vuser 60:0:77 } kernel.pernode.cpu.wait { total 60:0:69 } kernel.pernode.cpu.irq { soft 60:0:70 hard 60:0:71 } kernel.uname { release 60:12:0 version 60:12:1 sysname 60:12:2 machine 60:12:3 nodename 60:12:4 distro 60:12:7 } ipc { sem msg shm } ipc.sem { max_semmap 60:21:0 max_semid 60:21:1 max_sem 60:21:2 num_undo 60:21:3 max_perid 60:21:4 max_ops 60:21:5 max_undoent 60:21:6 sz_semundo 60:21:7 max_semval 60:21:8 max_exit 60:21:9 } ipc.msg { sz_pool 60:22:0 mapent 60:22:1 max_msgsz 60:22:2 max_defmsgq 60:22:3 max_msgqid 60:22:4 max_msgseg 60:22:5 num_smsghdr 60:22:6 max_seg 60:22:7 } ipc.shm { max_segsz 60:23:0 min_segsz 60:23:1 max_seg 60:23:2 max_segproc 60:23:3 max_shmsys 60:23:4 } pmda { uname 60:12:5 version 60:12:6 } disk { dev all partitions } disk.dev { read 60:0:4 write 60:0:5 total 60:0:28 blkread 60:0:6 blkwrite 60:0:7 blktotal 60:0:36 read_bytes 60:0:38 write_bytes 60:0:39 total_bytes 60:0:40 read_merge 60:0:49 write_merge 60:0:50 avactive 60:0:46 read_rawactive 60:0:72 write_rawactive 60:0:73 aveq 60:0:47 scheduler 60:0:59 } disk.all { read 60:0:24 write 60:0:25 total 60:0:29 blkread 60:0:26 blkwrite 60:0:27 blktotal 60:0:37 read_bytes 60:0:41 write_bytes 60:0:42 total_bytes 60:0:43 read_merge 60:0:51 write_merge 60:0:52 avactive 60:0:44 read_rawactive 60:0:74 write_rawactive 60:0:75 aveq 60:0:45 } disk.partitions { read 60:10:0 write 60:10:1 total 60:10:2 blkread 60:10:3 blkwrite 60:10:4 blktotal 60:10:5 read_bytes 60:10:6 write_bytes 60:10:7 total_bytes 60:10:8 } mem { physmem 60:1:0 freemem 60:1:10 util numa slabinfo vmstat } mem.util { used 60:1:1 free 60:1:2 shared 60:1:3 bufmem 60:1:4 cached 60:1:5 other 60:1:12 swapCached 60:1:13 active 60:1:14 inactive 60:1:15 highTotal 60:1:16 highFree 60:1:17 lowTotal 60:1:18 lowFree 60:1:19 swapTotal 60:1:20 swapFree 60:1:21 dirty 60:1:22 writeback 60:1:23 mapped 60:1:24 slab 60:1:25 committed_AS 60:1:26 pageTables 60:1:27 reverseMaps 60:1:28 cache_clean 60:1:29 anonpages 60:1:30 commitLimit 60:1:31 bounce 60:1:32 NFS_Unstable 60:1:33 slabReclaimable 60:1:34 slabUnreclaimable 60:1:35 active_anon 60:1:36 inactive_anon 60:1:37 active_file 60:1:38 inactive_file 60:1:39 unevictable 60:1:40 mlocked 60:1:41 shmem 60:1:42 kernelStack 60:1:43 hugepagesTotal 60:1:44 hugepagesFree 60:1:45 hugepagesRsvd 60:1:46 hugepagesSurp 60:1:47 directMap4k 60:1:48 directMap2M 60:1:49 vmallocTotal 60:1:50 vmallocUsed 60:1:51 vmallocChunk 60:1:52 mmap_copy 60:1:53 quicklists 60:1:54 corrupthardware 60:1:55 anonhugepages 60:1:56 directMap1G 60:1:57 } mem.numa { util alloc } mem.numa.util { total 60:36:0 free 60:36:1 used 60:36:2 active 60:36:3 inactive 60:36:4 active_anon 60:36:5 inactive_anon 60:36:6 active_file 60:36:7 inactive_file 60:36:8 highTotal 60:36:9 highFree 60:36:10 lowTotal 60:36:11 lowFree 60:36:12 unevictable 60:36:13 mlocked 60:36:14 dirty 60:36:15 writeback 60:36:16 filePages 60:36:17 mapped 60:36:18 anonpages 60:36:19 shmem 60:36:20 kernelStack 60:36:21 pageTables 60:36:22 NFS_Unstable 60:36:23 bounce 60:36:24 writebackTmp 60:36:25 slab 60:36:26 slabReclaimable 60:36:27 slabUnreclaimable 60:36:28 hugepagesTotal 60:36:29 hugepagesFree 60:36:30 hugepagesSurp 60:36:31 } mem.numa.alloc { hit 60:36:32 miss 60:36:33 foreign 60:36:34 interleave_hit 60:36:35 local_node 60:36:36 other_node 60:36:37 } swap { pagesin 60:0:8 pagesout 60:0:9 in 60:0:10 out 60:0:11 free 60:1:8 length 60:1:6 used 60:1:7 } network { interface sockstat ip icmp icmpmsg tcp udp udplite tcpconn } network.interface { collisions 60:3:13 in out total mtu 60:3:21 speed 60:3:22 baudrate 60:3:23 duplex 60:3:24 up 60:3:25 running 60:3:26 inet_addr 60:33:0 ipv6_addr 60:33:1 ipv6_scope 60:33:2 hw_addr 60:33:3 } network.interface.in { bytes 60:3:0 packets 60:3:1 errors 60:3:2 drops 60:3:3 fifo 60:3:4 frame 60:3:5 compressed 60:3:6 mcasts 60:3:7 } network.interface.out { bytes 60:3:8 packets 60:3:9 errors 60:3:10 drops 60:3:11 fifo 60:3:12 carrier 60:3:14 compressed 60:3:15 } network.interface.total { bytes 60:3:16 packets 60:3:17 errors 60:3:18 drops 60:3:19 mcasts 60:3:20 } network.sockstat { tcp udp raw } network.sockstat.tcp { inuse 60:11:0 highest 60:11:1 util 60:11:2 } network.sockstat.udp { inuse 60:11:3 highest 60:11:4 util 60:11:5 } network.sockstat.raw { inuse 60:11:6 highest 60:11:7 util 60:11:8 } network.ip { forwarding 60:14:00 defaultttl 60:14:01 inreceives 60:14:02 inhdrerrors 60:14:03 inaddrerrors 60:14:04 forwdatagrams 60:14:05 inunknownprotos 60:14:06 indiscards 60:14:07 indelivers 60:14:08 outrequests 60:14:09 outdiscards 60:14:10 outnoroutes 60:14:11 reasmtimeout 60:14:12 reasmreqds 60:14:13 reasmoks 60:14:14 reasmfails 60:14:15 fragoks 60:14:16 fragfails 60:14:17 fragcreates 60:14:18 } network.icmp { inmsgs 60:14:20 inerrors 60:14:21 indestunreachs 60:14:22 intimeexcds 60:14:23 inparmprobs 60:14:24 insrcquenchs 60:14:25 inredirects 60:14:26 inechos 60:14:27 inechoreps 60:14:28 intimestamps 60:14:29 intimestampreps 60:14:30 inaddrmasks 60:14:31 inaddrmaskreps 60:14:32 outmsgs 60:14:33 outerrors 60:14:34 outdestunreachs 60:14:35 outtimeexcds 60:14:36 outparmprobs 60:14:37 outsrcquenchs 60:14:38 outredirects 60:14:39 outechos 60:14:40 outechoreps 60:14:41 outtimestamps 60:14:42 outtimestampreps 60:14:43 outaddrmasks 60:14:44 outaddrmaskreps 60:14:45 incsumerrors 60:14:46 } network.tcp { rtoalgorithm 60:14:50 rtomin 60:14:51 rtomax 60:14:52 maxconn 60:14:53 activeopens 60:14:54 passiveopens 60:14:55 attemptfails 60:14:56 estabresets 60:14:57 currestab 60:14:58 insegs 60:14:59 outsegs 60:14:60 retranssegs 60:14:61 inerrs 60:14:62 outrsts 60:14:63 incsumerrors 60:14:64 } network.udp { indatagrams 60:14:70 noports 60:14:71 inerrors 60:14:72 outdatagrams 60:14:74 recvbuferrors 60:14:75 sndbuferrors 60:14:76 incsumerrors 60:14:83 } network.udplite { indatagrams 60:14:77 noports 60:14:78 inerrors 60:14:79 outdatagrams 60:14:80 recvbuferrors 60:14:81 sndbuferrors 60:14:82 incsumerrors 60:14:84 } network.icmpmsg { intype 60:14:88 outtype 60:14:89 } filesys { capacity 60:5:1 used 60:5:2 free 60:5:3 maxfiles 60:5:4 usedfiles 60:5:5 freefiles 60:5:6 mountdir 60:5:7 full 60:5:8 blocksize 60:5:9 avail 60:5:10 readonly 60:5:11 } tmpfs { capacity 60:34:1 used 60:34:2 free 60:34:3 maxfiles 60:34:4 usedfiles 60:34:5 freefiles 60:34:6 full 60:34:7 } swapdev { free 60:6:0 length 60:6:1 maxswap 60:6:2 vlength 60:6:3 priority 60:6:4 } nfs { client server } nfs.client { calls 60:7:1 reqs 60:7:4 } nfs.server { calls 60:7:50 reqs 60:7:12 } rpc { client server } rpc.client { rpccnt 60:7:20 rpcretrans 60:7:21 rpcauthrefresh 60:7:22 netcnt 60:7:24 netudpcnt 60:7:25 nettcpcnt 60:7:26 nettcpconn 60:7:27 } rpc.server { rpccnt 60:7:30 rpcerr 60:7:31 rpcbadfmt 60:7:32 rpcbadauth 60:7:33 rpcbadclnt 60:7:34 rchits 60:7:35 rcmisses 60:7:36 rcnocache 60:7:37 fh_cached 60:7:38 fh_valid 60:7:39 fh_fixup 60:7:40 fh_lookup 60:7:41 fh_stale 60:7:42 fh_concurrent 60:7:43 netcnt 60:7:44 netudpcnt 60:7:45 nettcpcnt 60:7:46 nettcpconn 60:7:47 fh_anon 60:7:51 fh_nocache_dir 60:7:52 fh_nocache_nondir 60:7:53 io_read 60:7:54 io_write 60:7:55 th_cnt 60:7:56 th_fullcnt 60:7:57 } nfs3 { client server } nfs3.client { calls 60:7:60 reqs 60:7:61 } nfs3.server { calls 60:7:62 reqs 60:7:63 } nfs4 { client server } nfs4.client { calls 60:7:64 reqs 60:7:65 } nfs4.server { calls 60:7:66 reqs 60:7:67 } network.tcpconn { established 60:19:1 syn_sent 60:19:2 syn_recv 60:19:3 fin_wait1 60:19:4 fin_wait2 60:19:5 time_wait 60:19:6 close 60:19:7 close_wait 60:19:8 last_ack 60:19:9 listen 60:19:10 closing 60:19:11 } mem.slabinfo { objects slabs } mem.slabinfo.objects { active 60:20:0 total 60:20:1 size 60:20:2 } mem.slabinfo.slabs { active 60:20:3 total 60:20:4 pages_per_slab 60:20:5 objects_per_slab 60:20:6 total_size 60:20:7 } mem.vmstat { /* sorted by name to make maintenance easier */ allocstall 60:28:35 compact_blocks_moved 60:28:57 compact_fail 60:28:58 compact_pagemigrate_failed 60:28:59 compact_pages_moved 60:28:60 compact_stall 60:28:61 compact_success 60:28:62 htlb_buddy_alloc_fail 60:28:43 htlb_buddy_alloc_success 60:28:44 kswapd_inodesteal 60:28:33 kswapd_low_wmark_hit_quickly 60:28:87 kswapd_high_wmark_hit_quickly 60:28:88 kswapd_skip_congestion_wait 60:28:89 kswapd_steal 60:28:32 nr_active_anon 60:28:45 nr_active_file 60:28:46 nr_anon_pages 60:28:39 nr_anon_transparent_hugepages 60:28:90 nr_bounce 60:28:40 nr_dirtied 60:28:91 nr_dirty 60:28:0 nr_dirty_background_threshold 60:28:92 nr_dirty_threshold 60:28:93 nr_free_pages 60:28:47 nr_inactive_anon 60:28:48 nr_inactive_file 60:28:49 nr_isolated_anon 60:28:50 nr_isolated_file 60:28:51 nr_kernel_stack 60:28:52 nr_mapped 60:28:4 nr_mlock 60:28:53 nr_page_table_pages 60:28:3 nr_shmem 60:28:54 nr_slab 60:28:5 nr_slab_reclaimable 60:28:37 nr_slab_unreclaimable 60:28:38 nr_unevictable 60:28:55 nr_unstable 60:28:2 nr_vmscan_write 60:28:42 nr_writeback 60:28:1 nr_writeback_temp 60:28:56 nr_written 60:28:94 numa_foreign 60:28:95 numa_hit 60:28:96 numa_interleave 60:28:97 numa_local 60:28:98 numa_miss 60:28:99 numa_other 60:28:100 pageoutrun 60:28:34 pgactivate 60:28:14 pgalloc_dma 60:28:12 pgalloc_dma32 60:28:63 pgalloc_high 60:28:10 pgalloc_movable 60:28:64 pgalloc_normal 60:28:11 pgrefill_dma32 60:28:65 pgrefill_movable 60:28:66 pgdeactivate 60:28:15 pgfault 60:28:16 pgfree 60:28:13 pginodesteal 60:28:30 pgmajfault 60:28:17 pgpgin 60:28:6 pgpgout 60:28:7 pgrefill_dma 60:28:20 pgrefill_high 60:28:18 pgrefill_normal 60:28:19 pgrotated 60:28:36 pgscan_direct_dma 60:28:29 pgscan_direct_dma32 60:28:67 pgscan_direct_high 60:28:27 pgscan_direct_movable 60:28:68 pgscan_direct_normal 60:28:28 pgscan_kswapd_dma 60:28:26 pgscan_kswapd_dma32 60:28:69 pgscan_kswapd_high 60:28:24 pgscan_kswapd_movable 60:28:70 pgscan_kswapd_normal 60:28:25 pgsteal_dma 60:28:23 pgsteal_dma32 60:28:71 pgsteal_high 60:28:21 pgsteal_movable 60:28:72 pgsteal_normal 60:28:22 pswpin 60:28:8 pswpout 60:28:9 slabs_scanned 60:28:31 thp_fault_alloc 60:28:73 thp_fault_fallback 60:28:74 thp_collapse_alloc 60:28:75 thp_collapse_alloc_failed 60:28:76 thp_split 60:28:77 unevictable_pgs_cleared 60:28:78 unevictable_pgs_culled 60:28:79 unevictable_pgs_mlocked 60:28:80 unevictable_pgs_mlockfreed 60:28:81 unevictable_pgs_munlocked 60:28:82 unevictable_pgs_rescued 60:28:83 unevictable_pgs_scanned 60:28:84 unevictable_pgs_stranded 60:28:85 zone_reclaim_failed 60:28:86 } vfs { files inodes dentry } vfs.files { count 60:27:0 free 60:27:1 max 60:27:2 } vfs.inodes { count 60:27:3 free 60:27:4 } vfs.dentry { count 60:27:5 free 60:27:6 } sysfs { kernel } sysfs.kernel { uevent_seqnum 60:35:0 } pcp-3.8.12ubuntu1/src/pmdas/linux/numa_meminfo.c0000664000000000000000000001062312272262501016454 0ustar /* * Linux NUMA meminfo metrics cluster from sysfs * * Copyright (c) 2012 Red Hat. * Copyright (c) 2009 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "indom.h" #include "linux_table.h" #include "proc_cpuinfo.h" #include "proc_stat.h" #include "numa_meminfo.h" /* sysfs file for numa meminfo */ static struct linux_table numa_meminfo_table[] = { { field: "MemTotal:", maxval: 0x0 }, { field: "MemFree:", maxval: 0x0 }, { field: "MemUsed:", maxval: 0x0 }, { field: "Active:", maxval: 0x0 }, { field: "Inactive:", maxval: 0x0 }, { field: "Active(anon):", maxval: 0x0 }, { field: "Inactive(anon):", maxval: 0x0 }, { field: "Active(file):", maxval: 0x0 }, { field: "Inactive(file):", maxval: 0x0 }, { field: "HighTotal:", maxval: 0x0 }, { field: "HighFree:", maxval: 0x0 }, { field: "LowTotal:", maxval: 0x0 }, { field: "LowFree:", maxval: 0x0 }, { field: "Unevictable:", maxval: 0x0 }, { field: "Mlocked:", maxval: 0x0 }, { field: "Dirty:", maxval: 0x0 }, { field: "Writeback:", maxval: 0x0 }, { field: "FilePages:", maxval: 0x0 }, { field: "Mapped:", maxval: 0x0 }, { field: "AnonPages:", maxval: 0x0 }, { field: "Shmem:", maxval: 0x0 }, { field: "KernelStack:", maxval: 0x0 }, { field: "PageTables:", maxval: 0x0 }, { field: "NFS_Unstable:", maxval: 0x0 }, { field: "Bounce:", maxval: 0x0 }, { field: "WritebackTmp:", maxval: 0x0 }, { field: "Slab:", maxval: 0x0 }, { field: "SReclaimable:", maxval: 0x0 }, { field: "SUnreclaim:", maxval: 0x0 }, { field: "HugePages_Total:", maxval: 0x0 }, { field: "HugePages_Free:", maxval: 0x0 }, { field: "HugePages_Surp:", maxval: 0x0 }, { field: NULL } }; /* sysfs file for numastat */ static struct linux_table numa_memstat_table[] = { { field: "numa_hit", maxval: ULONGLONG_MAX }, { field: "numa_miss", maxval: ULONGLONG_MAX }, { field: "numa_foreign", maxval: ULONGLONG_MAX }, { field: "interleave_hit", maxval: ULONGLONG_MAX }, { field: "local_node", maxval: ULONGLONG_MAX }, { field: "other_node", maxval: ULONGLONG_MAX }, { field: NULL } }; int refresh_numa_meminfo(numa_meminfo_t *numa_meminfo, proc_cpuinfo_t *proc_cpuinfo, proc_stat_t *proc_stat) { int i; FILE *fp; pmdaIndom *idp = PMDAINDOM(NODE_INDOM); static int started; /* First time only */ if (!started) { refresh_proc_stat(proc_cpuinfo, proc_stat); if (!numa_meminfo->node_info) /* may have allocated this, but failed below */ numa_meminfo->node_info = (nodeinfo_t *)calloc(idp->it_numinst, sizeof(nodeinfo_t)); if (!numa_meminfo->node_info) { fprintf(stderr, "%s: error allocating numa node_info: %s\n", __FUNCTION__, osstrerror()); return -1; } for (i = 0; i < idp->it_numinst; i++) { numa_meminfo->node_info[i].meminfo = linux_table_clone(numa_meminfo_table); if (!numa_meminfo->node_info[i].meminfo) { fprintf(stderr, "%s: error allocating meminfo: %s\n", __FUNCTION__, osstrerror()); return -1; } numa_meminfo->node_info[i].memstat = linux_table_clone(numa_memstat_table); if (!numa_meminfo->node_info[i].memstat) { fprintf(stderr, "%s: error allocating memstat: %s\n", __FUNCTION__, osstrerror()); return -1; } } numa_meminfo->node_indom = idp; started = 1; } /* Refresh */ for (i = 0; i < idp->it_numinst; i++) { char buf[1024]; sprintf(buf, "/sys/devices/system/node/node%d/meminfo", i); if ((fp = fopen(buf, "r")) != NULL) { linux_table_scan(fp, numa_meminfo->node_info[i].meminfo); fclose(fp); } sprintf(buf, "/sys/devices/system/node/node%d/numastat", i); if ((fp = fopen(buf, "r")) != NULL) { linux_table_scan(fp, numa_meminfo->node_info[i].memstat); fclose(fp); } } return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/pmda.c0000664000000000000000000050663212272262501014735 0ustar /* * Linux PMDA * * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 2007-2011 Aconex. All Rights Reserved. * Copyright (c) 2002 International Business Machines Corp. * Copyright (c) 2000,2004,2007-2008 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #undef LINUX /* defined in NSS/NSPR headers as something different, which we do not need. */ #include "domain.h" #include #include #include #include #include #include #include #include #include "convert.h" #include "clusters.h" #include "indom.h" #include "proc_cpuinfo.h" #include "proc_stat.h" #include "proc_meminfo.h" #include "proc_loadavg.h" #include "proc_net_dev.h" #include "filesys.h" #include "swapdev.h" #include "getinfo.h" #include "proc_net_rpc.h" #include "proc_net_sockstat.h" #include "proc_net_tcp.h" #include "proc_partitions.h" #include "proc_net_snmp.h" #include "proc_scsi.h" #include "proc_slabinfo.h" #include "proc_uptime.h" #include "sem_limits.h" #include "msg_limits.h" #include "shm_limits.h" #include "proc_sys_fs.h" #include "proc_vmstat.h" #include "sysfs_kernel.h" #include "linux_table.h" #include "numa_meminfo.h" #include "interrupts.h" #include "devmapper.h" static proc_stat_t proc_stat; static proc_meminfo_t proc_meminfo; static proc_loadavg_t proc_loadavg; static proc_net_rpc_t proc_net_rpc; static proc_net_tcp_t proc_net_tcp; static proc_net_sockstat_t proc_net_sockstat; static struct utsname kernel_uname; static char uname_string[sizeof(kernel_uname)]; static proc_scsi_t proc_scsi; static dev_mapper_t dev_mapper; static proc_cpuinfo_t proc_cpuinfo; static proc_slabinfo_t proc_slabinfo; static sem_limits_t sem_limits; static msg_limits_t msg_limits; static shm_limits_t shm_limits; static proc_uptime_t proc_uptime; static proc_sys_fs_t proc_sys_fs; static sysfs_kernel_t sysfs_kernel; static numa_meminfo_t numa_meminfo; static int _isDSO = 1; /* =0 I am a daemon */ static char *username; /* globals */ size_t _pm_system_pagesize; /* for hinv.pagesize and used elsewhere */ int _pm_have_proc_vmstat; /* if /proc/vmstat is available */ int _pm_intr_size; /* size in bytes of interrupt sum count metric */ int _pm_ctxt_size; /* size in bytes of context switch count metric */ int _pm_cputime_size; /* size in bytes of most of the cputime metrics */ int _pm_idletime_size; /* size in bytes of the idle cputime metric */ proc_vmstat_t _pm_proc_vmstat; proc_net_snmp_t _pm_proc_net_snmp; pmdaInstid _pm_proc_net_snmp_indom_id[NR_ICMPMSG_COUNTERS]; /* * Metric Instance Domains (statically initialized ones only) */ static pmdaInstid loadavg_indom_id[] = { { 1, "1 minute" }, { 5, "5 minute" }, { 15, "15 minute" } }; static pmdaInstid nfs_indom_id[] = { { 0, "null" }, { 1, "getattr" }, { 2, "setattr" }, { 3, "root" }, { 4, "lookup" }, { 5, "readlink" }, { 6, "read" }, { 7, "wrcache" }, { 8, "write" }, { 9, "create" }, { 10, "remove" }, { 11, "rename" }, { 12, "link" }, { 13, "symlink" }, { 14, "mkdir" }, { 15, "rmdir" }, { 16, "readdir" }, { 17, "statfs" } }; static pmdaInstid nfs3_indom_id[] = { { 0, "null" }, { 1, "getattr" }, { 2, "setattr" }, { 3, "lookup" }, { 4, "access" }, { 5, "readlink" }, { 6, "read" }, { 7, "write" }, { 8, "create" }, { 9, "mkdir" }, { 10, "symlink" }, { 11, "mknod" }, { 12, "remove" }, { 13, "rmdir" }, { 14, "rename" }, { 15, "link" }, { 16, "readdir" }, { 17, "readdir+" }, { 18, "statfs" }, { 19, "fsinfo" }, { 20, "pathconf" }, { 21, "commit" } }; static pmdaInstid nfs4_cli_indom_id[] = { { 0, "null" }, { 1, "read" }, { 2, "write" }, { 3, "commit" }, { 4, "open" }, { 5, "open_conf" }, { 6, "open_noat" }, { 7, "open_dgrd" }, { 8, "close" }, { 9, "setattr" }, { 10, "fsinfo" }, { 11, "renew" }, { 12, "setclntid" }, { 13, "confirm" }, { 14, "lock" }, { 15, "lockt" }, { 16, "locku" }, { 17, "access" }, { 18, "getattr" }, { 19, "lookup" }, { 20, "lookup_root" }, { 21, "remove" }, { 22, "rename" }, { 23, "link" }, { 24, "symlink" }, { 25, "create" }, { 26, "pathconf" }, { 27, "statfs" }, { 28, "readlink" }, { 29, "readdir" }, { 30, "server_caps" }, { 31, "delegreturn" }, { 32, "getacl" }, { 33, "setacl" }, { 34, "fs_locatns" }, }; static pmdaInstid nfs4_svr_indom_id[] = { { 0, "null" }, { 1, "op0-unused" }, { 2, "op1-unused"}, { 3, "minorversion"}, /* future use */ { 4, "access" }, { 5, "close" }, { 6, "commit" }, { 7, "create" }, { 8, "delegpurge" }, { 9, "delegreturn" }, { 10, "getattr" }, { 11, "getfh" }, { 12, "link" }, { 13, "lock" }, { 14, "lockt" }, { 15, "locku" }, { 16, "lookup" }, { 17, "lookup_root" }, { 18, "nverify" }, { 19, "open" }, { 20, "openattr" }, { 21, "open_conf" }, { 22, "open_dgrd" }, { 23, "putfh" }, { 24, "putpubfh" }, { 25, "putrootfh" }, { 26, "read" }, { 27, "readdir" }, { 28, "readlink" }, { 29, "remove" }, { 30, "rename" }, { 31, "renew" }, { 32, "restorefh" }, { 33, "savefh" }, { 34, "secinfo" }, { 35, "setattr" }, { 36, "setcltid" }, { 37, "setcltidconf" }, { 38, "verify" }, { 39, "write" }, { 40, "rellockowner" }, }; static pmdaIndom indomtab[] = { { CPU_INDOM, 0, NULL }, { DISK_INDOM, 0, NULL }, /* cached */ { LOADAVG_INDOM, 3, loadavg_indom_id }, { NET_DEV_INDOM, 0, NULL }, { PROC_INTERRUPTS_INDOM, 0, NULL }, /* deprecated */ { FILESYS_INDOM, 0, NULL }, { SWAPDEV_INDOM, 0, NULL }, { NFS_INDOM, NR_RPC_COUNTERS, nfs_indom_id }, { NFS3_INDOM, NR_RPC3_COUNTERS, nfs3_indom_id }, { PROC_PROC_INDOM, 0, NULL }, /* migrated to the proc PMDA */ { PARTITIONS_INDOM, 0, NULL }, /* cached */ { SCSI_INDOM, 0, NULL }, { SLAB_INDOM, 0, NULL }, { STRINGS_INDOM, 0, NULL }, { NFS4_CLI_INDOM, NR_RPC4_CLI_COUNTERS, nfs4_cli_indom_id }, { NFS4_SVR_INDOM, NR_RPC4_SVR_COUNTERS, nfs4_svr_indom_id }, { QUOTA_PRJ_INDOM, 0, NULL }, /* migrated to the xfs PMDA */ { NET_ADDR_INDOM, 0, NULL }, { TMPFS_INDOM, 0, NULL }, { NODE_INDOM, 0, NULL }, { PROC_CGROUP_SUBSYS_INDOM, 0, NULL }, { PROC_CGROUP_MOUNTS_INDOM, 0, NULL }, { LV_INDOM, 0, NULL }, { ICMPMSG_INDOM, NR_ICMPMSG_COUNTERS, _pm_proc_net_snmp_indom_id }, }; /* * all metrics supported in this PMDA - one table entry for each */ static pmdaMetric metrictab[] = { /* * /proc/stat cluster */ /* kernel.percpu.cpu.user */ { NULL, { PMDA_PMID(CLUSTER_STAT,0), KERNEL_UTYPE, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.nice */ { NULL, { PMDA_PMID(CLUSTER_STAT,1), KERNEL_UTYPE, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.sys */ { NULL, { PMDA_PMID(CLUSTER_STAT,2), KERNEL_UTYPE, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.idle */ { NULL, { PMDA_PMID(CLUSTER_STAT,3), KERNEL_UTYPE, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.wait.total */ { NULL, { PMDA_PMID(CLUSTER_STAT,30), KERNEL_UTYPE, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.intr */ { NULL, { PMDA_PMID(CLUSTER_STAT,31), KERNEL_UTYPE, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.irq.soft */ { NULL, { PMDA_PMID(CLUSTER_STAT,56), KERNEL_UTYPE, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.irq.hard */ { NULL, { PMDA_PMID(CLUSTER_STAT,57), KERNEL_UTYPE, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.steal */ { NULL, { PMDA_PMID(CLUSTER_STAT,58), KERNEL_UTYPE, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.guest */ { NULL, { PMDA_PMID(CLUSTER_STAT,61), KERNEL_UTYPE, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.percpu.cpu.vuser */ { NULL, { PMDA_PMID(CLUSTER_STAT,76), KERNEL_UTYPE, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.pernode.cpu.user */ { NULL, { PMDA_PMID(CLUSTER_STAT,62), KERNEL_UTYPE, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.pernode.cpu.nice */ { NULL, { PMDA_PMID(CLUSTER_STAT,63), KERNEL_UTYPE, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.pernode.cpu.sys */ { NULL, { PMDA_PMID(CLUSTER_STAT,64), KERNEL_UTYPE, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.pernode.cpu.idle */ { NULL, { PMDA_PMID(CLUSTER_STAT,65), KERNEL_UTYPE, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.pernode.cpu.wait.total */ { NULL, { PMDA_PMID(CLUSTER_STAT,69), KERNEL_UTYPE, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.pernode.cpu.intr */ { NULL, { PMDA_PMID(CLUSTER_STAT,66), KERNEL_UTYPE, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.pernode.cpu.irq.soft */ { NULL, { PMDA_PMID(CLUSTER_STAT,70), KERNEL_UTYPE, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.pernode.cpu.irq.hard */ { NULL, { PMDA_PMID(CLUSTER_STAT,71), KERNEL_UTYPE, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.pernode.cpu.steal */ { NULL, { PMDA_PMID(CLUSTER_STAT,67), KERNEL_UTYPE, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.pernode.cpu.guest */ { NULL, { PMDA_PMID(CLUSTER_STAT,68), KERNEL_UTYPE, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.pernode.cpu.vuser */ { NULL, { PMDA_PMID(CLUSTER_STAT,77), KERNEL_UTYPE, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* disk.dev.read */ { NULL, { PMDA_PMID(CLUSTER_STAT,4), KERNEL_ULONG, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.write */ { NULL, { PMDA_PMID(CLUSTER_STAT,5), KERNEL_ULONG, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.blkread */ { NULL, { PMDA_PMID(CLUSTER_STAT,6), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.blkwrite */ { NULL, { PMDA_PMID(CLUSTER_STAT,7), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.avactive */ { NULL, { PMDA_PMID(CLUSTER_STAT,46), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* disk.dev.aveq */ { NULL, { PMDA_PMID(CLUSTER_STAT,47), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* disk.dev.read_merge */ { NULL, { PMDA_PMID(CLUSTER_STAT,49), KERNEL_ULONG, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.write_merge */ { NULL, { PMDA_PMID(CLUSTER_STAT,50), KERNEL_ULONG, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.scheduler */ { NULL, { PMDA_PMID(CLUSTER_STAT,59), PM_TYPE_STRING, DISK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* disk.dev.read_rawactive */ { NULL, { PMDA_PMID(CLUSTER_STAT,72), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* disk.dev.write_rawactive */ { NULL, { PMDA_PMID(CLUSTER_STAT,73), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* disk.all.avactive */ { NULL, { PMDA_PMID(CLUSTER_STAT,44), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* disk.all.aveq */ { NULL, { PMDA_PMID(CLUSTER_STAT,45), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* disk.all.read_merge */ { NULL, { PMDA_PMID(CLUSTER_STAT,51), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.write_merge */ { NULL, { PMDA_PMID(CLUSTER_STAT,52), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.read_rawactive */ { NULL, { PMDA_PMID(CLUSTER_STAT,74), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* disk.all.read_rawactive */ { NULL, { PMDA_PMID(CLUSTER_STAT,75), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* swap.pagesin */ { NULL, { PMDA_PMID(CLUSTER_STAT,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* swap.pagesout */ { NULL, { PMDA_PMID(CLUSTER_STAT,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* swap.in */ { NULL, { PMDA_PMID(CLUSTER_STAT,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* swap.out */ { NULL, { PMDA_PMID(CLUSTER_STAT,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* kernel.all.intr */ { NULL, { PMDA_PMID(CLUSTER_STAT,12), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* kernel.all.pswitch */ { NULL, { PMDA_PMID(CLUSTER_STAT,13), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* kernel.all.sysfork */ { NULL, { PMDA_PMID(CLUSTER_STAT,14), KERNEL_ULONG, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* kernel.all.cpu.user */ { NULL, { PMDA_PMID(CLUSTER_STAT,20), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.nice */ { NULL, { PMDA_PMID(CLUSTER_STAT,21), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.sys */ { NULL, { PMDA_PMID(CLUSTER_STAT,22), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.idle */ { NULL, { PMDA_PMID(CLUSTER_STAT,23), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.intr */ { NULL, { PMDA_PMID(CLUSTER_STAT,34), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.wait.total */ { NULL, { PMDA_PMID(CLUSTER_STAT,35), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.irq.soft */ { NULL, { PMDA_PMID(CLUSTER_STAT,53), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.irq.hard */ { NULL, { PMDA_PMID(CLUSTER_STAT,54), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.steal */ { NULL, { PMDA_PMID(CLUSTER_STAT,55), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.guest */ { NULL, { PMDA_PMID(CLUSTER_STAT,60), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* kernel.all.cpu.vuser */ { NULL, { PMDA_PMID(CLUSTER_STAT,78), KERNEL_UTYPE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, }, /* disk.all.read */ { NULL, { PMDA_PMID(CLUSTER_STAT,24), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.write */ { NULL, { PMDA_PMID(CLUSTER_STAT,25), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.blkread */ { NULL, { PMDA_PMID(CLUSTER_STAT,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.blkwrite */ { NULL, { PMDA_PMID(CLUSTER_STAT,27), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.total */ { NULL, { PMDA_PMID(CLUSTER_STAT,28), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.dev.blktotal */ { NULL, { PMDA_PMID(CLUSTER_STAT,36), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.total */ { NULL, { PMDA_PMID(CLUSTER_STAT,29), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.all.blktotal */ { NULL, { PMDA_PMID(CLUSTER_STAT,37), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* hinv.ncpu */ { NULL, { PMDA_PMID(CLUSTER_STAT,32), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* hinv.ndisk */ { NULL, { PMDA_PMID(CLUSTER_STAT,33), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* hinv.nnode */ { NULL, { PMDA_PMID(CLUSTER_STAT,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* kernel.all.hz */ { NULL, { PMDA_PMID(CLUSTER_STAT,48), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE) }, }, /* * /proc/uptime cluster * Uptime modified and idletime added by Mike Mason */ /* kernel.all.uptime */ { NULL, { PMDA_PMID(CLUSTER_UPTIME,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, }, /* kernel.all.idletime */ { NULL, { PMDA_PMID(CLUSTER_UPTIME,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, }, /* * /proc/meminfo cluster */ /* mem.physmem */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.used */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.free */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.shared */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.bufmem */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.cached */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.active */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.inactive */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.swapCached */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,13), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.highTotal */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.highFree */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.lowTotal */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,18), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.lowFree */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,19), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.swapTotal */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,20), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.swapFree */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,21), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.dirty */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,22), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.writeback */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,23), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.mapped */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,24), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.slab */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,25), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.committed_AS */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.pageTables */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,27), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.reverseMaps */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,28), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.cache_clean */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,29), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.anonpages */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,30), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.commitLimit */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,31), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.bounce */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,32), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.NFS_Unstable */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,33), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.slabReclaimable */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,34), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.slabUnreclaimable */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,35), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.active_anon */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,36), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.inactive_anon */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,37), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.active_file */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,38), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.inactive_file */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,39), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.unevictable */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,40), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.mlocked */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,41), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.shmem */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,42), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.kernelStack */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,43), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.hugepagesTotal */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,44), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.util.hugepagesFree */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,45), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.util.hugepagesRsvd */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,46), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.util.hugepagesSurp */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,47), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.util.directMap4k */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,48), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.directMap2M */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,49), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.vmallocTotal */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,50), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.vmallocUsed */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,51), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.vmallocChunk */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,52), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.mmap_copy */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,53), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.quicklists */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,54), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.corrupthardware */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,55), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.mmap_copy */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,56), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.util.directMap1G */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,57), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.total */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,0), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.free */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,1), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.used */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,2), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.active */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,3), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.inactive */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,4), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.active_anon */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,5), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.inactive_anon */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,6), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.active_file */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,7), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.inactive_file */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,8), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.highTotal */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,9), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.highFree */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,10), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.lowTotal */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,11), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.lowFree */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,12), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.unevictable */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,13), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.mlocked */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,14), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.dirty */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,15), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.writeback */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,16), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.filePages */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,17), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.mapped */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,18), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.anonpages */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,19), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.shmem */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,20), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.kernelStack */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,21), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.pageTables */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,22), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.NFS_Unstable */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,23), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.bounce */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,24), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.writebackTmp */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,25), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.slab */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,26), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.slabReclaimable */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,27), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.slabUnreclaimable */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,28), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* mem.numa.util.hugepagesTotal */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,29), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.numa.util.hugepagesFree */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,30), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.numa.util.hugepagesSurp */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,31), PM_TYPE_U64, NODE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.numa.alloc.hit */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,32), PM_TYPE_U64, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.numa.alloc.miss */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,33), PM_TYPE_U64, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.numa.alloc.foreign */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,34), PM_TYPE_U64, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.numa.alloc.interleave_hit */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,35), PM_TYPE_U64, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.numa.alloc.local_node */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,36), PM_TYPE_U64, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.numa.alloc.other_node */ { NULL, { PMDA_PMID(CLUSTER_NUMA_MEMINFO,37), PM_TYPE_U64, NODE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* swap.length */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* swap.used */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* swap.free */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* hinv.physmem */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_MBYTE,0,0) }, }, /* mem.freemem */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* hinv.pagesize */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* mem.util.other */ { NULL, { PMDA_PMID(CLUSTER_MEMINFO,12), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* * /proc/slabinfo cluster */ /* mem.slabinfo.objects.active */ { NULL, { PMDA_PMID(CLUSTER_SLAB,0), PM_TYPE_U64, SLAB_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* mem.slabinfo.objects.total */ { NULL, { PMDA_PMID(CLUSTER_SLAB,1), PM_TYPE_U64, SLAB_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* mem.slabinfo.objects.size */ { NULL, { PMDA_PMID(CLUSTER_SLAB,2), PM_TYPE_U32, SLAB_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* mem.slabinfo.slabs.active */ { NULL, { PMDA_PMID(CLUSTER_SLAB,3), PM_TYPE_U32, SLAB_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* mem.slabinfo.slabs.total */ { NULL, { PMDA_PMID(CLUSTER_SLAB,4), PM_TYPE_U32, SLAB_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* mem.slabinfo.slabs.pages_per_slab */ { NULL, { PMDA_PMID(CLUSTER_SLAB,5), PM_TYPE_U32, SLAB_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* mem.slabinfo.slabs.objects_per_slab */ { NULL, { PMDA_PMID(CLUSTER_SLAB,6), PM_TYPE_U32, SLAB_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* mem.slabinfo.slabs.total_size */ { NULL, { PMDA_PMID(CLUSTER_SLAB,7), PM_TYPE_U64, SLAB_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* * /proc/loadavg cluster */ /* kernel.all.load */ { NULL, { PMDA_PMID(CLUSTER_LOADAVG,0), PM_TYPE_FLOAT, LOADAVG_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* kernel.all.lastpid -- added by Mike Mason */ { NULL, { PMDA_PMID(CLUSTER_LOADAVG, 1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* kernel.all.runnable */ { NULL, { PMDA_PMID(CLUSTER_LOADAVG, 2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* kernel.all.nprocs */ { NULL, { PMDA_PMID(CLUSTER_LOADAVG, 3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* * /proc/net/dev cluster */ /* network.interface.in.bytes */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,0), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* network.interface.in.packets */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,1), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.in.errors */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,2), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.in.drops */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,3), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.in.fifo */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,4), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.in.frame */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,5), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.in.compressed */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,6), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.in.mcasts */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,7), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.out.bytes */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,8), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* network.interface.out.packets */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,9), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.out.errors */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,10), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.out.drops */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,11), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.out.fifo */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,12), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.collisions */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,13), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.out.carrier */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,14), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.out.compressed */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,15), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.total.bytes */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,16), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,0,PM_SPACE_BYTE,0) }, }, /* network.interface.total.packets */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,17), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.total.errors */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,18), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.total.drops */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,19), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.total.mcasts */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,20), PM_TYPE_U64, NET_DEV_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* network.interface.mtu */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,21), PM_TYPE_U32, NET_DEV_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,0,PM_SPACE_BYTE,0) }, }, /* network.interface.speed */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,22), PM_TYPE_FLOAT, NET_DEV_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,-1,0,PM_SPACE_MBYTE,PM_TIME_SEC,0) }, }, /* network.interface.baudrate */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,23), PM_TYPE_U32, NET_DEV_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_SEC,0) }, }, /* network.interface.duplex */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,24), PM_TYPE_U32, NET_DEV_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* network.interface.up */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,25), PM_TYPE_U32, NET_DEV_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* network.interface.running */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,26), PM_TYPE_U32, NET_DEV_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* hinv.ninterface */ { NULL, { PMDA_PMID(CLUSTER_NET_DEV,27), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* network.interface.inet_addr */ { NULL, { PMDA_PMID(CLUSTER_NET_ADDR,0), PM_TYPE_STRING, NET_ADDR_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* network.interface.ipv6_addr */ { NULL, { PMDA_PMID(CLUSTER_NET_ADDR,1), PM_TYPE_STRING, NET_ADDR_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* network.interface.ipv6_scope */ { NULL, { PMDA_PMID(CLUSTER_NET_ADDR,2), PM_TYPE_STRING, NET_ADDR_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* network.interface.hw_addr */ { NULL, { PMDA_PMID(CLUSTER_NET_ADDR,3), PM_TYPE_STRING, NET_ADDR_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* * filesys cluster */ /* hinv.nmounts */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* filesys.capacity */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,1), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* filesys.used */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,2), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* filesys.free */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,3), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* filesys.maxfiles */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,4), PM_TYPE_U32, FILESYS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* filesys.usedfiles */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,5), PM_TYPE_U32, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* filesys.freefiles */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,6), PM_TYPE_U32, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* filesys.mountdir */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,7), PM_TYPE_STRING, FILESYS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* filesys.full */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,8), PM_TYPE_DOUBLE, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* filesys.blocksize */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,9), PM_TYPE_U32, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, /* filesys.avail */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,10), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* filesys.readonly */ { NULL, { PMDA_PMID(CLUSTER_FILESYS,11), PM_TYPE_U32, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* * tmpfs filesystem cluster */ /* tmpfs.capacity */ { NULL, { PMDA_PMID(CLUSTER_TMPFS,1), PM_TYPE_U64, TMPFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* tmpfs.used */ { NULL, { PMDA_PMID(CLUSTER_TMPFS,2), PM_TYPE_U64, TMPFS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* tmpfs.free */ { NULL, { PMDA_PMID(CLUSTER_TMPFS,3), PM_TYPE_U64, TMPFS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* tmpfs.maxfiles */ { NULL, { PMDA_PMID(CLUSTER_TMPFS,4), PM_TYPE_U32, TMPFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* tmpfs.usedfiles */ { NULL, { PMDA_PMID(CLUSTER_TMPFS,5), PM_TYPE_U32, TMPFS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* tmpfs.freefiles */ { NULL, { PMDA_PMID(CLUSTER_TMPFS,6), PM_TYPE_U32, TMPFS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* tmpfs.full */ { NULL, { PMDA_PMID(CLUSTER_TMPFS,7), PM_TYPE_DOUBLE, TMPFS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* * swapdev cluster */ /* swapdev.free */ { NULL, { PMDA_PMID(CLUSTER_SWAPDEV,0), PM_TYPE_U32, SWAPDEV_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* swapdev.length */ { NULL, { PMDA_PMID(CLUSTER_SWAPDEV,1), PM_TYPE_U32, SWAPDEV_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* swapdev.maxswap */ { NULL, { PMDA_PMID(CLUSTER_SWAPDEV,2), PM_TYPE_U32, SWAPDEV_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* swapdev.vlength */ { NULL, { PMDA_PMID(CLUSTER_SWAPDEV,3), PM_TYPE_U32, SWAPDEV_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* swapdev.priority */ { NULL, { PMDA_PMID(CLUSTER_SWAPDEV,4), PM_TYPE_32, SWAPDEV_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* * socket stat cluster */ /* network.sockstat.tcp.inuse */ { &proc_net_sockstat.tcp[_PM_SOCKSTAT_INUSE], { PMDA_PMID(CLUSTER_NET_SOCKSTAT,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.sockstat.tcp.highest */ { &proc_net_sockstat.tcp[_PM_SOCKSTAT_HIGHEST], { PMDA_PMID(CLUSTER_NET_SOCKSTAT,1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.sockstat.tcp.util */ { &proc_net_sockstat.tcp[_PM_SOCKSTAT_UTIL], { PMDA_PMID(CLUSTER_NET_SOCKSTAT,2), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* network.sockstat.udp.inuse */ { &proc_net_sockstat.udp[_PM_SOCKSTAT_INUSE], { PMDA_PMID(CLUSTER_NET_SOCKSTAT,3), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.sockstat.udp.highest */ { &proc_net_sockstat.udp[_PM_SOCKSTAT_HIGHEST], { PMDA_PMID(CLUSTER_NET_SOCKSTAT,4), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.sockstat.udp.util */ { &proc_net_sockstat.udp[_PM_SOCKSTAT_UTIL], { PMDA_PMID(CLUSTER_NET_SOCKSTAT,5), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* network.sockstat.raw.inuse */ { &proc_net_sockstat.raw[_PM_SOCKSTAT_INUSE], { PMDA_PMID(CLUSTER_NET_SOCKSTAT,6), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.sockstat.raw.highest */ { &proc_net_sockstat.raw[_PM_SOCKSTAT_HIGHEST], { PMDA_PMID(CLUSTER_NET_SOCKSTAT,7), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.sockstat.raw.util */ { &proc_net_sockstat.raw[_PM_SOCKSTAT_UTIL], { PMDA_PMID(CLUSTER_NET_SOCKSTAT,8), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* * nfs cluster */ /* nfs.client.calls */ { NULL, { PMDA_PMID(CLUSTER_NET_NFS,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* nfs.client.reqs */ { NULL, { PMDA_PMID(CLUSTER_NET_NFS,4), PM_TYPE_U32, NFS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* nfs.server.calls */ { NULL, { PMDA_PMID(CLUSTER_NET_NFS,50), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* nfs.server.reqs */ { NULL, { PMDA_PMID(CLUSTER_NET_NFS,12), PM_TYPE_U32, NFS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* nfs3.client.calls */ { NULL, { PMDA_PMID(CLUSTER_NET_NFS,60), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* nfs3.client.reqs */ { NULL, { PMDA_PMID(CLUSTER_NET_NFS,61), PM_TYPE_U32, NFS3_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* nfs3.server.calls */ { NULL, { PMDA_PMID(CLUSTER_NET_NFS,62), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* nfs3.server.reqs */ { NULL, { PMDA_PMID(CLUSTER_NET_NFS,63), PM_TYPE_U32, NFS3_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* nfs4.client.calls */ { NULL, { PMDA_PMID(CLUSTER_NET_NFS,64), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* nfs4.client.reqs */ { NULL, { PMDA_PMID(CLUSTER_NET_NFS,65), PM_TYPE_U32, NFS4_CLI_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* nfs4.server.calls */ { NULL, { PMDA_PMID(CLUSTER_NET_NFS,66), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* nfs4.server.reqs */ { NULL, { PMDA_PMID(CLUSTER_NET_NFS,67), PM_TYPE_U32, NFS4_SVR_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.client.rpccnt */ { &proc_net_rpc.client.rpccnt, { PMDA_PMID(CLUSTER_NET_NFS,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.client.rpcretrans */ { &proc_net_rpc.client.rpcretrans, { PMDA_PMID(CLUSTER_NET_NFS,21), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.client.rpcauthrefresh */ { &proc_net_rpc.client.rpcauthrefresh, { PMDA_PMID(CLUSTER_NET_NFS,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.client.netcnt */ { &proc_net_rpc.client.netcnt, { PMDA_PMID(CLUSTER_NET_NFS,24), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.client.netudpcnt */ { &proc_net_rpc.client.netudpcnt, { PMDA_PMID(CLUSTER_NET_NFS,25), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.client.nettcpcnt */ { &proc_net_rpc.client.nettcpcnt, { PMDA_PMID(CLUSTER_NET_NFS,26), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.client.nettcpconn */ { &proc_net_rpc.client.nettcpconn, { PMDA_PMID(CLUSTER_NET_NFS,27), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.rpccnt */ { &proc_net_rpc.server.rpccnt, { PMDA_PMID(CLUSTER_NET_NFS,30), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.rpcerr */ { &proc_net_rpc.server.rpcerr, { PMDA_PMID(CLUSTER_NET_NFS,31), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.rpcbadfmt */ { &proc_net_rpc.server.rpcbadfmt, { PMDA_PMID(CLUSTER_NET_NFS,32), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.rpcbadauth */ { &proc_net_rpc.server.rpcbadauth, { PMDA_PMID(CLUSTER_NET_NFS,33), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.rpcbadclnt */ { &proc_net_rpc.server.rpcbadclnt, { PMDA_PMID(CLUSTER_NET_NFS,34), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.rchits */ { &proc_net_rpc.server.rchits, { PMDA_PMID(CLUSTER_NET_NFS,35), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.rcmisses */ { &proc_net_rpc.server.rcmisses, { PMDA_PMID(CLUSTER_NET_NFS,36), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.rcnocache */ { &proc_net_rpc.server.rcnocache, { PMDA_PMID(CLUSTER_NET_NFS,37), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.fh_cached */ { &proc_net_rpc.server.fh_cached, { PMDA_PMID(CLUSTER_NET_NFS,38), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.fh_valid */ { &proc_net_rpc.server.fh_valid, { PMDA_PMID(CLUSTER_NET_NFS,39), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.fh_fixup */ { &proc_net_rpc.server.fh_fixup, { PMDA_PMID(CLUSTER_NET_NFS,40), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.fh_lookup */ { &proc_net_rpc.server.fh_lookup, { PMDA_PMID(CLUSTER_NET_NFS,41), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.fh_stale */ { &proc_net_rpc.server.fh_stale, { PMDA_PMID(CLUSTER_NET_NFS,42), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.fh_concurrent */ { &proc_net_rpc.server.fh_concurrent, { PMDA_PMID(CLUSTER_NET_NFS,43), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.netcnt */ { &proc_net_rpc.server.netcnt, { PMDA_PMID(CLUSTER_NET_NFS,44), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.netudpcnt */ { &proc_net_rpc.server.netudpcnt, { PMDA_PMID(CLUSTER_NET_NFS,45), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.nettcpcnt */ { &proc_net_rpc.server.nettcpcnt, { PMDA_PMID(CLUSTER_NET_NFS,46), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.nettcpconn */ { &proc_net_rpc.server.nettcpcnt, { PMDA_PMID(CLUSTER_NET_NFS,47), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.fh_anon */ { &proc_net_rpc.server.fh_anon, { PMDA_PMID(CLUSTER_NET_NFS,51), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.fh_nocache_dir */ { &proc_net_rpc.server.fh_nocache_dir, { PMDA_PMID(CLUSTER_NET_NFS,52), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.fh_nocache_nondir */ { &proc_net_rpc.server.fh_nocache_nondir, { PMDA_PMID(CLUSTER_NET_NFS,53), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.io_read */ { &proc_net_rpc.server.io_read, { PMDA_PMID(CLUSTER_NET_NFS,54), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, /* rpc.server.io_write */ { &proc_net_rpc.server.io_write, { PMDA_PMID(CLUSTER_NET_NFS,55), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, /* rpc.server.th_cnt */ { &proc_net_rpc.server.th_cnt, { PMDA_PMID(CLUSTER_NET_NFS,56), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* rpc.server.th_fullcnt */ { &proc_net_rpc.server.th_fullcnt, { PMDA_PMID(CLUSTER_NET_NFS,57), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* * /proc/partitions cluster */ /* disk.partitions.read */ { NULL, { PMDA_PMID(CLUSTER_PARTITIONS,0), PM_TYPE_U32, PARTITIONS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.partitions.write */ { NULL, { PMDA_PMID(CLUSTER_PARTITIONS,1), PM_TYPE_U32, PARTITIONS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.partitions.total */ { NULL, { PMDA_PMID(CLUSTER_PARTITIONS,2), PM_TYPE_U32, PARTITIONS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.partitions.blkread */ { NULL, { PMDA_PMID(CLUSTER_PARTITIONS,3), PM_TYPE_U32, PARTITIONS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.partitions.blkwrite */ { NULL, { PMDA_PMID(CLUSTER_PARTITIONS,4), PM_TYPE_U32, PARTITIONS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.partitions.blktotal */ { NULL, { PMDA_PMID(CLUSTER_PARTITIONS,5), PM_TYPE_U32, PARTITIONS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* disk.partitions.read_bytes */ { NULL, { PMDA_PMID(CLUSTER_PARTITIONS,6), PM_TYPE_U32, PARTITIONS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.partitions.write_bytes */ { NULL, { PMDA_PMID(CLUSTER_PARTITIONS,7), PM_TYPE_U32, PARTITIONS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.partitions.total_bytes */ { NULL, { PMDA_PMID(CLUSTER_PARTITIONS,8), PM_TYPE_U32, PARTITIONS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.dev.read_bytes */ { NULL, { PMDA_PMID(CLUSTER_STAT,38), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.dev.write_bytes */ { NULL, { PMDA_PMID(CLUSTER_STAT,39), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.dev.total_bytes */ { NULL, { PMDA_PMID(CLUSTER_STAT,40), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.all.read_bytes */ { NULL, { PMDA_PMID(CLUSTER_STAT,41), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.all.write_bytes */ { NULL, { PMDA_PMID(CLUSTER_STAT,42), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* disk.all.total_bytes */ { NULL, { PMDA_PMID(CLUSTER_STAT,43), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, }, /* * kernel_uname cluster */ /* kernel.uname.release */ { kernel_uname.release, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* kernel.uname.version */ { kernel_uname.version, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* kernel.uname.sysname */ { kernel_uname.sysname, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 2), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* kernel.uname.machine */ { kernel_uname.machine, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 3), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* kernel.uname.nodename */ { kernel_uname.nodename, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 4), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* pmda.uname */ { NULL, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 5), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* pmda.version */ { NULL, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 6), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* kernel.uname.distro */ { NULL, { PMDA_PMID(CLUSTER_KERNEL_UNAME, 7), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* * network snmp cluster */ /* network.ip.forwarding */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_FORWARDING], { PMDA_PMID(CLUSTER_NET_SNMP,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.defaultttl */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_DEFAULTTTL], { PMDA_PMID(CLUSTER_NET_SNMP,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.inreceives */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_INRECEIVES], { PMDA_PMID(CLUSTER_NET_SNMP,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.inhdrerrors */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_INHDRERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.inaddrerrors */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_INADDRERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.forwdatagrams */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_FORWDATAGRAMS], { PMDA_PMID(CLUSTER_NET_SNMP,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.inunknownprotos */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_INUNKNOWNPROTOS], { PMDA_PMID(CLUSTER_NET_SNMP,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.indiscards */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_INDISCARDS], { PMDA_PMID(CLUSTER_NET_SNMP,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.indelivers */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_INDELIVERS], { PMDA_PMID(CLUSTER_NET_SNMP,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.outrequests */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_OUTREQUESTS], { PMDA_PMID(CLUSTER_NET_SNMP,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.outdiscards */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_OUTDISCARDS], { PMDA_PMID(CLUSTER_NET_SNMP,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.outnoroutes */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_OUTNOROUTES], { PMDA_PMID(CLUSTER_NET_SNMP,11), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.reasmtimeout */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_REASMTIMEOUT], { PMDA_PMID(CLUSTER_NET_SNMP,12), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.reasmreqds */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_REASMREQDS], { PMDA_PMID(CLUSTER_NET_SNMP,13), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.reasmoks */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_REASMOKS], { PMDA_PMID(CLUSTER_NET_SNMP,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.reasmfails */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_REASMFAILS], { PMDA_PMID(CLUSTER_NET_SNMP,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.fragoks */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_FRAGOKS], { PMDA_PMID(CLUSTER_NET_SNMP,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.fragfails */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_FRAGFAILS], { PMDA_PMID(CLUSTER_NET_SNMP,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.ip.fragcreates */ { &_pm_proc_net_snmp.ip[_PM_SNMP_IP_FRAGCREATES], { PMDA_PMID(CLUSTER_NET_SNMP,18), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.inmsgs */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INMSGS], { PMDA_PMID(CLUSTER_NET_SNMP,20), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.inerrors */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,21), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.indestunreachs */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INDESTUNREACHS], { PMDA_PMID(CLUSTER_NET_SNMP,22), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.intimeexcds */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INTIMEEXCDS], { PMDA_PMID(CLUSTER_NET_SNMP,23), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.inparmprobs */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INPARMPROBS], { PMDA_PMID(CLUSTER_NET_SNMP,24), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.insrcquenchs */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INSRCQUENCHS], { PMDA_PMID(CLUSTER_NET_SNMP,25), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.inredirects */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INREDIRECTS], { PMDA_PMID(CLUSTER_NET_SNMP,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.inechos */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INECHOS], { PMDA_PMID(CLUSTER_NET_SNMP,27), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.inechoreps */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INECHOREPS], { PMDA_PMID(CLUSTER_NET_SNMP,28), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.intimestamps */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INTIMESTAMPS], { PMDA_PMID(CLUSTER_NET_SNMP,29), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.intimestampreps */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INTIMESTAMPREPS], { PMDA_PMID(CLUSTER_NET_SNMP,30), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.inaddrmasks */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INADDRMASKS], { PMDA_PMID(CLUSTER_NET_SNMP,31), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.inaddrmaskreps */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INADDRMASKREPS], { PMDA_PMID(CLUSTER_NET_SNMP,32), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outmsgs */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTMSGS], { PMDA_PMID(CLUSTER_NET_SNMP,33), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outerrors */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,34), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outdestunreachs */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTDESTUNREACHS], { PMDA_PMID(CLUSTER_NET_SNMP,35), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outtimeexcds */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTTIMEEXCDS], { PMDA_PMID(CLUSTER_NET_SNMP,36), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outparmprobs */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTPARMPROBS], { PMDA_PMID(CLUSTER_NET_SNMP,37), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outsrcquenchs */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTSRCQUENCHS], { PMDA_PMID(CLUSTER_NET_SNMP,38), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outredirects */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTREDIRECTS], { PMDA_PMID(CLUSTER_NET_SNMP,39), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outechos */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTECHOS], { PMDA_PMID(CLUSTER_NET_SNMP,40), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outechoreps */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTECHOREPS], { PMDA_PMID(CLUSTER_NET_SNMP,41), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outtimestamps */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTTIMESTAMPS], { PMDA_PMID(CLUSTER_NET_SNMP,42), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outtimestampreps */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTTIMESTAMPREPS], { PMDA_PMID(CLUSTER_NET_SNMP,43), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outaddrmasks */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTADDRMASKS], { PMDA_PMID(CLUSTER_NET_SNMP,44), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.outaddrmaskreps */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_OUTADDRMASKREPS], { PMDA_PMID(CLUSTER_NET_SNMP,45), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmp.incsumerrors */ { &_pm_proc_net_snmp.icmp[_PM_SNMP_ICMP_INCSUMERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,46), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.rtoalgorithm */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_RTOALGORITHM], { PMDA_PMID(CLUSTER_NET_SNMP,50), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.rtomin */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_RTOMIN], { PMDA_PMID(CLUSTER_NET_SNMP,51), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.rtomax */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_RTOMAX], { PMDA_PMID(CLUSTER_NET_SNMP,52), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.maxconn */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_MAXCONN], { PMDA_PMID(CLUSTER_NET_SNMP,53), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcpconn.established */ { &proc_net_tcp.stat[_PM_TCP_ESTABLISHED], { PMDA_PMID(CLUSTER_NET_TCP, 1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcpconn.syn_sent */ { &proc_net_tcp.stat[_PM_TCP_SYN_SENT], { PMDA_PMID(CLUSTER_NET_TCP, 2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcpconn.syn_recv */ { &proc_net_tcp.stat[_PM_TCP_SYN_RECV], { PMDA_PMID(CLUSTER_NET_TCP, 3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcpconn.fin_wait1 */ { &proc_net_tcp.stat[_PM_TCP_FIN_WAIT1], { PMDA_PMID(CLUSTER_NET_TCP, 4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcpconn.fin_wait2 */ { &proc_net_tcp.stat[_PM_TCP_FIN_WAIT2], { PMDA_PMID(CLUSTER_NET_TCP, 5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcpconn.time_wait */ { &proc_net_tcp.stat[_PM_TCP_TIME_WAIT], { PMDA_PMID(CLUSTER_NET_TCP, 6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcpconn.close */ { &proc_net_tcp.stat[_PM_TCP_CLOSE], { PMDA_PMID(CLUSTER_NET_TCP, 7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcpconn.close_wait */ { &proc_net_tcp.stat[_PM_TCP_CLOSE_WAIT], { PMDA_PMID(CLUSTER_NET_TCP, 8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcpconn.last_ack */ { &proc_net_tcp.stat[_PM_TCP_LAST_ACK], { PMDA_PMID(CLUSTER_NET_TCP, 9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcpconn.listen */ { &proc_net_tcp.stat[_PM_TCP_LISTEN], { PMDA_PMID(CLUSTER_NET_TCP, 10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcpconn.closing */ { &proc_net_tcp.stat[_PM_TCP_CLOSING], { PMDA_PMID(CLUSTER_NET_TCP, 11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.activeopens */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_ACTIVEOPENS], { PMDA_PMID(CLUSTER_NET_SNMP,54), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.passiveopens */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_PASSIVEOPENS], { PMDA_PMID(CLUSTER_NET_SNMP,55), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.attemptfails */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_ATTEMPTFAILS], { PMDA_PMID(CLUSTER_NET_SNMP,56), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.estabresets */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_ESTABRESETS], { PMDA_PMID(CLUSTER_NET_SNMP,57), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.currestab */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_CURRESTAB], { PMDA_PMID(CLUSTER_NET_SNMP,58), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.insegs */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_INSEGS], { PMDA_PMID(CLUSTER_NET_SNMP,59), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.outsegs */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_OUTSEGS], { PMDA_PMID(CLUSTER_NET_SNMP,60), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.retranssegs */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_RETRANSSEGS], { PMDA_PMID(CLUSTER_NET_SNMP,61), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.inerrs */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_INERRS], { PMDA_PMID(CLUSTER_NET_SNMP,62), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.outrsts */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_OUTRSTS], { PMDA_PMID(CLUSTER_NET_SNMP,63), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.tcp.incsumerrors */ { &_pm_proc_net_snmp.tcp[_PM_SNMP_TCP_INCSUMERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,64), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udp.indatagrams */ { &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_INDATAGRAMS], { PMDA_PMID(CLUSTER_NET_SNMP,70), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udp.noports */ { &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_NOPORTS], { PMDA_PMID(CLUSTER_NET_SNMP,71), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udp.inerrors */ { &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_INERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,72), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udp.outdatagrams */ { &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_OUTDATAGRAMS], { PMDA_PMID(CLUSTER_NET_SNMP,74), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udp.recvbuferrors */ { &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_RECVBUFERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,75), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udp.sndbuferrors */ { &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_SNDBUFERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,76), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udp.incsumerrors */ { &_pm_proc_net_snmp.udp[_PM_SNMP_UDP_INCSUMERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,83), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udplite.indatagrams */ { &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_INDATAGRAMS], { PMDA_PMID(CLUSTER_NET_SNMP,77), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udplite.noports */ { &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_NOPORTS], { PMDA_PMID(CLUSTER_NET_SNMP,78), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udplite.inerrors */ { &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_INERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,79), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udplite.outdatagrams */ { &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_OUTDATAGRAMS], { PMDA_PMID(CLUSTER_NET_SNMP,80), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udplite.recvbuferrors */ { &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_RECVBUFERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,81), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udplite.sndbuferrors */ { &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_SNDBUFERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,82), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.udplite.incsumerrors */ { &_pm_proc_net_snmp.udplite[_PM_SNMP_UDPLITE_INCSUMERRORS], { PMDA_PMID(CLUSTER_NET_SNMP,84), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmpmsg.intype */ { &_pm_proc_net_snmp.icmpmsg[_PM_SNMP_ICMPMSG_INTYPE], { PMDA_PMID(CLUSTER_NET_SNMP,88), PM_TYPE_U64, ICMPMSG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* network.icmpmsg.outtype */ { &_pm_proc_net_snmp.icmpmsg[_PM_SNMP_ICMPMSG_OUTTYPE], { PMDA_PMID(CLUSTER_NET_SNMP,89), PM_TYPE_U64, ICMPMSG_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* hinv.map.scsi */ { NULL, { PMDA_PMID(CLUSTER_SCSI,0), PM_TYPE_STRING, SCSI_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* hinv.map.lvname */ { NULL, { PMDA_PMID(CLUSTER_LV,0), PM_TYPE_STRING, LV_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* hinv.nlv */ { NULL, { PMDA_PMID(CLUSTER_LV,1), PM_TYPE_U32, LV_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* * /proc/cpuinfo cluster (cpu indom) */ /* hinv.cpu.clock */ { NULL, { PMDA_PMID(CLUSTER_CPUINFO, 0), PM_TYPE_FLOAT, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,1,0,-6,0) } }, /* hinv.cpu.vendor */ { NULL, { PMDA_PMID(CLUSTER_CPUINFO, 1), PM_TYPE_STRING, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* hinv.cpu.model */ { NULL, { PMDA_PMID(CLUSTER_CPUINFO, 2), PM_TYPE_STRING, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* hinv.cpu.stepping */ { NULL, { PMDA_PMID(CLUSTER_CPUINFO, 3), PM_TYPE_STRING, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* hinv.cpu.cache */ { NULL, { PMDA_PMID(CLUSTER_CPUINFO, 4), PM_TYPE_U32, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,PM_SPACE_KBYTE,0,0) } }, /* hinv.cpu.bogomips */ { NULL, { PMDA_PMID(CLUSTER_CPUINFO, 5), PM_TYPE_FLOAT, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* hinv.map.cpu_num */ { NULL, { PMDA_PMID(CLUSTER_CPUINFO, 6), PM_TYPE_U32, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* hinv.machine */ { NULL, { PMDA_PMID(CLUSTER_CPUINFO, 7), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* hinv.map.cpu_node */ { NULL, { PMDA_PMID(CLUSTER_CPUINFO, 8), PM_TYPE_U32, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* hinv.cpu.model_name */ { NULL, { PMDA_PMID(CLUSTER_CPUINFO, 9), PM_TYPE_STRING, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* hinv.cpu.flags */ { NULL, { PMDA_PMID(CLUSTER_CPUINFO, 10), PM_TYPE_STRING, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* hinv.cpu.cache_alignment */ { NULL, { PMDA_PMID(CLUSTER_CPUINFO, 11), PM_TYPE_U32, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,PM_SPACE_BYTE,0,0) } }, /* * semaphore limits cluster * Cluster added by Mike Mason */ /* ipc.sem.max_semmap */ { NULL, { PMDA_PMID(CLUSTER_SEM_LIMITS, 0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.sem.max_semid */ { NULL, { PMDA_PMID(CLUSTER_SEM_LIMITS, 1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.sem.max_sem */ { NULL, { PMDA_PMID(CLUSTER_SEM_LIMITS, 2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.sem.num_undo */ { NULL, { PMDA_PMID(CLUSTER_SEM_LIMITS, 3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.sem.max_perid */ { NULL, { PMDA_PMID(CLUSTER_SEM_LIMITS, 4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.sem.max_ops */ { NULL, { PMDA_PMID(CLUSTER_SEM_LIMITS, 5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.sem.max_undoent */ { NULL, { PMDA_PMID(CLUSTER_SEM_LIMITS, 6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.sem.sz_semundo */ { NULL, { PMDA_PMID(CLUSTER_SEM_LIMITS, 7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.sem.max_semval */ { NULL, { PMDA_PMID(CLUSTER_SEM_LIMITS, 8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.sem.max_exit */ { NULL, { PMDA_PMID(CLUSTER_SEM_LIMITS, 9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* * message limits cluster * Cluster added by Mike Mason */ /* ipc.msg.sz_pool */ { NULL, { PMDA_PMID(CLUSTER_MSG_LIMITS, 0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0, PM_SPACE_KBYTE,0,0)}}, /* ipc.msg.mapent */ { NULL, { PMDA_PMID(CLUSTER_MSG_LIMITS, 1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.msg.max_msgsz */ { NULL, { PMDA_PMID(CLUSTER_MSG_LIMITS, 2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.msg.max_defmsgq */ { NULL, { PMDA_PMID(CLUSTER_MSG_LIMITS, 3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.msg.max_msgqid */ { NULL, { PMDA_PMID(CLUSTER_MSG_LIMITS, 4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.msg.max_msgseg */ { NULL, { PMDA_PMID(CLUSTER_MSG_LIMITS, 5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0, 0,0,0)}}, /* ipc.msg.max_smsghdr */ { NULL, { PMDA_PMID(CLUSTER_MSG_LIMITS, 6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.msg.max_seg */ { NULL, { PMDA_PMID(CLUSTER_MSG_LIMITS, 7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* * shared memory limits cluster * Cluster added by Mike Mason */ /* ipc.shm.max_segsz */ { NULL, { PMDA_PMID(CLUSTER_SHM_LIMITS, 0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0)}}, /* ipc.shm.min_segsz */ { NULL, { PMDA_PMID(CLUSTER_SHM_LIMITS, 1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0)}}, /* ipc.shm.max_seg */ { NULL, { PMDA_PMID(CLUSTER_SHM_LIMITS, 2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.shm.max_segproc */ { NULL, { PMDA_PMID(CLUSTER_SHM_LIMITS, 3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* ipc.shm.max_shmsys */ { NULL, { PMDA_PMID(CLUSTER_SHM_LIMITS, 4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* * number of users cluster */ /* kernel.all.nusers */ { NULL, { PMDA_PMID(CLUSTER_NUSERS, 0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0)}}, /* * /proc/sys/fs vfs cluster */ /* vfs.files */ { &proc_sys_fs.fs_files_count, { PMDA_PMID(CLUSTER_VFS,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { &proc_sys_fs.fs_files_free, { PMDA_PMID(CLUSTER_VFS,1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { &proc_sys_fs.fs_files_max, { PMDA_PMID(CLUSTER_VFS,2), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { &proc_sys_fs.fs_inodes_count, { PMDA_PMID(CLUSTER_VFS,3), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { &proc_sys_fs.fs_inodes_free, { PMDA_PMID(CLUSTER_VFS,4), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { &proc_sys_fs.fs_dentry_count, { PMDA_PMID(CLUSTER_VFS,5), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, { &proc_sys_fs.fs_dentry_free, { PMDA_PMID(CLUSTER_VFS,6), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* * mem.vmstat cluster */ /* mem.vmstat.nr_dirty */ { &_pm_proc_vmstat.nr_dirty, {PMDA_PMID(28,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mem.vmstat.nr_writeback */ { &_pm_proc_vmstat.nr_writeback, {PMDA_PMID(28,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mem.vmstat.nr_unstable */ { &_pm_proc_vmstat.nr_unstable, {PMDA_PMID(28,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mem.vmstat.nr_page_table_pages */ { &_pm_proc_vmstat.nr_page_table_pages, {PMDA_PMID(28,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mem.vmstat.nr_mapped */ { &_pm_proc_vmstat.nr_mapped, {PMDA_PMID(28,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mem.vmstat.nr_slab */ { &_pm_proc_vmstat.nr_slab, {PMDA_PMID(28,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mem.vmstat.pgpgin */ { &_pm_proc_vmstat.pgpgin, {PMDA_PMID(28,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgpgout */ { &_pm_proc_vmstat.pgpgout, {PMDA_PMID(28,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pswpin */ { &_pm_proc_vmstat.pswpin, {PMDA_PMID(28,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pswpout */ { &_pm_proc_vmstat.pswpout, {PMDA_PMID(28,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgalloc_high */ { &_pm_proc_vmstat.pgalloc_high, {PMDA_PMID(28,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgalloc_normal */ { &_pm_proc_vmstat.pgalloc_normal, {PMDA_PMID(28,11), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgalloc_dma */ { &_pm_proc_vmstat.pgalloc_dma, {PMDA_PMID(28,12), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgfree */ { &_pm_proc_vmstat.pgfree, {PMDA_PMID(28,13), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgactivate */ { &_pm_proc_vmstat.pgactivate, {PMDA_PMID(28,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgdeactivate */ { &_pm_proc_vmstat.pgdeactivate, {PMDA_PMID(28,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgfault */ { &_pm_proc_vmstat.pgfault, {PMDA_PMID(28,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgmajfault */ { &_pm_proc_vmstat.pgmajfault, {PMDA_PMID(28,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgrefill_high */ { &_pm_proc_vmstat.pgrefill_high, {PMDA_PMID(28,18), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgrefill_normal */ { &_pm_proc_vmstat.pgrefill_normal, {PMDA_PMID(28,19), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgrefill_dma */ { &_pm_proc_vmstat.pgrefill_dma, {PMDA_PMID(28,20), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgsteal_high */ { &_pm_proc_vmstat.pgsteal_high, {PMDA_PMID(28,21), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgsteal_normal */ { &_pm_proc_vmstat.pgsteal_normal, {PMDA_PMID(28,22), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgsteal_dma */ { &_pm_proc_vmstat.pgsteal_dma, {PMDA_PMID(28,23), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgscan_kswapd_high */ { &_pm_proc_vmstat.pgscan_kswapd_high, {PMDA_PMID(28,24), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgscan_kswapd_normal */ { &_pm_proc_vmstat.pgscan_kswapd_normal, {PMDA_PMID(28,25), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgscan_kswapd_dma */ { &_pm_proc_vmstat.pgscan_kswapd_dma, {PMDA_PMID(28,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgscan_direct_high */ { &_pm_proc_vmstat.pgscan_direct_high, {PMDA_PMID(28,27), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgscan_direct_normal */ { &_pm_proc_vmstat.pgscan_direct_normal, {PMDA_PMID(28,28), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgscan_direct_dma */ { &_pm_proc_vmstat.pgscan_direct_dma, {PMDA_PMID(28,29), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pginodesteal */ { &_pm_proc_vmstat.pginodesteal, {PMDA_PMID(28,30), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.slabs_scanned */ { &_pm_proc_vmstat.slabs_scanned, {PMDA_PMID(28,31), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.kswapd_steal */ { &_pm_proc_vmstat.kswapd_steal, {PMDA_PMID(28,32), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.kswapd_inodesteal */ { &_pm_proc_vmstat.kswapd_inodesteal, {PMDA_PMID(28,33), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pageoutrun */ { &_pm_proc_vmstat.pageoutrun, {PMDA_PMID(28,34), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.allocstall */ { &_pm_proc_vmstat.allocstall, {PMDA_PMID(28,35), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgrotated */ { &_pm_proc_vmstat.pgrotated, {PMDA_PMID(28,36), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_slab_reclaimable */ { &_pm_proc_vmstat.nr_slab_reclaimable, {PMDA_PMID(28,37), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mem.vmstat.nr_slab_unreclaimable */ { &_pm_proc_vmstat.nr_slab_unreclaimable, {PMDA_PMID(28,38), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mem.vmstat.nr_anon_pages */ { &_pm_proc_vmstat.nr_anon_pages, {PMDA_PMID(28,39), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mem.vmstat.nr_bounce */ { &_pm_proc_vmstat.nr_bounce, {PMDA_PMID(28,40), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mem.vmstat.nr_file_pages */ { &_pm_proc_vmstat.nr_file_pages, {PMDA_PMID(28,41), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* mem.vmstat.nr_vmscan_write */ { &_pm_proc_vmstat.nr_vmscan_write, {PMDA_PMID(28,42), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.htlb_buddy_alloc_fail */ { &_pm_proc_vmstat.htlb_buddy_alloc_fail, {PMDA_PMID(28,43), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.htlb_buddy_alloc_success */ { &_pm_proc_vmstat.htlb_buddy_alloc_success, {PMDA_PMID(28,44), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_active_anon */ { &_pm_proc_vmstat.nr_active_anon, {PMDA_PMID(28,45), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_active_file */ { &_pm_proc_vmstat.nr_active_file, {PMDA_PMID(28,46), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_free_pages */ { &_pm_proc_vmstat.nr_free_pages, {PMDA_PMID(28,47), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_inactive_anon */ { &_pm_proc_vmstat.nr_inactive_anon, {PMDA_PMID(28,48), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_inactive_file */ { &_pm_proc_vmstat.nr_inactive_file, {PMDA_PMID(28,49), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_isolated_anon */ { &_pm_proc_vmstat.nr_isolated_anon, {PMDA_PMID(28,50), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_isolated_file */ { &_pm_proc_vmstat.nr_isolated_file, {PMDA_PMID(28,51), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_kernel_stack */ { &_pm_proc_vmstat.nr_kernel_stack, {PMDA_PMID(28,52), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_mlock */ { &_pm_proc_vmstat.nr_mlock, {PMDA_PMID(28,53), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_shmem */ { &_pm_proc_vmstat.nr_shmem, {PMDA_PMID(28,54), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_unevictable */ { &_pm_proc_vmstat.nr_unevictable, {PMDA_PMID(28,55), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_writeback_temp */ { &_pm_proc_vmstat.nr_writeback_temp, {PMDA_PMID(28,56), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.compact_blocks_moved */ { &_pm_proc_vmstat.compact_blocks_moved, {PMDA_PMID(28,57), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.compact_fail */ { &_pm_proc_vmstat.compact_fail, {PMDA_PMID(28,58), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.compact_pagemigrate_failed */ { &_pm_proc_vmstat.compact_pagemigrate_failed, {PMDA_PMID(28,59), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.compact_pages_moved */ { &_pm_proc_vmstat.compact_pages_moved, {PMDA_PMID(28,60), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.compact_stall */ { &_pm_proc_vmstat.compact_stall, {PMDA_PMID(28,61), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.compact_success */ { &_pm_proc_vmstat.compact_success, {PMDA_PMID(28,62), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgalloc_dma32 */ { &_pm_proc_vmstat.pgalloc_dma32, {PMDA_PMID(28,63), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgalloc_movable */ { &_pm_proc_vmstat.pgalloc_movable, {PMDA_PMID(28,64), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgrefill_dma32 */ { &_pm_proc_vmstat.pgrefill_dma32, {PMDA_PMID(28,65), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgrefill_movable */ { &_pm_proc_vmstat.pgrefill_movable, {PMDA_PMID(28,66), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgscan_direct_dma32 */ { &_pm_proc_vmstat.pgscan_direct_dma32, {PMDA_PMID(28,67), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgscan_direct_movable */ { &_pm_proc_vmstat.pgscan_direct_movable, {PMDA_PMID(28,68), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgscan_kswapd_dma32 */ { &_pm_proc_vmstat.pgscan_kswapd_dma32, {PMDA_PMID(28,69), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgscan_kswapd_movable */ { &_pm_proc_vmstat.pgscan_kswapd_movable, {PMDA_PMID(28,70), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgsteal_dma32 */ { &_pm_proc_vmstat.pgsteal_dma32, {PMDA_PMID(28,71), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.pgsteal_movable */ { &_pm_proc_vmstat.pgsteal_movable, {PMDA_PMID(28,72), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.thp_fault_alloc */ { &_pm_proc_vmstat.thp_fault_alloc, {PMDA_PMID(28,73), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.thp_fault_fallback */ { &_pm_proc_vmstat.thp_fault_fallback, {PMDA_PMID(28,74), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.thp_collapse_alloc */ { &_pm_proc_vmstat.thp_collapse_alloc, {PMDA_PMID(28,75), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.thp_collapse_alloc_failed */ { &_pm_proc_vmstat.thp_collapse_alloc_failed, {PMDA_PMID(28,76), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.thp_split */ { &_pm_proc_vmstat.thp_split, {PMDA_PMID(28,77), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.unevictable_pgs_cleared */ { &_pm_proc_vmstat.unevictable_pgs_cleared, {PMDA_PMID(28,78), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.unevictable_pgs_culled */ { &_pm_proc_vmstat.unevictable_pgs_culled, {PMDA_PMID(28,79), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.unevictable_pgs_mlocked */ { &_pm_proc_vmstat.unevictable_pgs_mlocked, {PMDA_PMID(28,80), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.unevictable_pgs_mlockfreed */ { &_pm_proc_vmstat.unevictable_pgs_mlockfreed, {PMDA_PMID(28,81), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.unevictable_pgs_munlocked */ { &_pm_proc_vmstat.unevictable_pgs_munlocked, {PMDA_PMID(28,82), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.unevictable_pgs_rescued */ { &_pm_proc_vmstat.unevictable_pgs_rescued, {PMDA_PMID(28,83), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.unevictable_pgs_scanned */ { &_pm_proc_vmstat.unevictable_pgs_scanned, {PMDA_PMID(28,84), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.unevictable_pgs_stranded */ { &_pm_proc_vmstat.unevictable_pgs_stranded, {PMDA_PMID(28,85), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.zone_reclaim_failed */ { &_pm_proc_vmstat.zone_reclaim_failed, {PMDA_PMID(28,86), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.kswapd_low_wmark_hit_quickly */ { &_pm_proc_vmstat.kswapd_low_wmark_hit_quickly, {PMDA_PMID(28,87), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.kswapd_high_wmark_hit_quickly */ { &_pm_proc_vmstat.kswapd_high_wmark_hit_quickly, {PMDA_PMID(28,88), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.kswapd_skip_congestion_wait */ { &_pm_proc_vmstat.kswapd_skip_congestion_wait, {PMDA_PMID(28,89), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_anon_transparent_hugepages */ { &_pm_proc_vmstat.nr_anon_transparent_hugepages, {PMDA_PMID(28,90), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_dirtied */ { &_pm_proc_vmstat.nr_dirtied, {PMDA_PMID(28,91), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_dirty_background_threshold */ { &_pm_proc_vmstat.nr_dirty_background_threshold, {PMDA_PMID(28,92), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_dirty_threshold */ { &_pm_proc_vmstat.nr_dirty_threshold, {PMDA_PMID(28,93), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.nr_written */ { &_pm_proc_vmstat.nr_written, {PMDA_PMID(28,94), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.numa_foreign */ { &_pm_proc_vmstat.numa_foreign, {PMDA_PMID(28,95), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.numa_hit */ { &_pm_proc_vmstat.numa_hit, {PMDA_PMID(28,96), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.numa_interleave */ { &_pm_proc_vmstat.numa_interleave, {PMDA_PMID(28,97), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.numa_local */ { &_pm_proc_vmstat.numa_local, {PMDA_PMID(28,98), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.numa_miss */ { &_pm_proc_vmstat.numa_miss, {PMDA_PMID(28,99), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* mem.vmstat.numa_other */ { &_pm_proc_vmstat.numa_other, {PMDA_PMID(28,100), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* * sysfs_kernel cluster */ /* sysfs.kernel.uevent_seqnum */ { &sysfs_kernel.uevent_seqnum, { PMDA_PMID(CLUSTER_SYSFS_KERNEL,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* * /proc/interrupts cluster */ /* kernel.all.interrupts.errors */ { &irq_err_count, { PMDA_PMID(CLUSTER_INTERRUPTS, 3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* kernel.percpu.interrupts.line[] */ { NULL, { PMDA_PMID(CLUSTER_INTERRUPT_LINES, 0), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* kernel.percpu.interrupts.[] */ { NULL, { PMDA_PMID(CLUSTER_INTERRUPT_OTHER, 0), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, }; static void linux_refresh(pmdaExt *pmda, int *need_refresh) { int need_refresh_mtab = 0; if (need_refresh[CLUSTER_PARTITIONS]) refresh_proc_partitions(INDOM(DISK_INDOM), INDOM(PARTITIONS_INDOM)); if (need_refresh[CLUSTER_STAT]) refresh_proc_stat(&proc_cpuinfo, &proc_stat); if (need_refresh[CLUSTER_CPUINFO]) refresh_proc_cpuinfo(&proc_cpuinfo); if (need_refresh[CLUSTER_MEMINFO]) refresh_proc_meminfo(&proc_meminfo); if (need_refresh[CLUSTER_NUMA_MEMINFO]) refresh_numa_meminfo(&numa_meminfo, &proc_cpuinfo, &proc_stat); if (need_refresh[CLUSTER_LOADAVG]) refresh_proc_loadavg(&proc_loadavg); if (need_refresh[CLUSTER_NET_DEV]) refresh_proc_net_dev(INDOM(NET_DEV_INDOM)); if (need_refresh[CLUSTER_NET_ADDR]) refresh_net_dev_addr(INDOM(NET_ADDR_INDOM)); if (need_refresh[CLUSTER_FILESYS] || need_refresh[CLUSTER_TMPFS]) refresh_filesys(INDOM(FILESYS_INDOM), INDOM(TMPFS_INDOM)); if (need_refresh[CLUSTER_INTERRUPTS] || need_refresh[CLUSTER_INTERRUPT_LINES] || need_refresh[CLUSTER_INTERRUPT_OTHER]) need_refresh_mtab |= refresh_interrupt_values(); if (need_refresh[CLUSTER_SWAPDEV]) refresh_swapdev(INDOM(SWAPDEV_INDOM)); if (need_refresh[CLUSTER_NET_NFS]) refresh_proc_net_rpc(&proc_net_rpc); if (need_refresh[CLUSTER_NET_SOCKSTAT]) refresh_proc_net_sockstat(&proc_net_sockstat); if (need_refresh[CLUSTER_KERNEL_UNAME]) uname(&kernel_uname); if (need_refresh[CLUSTER_NET_SNMP]) refresh_proc_net_snmp(&_pm_proc_net_snmp); if (need_refresh[CLUSTER_SCSI]) refresh_proc_scsi(&proc_scsi); if (need_refresh[CLUSTER_LV]) refresh_dev_mapper(&dev_mapper); if (need_refresh[CLUSTER_NET_TCP]) refresh_proc_net_tcp(&proc_net_tcp); if (need_refresh[CLUSTER_SLAB]) refresh_proc_slabinfo(&proc_slabinfo); if (need_refresh[CLUSTER_SEM_LIMITS]) refresh_sem_limits(&sem_limits); if (need_refresh[CLUSTER_MSG_LIMITS]) refresh_msg_limits(&msg_limits); if (need_refresh[CLUSTER_SHM_LIMITS]) refresh_shm_limits(&shm_limits); if (need_refresh[CLUSTER_UPTIME]) refresh_proc_uptime(&proc_uptime); if (need_refresh[CLUSTER_VFS]) refresh_proc_sys_fs(&proc_sys_fs); if (need_refresh[CLUSTER_VMSTAT]) refresh_proc_vmstat(&_pm_proc_vmstat); if (need_refresh[CLUSTER_SYSFS_KERNEL]) refresh_sysfs_kernel(&sysfs_kernel); if (need_refresh_mtab) pmdaDynamicMetricTable(pmda); } static int linux_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) { __pmInDom_int *indomp = (__pmInDom_int *)&indom; int need_refresh[NUM_CLUSTERS]; memset(need_refresh, 0, sizeof(need_refresh)); switch (indomp->serial) { case DISK_INDOM: case PARTITIONS_INDOM: need_refresh[CLUSTER_PARTITIONS]++; break; case CPU_INDOM: need_refresh[CLUSTER_STAT]++; break; case NODE_INDOM: need_refresh[CLUSTER_NUMA_MEMINFO]++; break; case LOADAVG_INDOM: need_refresh[CLUSTER_LOADAVG]++; break; case NET_DEV_INDOM: need_refresh[CLUSTER_NET_DEV]++; break; case FILESYS_INDOM: need_refresh[CLUSTER_FILESYS]++; break; case TMPFS_INDOM: need_refresh[CLUSTER_TMPFS]++; break; case SWAPDEV_INDOM: need_refresh[CLUSTER_SWAPDEV]++; break; case NFS_INDOM: case NFS3_INDOM: case NFS4_CLI_INDOM: case NFS4_SVR_INDOM: need_refresh[CLUSTER_NET_NFS]++; break; case SCSI_INDOM: need_refresh[CLUSTER_SCSI]++; break; case LV_INDOM: need_refresh[CLUSTER_LV]++; break; case SLAB_INDOM: need_refresh[CLUSTER_SLAB]++; break; case ICMPMSG_INDOM: need_refresh[CLUSTER_NET_SNMP]++; break; /* no default label : pmdaInstance will pick up errors */ } linux_refresh(pmda, need_refresh); return pmdaInstance(indom, inst, name, result, pmda); } /* * callback provided to pmdaFetch */ static int linux_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); int i; int sts; long sl; struct filesys *fs; net_addr_t *addrp; net_interface_t *netip; if (mdesc->m_user != NULL) { /* * The metric value is extracted directly via the address specified * in metrictab. Note: not all metrics support this - those that * don't have NULL for the m_user field in their respective * metrictab slot. */ if (idp->cluster == CLUSTER_VMSTAT) { if (!(_pm_have_proc_vmstat) || *(__uint64_t *)mdesc->m_user == (__uint64_t)-1) return 0; /* no value available on this kernel */ } else if (idp->cluster == CLUSTER_NET_SNMP) { __uint64_t value; /* network.icmpmsg has an indom - deal with it now */ if (idp->item == 88 || idp->item == 89) { if (inst > NR_ICMPMSG_COUNTERS) return PM_ERR_INST; value = *((__uint64_t *)mdesc->m_user + inst); if (value == (__uint64_t)-1) return 0; /* no value for this instance */ atom->ull = value; return 1; } if (*(__uint64_t *)mdesc->m_user == (__uint64_t)-1) if (idp->item != 53) /* tcp.maxconn is special */ return 0; /* no value available on this kernel */ } else if (idp->cluster == CLUSTER_NET_NFS) { /* * check if rpc stats are available */ if (idp->item >= 20 && idp->item <= 27 && proc_net_rpc.client.errcode != 0) /* no values available for client rpc/nfs - this is expected <= 2.0.36 */ return 0; else if (idp->item >= 30 && idp->item <= 47 && proc_net_rpc.server.errcode != 0) /* no values available - expected without /proc/net/rpc/nfsd */ return 0; /* no values available */ if (idp->item >= 51 && idp->item <= 57 && proc_net_rpc.server.errcode != 0) /* no values available - expected without /proc/net/rpc/nfsd */ return 0; /* no values available */ } if (idp->cluster == CLUSTER_SYSFS_KERNEL) { /* no values available for udev metrics */ if (idp->item == 0 && !sysfs_kernel.valid_uevent_seqnum) { return 0; } } switch (mdesc->m_desc.type) { case PM_TYPE_32: atom->l = *(__int32_t *)mdesc->m_user; break; case PM_TYPE_U32: atom->ul = *(__uint32_t *)mdesc->m_user; break; case PM_TYPE_64: atom->ll = *(__int64_t *)mdesc->m_user; break; case PM_TYPE_U64: atom->ull = *(__uint64_t *)mdesc->m_user; break; case PM_TYPE_FLOAT: atom->f = *(float *)mdesc->m_user; break; case PM_TYPE_DOUBLE: atom->d = *(double *)mdesc->m_user; break; case PM_TYPE_STRING: atom->cp = (char *)mdesc->m_user; break; default: return 0; } } else switch (idp->cluster) { case CLUSTER_STAT: /* * All metrics from /proc/stat */ switch (idp->item) { case 0: /* kernel.percpu.cpu.user */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.p_user[inst] / proc_stat.hz); break; case 1: /* kernel.percpu.cpu.nice */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.p_nice[inst] / proc_stat.hz); break; case 2: /* kernel.percpu.cpu.sys */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.p_sys[inst] / proc_stat.hz); break; case 3: /* kernel.percpu.cpu.idle */ _pm_assign_utype(_pm_idletime_size, atom, 1000 * (double)proc_stat.p_idle[inst] / proc_stat.hz); break; case 30: /* kernel.percpu.cpu.wait.total */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.p_wait[inst] / proc_stat.hz); break; case 31: /* kernel.percpu.cpu.intr */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * ((double)proc_stat.p_irq[inst] + (double)proc_stat.p_sirq[inst]) / proc_stat.hz); break; case 56: /* kernel.percpu.cpu.irq.soft */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.p_sirq[inst] / proc_stat.hz); break; case 57: /* kernel.percpu.cpu.irq.hard */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.p_irq[inst] / proc_stat.hz); break; case 58: /* kernel.percpu.cpu.steal */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.p_steal[inst] / proc_stat.hz); break; case 61: /* kernel.percpu.cpu.guest */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.p_guest[inst] / proc_stat.hz); break; case 76: /* kernel.percpu.cpu.vuser */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * ((double)proc_stat.p_user[inst] - (double)proc_stat.p_guest[inst]) / proc_stat.hz); break; case 62: /* kernel.pernode.cpu.user */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.n_user[inst] / proc_stat.hz); break; case 63: /* kernel.pernode.cpu.nice */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.n_nice[inst] / proc_stat.hz); break; case 64: /* kernel.pernode.cpu.sys */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.n_sys[inst] / proc_stat.hz); break; case 65: /* kernel.pernode.cpu.idle */ _pm_assign_utype(_pm_idletime_size, atom, 1000 * (double)proc_stat.n_idle[inst] / proc_stat.hz); break; case 69: /* kernel.pernode.cpu.wait.total */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.n_wait[inst] / proc_stat.hz); break; case 66: /* kernel.pernode.cpu.intr */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * ((double)proc_stat.n_irq[inst] + (double)proc_stat.n_sirq[inst]) / proc_stat.hz); break; case 70: /* kernel.pernode.cpu.irq.soft */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.n_sirq[inst] / proc_stat.hz); break; case 71: /* kernel.pernode.cpu.irq.hard */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.n_irq[inst] / proc_stat.hz); break; case 67: /* kernel.pernode.cpu.steal */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.n_steal[inst] / proc_stat.hz); break; case 68: /* kernel.pernode.cpu.guest */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.n_guest[inst] / proc_stat.hz); break; case 77: /* kernel.pernode.cpu.guest */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * ((double)proc_stat.n_user[inst] - (double)proc_stat.n_guest[inst]) / proc_stat.hz); break; case 8: /* pagesin */ if (_pm_have_proc_vmstat) atom->ul = _pm_proc_vmstat.pswpin; else atom->ul = proc_stat.swap[0]; break; case 9: /* pagesout */ if (_pm_have_proc_vmstat) atom->ul = _pm_proc_vmstat.pswpout; else atom->ul = proc_stat.swap[1]; break; case 10: /* in */ if (_pm_have_proc_vmstat) return PM_ERR_APPVERSION; /* no swap operation counts in 2.6 */ else atom->ul = proc_stat.page[0]; break; case 11: /* out */ if (_pm_have_proc_vmstat) return PM_ERR_APPVERSION; /* no swap operation counts in 2.6 */ else atom->ul = proc_stat.page[1]; break; case 12: /* intr */ _pm_assign_utype(_pm_intr_size, atom, proc_stat.intr); break; case 13: /* ctxt */ _pm_assign_utype(_pm_ctxt_size, atom, proc_stat.ctxt); break; case 14: /* processes */ _pm_assign_ulong(atom, proc_stat.processes); break; case 20: /* kernel.all.cpu.user */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.user / proc_stat.hz); break; case 21: /* kernel.all.cpu.nice */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.nice / proc_stat.hz); break; case 22: /* kernel.all.cpu.sys */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.sys / proc_stat.hz); break; case 23: /* kernel.all.cpu.idle */ _pm_assign_utype(_pm_idletime_size, atom, 1000 * (double)proc_stat.idle / proc_stat.hz); break; case 34: /* kernel.all.cpu.intr */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * ((double)proc_stat.irq + (double)proc_stat.sirq) / proc_stat.hz); break; case 35: /* kernel.all.cpu.wait.total */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.wait / proc_stat.hz); break; case 53: /* kernel.all.cpu.irq.soft */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.sirq / proc_stat.hz); break; case 54: /* kernel.all.cpu.irq.hard */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.irq / proc_stat.hz); break; case 55: /* kernel.all.cpu.steal */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.steal / proc_stat.hz); break; case 60: /* kernel.all.cpu.guest */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * (double)proc_stat.guest / proc_stat.hz); break; case 78: /* kernel.all.cpu.vuser */ _pm_assign_utype(_pm_cputime_size, atom, 1000 * ((double)proc_stat.user - (double)proc_stat.guest) / proc_stat.hz); break; case 19: /* hinv.nnode */ atom->ul = indomtab[NODE_INDOM].it_numinst; break; case 32: /* hinv.ncpu */ atom->ul = indomtab[CPU_INDOM].it_numinst; break; case 33: /* hinv.ndisk */ atom->ul = pmdaCacheOp(INDOM(DISK_INDOM), PMDA_CACHE_SIZE_ACTIVE); break; case 48: /* kernel.all.hz */ atom->ul = proc_stat.hz; break; default: /* * Disk metrics used to be fetched from /proc/stat (2.2 kernels) * but have since moved to /proc/partitions (2.4 kernels) and * /proc/diskstats (2.6 kernels). We preserve the cluster number * (middle bits of a PMID) for backward compatibility. * * Note that proc_partitions_fetch() will return PM_ERR_PMID * if we have tried to fetch an unknown metric. */ return proc_partitions_fetch(mdesc, inst, atom); } break; case CLUSTER_UPTIME: /* uptime */ switch (idp->item) { case 0: /* * kernel.all.uptime (in seconds) * contributed by "gilly" * modified by Mike Mason" */ atom->ul = proc_uptime.uptime; break; case 1: /* * kernel.all.idletime (in seconds) * contributed by "Mike Mason" */ atom->ul = proc_uptime.idletime; break; default: return PM_ERR_PMID; } break; case CLUSTER_MEMINFO: /* mem */ #define VALID_VALUE(x) ((x) != (uint64_t)-1) #define VALUE_OR_ZERO(x) (((x) == (uint64_t)-1) ? 0 : (x)) switch (idp->item) { case 0: /* mem.physmem (in kbytes) */ if (!VALID_VALUE(proc_meminfo.MemTotal)) return 0; /* no values available */ atom->ull = proc_meminfo.MemTotal >> 10; break; case 1: /* mem.util.used (in kbytes) */ if (!VALID_VALUE(proc_meminfo.MemTotal) || !VALID_VALUE(proc_meminfo.MemFree)) return 0; /* no values available */ atom->ull = (proc_meminfo.MemTotal - proc_meminfo.MemFree) >> 10; break; case 2: /* mem.util.free (in kbytes) */ if (!VALID_VALUE(proc_meminfo.MemFree)) return 0; /* no values available */ atom->ull = proc_meminfo.MemFree >> 10; break; case 3: /* mem.util.shared (in kbytes) */ /* * If this metric is exported by the running kernel, it is always * zero (deprecated). PCP exports it for compatibility with older * PCP monitoring tools, e.g. pmgsys running on IRIX(TM). */ if (!VALID_VALUE(proc_meminfo.MemShared)) return 0; /* no values available */ atom->ull = proc_meminfo.MemShared >> 10; break; case 4: /* mem.util.bufmem (in kbytes) */ if (!VALID_VALUE(proc_meminfo.Buffers)) return 0; /* no values available */ atom->ull = proc_meminfo.Buffers >> 10; break; case 5: /* mem.util.cached (in kbytes) */ if (!VALID_VALUE(proc_meminfo.Cached)) return 0; /* no values available */ atom->ull = proc_meminfo.Cached >> 10; break; case 6: /* swap.length (in bytes) */ if (!VALID_VALUE(proc_meminfo.SwapTotal)) return 0; /* no values available */ atom->ull = proc_meminfo.SwapTotal; break; case 7: /* swap.used (in bytes) */ if (!VALID_VALUE(proc_meminfo.SwapTotal) || !VALID_VALUE(proc_meminfo.SwapFree)) return 0; /* no values available */ atom->ull = proc_meminfo.SwapTotal - proc_meminfo.SwapFree; break; case 8: /* swap.free (in bytes) */ if (!VALID_VALUE(proc_meminfo.SwapFree)) return 0; /* no values available */ atom->ull = proc_meminfo.SwapFree; break; case 9: /* hinv.physmem (in mbytes) */ if (!VALID_VALUE(proc_meminfo.MemTotal)) return 0; /* no values available */ atom->ul = proc_meminfo.MemTotal >> 20; break; case 10: /* mem.freemem (in kbytes) */ if (!VALID_VALUE(proc_meminfo.MemFree)) return 0; /* no values available */ atom->ull = proc_meminfo.MemFree >> 10; break; case 11: /* hinv.pagesize (in bytes) */ atom->ul = _pm_system_pagesize; break; case 12: /* mem.util.other (in kbytes) */ /* other = used - (cached+buffers) */ if (!VALID_VALUE(proc_meminfo.MemTotal) || !VALID_VALUE(proc_meminfo.MemFree) || !VALID_VALUE(proc_meminfo.Cached) || !VALID_VALUE(proc_meminfo.Buffers)) return 0; /* no values available */ sl = (proc_meminfo.MemTotal - proc_meminfo.MemFree - proc_meminfo.Cached - proc_meminfo.Buffers) >> 10; atom->ull = sl >= 0 ? sl : 0; break; case 13: /* mem.util.swapCached (in kbytes) */ if (!VALID_VALUE(proc_meminfo.SwapCached)) return 0; /* no values available */ atom->ull = proc_meminfo.SwapCached >> 10; break; case 14: /* mem.util.active (in kbytes) */ if (!VALID_VALUE(proc_meminfo.Active)) return 0; /* no values available */ atom->ull = proc_meminfo.Active >> 10; break; case 15: /* mem.util.inactive (in kbytes) */ if (!VALID_VALUE(proc_meminfo.Inactive)) return 0; /* no values available */ atom->ull = proc_meminfo.Inactive >> 10; break; case 16: /* mem.util.highTotal (in kbytes) */ if (!VALID_VALUE(proc_meminfo.HighTotal)) return 0; /* no values available */ atom->ull = proc_meminfo.HighTotal >> 10; break; case 17: /* mem.util.highFree (in kbytes) */ if (!VALID_VALUE(proc_meminfo.HighFree)) return 0; /* no values available */ atom->ull = proc_meminfo.HighFree >> 10; break; case 18: /* mem.util.lowTotal (in kbytes) */ if (!VALID_VALUE(proc_meminfo.LowTotal)) return 0; /* no values available */ atom->ull = proc_meminfo.LowTotal >> 10; break; case 19: /* mem.util.lowFree (in kbytes) */ if (!VALID_VALUE(proc_meminfo.LowFree)) return 0; /* no values available */ atom->ull = proc_meminfo.LowFree >> 10; break; case 20: /* mem.util.swapTotal (in kbytes) */ if (!VALID_VALUE(proc_meminfo.SwapTotal)) return 0; /* no values available */ atom->ull = proc_meminfo.SwapTotal >> 10; break; case 21: /* mem.util.swapFree (in kbytes) */ if (!VALID_VALUE(proc_meminfo.SwapFree)) return 0; /* no values available */ atom->ull = proc_meminfo.SwapFree >> 10; break; case 22: /* mem.util.dirty (in kbytes) */ if (!VALID_VALUE(proc_meminfo.Dirty)) return 0; /* no values available */ atom->ull = proc_meminfo.Dirty >> 10; break; case 23: /* mem.util.writeback (in kbytes) */ if (!VALID_VALUE(proc_meminfo.Writeback)) return 0; /* no values available */ atom->ull = proc_meminfo.Writeback >> 10; break; case 24: /* mem.util.mapped (in kbytes) */ if (!VALID_VALUE(proc_meminfo.Mapped)) return 0; /* no values available */ atom->ull = proc_meminfo.Mapped >> 10; break; case 25: /* mem.util.slab (in kbytes) */ if (!VALID_VALUE(proc_meminfo.Slab)) return 0; /* no values available */ atom->ull = proc_meminfo.Slab >> 10; break; case 26: /* mem.util.committed_AS (in kbytes) */ if (!VALID_VALUE(proc_meminfo.Committed_AS)) return 0; /* no values available */ atom->ull = proc_meminfo.Committed_AS >> 10; break; case 27: /* mem.util.pageTables (in kbytes) */ if (!VALID_VALUE(proc_meminfo.PageTables)) return 0; /* no values available */ atom->ull = proc_meminfo.PageTables >> 10; break; case 28: /* mem.util.reverseMaps (in kbytes) */ if (!VALID_VALUE(proc_meminfo.ReverseMaps)) return 0; /* no values available */ atom->ull = proc_meminfo.ReverseMaps >> 10; break; case 29: /* mem.util.clean_cache (in kbytes) */ /* clean=cached-(dirty+writeback) */ if (!VALID_VALUE(proc_meminfo.Cached) || !VALID_VALUE(proc_meminfo.Dirty) || !VALID_VALUE(proc_meminfo.Writeback)) return 0; /* no values available */ sl = (proc_meminfo.Cached - proc_meminfo.Dirty - proc_meminfo.Writeback) >> 10; atom->ull = sl >= 0 ? sl : 0; break; case 30: /* mem.util.anonpages */ if (!VALID_VALUE(proc_meminfo.AnonPages)) return 0; /* no values available */ atom->ull = proc_meminfo.AnonPages >> 10; break; case 31: /* mem.util.commitLimit (in kbytes) */ if (!VALID_VALUE(proc_meminfo.CommitLimit)) return 0; /* no values available */ atom->ull = proc_meminfo.CommitLimit >> 10; break; case 32: /* mem.util.bounce */ if (!VALID_VALUE(proc_meminfo.Bounce)) return 0; /* no values available */ atom->ull = proc_meminfo.Bounce >> 10; break; case 33: /* mem.util.NFS_Unstable */ if (!VALID_VALUE(proc_meminfo.NFS_Unstable)) return 0; /* no values available */ atom->ull = proc_meminfo.NFS_Unstable >> 10; break; case 34: /* mem.util.slabReclaimable */ if (!VALID_VALUE(proc_meminfo.SlabReclaimable)) return 0; /* no values available */ atom->ull = proc_meminfo.SlabReclaimable >> 10; break; case 35: /* mem.util.slabUnreclaimable */ if (!VALID_VALUE(proc_meminfo.SlabUnreclaimable)) return 0; /* no values available */ atom->ull = proc_meminfo.SlabUnreclaimable >> 10; break; case 36: /* mem.util.active_anon */ if (!VALID_VALUE(proc_meminfo.Active_anon)) return 0; /* no values available */ atom->ull = proc_meminfo.Active_anon >> 10; break; case 37: /* mem.util.inactive_anon */ if (!VALID_VALUE(proc_meminfo.Inactive_anon)) return 0; /* no values available */ atom->ull = proc_meminfo.Inactive_anon >> 10; break; case 38: /* mem.util.active_file */ if (!VALID_VALUE(proc_meminfo.Active_file)) return 0; /* no values available */ atom->ull = proc_meminfo.Active_file >> 10; break; case 39: /* mem.util.inactive_file */ if (!VALID_VALUE(proc_meminfo.Inactive_file)) return 0; /* no values available */ atom->ull = proc_meminfo.Inactive_file >> 10; break; case 40: /* mem.util.unevictable */ if (!VALID_VALUE(proc_meminfo.Unevictable)) return 0; /* no values available */ atom->ull = proc_meminfo.Unevictable >> 10; break; case 41: /* mem.util.mlocked */ if (!VALID_VALUE(proc_meminfo.Mlocked)) return 0; /* no values available */ atom->ull = proc_meminfo.Mlocked >> 10; break; case 42: /* mem.util.shmem */ if (!VALID_VALUE(proc_meminfo.Shmem)) return 0; /* no values available */ atom->ull = proc_meminfo.Shmem >> 10; break; case 43: /* mem.util.kernelStack */ if (!VALID_VALUE(proc_meminfo.KernelStack)) return 0; /* no values available */ atom->ull = proc_meminfo.KernelStack >> 10; break; case 44: /* mem.util.hugepagesTotal */ if (!VALID_VALUE(proc_meminfo.HugepagesTotal)) return 0; /* no values available */ atom->ull = proc_meminfo.HugepagesTotal; break; case 45: /* mem.util.hugepagesFree */ if (!VALID_VALUE(proc_meminfo.HugepagesFree)) return 0; /* no values available */ atom->ull = proc_meminfo.HugepagesFree; break; case 46: /* mem.util.hugepagesRsvd */ if (!VALID_VALUE(proc_meminfo.HugepagesRsvd)) return 0; /* no values available */ atom->ull = proc_meminfo.HugepagesRsvd; break; case 47: /* mem.util.hugepagesSurp */ if (!VALID_VALUE(proc_meminfo.HugepagesSurp)) return 0; /* no values available */ atom->ull = proc_meminfo.HugepagesSurp; break; case 48: /* mem.util.directMap4k */ if (!VALID_VALUE(proc_meminfo.directMap4k)) return 0; /* no values available */ atom->ull = proc_meminfo.directMap4k >> 10; break; case 49: /* mem.util.directMap2M */ if (!VALID_VALUE(proc_meminfo.directMap2M)) return 0; /* no values available */ atom->ull = proc_meminfo.directMap2M >> 10; break; case 50: /* mem.util.vmallocTotal */ if (!VALID_VALUE(proc_meminfo.VmallocTotal)) return 0; /* no values available */ atom->ull = proc_meminfo.VmallocTotal >> 10; break; case 51: /* mem.util.vmallocUsed */ if (!VALID_VALUE(proc_meminfo.VmallocUsed)) return 0; /* no values available */ atom->ull = proc_meminfo.VmallocUsed >> 10; break; case 52: /* mem.util.vmallocChunk */ if (!VALID_VALUE(proc_meminfo.VmallocChunk)) return 0; /* no values available */ atom->ull = proc_meminfo.VmallocChunk >> 10; break; case 53: /* mem.util.mmap_copy */ if (!VALID_VALUE(proc_meminfo.MmapCopy)) return 0; /* no values available */ atom->ull = proc_meminfo.MmapCopy >> 10; break; case 54: /* mem.util.quicklists */ if (!VALID_VALUE(proc_meminfo.Quicklists)) return 0; /* no values available */ atom->ull = proc_meminfo.Quicklists >> 10; break; case 55: /* mem.util.corrupthardware */ if (!VALID_VALUE(proc_meminfo.HardwareCorrupted)) return 0; /* no values available */ atom->ull = proc_meminfo.HardwareCorrupted >> 10; break; case 56: /* mem.util.anonhugepages */ if (!VALID_VALUE(proc_meminfo.AnonHugePages)) return 0; /* no values available */ atom->ull = proc_meminfo.AnonHugePages >> 10; break; case 57: /* mem.util.directMap1G */ if (!VALID_VALUE(proc_meminfo.directMap1G)) return 0; /* no values available */ atom->ull = proc_meminfo.directMap1G >> 10; break; default: return PM_ERR_PMID; } break; case CLUSTER_LOADAVG: switch(idp->item) { case 0: /* kernel.all.load */ if (inst == 1) atom->f = proc_loadavg.loadavg[0]; else if (inst == 5) atom->f = proc_loadavg.loadavg[1]; else if (inst == 15) atom->f = proc_loadavg.loadavg[2]; else return PM_ERR_INST; break; case 1: /* kernel.all.lastpid -- added by "Mike Mason" */ atom->ul = proc_loadavg.lastpid; break; case 2: /* kernel.all.runnable */ atom->ul = proc_loadavg.runnable; break; case 3: /* kernel.all.nprocs */ atom->ul = proc_loadavg.nprocs; break; default: return PM_ERR_PMID; } break; case CLUSTER_NET_DEV: /* network.interface */ if (idp->item == 27) { /* hinv.ninterface */ atom->ul = pmdaCacheOp(INDOM(NET_DEV_INDOM), PMDA_CACHE_SIZE_ACTIVE); break; } sts = pmdaCacheLookup(INDOM(NET_DEV_INDOM), inst, NULL, (void **)&netip); if (sts < 0) return sts; if (idp->item <= 15) { /* network.interface.{in,out} */ atom->ull = netip->counters[idp->item]; } else switch (idp->item) { case 16: /* network.interface.total.bytes */ atom->ull = netip->counters[0] + netip->counters[8]; break; case 17: /* network.interface.total.packets */ atom->ull = netip->counters[1] + netip->counters[9]; break; case 18: /* network.interface.total.errors */ atom->ull = netip->counters[2] + netip->counters[10]; break; case 19: /* network.interface.total.drops */ atom->ull = netip->counters[3] + netip->counters[11]; break; case 20: /* network.interface.total.mcasts */ /* * NOTE: there is no network.interface.out.mcasts metric * so this total only includes network.interface.in.mcasts */ atom->ull = netip->counters[7]; break; case 21: /* network.interface.mtu */ if (!netip->ioc.mtu) return 0; atom->ul = netip->ioc.mtu; break; case 22: /* network.interface.speed */ if (!netip->ioc.speed) return 0; atom->f = ((float)netip->ioc.speed * 1000000) / 8 / 1024 / 1024; break; case 23: /* network.interface.baudrate */ if (!netip->ioc.speed) return 0; atom->ul = ((long long)netip->ioc.speed * 1000000 / 8); break; case 24: /* network.interface.duplex */ if (!netip->ioc.duplex) return 0; atom->ul = netip->ioc.duplex; break; case 25: /* network.interface.up */ atom->ul = netip->ioc.linkup; break; case 26: /* network.interface.running */ atom->ul = netip->ioc.running; break; default: return PM_ERR_PMID; } break; case CLUSTER_NET_ADDR: sts = pmdaCacheLookup(INDOM(NET_ADDR_INDOM), inst, NULL, (void **)&addrp); if (sts < 0) return sts; if (sts != PMDA_CACHE_ACTIVE) return PM_ERR_INST; switch (idp->item) { case 0: /* network.interface.inet_addr */ if (addrp->has_inet == 0) return 0; atom->cp = addrp->inet; break; case 1: /* network.interface.ipv6_addr */ if (addrp->has_ipv6 == 0) return 0; atom->cp = addrp->ipv6; break; case 2: /* network.interface.ipv6_scope */ if (addrp->has_ipv6 == 0) return 0; atom->cp = lookup_ipv6_scope(addrp->ipv6scope); break; case 3: /* network.interface.hw_addr */ if (addrp->has_hw == 0) return 0; atom->cp = addrp->hw_addr; break; default: return PM_ERR_PMID; } break; case CLUSTER_FILESYS: if (idp->item == 0) atom->ul = pmdaCacheOp(INDOM(FILESYS_INDOM), PMDA_CACHE_SIZE_ACTIVE); else { struct statfs *sbuf; __uint64_t ull, used; sts = pmdaCacheLookup(INDOM(FILESYS_INDOM), inst, NULL, (void **)&fs); if (sts < 0) return sts; if (sts != PMDA_CACHE_ACTIVE) return PM_ERR_INST; sbuf = &fs->stats; if (!(fs->flags & FSF_FETCHED)) { if (statfs(fs->path, sbuf) < 0) return PM_ERR_INST; fs->flags |= FSF_FETCHED; } switch (idp->item) { case 1: /* filesys.capacity */ ull = (__uint64_t)sbuf->f_blocks; atom->ull = ull * sbuf->f_bsize / 1024; break; case 2: /* filesys.used */ used = (__uint64_t)(sbuf->f_blocks - sbuf->f_bfree); atom->ull = used * sbuf->f_bsize / 1024; break; case 3: /* filesys.free */ ull = (__uint64_t)sbuf->f_bfree; atom->ull = ull * sbuf->f_bsize / 1024; break; case 4: /* filesys.maxfiles */ atom->ul = sbuf->f_files; break; case 5: /* filesys.usedfiles */ atom->ul = sbuf->f_files - sbuf->f_ffree; break; case 6: /* filesys.freefiles */ atom->ul = sbuf->f_ffree; break; case 7: /* filesys.mountdir */ atom->cp = fs->path; break; case 8: /* filesys.full */ used = (__uint64_t)(sbuf->f_blocks - sbuf->f_bfree); ull = used + (__uint64_t)sbuf->f_bavail; atom->d = (100.0 * (double)used) / (double)ull; break; case 9: /* filesys.blocksize -- added by Mike Mason */ atom->ul = sbuf->f_bsize; break; case 10: /* filesys.avail -- added by Mike Mason */ ull = (__uint64_t)sbuf->f_bavail; atom->ull = ull * sbuf->f_bsize / 1024; break; case 11: /* filesys.readonly */ atom->ul = (scan_filesys_options(fs->options, "ro") != NULL); break; default: return PM_ERR_PMID; } } break; case CLUSTER_TMPFS: { struct statfs *sbuf; __uint64_t ull, used; sts = pmdaCacheLookup(INDOM(TMPFS_INDOM), inst, NULL, (void **)&fs); if (sts < 0) return sts; if (sts != PMDA_CACHE_ACTIVE) return PM_ERR_INST; sbuf = &fs->stats; if (!(fs->flags & FSF_FETCHED)) { if (statfs(fs->path, sbuf) < 0) return PM_ERR_INST; fs->flags |= FSF_FETCHED; } switch (idp->item) { case 1: /* tmpfs.capacity */ ull = (__uint64_t)sbuf->f_blocks; atom->ull = ull * sbuf->f_bsize / 1024; break; case 2: /* tmpfs.used */ used = (__uint64_t)(sbuf->f_blocks - sbuf->f_bfree); atom->ull = used * sbuf->f_bsize / 1024; break; case 3: /* tmpfs.free */ ull = (__uint64_t)sbuf->f_bfree; atom->ull = ull * sbuf->f_bsize / 1024; break; case 4: /* tmpfs.maxfiles */ atom->ul = sbuf->f_files; break; case 5: /* tmpfs.usedfiles */ atom->ul = sbuf->f_files - sbuf->f_ffree; break; case 6: /* tmpfs.freefiles */ atom->ul = sbuf->f_ffree; break; case 7: /* tmpfs.full */ used = (__uint64_t)(sbuf->f_blocks - sbuf->f_bfree); ull = used + (__uint64_t)sbuf->f_bavail; atom->d = (100.0 * (double)used) / (double)ull; break; default: return PM_ERR_PMID; } } break; case CLUSTER_SWAPDEV: { struct swapdev *swap; sts = pmdaCacheLookup(INDOM(SWAPDEV_INDOM), inst, NULL, (void **)&swap); if (sts < 0) return sts; if (sts != PMDA_CACHE_ACTIVE) return PM_ERR_INST; switch (idp->item) { case 0: /* swapdev.free (kbytes) */ atom->ul = swap->size - swap->used; break; case 1: /* swapdev.length (kbytes) */ case 2: /* swapdev.maxswap (kbytes) */ atom->ul = swap->size; break; case 3: /* swapdev.vlength (kbytes) */ atom->ul = 0; break; case 4: /* swapdev.priority */ atom->l = swap->priority; break; default: return PM_ERR_PMID; } break; } case CLUSTER_NET_NFS: switch (idp->item) { case 1: /* nfs.client.calls */ if (proc_net_rpc.client.errcode != 0) return 0; /* no values available */ for (atom->ul=0, i=0; i < NR_RPC_COUNTERS; i++) { atom->ul += proc_net_rpc.client.reqcounts[i]; } break; case 50: /* nfs.server.calls */ if (proc_net_rpc.server.errcode != 0) return 0; /* no values available */ for (atom->ul=0, i=0; i < NR_RPC_COUNTERS; i++) { atom->ul += proc_net_rpc.server.reqcounts[i]; } break; case 4: /* nfs.client.reqs */ if (proc_net_rpc.client.errcode != 0) return 0; /* no values available */ if (inst < NR_RPC_COUNTERS) atom->ul = proc_net_rpc.client.reqcounts[inst]; else return PM_ERR_INST; break; case 12: /* nfs.server.reqs */ if (proc_net_rpc.server.errcode != 0) return 0; /* no values available */ if (inst < NR_RPC_COUNTERS) atom->ul = proc_net_rpc.server.reqcounts[inst]; else return PM_ERR_INST; break; case 60: /* nfs3.client.calls */ if (proc_net_rpc.client.errcode != 0) return 0; /* no values available */ for (atom->ul=0, i=0; i < NR_RPC3_COUNTERS; i++) { atom->ul += proc_net_rpc.client.reqcounts3[i]; } break; case 62: /* nfs3.server.calls */ if (proc_net_rpc.server.errcode != 0) return 0; /* no values available */ for (atom->ul=0, i=0; i < NR_RPC3_COUNTERS; i++) { atom->ul += proc_net_rpc.server.reqcounts3[i]; } break; case 61: /* nfs3.client.reqs */ if (proc_net_rpc.client.errcode != 0) return 0; /* no values available */ if (inst < NR_RPC3_COUNTERS) atom->ul = proc_net_rpc.client.reqcounts3[inst]; else return PM_ERR_INST; break; case 63: /* nfs3.server.reqs */ if (proc_net_rpc.server.errcode != 0) return 0; /* no values available */ if (inst < NR_RPC3_COUNTERS) atom->ul = proc_net_rpc.server.reqcounts3[inst]; else return PM_ERR_INST; break; case 64: /* nfs4.client.calls */ if (proc_net_rpc.client.errcode != 0) return 0; /* no values available */ for (atom->ul=0, i=0; i < NR_RPC4_CLI_COUNTERS; i++) { atom->ul += proc_net_rpc.client.reqcounts4[i]; } break; case 66: /* nfs4.server.calls */ if (proc_net_rpc.server.errcode != 0) return 0; /* no values available */ for (atom->ul=0, i=0; i < NR_RPC4_SVR_COUNTERS; i++) { atom->ul += proc_net_rpc.server.reqcounts4[i]; } break; case 65: /* nfs4.client.reqs */ if (proc_net_rpc.client.errcode != 0) return 0; /* no values available */ if (inst < NR_RPC4_CLI_COUNTERS) atom->ul = proc_net_rpc.client.reqcounts4[inst]; else return PM_ERR_INST; break; case 67: /* nfs4.server.reqs */ if (proc_net_rpc.server.errcode != 0) return 0; /* no values available */ if (inst < NR_RPC4_SVR_COUNTERS) atom->ul = proc_net_rpc.server.reqcounts4[inst]; else return PM_ERR_INST; break; /* * Note: all other rpc metric values are extracted directly via the * address specified in the metrictab (see above) */ default: return PM_ERR_PMID; } break; case CLUSTER_SLAB: if (proc_slabinfo.ncaches == 0) return 0; /* no values available */ if (inst >= proc_slabinfo.ncaches) return PM_ERR_INST; switch(idp->item) { case 0: /* mem.slabinfo.objects.active */ atom->ull = proc_slabinfo.caches[inst].num_active_objs; break; case 1: /* mem.slabinfo.objects.total */ atom->ull = proc_slabinfo.caches[inst].total_objs; break; case 2: /* mem.slabinfo.objects.size */ if (proc_slabinfo.caches[inst].seen < 11) /* version 1.1 or later only */ return 0; atom->ul = proc_slabinfo.caches[inst].object_size; break; case 3: /* mem.slabinfo.slabs.active */ if (proc_slabinfo.caches[inst].seen < 11) /* version 1.1 or later only */ return 0; atom->ul = proc_slabinfo.caches[inst].num_active_slabs; break; case 4: /* mem.slabinfo.slabs.total */ if (proc_slabinfo.caches[inst].seen == 11) /* version 1.1 only */ return 0; atom->ul = proc_slabinfo.caches[inst].total_slabs; break; case 5: /* mem.slabinfo.slabs.pages_per_slab */ if (proc_slabinfo.caches[inst].seen < 11) /* version 1.1 or later only */ return 0; atom->ul = proc_slabinfo.caches[inst].pages_per_slab; break; case 6: /* mem.slabinfo.slabs.objects_per_slab */ if (proc_slabinfo.caches[inst].seen != 20) /* version 2.0 only */ return 0; atom->ul = proc_slabinfo.caches[inst].objects_per_slab; break; case 7: /* mem.slabinfo.slabs.total_size */ if (proc_slabinfo.caches[inst].seen < 11) /* version 1.1 or later only */ return 0; atom->ull = proc_slabinfo.caches[inst].total_size; break; default: return PM_ERR_PMID; } break; case CLUSTER_PARTITIONS: return proc_partitions_fetch(mdesc, inst, atom); case CLUSTER_SCSI: if (proc_scsi.nscsi == 0) return 0; /* no values available */ switch(idp->item) { case 0: /* hinv.map.scsi */ atom->cp = (char *)NULL; for (i=0; i < proc_scsi.nscsi; i++) { if (proc_scsi.scsi[i].id == inst) { atom->cp = proc_scsi.scsi[i].dev_name; break; } } if (i == proc_scsi.nscsi) return PM_ERR_INST; break; default: return PM_ERR_PMID; } break; case CLUSTER_LV: switch(idp->item) { case 0: /* hinv.map.lvname */ if (dev_mapper.nlv == 0) return 0; /* no values available */ atom->cp = (char *)NULL; for (i = 0; i < dev_mapper.nlv; i++) { if (dev_mapper.lv[i].id == inst) { atom->cp = dev_mapper.lv[i].dev_name; break; } } if (i == dev_mapper.nlv) return PM_ERR_INST; break; case 1: /* hinv.nlv */ atom->ul = dev_mapper.nlv; break; default: return PM_ERR_PMID; } break; case CLUSTER_KERNEL_UNAME: switch(idp->item) { case 5: /* pmda.uname */ sprintf(uname_string, "%s %s %s %s %s", kernel_uname.sysname, kernel_uname.nodename, kernel_uname.release, kernel_uname.version, kernel_uname.machine); atom->cp = uname_string; break; case 6: /* pmda.version */ atom->cp = pmGetConfig("PCP_VERSION"); break; case 7: /* kernel.uname.distro ... not from uname(2) */ atom->cp = get_distro_info(); break; default: return PM_ERR_PMID; } break; case CLUSTER_CPUINFO: if (idp->item != 7 && /* hinv.machine is singular */ (inst >= proc_cpuinfo.cpuindom->it_numinst)) return PM_ERR_INST; switch(idp->item) { case 0: /* hinv.cpu.clock */ if (proc_cpuinfo.cpuinfo[inst].clock == 0.0) return 0; atom->f = proc_cpuinfo.cpuinfo[inst].clock; break; case 1: /* hinv.cpu.vendor */ i = proc_cpuinfo.cpuinfo[inst].vendor; atom->cp = linux_strings_lookup(i); if (atom->cp == NULL) atom->cp = "unknown"; break; case 2: /* hinv.cpu.model */ if ((i = proc_cpuinfo.cpuinfo[inst].model) < 0) i = proc_cpuinfo.cpuinfo[inst].model_name; atom->cp = linux_strings_lookup(i); if (atom->cp == NULL) atom->cp = "unknown"; break; case 3: /* hinv.cpu.stepping */ i = proc_cpuinfo.cpuinfo[inst].stepping; atom->cp = linux_strings_lookup(i); if (atom->cp == NULL) atom->cp = "unknown"; break; case 4: /* hinv.cpu.cache */ if (!proc_cpuinfo.cpuinfo[inst].cache) return 0; atom->ul = proc_cpuinfo.cpuinfo[inst].cache; break; case 5: /* hinv.cpu.bogomips */ if (proc_cpuinfo.cpuinfo[inst].bogomips == 0.0) return 0; atom->f = proc_cpuinfo.cpuinfo[inst].bogomips; break; case 6: /* hinv.map.cpu_num */ atom->ul = proc_cpuinfo.cpuinfo[inst].cpu_num; break; case 7: /* hinv.machine */ atom->cp = proc_cpuinfo.machine; break; case 8: /* hinv.map.cpu_node */ atom->ul = proc_cpuinfo.cpuinfo[inst].node; break; case 9: /* hinv.cpu.model_name */ if ((i = proc_cpuinfo.cpuinfo[inst].model_name) < 0) i = proc_cpuinfo.cpuinfo[inst].model; atom->cp = linux_strings_lookup(i); if (atom->cp == NULL) atom->cp = "unknown"; break; case 10: /* hinv.cpu.flags */ i = proc_cpuinfo.cpuinfo[inst].flags; atom->cp = linux_strings_lookup(i); if (atom->cp == NULL) atom->cp = "unknown"; break; case 11: /* hinv.cpu.cache_alignment */ if (!proc_cpuinfo.cpuinfo[inst].cache_align) return 0; atom->ul = proc_cpuinfo.cpuinfo[inst].cache_align; break; default: return PM_ERR_PMID; } break; /* * Cluster added by Mike Mason */ case CLUSTER_SEM_LIMITS: switch (idp->item) { case 0: /* ipc.sem.max_semmap */ atom->ul = sem_limits.semmap; break; case 1: /* ipc.sem.max_semid */ atom->ul = sem_limits.semmni; break; case 2: /* ipc.sem.max_sem */ atom->ul = sem_limits.semmns; break; case 3: /* ipc.sem.num_undo */ atom->ul = sem_limits.semmnu; break; case 4: /* ipc.sem.max_perid */ atom->ul = sem_limits.semmsl; break; case 5: /* ipc.sem.max_ops */ atom->ul = sem_limits.semopm; break; case 6: /* ipc.sem.max_undoent */ atom->ul = sem_limits.semume; break; case 7: /* ipc.sem.sz_semundo */ atom->ul = sem_limits.semusz; break; case 8: /* ipc.sem.max_semval */ atom->ul = sem_limits.semvmx; break; case 9: /* ipc.sem.max_exit */ atom->ul = sem_limits.semaem; break; default: return PM_ERR_PMID; } break; /* * Cluster added by Mike Mason */ case CLUSTER_MSG_LIMITS: switch (idp->item) { case 0: /* ipc.msg.sz_pool */ atom->ul = msg_limits.msgpool; break; case 1: /* ipc.msg.mapent */ atom->ul = msg_limits.msgmap; break; case 2: /* ipc.msg.max_msgsz */ atom->ul = msg_limits.msgmax; break; case 3: /* ipc.msg.max_defmsgq */ atom->ul = msg_limits.msgmnb; break; case 4: /* ipc.msg.max_msgqid */ atom->ul = msg_limits.msgmni; break; case 5: /* ipc.msg.sz_msgseg */ atom->ul = msg_limits.msgssz; break; case 6: /* ipc.msg.num_smsghdr */ atom->ul = msg_limits.msgtql; break; case 7: /* ipc.msg.max_seg */ atom->ul = (unsigned long) msg_limits.msgseg; break; default: return PM_ERR_PMID; } break; /* * Cluster added by Mike Mason */ case CLUSTER_SHM_LIMITS: switch (idp->item) { case 0: /* ipc.shm.max_segsz */ atom->ul = shm_limits.shmmax; break; case 1: /* ipc.shm.min_segsz */ atom->ul = shm_limits.shmmin; break; case 2: /* ipc.shm.max_seg */ atom->ul = shm_limits.shmmni; break; case 3: /* ipc.shm.max_segproc */ atom->ul = shm_limits.shmseg; break; case 4: /* ipc.shm.max_shmsys */ atom->ul = shm_limits.shmall; break; default: return PM_ERR_PMID; } break; /* * Cluster added by Mike Mason */ case CLUSTER_NUSERS: { /* count the number of users */ struct utmp *ut; atom->ul = 0; setutent(); while ((ut = getutent())) { if ((ut->ut_type == USER_PROCESS) && (ut->ut_name[0] != '\0')) atom->ul++; } endutent(); } break; case CLUSTER_IB: /* deprecated: network.ib, use infiniband PMDA */ return PM_ERR_APPVERSION; case CLUSTER_NUMA_MEMINFO: /* NUMA memory metrics from /sys/devices/system/node/nodeX */ if (inst >= numa_meminfo.node_indom->it_numinst) return PM_ERR_INST; switch(idp->item) { case 0: /* mem.numa.util.total */ sts = linux_table_lookup("MemTotal:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 1: /* mem.numa.util.free */ sts = linux_table_lookup("MemFree:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 2: /* mem.numa.util.used */ sts = linux_table_lookup("MemUsed:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 3: /* mem.numa.util.active */ sts = linux_table_lookup("Active:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 4: /* mem.numa.util.inactive */ sts = linux_table_lookup("Inactive:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 5: /* mem.numa.util.active_anon */ sts = linux_table_lookup("Active(anon):", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 6: /* mem.numa.util.inactive_anon */ sts = linux_table_lookup("Inactive(anon):", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 7: /* mem.numa.util.active_file */ sts = linux_table_lookup("Active(file):", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 8: /* mem.numa.util.inactive_file */ sts = linux_table_lookup("Inactive(file):", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 9: /* mem.numa.util.highTotal */ sts = linux_table_lookup("HighTotal:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 10: /* mem.numa.util.highFree */ sts = linux_table_lookup("HighFree:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 11: /* mem.numa.util.lowTotal */ sts = linux_table_lookup("LowTotal:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 12: /* mem.numa.util.lowFree */ sts = linux_table_lookup("LowFree:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 13: /* mem.numa.util.unevictable */ sts = linux_table_lookup("Unevictable:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 14: /* mem.numa.util.mlocked */ sts = linux_table_lookup("Mlocked:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 15: /* mem.numa.util.dirty */ sts = linux_table_lookup("Dirty:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 16: /* mem.numa.util.writeback */ sts = linux_table_lookup("Writeback:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 17: /* mem.numa.util.filePages */ sts = linux_table_lookup("FilePages:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 18: /* mem.numa.util.mapped */ sts = linux_table_lookup("Mapped:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 19: /* mem.numa.util.anonPages */ sts = linux_table_lookup("AnonPages:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 20: /* mem.numa.util.shmem */ sts = linux_table_lookup("Shmem:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 21: /* mem.numa.util.kernelStack */ sts = linux_table_lookup("KernelStack:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 22: /* mem.numa.util.pageTables */ sts = linux_table_lookup("PageTables:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 23: /* mem.numa.util.NFS_Unstable */ sts = linux_table_lookup("NFS_Unstable:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 24: /* mem.numa.util.bounce */ sts = linux_table_lookup("Bounce:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 25: /* mem.numa.util.writebackTmp */ sts = linux_table_lookup("WritebackTmp:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 26: /* mem.numa.util.slab */ sts = linux_table_lookup("Slab:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 27: /* mem.numa.util.slabReclaimable */ sts = linux_table_lookup("SReclaimable:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 28: /* mem.numa.util.slabUnreclaimable */ sts = linux_table_lookup("SUnreclaim:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 29: /* mem.numa.util.hugepagesTotal */ sts = linux_table_lookup("HugePages_Total:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 30: /* mem.numa.util.hugepagesFree */ sts = linux_table_lookup("HugePages_Free:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 31: /* mem.numa.util.hugepagesSurp */ sts = linux_table_lookup("HugePages_Surp:", numa_meminfo.node_info[inst].meminfo, &atom->ull); break; case 32: /* mem.numa.alloc.hit */ sts = linux_table_lookup("numa_hit", numa_meminfo.node_info[inst].memstat, &atom->ull); break; case 33: /* mem.numa.alloc.miss */ sts = linux_table_lookup("numa_miss", numa_meminfo.node_info[inst].memstat, &atom->ull); break; case 34: /* mem.numa.alloc.foreign */ sts = linux_table_lookup("numa_foreign", numa_meminfo.node_info[inst].memstat, &atom->ull); break; case 35: /* mem.numa.alloc.interleave_hit */ sts = linux_table_lookup("interleave_hit", numa_meminfo.node_info[inst].memstat, &atom->ull); break; case 36: /* mem.numa.alloc.local_node */ sts = linux_table_lookup("local_node", numa_meminfo.node_info[inst].memstat, &atom->ull); break; case 37: /* mem.numa.alloc.other_node */ sts = linux_table_lookup("other_node", numa_meminfo.node_info[inst].memstat, &atom->ull); break; default: return PM_ERR_PMID; } return sts; case CLUSTER_INTERRUPTS: switch (idp->item) { case 3: /* kernel.all.interrupts.error */ atom->ul = irq_err_count; break; default: return PM_ERR_PMID; } break; case CLUSTER_INTERRUPT_LINES: case CLUSTER_INTERRUPT_OTHER: if (inst >= indomtab[CPU_INDOM].it_numinst) return PM_ERR_INST; return interrupts_fetch(idp->cluster, idp->item, inst, atom); default: /* unknown cluster */ return PM_ERR_PMID; } return 1; } static int linux_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i; int need_refresh[NUM_CLUSTERS]; memset(need_refresh, 0, sizeof(need_refresh)); for (i=0; i < numpmid; i++) { __pmID_int *idp = (__pmID_int *)&(pmidlist[i]); if (idp->cluster < NUM_CLUSTERS) { need_refresh[idp->cluster]++; if (idp->cluster == CLUSTER_STAT && need_refresh[CLUSTER_PARTITIONS] == 0 && is_partitions_metric(pmidlist[i])) need_refresh[CLUSTER_PARTITIONS]++; if (idp->cluster == CLUSTER_CPUINFO || idp->cluster == CLUSTER_INTERRUPT_LINES || idp->cluster == CLUSTER_INTERRUPT_OTHER || idp->cluster == CLUSTER_INTERRUPTS) need_refresh[CLUSTER_STAT]++; } /* In 2.6 kernels, swap.{pagesin,pagesout} are in /proc/vmstat */ if (_pm_have_proc_vmstat && idp->cluster == CLUSTER_STAT) { if (idp->item >= 8 && idp->item <= 11) need_refresh[CLUSTER_VMSTAT]++; } } linux_refresh(pmda, need_refresh); return pmdaFetch(numpmid, pmidlist, resp, pmda); } static int linux_text(int ident, int type, char **buf, pmdaExt *pmda) { if ((type & PM_TEXT_PMID) == PM_TEXT_PMID) { int sts = pmdaDynamicLookupText(ident, type, buf, pmda); if (sts != -ENOENT) return sts; } return pmdaText(ident, type, buf, pmda); } static int linux_pmid(const char *name, pmID *pmid, pmdaExt *pmda) { pmdaNameSpace *tree = pmdaDynamicLookupName(pmda, name); return pmdaTreePMID(tree, name, pmid); } static int linux_name(pmID pmid, char ***nameset, pmdaExt *pmda) { pmdaNameSpace *tree = pmdaDynamicLookupPMID(pmda, pmid); return pmdaTreeName(tree, pmid, nameset); } static int linux_children(const char *name, int flag, char ***kids, int **sts, pmdaExt *pmda) { pmdaNameSpace *tree = pmdaDynamicLookupName(pmda, name); return pmdaTreeChildren(tree, name, flag, kids, sts); } pmInDom linux_indom(int serial) { return indomtab[serial].it_indom; } pmdaIndom * linux_pmda_indom(int serial) { return &indomtab[serial]; } /* * Helper routines for accessing a generic static string dictionary */ char * linux_strings_lookup(int index) { char *value; pmInDom dict = INDOM(STRINGS_INDOM); if (pmdaCacheLookup(dict, index, &value, NULL) == PMDA_CACHE_ACTIVE) return value; return NULL; } int linux_strings_insert(const char *buf) { pmInDom dict = INDOM(STRINGS_INDOM); return pmdaCacheStore(dict, PMDA_CACHE_ADD, buf, NULL); } /* * Initialise the agent (both daemon and DSO). */ void __PMDA_INIT_CALL linux_init(pmdaInterface *dp) { int i, major, minor, point; size_t nmetrics, nindoms; __pmID_int *idp; _pm_system_pagesize = getpagesize(); if (_isDSO) { char helppath[MAXPATHLEN]; int sep = __pmPathSeparator(); snprintf(helppath, sizeof(helppath), "%s%c" "linux" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_4, "linux DSO", helppath); } else { __pmSetProcessIdentity(username); } if (dp->status != 0) return; dp->version.four.instance = linux_instance; dp->version.four.fetch = linux_fetch; dp->version.four.text = linux_text; dp->version.four.pmid = linux_pmid; dp->version.four.name = linux_name; dp->version.four.children = linux_children; pmdaSetFetchCallBack(dp, linux_fetchCallBack); proc_stat.cpu_indom = proc_cpuinfo.cpuindom = &indomtab[CPU_INDOM]; numa_meminfo.node_indom = proc_cpuinfo.node_indom = &indomtab[NODE_INDOM]; proc_scsi.scsi_indom = &indomtab[SCSI_INDOM]; dev_mapper.lv_indom = &indomtab[LV_INDOM]; proc_slabinfo.indom = &indomtab[SLAB_INDOM]; /* * Figure out kernel version. The precision of certain metrics * (e.g. percpu time counters) has changed over kernel versions. * See include/linux/kernel_stat.h for all the various flavours. */ uname(&kernel_uname); _pm_ctxt_size = 8; _pm_intr_size = 8; _pm_cputime_size = 8; _pm_idletime_size = 8; if (sscanf(kernel_uname.release, "%d.%d.%d", &major, &minor, &point) == 3) { if (major < 2 || (major == 2 && minor <= 4)) { /* 2.4 and earlier */ _pm_ctxt_size = 4; _pm_intr_size = 4; _pm_cputime_size = 4; _pm_idletime_size = sizeof(unsigned long); } else if (major == 2 && minor == 6 && point >= 0 && point <= 4) { /* 2.6.0->.4 */ _pm_cputime_size = 4; _pm_idletime_size = 4; } } for (i = 0; i < sizeof(metrictab)/sizeof(pmdaMetric); i++) { idp = (__pmID_int *)&(metrictab[i].m_desc.pmid); if (idp->cluster == CLUSTER_STAT) { switch (idp->item) { case 0: /* kernel.percpu.cpu.user */ case 1: /* kernel.percpu.cpu.nice */ case 2: /* kernel.percpu.cpu.sys */ case 20: /* kernel.all.cpu.user */ case 21: /* kernel.all.cpu.nice */ case 22: /* kernel.all.cpu.sys */ case 30: /* kernel.percpu.cpu.wait.total */ case 31: /* kernel.percpu.cpu.intr */ case 34: /* kernel.all.cpu.intr */ case 35: /* kernel.all.cpu.wait.total */ case 53: /* kernel.all.cpu.irq.soft */ case 54: /* kernel.all.cpu.irq.hard */ case 55: /* kernel.all.cpu.steal */ case 56: /* kernel.percpu.cpu.irq.soft */ case 57: /* kernel.percpu.cpu.irq.hard */ case 58: /* kernel.percpu.cpu.steal */ case 60: /* kernel.all.cpu.guest */ case 78: /* kernel.all.cpu.vuser */ case 61: /* kernel.percpu.cpu.guest */ case 76: /* kernel.percpu.cpu.vuser */ case 62: /* kernel.pernode.cpu.user */ case 63: /* kernel.pernode.cpu.nice */ case 64: /* kernel.pernode.cpu.sys */ case 69: /* kernel.pernode.cpu.wait.total */ case 66: /* kernel.pernode.cpu.intr */ case 70: /* kernel.pernode.cpu.irq.soft */ case 71: /* kernel.pernode.cpu.irq.hard */ case 67: /* kernel.pernode.cpu.steal */ case 68: /* kernel.pernode.cpu.guest */ case 77: /* kernel.pernode.cpu.vuser */ _pm_metric_type(metrictab[i].m_desc.type, _pm_cputime_size); break; case 3: /* kernel.percpu.cpu.idle */ case 23: /* kernel.all.cpu.idle */ case 65: /* kernel.pernode.cpu.idle */ _pm_metric_type(metrictab[i].m_desc.type, _pm_idletime_size); break; case 12: /* kernel.all.intr */ _pm_metric_type(metrictab[i].m_desc.type, _pm_intr_size); break; case 13: /* kernel.all.pswitch */ _pm_metric_type(metrictab[i].m_desc.type, _pm_ctxt_size); break; } } if (metrictab[i].m_desc.type == PM_TYPE_NOSUPPORT) fprintf(stderr, "Bad kernel metric descriptor type (%u.%u)\n", idp->cluster, idp->item); } nindoms = sizeof(indomtab)/sizeof(indomtab[0]); nmetrics = sizeof(metrictab)/sizeof(metrictab[0]); proc_vmstat_init(); interrupts_init(metrictab, nmetrics); pmdaSetFlags(dp, PMDA_EXT_FLAG_HASHED); pmdaInit(dp, indomtab, nindoms, metrictab, nmetrics); /* string metrics use the pmdaCache API for value indexing */ pmdaCacheOp(INDOM(STRINGS_INDOM), PMDA_CACHE_STRINGS); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int sep = __pmPathSeparator(); int err = 0; int c; pmdaInterface dispatch; char helppath[MAXPATHLEN]; _isDSO = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(helppath, sizeof(helppath), "%s%c" "linux" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_4, pmProgname, LINUX, "linux.log", helppath); while ((c = pmdaGetOpt(argc, argv, "D:d:l:U:?", &dispatch, &err)) != EOF) { switch(c) { case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&dispatch); linux_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_sys_fs.h0000664000000000000000000000217212272262501016340 0ustar /* * Linux /proc/sys/fs metrics cluster * * Copyright (c) 2003,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ typedef struct { int errcode; /* error from previous refresh */ int fs_files_count; int fs_files_free; int fs_files_max; int fs_inodes_count; int fs_inodes_free; int fs_dentry_count; int fs_dentry_free; } proc_sys_fs_t; extern int refresh_proc_sys_fs(proc_sys_fs_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/proc_net_snmp_migrate.conf0000664000000000000000000000041212272262501021056 0ustar # Copyright 2013 Red Hat. # # pmlogrewrite configuration for migrating archives containing old # 32 bit /proc/net/snmp values to the 64 bit variants, matching up # with changes in the metadata supplied by the PMDA (and the kernel). # metric 60.14.* { type -> U64 } pcp-3.8.12ubuntu1/src/pmdas/linux/devmapper.c0000664000000000000000000000462512272262501015772 0ustar /* * Linux LVM Devices Cluster * * Copyright (c) 2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "devmapper.h" #define MAPDIR "/dev/mapper" int refresh_dev_mapper(dev_mapper_t *lvs) { int i; DIR *dirp; struct dirent *dentry; struct stat statbuf; char path[MAXPATHLEN]; dirp = opendir(MAPDIR); if (dirp == NULL) return 1; for (i = 0; i < lvs->nlv; i++) { free(lvs->lv[i].dev_name); free(lvs->lv[i].lv_name); } lvs->nlv = 0; lvs->lv = NULL; while ((dentry = readdir(dirp)) != NULL) { char linkname[MAXPATHLEN]; int linkname_len; snprintf(path, sizeof(path), "%s/%s", MAPDIR, dentry->d_name); if (stat(path, &statbuf) == -1) continue; if (!S_ISBLK(statbuf.st_mode)) continue; if ((linkname_len = readlink(path, linkname, sizeof(linkname)-1)) < 0) continue; linkname[linkname_len] = '\0'; i = lvs->nlv; lvs->nlv++; lvs->lv = (lv_entry_t *)realloc(lvs->lv, lvs->nlv * sizeof(lv_entry_t)); lvs->lv[i].id = lvs->nlv; lvs->lv[i].dev_name = malloc(strlen(dentry->d_name)+1); strcpy(lvs->lv[i].dev_name, dentry->d_name); lvs->lv[i].lv_name = malloc(linkname_len+1); strcpy(lvs->lv[i].lv_name, linkname); } closedir(dirp); if (lvs->lv_indom->it_numinst != lvs->nlv) { lvs->lv_indom->it_numinst = lvs->nlv; lvs->lv_indom->it_set = (pmdaInstid *) realloc(lvs->lv_indom->it_set, lvs->nlv * sizeof(pmdaInstid)); } for (i = 0; i < lvs->nlv; i++) { int skip_prefix = 0; lvs->lv_indom->it_set[i].i_inst = lvs->lv[i].id; if (strncmp (lvs->lv[i].lv_name, "../", 3) == 0) skip_prefix = 3; lvs->lv_indom->it_set[i].i_name = lvs->lv[i].lv_name + skip_prefix; } return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_scsi.h0000664000000000000000000000237412272262501015777 0ustar /* * Linux /proc/scsi/scsi metrics cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ typedef struct { int id; /* internal instance id */ char *namebuf; /* external name, i.e. host:channel:id:lun */ int dev_host; int dev_channel; int dev_id; int dev_lun; char *dev_type; char *dev_name; } scsi_entry_t; typedef struct { int nscsi; scsi_entry_t *scsi; pmdaIndom *scsi_indom; } proc_scsi_t; extern int refresh_proc_scsi(proc_scsi_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/msg_limits.h0000664000000000000000000000257712272262501016167 0ustar /* * Copyright (c) International Business Machines Corp., 2002 * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * This code contributed by Mike Mason (mmlnx@us.ibm.com) */ typedef struct { unsigned int msgpool; /* size of message pool (kbytes) */ unsigned int msgmap; /* # of entries in message map */ unsigned int msgmax; /* maximum size of a message */ unsigned int msgmnb; /* default maximum size of message queue */ unsigned int msgmni; /* maximum # of message queue identifiers */ unsigned int msgssz; /* message segment size */ unsigned int msgtql; /* # of system message headers */ unsigned int msgseg; /* maximum # of message segments */ } msg_limits_t; extern int refresh_msg_limits(msg_limits_t*); pcp-3.8.12ubuntu1/src/pmdas/linux/proc_stat.h0000664000000000000000000000406112272262501016004 0ustar /* * Linux /proc/stat metrics cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2008 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ typedef struct { unsigned long long user; unsigned long long sys; unsigned long long nice; unsigned long long idle; unsigned long long wait; unsigned long long irq; unsigned long long sirq; unsigned long long steal; unsigned long long guest; unsigned int ncpu; /* per-cpu */ unsigned long long *p_user; unsigned long long *p_sys; unsigned long long *p_nice; unsigned long long *p_idle; unsigned long long *p_wait; unsigned long long *p_irq; unsigned long long *p_sirq; unsigned long long *p_steal; unsigned long long *p_guest; /* per-node */ unsigned long long *n_user; unsigned long long *n_sys; unsigned long long *n_nice; unsigned long long *n_idle; unsigned long long *n_wait; unsigned long long *n_irq; unsigned long long *n_sirq; unsigned long long *n_steal; unsigned long long *n_guest; unsigned int ndisk; unsigned int page[2]; /* unused in 2.6 now in /proc/vmstat */ unsigned int swap[2]; /* unused in 2.6 now in /proc/vmstat */ unsigned long long intr; unsigned long long ctxt; unsigned long btime; unsigned long processes; pmdaIndom *cpu_indom; unsigned int hz; } proc_stat_t; extern int refresh_proc_stat(proc_cpuinfo_t *, proc_stat_t *); pcp-3.8.12ubuntu1/src/pmdas/linux/proc_sys_fs.c0000664000000000000000000000432112272262501016331 0ustar /* * Linux /proc/sys/fs metrics cluster * * Copyright (c) 2003,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "proc_sys_fs.h" int refresh_proc_sys_fs(proc_sys_fs_t *proc_sys_fs) { static int err_reported; FILE *filesp = NULL; FILE *inodep = NULL; FILE *dentryp = NULL; memset(proc_sys_fs, 0, sizeof(proc_sys_fs_t)); if ( (filesp = fopen("/proc/sys/fs/file-nr", "r")) == (FILE *)NULL || (inodep = fopen("/proc/sys/fs/inode-state", "r")) == (FILE *)NULL || (dentryp = fopen("/proc/sys/fs/dentry-state", "r")) == (FILE *)NULL) { proc_sys_fs->errcode = -oserror(); if (err_reported == 0) fprintf(stderr, "Warning: vfs metrics are not available : %s\n", osstrerror()); } else { proc_sys_fs->errcode = 0; if (fscanf(filesp, "%d %d %d", &proc_sys_fs->fs_files_count, &proc_sys_fs->fs_files_free, &proc_sys_fs->fs_files_max) != 3) proc_sys_fs->errcode = PM_ERR_VALUE; if (fscanf(inodep, "%d %d", &proc_sys_fs->fs_inodes_count, &proc_sys_fs->fs_inodes_free) != 2) proc_sys_fs->errcode = PM_ERR_VALUE; if (fscanf(dentryp, "%d %d", &proc_sys_fs->fs_dentry_count, &proc_sys_fs->fs_dentry_free) != 2) proc_sys_fs->errcode = PM_ERR_VALUE; #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { if (proc_sys_fs->errcode == 0) fprintf(stderr, "refresh_proc_sys_fs: found vfs metrics\n"); else fprintf(stderr, "refresh_proc_sys_fs: botch! missing vfs metrics\n"); } #endif } if (filesp) fclose(filesp); if (inodep) fclose(inodep); if (dentryp) fclose(dentryp); if (!err_reported) err_reported = 1; if (proc_sys_fs->errcode == 0) return 0; return -1; } pcp-3.8.12ubuntu1/src/pmdas/linux/help0000664000000000000000000015241712272262501014521 0ustar # # Copyright (c) 2000,2004-2008 Silicon Graphics, Inc. All Rights Reserved. # Portions Copyright (c) International Business Machines Corp., 2002 # Portions Copyright (c) 2007-2009 Aconex. All Rights Reserved. # Portions Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Linux PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ kernel.uname.release release level of the running kernel Release level of the running kernel as reported via the release[] value returned from uname(2) or uname -r. See also pmda.uname. @ kernel.uname.version version level (build number) and build date of the running kernel Version level of the running kernel as reported by the version[] value returned from uname(2) or uname -v. Usually a build number followed by a build date. See also pmda.uname. @ kernel.uname.sysname name of the implementation of the operating system Name of the implementation of the running operating system as reported by the sysname[] value returned from uname(2) or uname -s. Usually "Linux". See also pmda.uname. @ kernel.uname.machine name of the hardware type the system is running on Name of the hardware type the system is running on as reported by the machine[] value returned from uname(2) or uname -m, e.g. "i686". See also pmda.uname. @ kernel.uname.nodename host name of this node on the network Name of this node on the network as reported by the nodename[] value returned from uname(2) or uname -n. Usually a synonym for the host name. See also pmda.uname. @ kernel.uname.distro Linux distribution name The Linux distribution name, as determined by a number of heuristics. For example: + on Fedora, the contents of /etc/fedora-release + on RedHat, the contents of /etc/redhat-release @ kernel.percpu.cpu.user percpu user CPU time metric from /proc/stat, including guest CPU time @ kernel.percpu.cpu.vuser percpu user CPU time metric from /proc/stat, excluding guest CPU time @ kernel.percpu.cpu.nice percpu nice user CPU time metric from /proc/stat @ kernel.percpu.cpu.sys percpu sys CPU time metric from /proc/stat @ kernel.percpu.cpu.idle percpu idle CPU time metric from /proc/stat @ kernel.percpu.cpu.wait.total percpu wait CPU time Per-CPU I/O wait CPU time - time spent with outstanding I/O requests. @ kernel.percpu.cpu.intr percpu interrupt CPU time Total time spent processing interrupts on each CPU (this includes both soft and hard interrupt processing time). @ kernel.percpu.cpu.irq.soft percpu soft interrupt CPU time Per-CPU soft interrupt CPU time (deferred interrupt handling code, not run in the initial interrupt handler). @ kernel.percpu.cpu.irq.hard percpu hard interrupt CPU time Per-CPU hard interrupt CPU time ("hard" interrupt handling code is the code run directly on receipt of the initial hardware interrupt, and does not include "soft" interrupt handling code which is deferred until later). @ kernel.percpu.cpu.steal percpu CPU steal time Per-CPU time when the CPU had a runnable process, but the hypervisor (virtualisation layer) chose to run something else instead. @ kernel.percpu.cpu.guest percpu guest CPU time Per-CPU time spent running (virtual) guest operating systems. @ kernel.all.interrupts.errors interrupt error count from /proc/interrupts This is a global counter (normally converted to a count/second) for any and all errors that occur while handling interrupts. @ disk.dev.read per-disk read operations Cumulative number of disk read operations since system boot time (subject to counter wrap). @ disk.dev.write per-disk write operations Cumulative number of disk write operations since system boot time (subject to counter wrap). @ disk.dev.total per-disk total (read+write) operations Cumulative number of disk read and write operations since system boot time (subject to counter wrap). @ disk.dev.blkread per-disk block read operations Cumulative number of disk block read operations since system boot time (subject to counter wrap). @ disk.dev.blkwrite per-disk block write operations Cumulative number of disk block write operations since system boot time (subject to counter wrap). @ disk.dev.blktotal per-disk total (read+write) block operations Cumulative number of disk block read and write operations since system boot time (subject to counter wrap). @ disk.dev.read_bytes per-disk count of bytes read @ disk.dev.write_bytes per-disk count of bytes written @ disk.dev.total_bytes per-disk count of total bytes read and written @ disk.dev.scheduler per-disk I/O scheduler The name of the I/O scheduler in use for each device. The scheduler is part of the block layer in the kernel, and attempts to optimise the I/O submission patterns using various techniques (typically, sorting and merging adjacent requests into larger ones to reduce seek activity, but certainly not limited to that). @ disk.dev.avactive per-disk count of active time When converted to a rate, this metric represents the average utilization of the disk during the sampling interval. A value of 0.5 (or 50%) means the disk was active (i.e. busy) half the time. @ disk.dev.read_rawactive per-disk raw count of active read time When converted to a rate, this metric represents the raw utilization of the disk during the sampling interval as a result of reads. Accounting for this metric is only done on I/O completion and can thus result in more than a second's worth of IO being accounted for within any one second, leading to >100% utilisation. It is suitable mainly for use in calculations with other metrics, e.g. mirroring the results from existing performance tools: iostat.dev.r_await = delta(disk.dev.read_rawactive) / delta(disk.dev.read) @ disk.dev.write_rawactive per-disk raw count of active write time When converted to a rate, this metric represents the raw utilization of the disk during the sampling interval as a result of writes. Accounting for this metric is only done on I/O completion and can thus result in more than a second's worth of IO being accounted for within any one second, leading to >100% utilisation. It is suitable mainly for use in calculations with other metrics, e.g. mirroring the results from existing performance tools: iostat.dev.w_await = delta(disk.dev.write_rawactive) / delta(disk.dev.write) @ disk.dev.aveq per-disk time averaged count of request queue length When converted to a rate, this metric represents the time averaged disk request queue length during the sampling interval. A value of 2.5 (or 250%) represents a time averaged queue length of 2.5 requests during the sampling interval. @ disk.dev.read_merge per-disk count of merged read requests Count of read requests that were merged with an already queued read request. @ disk.dev.write_merge per-disk count of merged write requests Count of write requests that were merged with an already queued write request. @ disk.all.read_merge total count of merged read requests, summed for all disks Total count of read requests that were merged with an already queued read request. @ disk.all.write_merge total count of merged write requests, summed for all disks Total count of write requests that were merged with an already queued write request. @ disk.all.avactive total count of active time, summed for all disks When converted to a rate, this metric represents the average utilization of all disks during the sampling interval. A value of 0.25 (or 25%) means that on average every disk was active (i.e. busy) one quarter of the time. @ disk.all.read_rawactive raw count of active read time, summed for all disks When converted to a rate, this metric represents the raw utilization of all disks during the sampling interval due to read requests. The accounting for this metric is only done on I/O completion and can thus result in more than a second's worth of IO being accounted for within any one second, leading to >100% utilisation. It is suitable mainly for use in calculations with other metrics, e.g. mirroring the results from existing performance tools: iostat.all.r_await = delta(disk.all.read_rawactive) / delta(disk.all.read) @ disk.all.write_rawactive raw count of active write time, summed for all disks When converted to a rate, this metric represents the raw utilization of all disks during the sampling interval due to write requests. The accounting for this metric is only done on I/O completion and can thus result in more than a second's worth of IO being accounted for within any one second, leading to >100% utilisation. It is suitable mainly for use in calculations with other metrics, e.g. mirroring the result from existing performance tools: iostat.all.w_await = delta(disk.all.write_rawactive) / delta(disk.all.write) @ disk.all.aveq total time averaged count of request queue length, summed for all disks When converted to a rate, this metric represents the average across all disks of the time averaged request queue length during the sampling interval. A value of 1.5 (or 150%) suggests that (on average) each all disk experienced a time averaged queue length of 1.5 requests during the sampling interval. @ disk.all.read total read operations, summed for all disks Cumulative number of disk read operations since system boot time (subject to counter wrap), summed over all disk devices. @ disk.all.write total write operations, summed for all disks Cumulative number of disk read operations since system boot time (subject to counter wrap), summed over all disk devices. @ disk.all.total total (read+write) operations, summed for all disks Cumulative number of disk read and write operations since system boot time (subject to counter wrap), summed over all disk devices. @ disk.all.blkread block read operations, summed for all disks Cumulative number of disk block read operations since system boot time (subject to counter wrap), summed over all disk devices. @ disk.all.blkwrite block write operations, summed for all disks Cumulative number of disk block write operations since system boot time (subject to counter wrap), summed over all disk devices. @ disk.all.blktotal total (read+write) block operations, summed for all disks Cumulative number of disk block read and write operations since system boot time (subject to counter wrap), summed over all disk devices. @ disk.all.read_bytes count of bytes read for all disk devices @ disk.all.write_bytes count of bytes written for all disk devices @ disk.all.total_bytes total count of bytes read and written for all disk devices @ disk.partitions.read read operations metric for storage partitions Cumulative number of disk read operations since system boot time (subject to counter wrap) for individual disk partitions or logical volumes. @ disk.partitions.write write operations metric for storage partitions Cumulative number of disk write operations since system boot time (subject to counter wrap) for individual disk partitions or logical volumes. @ disk.partitions.total total (read+write) I/O operations metric for storage partitions Cumulative number of disk read and write operations since system boot time (subject to counter wrap) for individual disk partitions or logical volumes. @ disk.partitions.blkread block read operations metric for storage partitions Cumulative number of disk block read operations since system boot time (subject to counter wrap) for individual disk partitions or logical volumes. @ disk.partitions.blkwrite block write operations metric for storage partitions Cumulative number of disk block write operations since system boot time (subject to counter wrap) for individual disk partitions or logical volumes. @ disk.partitions.blktotal total (read+write) block operations metric for storage partitions Cumulative number of disk block read and write operations since system boot time (subject to counter wrap) for individual disk partitions or logical volumes. @ disk.partitions.read_bytes number of bytes read for storage partitions Cumulative number of bytes read since system boot time (subject to counter wrap) for individual disk partitions or logical volumes. @ disk.partitions.write_bytes number of bytes written for storage partitions Cumulative number of bytes written since system boot time (subject to counter wrap) for individual disk partitions or logical volumes. @ disk.partitions.total_bytes total number of bytes read and written for storage partitions Cumulative number of bytes read and written since system boot time (subject to counter wrap) for individual disk partitions or logical volumes. @ swap.pagesin pages read from swap devices due to demand for physical memory @ swap.pagesout pages written to swap devices due to demand for physical memory @ swap.in number of swap in operations @ swap.out number of swap out operations @ kernel.all.pswitch context switches metric from /proc/stat @ kernel.all.sysfork fork rate metric from /proc/stat @ kernel.all.intr intrrupt rate metric from /proc/stat The value is the first value from the intr field in /proc/stat, which is a counter of the total number of interrupts processed. The value is normally converted to a rate (count/second). This counter usually increases by at least HZ/second, i.e. the clock interrupt rate, wehich is usually 100/second. See also kernel.percpu.interrupts to get a breakdown of interrupt rates by interrupt type and which CPU processed each one. @ mem.physmem total system memory metric reported by /proc/meminfo The value of this metric corresponds to the "MemTotal" field reported by /proc/meminfo. Note that this does not necessarily correspond to actual installed physical memory - there may be areas of the physical address space mapped as ROM in various peripheral devices and the bios may be mirroring certain ROMs in RAM. @ mem.freemem free system memory metric from /proc/meminfo @ mem.util.used used memory metric from /proc/meminfo Used memory is the difference between mem.physmem and mem.freemem. @ mem.util.free free memory metric from /proc/meminfo Alias for mem.freemem. @ mem.util.shared shared memory metric from /proc/meminfo Shared memory metric. Currently always zero on Linux 2.4 kernels and has been removed from 2.6 kernels. @ mem.util.bufmem I/O buffers metric from /proc/meminfo Memory allocated for buffer_heads. @ mem.util.cached page cache metric from /proc/meminfo Memory used by the page cache, including buffered file data. This is in-memory cache for files read from the disk (the pagecache) but doesn't include SwapCached. @ mem.util.other unaccounted memory Memory that is not free (i.e. has been referenced) and is not cached. mem.physmem - mem.util.free - mem.util.cached - mem.util.buffers @ mem.util.active Kbytes on the active page list (recently referenced pages) Memory that has been used more recently and usually not reclaimed unless absolutely necessary. @ mem.util.inactive Kbytes on the inactive page list (candidates for discarding) Memory which has been less recently used. It is more eligible to be reclaimed for other purposes @ mem.util.swapCached Kbytes in swap cache, from /proc/meminfo Memory that once was swapped out, is swapped back in but still also is in the swapfile (if memory is needed it doesn't need to be swapped out AGAIN because it is already in the swapfile. This saves I/O) @ mem.util.highTotal Kbytes in high memory, from /proc/meminfo This is apparently an i386 specific metric, and seems to be always zero on ia64 architecture (and possibly others). On i386 arch (at least), highmem is all memory above ~860MB of physical memory. Highmem areas are for use by userspace programs, or for the pagecache. The kernel must use tricks to access this memory, making it slower to access than lowmem. @ mem.util.highFree Kbytes free high memory, from /proc/meminfo See mem.util.highTotal. Not used on ia64 arch (and possibly others). @ mem.util.lowTotal Kbytes in low memory total, from /proc/meminfo Lowmem is memory which can be used for everything that highmem can be used for, but it is also availble for the kernel's use for its own data structures. Among many other things, it is where everything from the Slab is allocated. Bad things happen when you're out of lowmem. (this may only be true on i386 architectures). @ mem.util.lowFree Kbytes free low memory, from /proc/meminfo See mem.util.lowTotal @ mem.util.swapTotal Kbytes swap, from /proc/meminfo total amount of swap space available @ mem.util.swapFree Kbytes free swap, from /proc/meminfo Memory which has been evicted from RAM, and is temporarily on the disk @ mem.util.dirty Kbytes in dirty pages, from /proc/meminfo Memory which is waiting to get written back to the disk @ mem.util.writeback Kbytes in writeback pages, from /proc/meminfo Memory which is actively being written back to the disk @ mem.util.mapped Kbytes in mapped pages, from /proc/meminfo files which have been mmaped, such as libraries @ mem.util.slab Kbytes in slab memory, from /proc/meminfo in-kernel data structures cache @ mem.util.commitLimit Kbytes limit for address space commit, from /proc/meminfo The static total, in Kbytes, available for commitment to address spaces. Thus, mem.util.committed_AS may range up to this total. Normally the kernel overcommits memory, so this value may exceed mem.physmem @ mem.util.committed_AS Kbytes committed to address spaces, from /proc/meminfo An estimate of how much RAM you would need to make a 99.99% guarantee that there never is OOM (out of memory) for this workload. Normally the kernel will overcommit memory. That means, say you do a 1GB malloc, nothing happens, really. Only when you start USING that malloc memory you will get real memory on demand, and just as much as you use. @ mem.util.pageTables Kbytes in kernel page tables, from /proc/meminfo @ mem.util.reverseMaps Kbytes in reverse mapped pages, from /proc/meminfo @ mem.util.cache_clean Kbytes cached and not dirty or writeback, derived from /proc/meminfo @ mem.util.anonpages Kbytes in user pages not backed by files, from /proc/meminfo @ mem.util.bounce Kbytes in bounce buffers, from /proc/meminfo @ mem.util.NFS_Unstable Kbytes in NFS unstable memory, from /proc/meminfo @ mem.util.slabReclaimable Kbytes in reclaimable slab pages, from /proc/meminfo @ mem.util.slabUnreclaimable Kbytes in unreclaimable slab pages, from /proc/meminfo @ mem.util.active_anon anonymous Active list LRU memory @ mem.util.inactive_anon anonymous Inactive list LRU memory @ mem.util.active_file file-backed Active list LRU memory @ mem.util.inactive_file file-backed Inactive list LRU memory @ mem.util.unevictable kbytes of memory that is unevictable @ mem.util.mlocked kbytes of memory that is pinned via mlock() @ mem.util.shmem kbytes of shmem @ mem.util.kernelStack kbytes of memory used for kernel stacks @ mem.util.hugepagesTotal a count of total hugepages @ mem.util.hugepagesFree a count of free hugepages @ mem.util.hugepagesSurp a count of surplus hugepages @ mem.util.directMap4k amount of memory that is directly mapped in 4kB pages @ mem.util.directMap2M amount of memory that is directly mapped in 2MB pages @ mem.util.directMap1G amount of memory that is directly mapped in 1GB pages @ mem.util.vmallocTotal amount of kernel memory allocated via vmalloc @ mem.util.vmallocUsed amount of used vmalloc memory @ mem.util.vmallocChunk amount of vmalloc chunk memory @ mem.util.mmap_copy amount of mmap_copy space (non-MMU kernels only) @ mem.util.quicklists amount of memory in the per-CPU quicklists @ mem.util.corrupthardware amount of memory in hardware corrupted pages @ mem.util.anonhugepages amount of memory in anonymous huge pages User memory (Kbytes) in pages not backed by files, e.g. from malloc() @ mem.numa.util.total per-node total memory @ mem.numa.util.free per-node free memory @ mem.numa.util.used per-node used memory @ mem.numa.util.active per-node Active list LRU memory @ mem.numa.util.inactive per-node Inactive list LRU memory @ mem.numa.util.active_anon per-node anonymous Active list LRU memory @ mem.numa.util.inactive_anon per-node anonymous Inactive list LRU memory @ mem.numa.util.active_file per-node file-backed Active list LRU memory @ mem.numa.util.inactive_file per-node file-backed Inactive list LRU memory @ mem.numa.util.highTotal per-node highmem total @ mem.numa.util.highFree per-node highmem free @ mem.numa.util.lowTotal per-node lowmem total @ mem.numa.util.lowFree per-node lowmem free @ mem.numa.util.unevictable per-node Unevictable memory @ mem.numa.util.mlocked per-node count of Mlocked memory @ mem.numa.util.dirty per-node dirty memory @ mem.numa.util.writeback per-node count of memory locked for writeback to stable storage @ mem.numa.util.filePages per-node count of memory backed by files @ mem.numa.util.mapped per-node mapped memory @ mem.numa.util.anonpages per-node anonymous memory @ mem.numa.util.shmem per-node amount of shared memory @ mem.numa.util.kernelStack per-node memory used as kernel stacks @ mem.numa.util.pageTables per-node memory used for pagetables @ mem.numa.util.NFS_Unstable per-node memory holding NFS data that needs writeback @ mem.numa.util.bounce per-node memory used for bounce buffers @ mem.numa.util.writebackTmp per-node temporary memory used for writeback @ mem.numa.util.slab per-node memory used for slab objects @ mem.numa.util.slabReclaimable per-node memory used for slab objects that can be reclaimed @ mem.numa.util.slabUnreclaimable per-node memory used for slab objects that is unreclaimable @ mem.numa.util.hugepagesTotal per-node total count of hugepages @ mem.numa.util.hugepagesFree per-node count of free hugepages @ mem.numa.util.hugepagesSurp per-node count of surplus hugepages @ mem.numa.alloc.hit per-node count of times a task wanted alloc on local node and succeeded @ mem.numa.alloc.miss per-node count of times a task wanted alloc on local node but got another node @ mem.numa.alloc.foreign count of times a task on another node alloced on that node, but got this node @ mem.numa.alloc.interleave_hit count of times interleaving wanted to allocate on this node and succeeded @ mem.numa.alloc.local_node count of times a process ran on this node and got memory on this node @ mem.numa.alloc.other_node count of times a process ran on this node and got memory from another node @ mem.vmstat.nr_dirty number of pages in dirty state Instantaneous number of pages in dirty state, from /proc/vmstat @ mem.vmstat.nr_dirtied count of pages dirtied Count of pages entering dirty state, from /proc/vmstat @ mem.vmstat.nr_writeback number of pages in writeback state Instantaneous number of pages in writeback state, from /proc/vmstat @ mem.vmstat.nr_unstable number of pages in unstable state Instantaneous number of pages in unstable state, from /proc/vmstat @ mem.vmstat.nr_page_table_pages number of page table pages Instantaneous number of page table pages, from /proc/vmstat @ mem.vmstat.nr_mapped number of mapped pagecache pages Instantaneous number of mapped pagecache pages, from /proc/vmstat See also mem.vmstat.nr_anon for anonymous mapped pages. @ mem.vmstat.nr_slab number of slab pages Instantaneous number of slab pages, from /proc/vmstat This counter was retired in 2.6.18 kernels, and is now the sum of mem.vmstat.nr_slab_reclaimable and mem.vmstat.nr_slab_unreclaimable. @ mem.vmstat.nr_written count of pages written out Count of pages written out, from /proc/vmstat @ mem.vmstat.numa_foreign count of foreign NUMA zone allocations @ mem.vmstat.numa_hit count of successful allocations from preferred NUMA zone @ mem.vmstat.numa_interleave count of interleaved NUMA allocations @ mem.vmstat.numa_local count of successful allocations from local NUMA zone @ mem.vmstat.numa_miss count of unsuccessful allocations from preferred NUMA zona @ mem.vmstat.numa_other count of unsuccessful allocations from local NUMA zone @ mem.vmstat.pgpgin page in operations Count of page in operations since boot, from /proc/vmstat @ mem.vmstat.pgpgout page out operations Count of page out operations since boot, from /proc/vmstat @ mem.vmstat.pswpin pages swapped in Count of pages swapped in since boot, from /proc/vmstat @ mem.vmstat.pswpout pages swapped out Count of pages swapped out since boot, from /proc/vmstat @ mem.vmstat.pgalloc_high high mem page allocations Count of high mem page allocations since boot, from /proc/vmstat @ mem.vmstat.pgalloc_normal normal mem page allocations Count of normal mem page allocations since boot, from /proc/vmstat @ mem.vmstat.pgalloc_dma dma mem page allocations Count of dma mem page allocations since boot, from /proc/vmstat @ mem.vmstat.pgalloc_dma32 dma32 mem page allocations Count of dma32 mem page allocations since boot, from /proc/vmstat @ mem.vmstat.pgalloc_movable movable mem page allocations Count of movable mem page allocations since boot, from /proc/vmstat @ mem.vmstat.pgfree page free operations Count of page free operations since boot, from /proc/vmstat @ mem.vmstat.pgactivate pages moved from inactive to active Count of pages moved from inactive to active since boot, from /proc/vmstat @ mem.vmstat.pgdeactivate pages moved from active to inactive Count of pages moved from active to inactive since boot, from /proc/vmstat @ mem.vmstat.pgfault page major and minor fault operations Count of page major and minor fault operations since boot, from /proc/vmstat @ mem.vmstat.pgmajfault major page fault operations Count of major page fault operations since boot, from /proc/vmstat @ mem.vmstat.pgrefill_high high mem pages inspected in refill_inactive_zone Count of high mem pages inspected in refill_inactive_zone since boot, from /proc/vmstat @ mem.vmstat.pgrefill_normal normal mem pages inspected in refill_inactive_zone Count of normal mem pages inspected in refill_inactive_zone since boot, from /proc/vmstat @ mem.vmstat.pgrefill_dma dma mem pages inspected in refill_inactive_zone Count of dma mem pages inspected in refill_inactive_zone since boot, from /proc/vmstat @ mem.vmstat.pgrefill_dma32 dma32 mem pages inspected in refill_inactive_zone Count of dma32 mem pages inspected in refill_inactive_zone since boot, from /proc/vmstat @ mem.vmstat.pgrefill_movable movable mem pages inspected in refill_inactive_zone Count of movable mem pages inspected in refill_inactive_zone since boot, from /proc/vmstat @ mem.vmstat.pgsteal_high high mem pages reclaimed Count of high mem pages reclaimed since boot, from /proc/vmstat @ mem.vmstat.pgsteal_normal normal mem pages reclaimed Count of normal mem pages reclaimed since boot, from /proc/vmstat @ mem.vmstat.pgsteal_dma dma mem pages reclaimed Count of dma mem pages reclaimed since boot, from /proc/vmstat @ mem.vmstat.pgsteal_dma32 dma32 mem pages reclaimed Count of dma32 mem pages reclaimed since boot, from /proc/vmstat @ mem.vmstat.pgsteal_movable movable mem pages reclaimed Count of movable mem pages reclaimed since boot, from /proc/vmstat @ mem.vmstat.pgscan_kswapd_high high mem pages scanned by kswapd Count of high mem pages scanned by kswapd since boot, from /proc/vmstat @ mem.vmstat.pgscan_kswapd_normal normal mem pages scanned by kswapd Count of normal mem pages scanned by kswapd since boot, from /proc/vmstat @ mem.vmstat.pgscan_kswapd_dma dma mem pages scanned by kswapd Count of dma mem pages scanned by kswapd since boot, from /proc/vmstat @ mem.vmstat.pgscan_kswapd_dma32 dma32 mem pages scanned by kswapd Count of dma32 mem pages scanned by kswapd since boot, from /proc/vmstat @ mem.vmstat.pgscan_kswapd_movable movable mem pages scanned by kswapd Count of movable mem pages scanned by kswapd since boot, from /proc/vmstat @ mem.vmstat.pgscan_direct_high high mem pages scanned Count of high mem pages scanned since boot, from /proc/vmstat @ mem.vmstat.pgscan_direct_normal normal mem pages scanned Count of normal mem pages scanned since boot, from /proc/vmstat @ mem.vmstat.pgscan_direct_dma dma mem pages scanned Count of dma mem pages scanned since boot, from /proc/vmstat @ mem.vmstat.pgscan_direct_dma32 dma32 mem pages scanned Count of dma32 mem pages scanned since boot, from /proc/vmstat @ mem.vmstat.pgscan_direct_movable Count of movable mem pages scanned since boot, from /proc/vmstat @ mem.vmstat.pginodesteal pages reclaimed via inode freeing Count of pages reclaimed via inode freeing since boot, from /proc/vmstat @ mem.vmstat.slabs_scanned slab pages scanned Count of slab pages scanned since boot, from /proc/vmstat @ mem.vmstat.kswapd_steal pages reclaimed by kswapd Count of pages reclaimed by kswapd since boot, from /proc/vmstat @ mem.vmstat.kswapd_low_wmark_hit_quickly count of times low watermark reached quickly Count of times kswapd reached low watermark quickly, from /proc/vmstat @ mem.vmstat.kswapd_high_wmark_hit_quickly count of times high watermark reached quickly Count of times kswapd reached high watermark quickly, from /proc/vmstat @ mem.vmstat.kswapd_skip_congestion_wait count of times kswapd skipped waiting on device congestion Count of times kswapd skipped waiting due to device congestion as a result of being under the low watermark, from /proc/vmstat @ mem.vmstat.kswapd_inodesteal pages reclaimed via kswapd inode freeing Count of pages reclaimed via kswapd inode freeing since boot, from /proc/vmstat @ mem.vmstat.pageoutrun kswapd calls to page reclaim Count of kswapd calls to page reclaim since boot, from /proc/vmstat @ mem.vmstat.allocstall direct reclaim calls Count of direct reclaim calls since boot, from /proc/vmstat @ mem.vmstat.pgrotated pages rotated to tail of the LRU Count of pages rotated to tail of the LRU since boot, from /proc/vmstat @mem.vmstat.nr_anon_pages number of anonymous mapped pagecache pages Instantaneous number of anonymous mapped pagecache pages, from /proc/vmstat See also mem.vmstat.mapped for other mapped pages. @mem.vmstat.nr_anon_transparent_hugepages number of anonymous transparent huge pages Instantaneous number of anonymous transparent huge pages, from /proc/vmstat @mem.vmstat.nr_bounce number of bounce buffer pages Instantaneous number of bounce buffer pages, from /proc/vmstat @mem.vmstat.nr_slab_reclaimable reclaimable slab pages Instantaneous number of reclaimable slab pages, from /proc/vmstat. @mem.vmstat.nr_slab_unreclaimable unreclaimable slab pages Instantaneous number of unreclaimable slab pages, from /proc/vmstat. @mem.vmstat.nr_vmscan_write pages written by VM scanner from LRU Count of pages written from the LRU by the VM scanner, from /proc/vmstat. The VM is supposed to minimise the number of pages which get written from the LRU (for IO scheduling efficiency, and for high reclaim-success rates). @ mem.vmstat.htlb_buddy_alloc_fail huge TLB page buddy allocation failures Count of huge TLB page buddy allocation failures, from /proc/vmstat @ mem.vmstat.htlb_buddy_alloc_success huge TLB page buddy allocation successes Count of huge TLB page buddy allocation successes, from /proc/vmstat @ mem.vmstat.nr_active_anon number of active anonymous memory pages @ mem.vmstat.nr_active_file number of active file memory memory pages @ mem.vmstat.nr_free_pages number of free pages @ mem.vmstat.nr_inactive_anon number of inactive anonymous memory pages @ mem.vmstat.nr_inactive_file number of inactive file memory pages @ mem.vmstat.nr_isolated_anon number of isolated anonymous memory pages @ mem.vmstat.nr_isolated_file number of isolated file memory pages @ mem.vmstat.nr_kernel_stack number of pages of kernel stack @ mem.vmstat.nr_mlock number of pages under mlock @ mem.vmstat.nr_shmem number of shared memory pages @ mem.vmstat.nr_unevictable number of unevictable pages @ mem.vmstat.nr_writeback_temp number of temporary writeback pages @ mem.vmstat.compact_blocks_moved count of compact blocks moved @ mem.vmstat.compact_fail count of unsuccessful compactions for high order allocations @ mem.vmstat.compact_pagemigrate_failed count of pages unsuccessfully compacted @ mem.vmstat.compact_pages_moved count of pages successfully moved for compaction @ mem.vmstat.compact_stall count of failures to even start compacting @ mem.vmstat.compact_success count of successful compactions for high order allocations @ mem.vmstat.thp_fault_alloc transparent huge page fault allocations @ mem.vmstat.thp_fault_fallback transparent huge page fault fallbacks @ mem.vmstat.thp_collapse_alloc transparent huge page collapse allocations @ mem.vmstat.thp_collapse_alloc_failed transparent huge page collapse failures @ mem.vmstat.thp_split count of transparent huge page splits @ mem.vmstat.unevictable_pgs_cleared count of unevictable pages cleared @ mem.vmstat.unevictable_pgs_culled count of unevictable pages culled @ mem.vmstat.unevictable_pgs_mlocked count of mlocked unevictable pages @ mem.vmstat.unevictable_pgs_mlockfreed count of unevictable pages mlock freed @ mem.vmstat.unevictable_pgs_munlocked count of unevictable pages munlocked @ mem.vmstat.unevictable_pgs_rescued count of unevictable pages rescued @ mem.vmstat.unevictable_pgs_scanned count of unevictable pages scanned @ mem.vmstat.unevictable_pgs_stranded count of unevictable pages stranded @ mem.vmstat.zone_reclaim_failed number of zone reclaim failures @ swap.length total swap available metric from /proc/meminfo @ swap.used swap used metric from /proc/meminfo @ swap.free swap free metric from /proc/meminfo @ kernel.all.load 1, 5 and 15 minute load average @ kernel.all.cpu.user total user CPU time from /proc/stat for all CPUs, including guest CPU time @ kernel.all.cpu.vuser total user CPU time from /proc/stat for all CPUs, excluding guest CPU time @ kernel.all.cpu.intr total interrupt CPU time from /proc/stat for all CPUs Total time spent processing interrupts on all CPUs. This value includes both soft and hard interrupt processing time. @ kernel.all.cpu.wait.total total wait CPU time from /proc/stat for all CPUs @ kernel.all.cpu.nice total nice user CPU time from /proc/stat for all CPUs @ kernel.all.cpu.sys total sys CPU time from /proc/stat for all CPUs @ kernel.all.cpu.idle total idle CPU time from /proc/stat for all CPUs @ kernel.all.cpu.irq.soft soft interrupt CPU time from /proc/stat for all CPUs Total soft interrupt CPU time (deferred interrupt handling code, not run in the initial interrupt handler). @ kernel.all.cpu.irq.hard hard interrupt CPU time from /proc/stat for all CPUs Total hard interrupt CPU time ("hard" interrupt handling code is the code run directly on receipt of the initial hardware interrupt, and does not include "soft" interrupt handling code which is deferred until later). @ kernel.all.cpu.steal total virtualisation CPU steal time for all CPUs Total CPU time when a CPU had a runnable process, but the hypervisor (virtualisation layer) chose to run something else instead. @ kernel.all.cpu.guest total virtual guest CPU time for all CPUs Total CPU time spent running virtual guest operating systems. @ kernel.all.nusers number of user sessions on system @ hinv.ninterface number of active (up) network interfaces @ network.interface.in.bytes network recv read bytes from /proc/net/dev per network interface @ network.interface.in.packets network recv read packets from /proc/net/dev per network interface @ network.interface.in.errors network recv read errors from /proc/net/dev per network interface @ network.interface.in.drops network recv read drops from /proc/net/dev per network interface @ network.interface.in.mcasts network recv compressed from /proc/net/dev per network interface @ network.interface.in.fifo network recv read fifos from /proc/net/dev per network interface @ network.interface.in.frame network recv read frames from /proc/net/dev per network interface @ network.interface.in.compressed network recv compressed from /proc/net/dev per network interface @ network.interface.out.bytes network send bytes from /proc/net/dev per network interface @ network.interface.out.packets network send packets from /proc/net/dev per network interface @ network.interface.out.errors network send errors from /proc/net/dev per network interface @ network.interface.out.drops network send drops from /proc/net/dev per network interface @ network.interface.out.fifo network send fifos from /proc/net/dev per network interface @ network.interface.collisions network send collisions from /proc/net/dev per network interface @ network.interface.out.carrier network send carrier from /proc/net/dev per network interface @ network.interface.out.compressed network send compressed from /proc/net/dev per network interface @ network.interface.total.bytes network total (in+out) bytes from /proc/net/dev per network interface @ network.interface.total.packets network total (in+out) packets from /proc/net/dev per network interface @ network.interface.total.errors network total (in+out) errors from /proc/net/dev per network interface @ network.interface.total.drops network total (in+out) drops from /proc/net/dev per network interface @ network.interface.total.mcasts network total (in+out) mcasts from /proc/net/dev per network interface @ network.interface.mtu maximum transmission unit on network interface @ network.interface.speed interface speed in megabytes per second The linespeed on the network interface, as reported by the kernel, scaled from Megabits/second to Megabytes/second. See also network.interface.baudrate for the bytes/second value. @ network.interface.baudrate interface speed in bytes per second The linespeed on the network interface, as reported by the kernel, scaled up from Megabits/second to bits/second and divided by 8 to convert to bytes/second. See also network.interface.speed for the Megabytes/second value. @ network.interface.duplex value one for half or two for full duplex interface @ network.interface.up boolean for whether interface is currently up or down @ network.interface.running boolean for whether interface has resources allocated @ network.interface.inet_addr string INET interface address (ifconfig style) @ network.interface.ipv6_addr string IPv6 interface address (ifconfig style) @ network.interface.ipv6_scope string IPv6 interface scope (ifconfig style) @ network.interface.hw_addr hardware address (from sysfs) @ network.sockstat.tcp.inuse instantaneous number of tcp sockets currently in use @ network.sockstat.tcp.highest highest number of tcp sockets in use at any one time since boot @ network.sockstat.tcp.util instantaneous tcp socket utilization (100 * inuse/highest) @ network.sockstat.udp.inuse instantaneous number of udp sockets currently in use @ network.sockstat.udp.highest highest number of udp sockets in use at any one time since boot @ network.sockstat.udp.util instantaneous udp socket utilization (100 * inuse/highest) @ network.sockstat.raw.inuse instantaneous number of raw sockets currently in use @ network.sockstat.raw.highest highest number of raw sockets in use at any one time since boot @ network.sockstat.raw.util instantaneous raw socket utilization (100 * inuse/highest) @ hinv.physmem total system memory metric from /proc/meminfo @ hinv.pagesize Memory page size The memory page size of the running kernel in bytes. @ hinv.ncpu number of CPUs in the system @ hinv.ndisk number of disks in the system @ hinv.nfilesys number of (local) file systems currently mounted @ hinv.nnode number of NUMA nodes in the system @ hinv.map.scsi list of active SCSI devices There is one string value for each SCSI device active in the system, as extracted from /proc/scsi/scsi. The external instance name for each device is in the format scsiD:C:I:L where D is controller number, C is channel number, I is device ID and L is the SCSI LUN number for the device. The values for this metric are the actual device names (sd[a-z] are SCSI disks, st[0-9] are SCSI tapes and scd[0-9] are SCSI CD-ROMS. @ hinv.nlv number of logical volumes @ hinv.map.lvname mapping of logical volume names for devices Provides a logical-volume-name to device-name mapping for the device mapper subsystem. @ filesys.capacity Total capacity of mounted filesystem (Kbytes) @ filesys.used Total space used on mounted filesystem (Kbytes) @ filesys.free Total space free on mounted filesystem (Kbytes) @ filesys.maxfiles Inodes capacity of mounted filesystem @ filesys.usedfiles Number of inodes allocated on mounted filesystem @ filesys.freefiles Number of unallocated inodes on mounted filesystem @ filesys.mountdir File system mount point @ filesys.full Percentage of filesystem in use @ filesys.blocksize Size of each block on mounted filesystem (Bytes) @ filesys.avail Total space free to non-superusers on mounted filesystem (Kbytes) @ filesys.readonly Indicates whether a filesystem is mounted readonly @ tmpfs.capacity Total capacity of mounted tmpfs filesystem (Kbytes) @ tmpfs.used Total space used on mounted tmpfs filesystem (Kbytes) @ tmpfs.free Total space free on mounted tmpfs filesystem (Kbytes) @ tmpfs.maxfiles Inodes capacity of mounted tmpfs filesystem @ tmpfs.usedfiles Number of inodes allocated on mounted tmpfs filesystem @ tmpfs.freefiles Number of unallocated inodes on mounted tmpfs filesystem @ tmpfs.full Percentage of tmpfs filesystem in use @ swapdev.free physical swap free space @ swapdev.length physical swap size @ swapdev.maxswap maximum swap length (same as swapdev.length on Linux) @ swapdev.vlength virtual swap size (always zero on Linux) Virtual swap size (always zero on Linux since Linux does not support virtual swap). This metric is retained on Linux for interoperability with PCP monitor tools running on IRIX. @ swapdev.priority swap resource priority @ nfs.client.calls cumulative total of client NFSv2 requests @ nfs.client.reqs cumulative total of client NFSv2 requests by request type @ nfs.server.calls cumulative total of server NFSv2 requests @ nfs.server.reqs cumulative total of client NFSv2 requests by request type @ nfs3.client.calls cumulative total of client NFSv3 requests @ nfs3.client.reqs cumulative total of client NFSv3 requests by request type @ nfs3.server.calls cumulative total of server NFSv3 requests @ nfs3.server.reqs cumulative total of client NFSv3 requests by request type @ nfs4.client.calls cumulative total of client NFSv4 requests @ nfs4.client.reqs cumulative total for each client NFSv4 request type @ nfs4.server.calls cumulative total of server NFSv4 operations, plus NULL requests @ nfs4.server.reqs cumulative total for each server NFSv4 operation, and for NULL requests @ rpc.client.rpccnt cumulative total of client RPC requests @ rpc.client.rpcretrans cumulative total of client RPC retransmissions @ rpc.client.rpcauthrefresh cumulative total of client RPC auth refreshes @ rpc.client.netcnt cumulative total of client RPC network layer requests @ rpc.client.netudpcnt cumulative total of client RPC UDP network layer requests @ rpc.client.nettcpcnt cumulative total of client RPC TCP network layer requests @ rpc.client.nettcpconn cumulative total of client RPC TCP network layer connection requests @ rpc.server.rpccnt cumulative total of server RPC requests @ rpc.server.rpcerr cumulative total of server RPC errors @ rpc.server.rpcbadfmt cumulative total of server RPC bad format errors @ rpc.server.rpcbadauth cumulative total of server RPC bad auth errors @ rpc.server.rpcbadclnt cumulative total of server RPC bad client errors @ rpc.server.rchits cumulative total of request-reply-cache hits @ rpc.server.rcmisses cumulative total of request-reply-cache misses @ rpc.server.rcnocache cumulative total of uncached request-reply-cache requests @ rpc.server.fh_cached cumulative total of file handle cache requests @ rpc.server.fh_valid cumulative total of file handle cache validations @ rpc.server.fh_fixup cumulative total of file handle cache fixup validations @ rpc.server.fh_lookup cumulative total of file handle cache new lookups @ rpc.server.fh_stale cumulative total of stale file handle cache errors @ rpc.server.fh_concurrent cumulative total of concurrent file handle cache requests @ rpc.server.netcnt cumulative total of server RPC network layer requests @ rpc.server.netudpcnt cumulative total of server RPC UDP network layer requests @ rpc.server.nettcpcnt cumulative total of server RPC TCP network layer requests @ rpc.server.nettcpconn cumulative total of server RPC TCP network layer connection requests @ rpc.server.fh_anon cumulative total anonymous file dentries returned @ rpc.server.fh_nocache_dir count of directory file handles not found cached @ rpc.server.fh_nocache_nondir count of non-directory file handles not found cached @ rpc.server.io_read cumulative count of bytes returned from read requests @ rpc.server.io_write cumulative count of bytes passed into write requests @ rpc.server.th_cnt available nfsd threads @ rpc.server.th_fullcnt number of times the last free nfsd thread was used @ network.ip.forwarding count of ip forwarding @ network.ip.defaultttl count of ip defaultttl @ network.ip.inreceives count of ip inreceives @ network.ip.inhdrerrors count of ip inhdrerrors @ network.ip.inaddrerrors count of ip inaddrerrors @ network.ip.forwdatagrams count of ip forwdatagrams @ network.ip.inunknownprotos count of ip inunknownprotos @ network.ip.indiscards count of ip indiscards @ network.ip.indelivers count of ip indelivers @ network.ip.outrequests count of ip outrequests @ network.ip.outdiscards count of ip outdiscards @ network.ip.outnoroutes count of ip outnoroutes @ network.ip.reasmtimeout count of ip reasmtimeout @ network.ip.reasmreqds count of ip reasmreqds @ network.ip.reasmoks count of ip reasmoks @ network.ip.reasmfails count of ip reasmfails @ network.ip.fragoks count of ip fragoks @ network.ip.fragfails count of ip fragfails @ network.ip.fragcreates count of ip fragcreates @ network.icmp.inmsgs count of icmp inmsgs @ network.icmp.inerrors count of icmp inerrors @ network.icmp.indestunreachs count of icmp indestunreachs @ network.icmp.intimeexcds count of icmp intimeexcds @ network.icmp.inparmprobs count of icmp inparmprobs @ network.icmp.insrcquenchs count of icmp insrcquenchs @ network.icmp.inredirects count of icmp inredirects @ network.icmp.inechos count of icmp inechos @ network.icmp.inechoreps count of icmp inechoreps @ network.icmp.intimestamps count of icmp intimestamps @ network.icmp.intimestampreps count of icmp intimestampreps @ network.icmp.inaddrmasks count of icmp inaddrmasks @ network.icmp.inaddrmaskreps count of icmp inaddrmaskreps @ network.icmp.outmsgs count of icmp outmsgs @ network.icmp.outerrors count of icmp outerrors @ network.icmp.outdestunreachs count of icmp outdestunreachs @ network.icmp.outtimeexcds count of icmp outtimeexcds @ network.icmp.outparmprobs count of icmp outparmprobs @ network.icmp.outsrcquenchs count of icmp outsrcquenchs @ network.icmp.outredirects count of icmp outredirects @ network.icmp.outechos count of icmp outechos @ network.icmp.outechoreps count of icmp outechoreps @ network.icmp.outtimestamps count of icmp outtimestamps @ network.icmp.outtimestampreps count of icmp outtimestampreps @ network.icmp.outaddrmasks count of icmp outaddrmasks @ network.icmp.outaddrmaskreps count of icmp outaddrmaskreps @ network.icmp.incsumerrors count of icmp in checksum errors @ network.icmpmsg.intype count of icmp message types recvd @ network.icmpmsg.outtype count of icmp message types sent @ network.tcp.rtoalgorithm count of tcp rtoalgorithm @ network.tcp.rtomin count of tcp rtomin @ network.tcp.rtomax count of tcp rtomax @ network.tcp.maxconn count of tcp maxconn @ network.tcp.activeopens count of tcp activeopens @ network.tcp.passiveopens count of tcp passiveopens @ network.tcp.attemptfails count of tcp attemptfails @ network.tcp.estabresets count of tcp estabresets @ network.tcp.currestab count of tcp currestab @ network.tcp.insegs count of tcp insegs @ network.tcp.outsegs count of tcp outsegs @ network.tcp.retranssegs count of tcp retranssegs @ network.tcp.inerrs count of tcp inerrs @ network.tcp.outrsts count of tcp outrsts @ network.tcp.incsumerrors count of tcp in checksum errors @ network.tcpconn.established Number of established connections @ network.tcpconn.syn_sent Number of SYN_SENT connections @ network.tcpconn.syn_recv Number of SYN_RECV connections @ network.tcpconn.fin_wait1 Number of FIN_WAIT1 connections @ network.tcpconn.fin_wait2 Number of FIN_WAIT2 connections @ network.tcpconn.time_wait Number of TIME_WAIT connections @ network.tcpconn.close Number of CLOSE connections @ network.tcpconn.close_wait Number of CLOSE_WAIT connections @ network.tcpconn.last_ack Number of LAST_ACK connections @ network.tcpconn.listen Number of LISTEN connections @ network.tcpconn.closing Number of CLOSING connections @ network.udp.indatagrams count of udp indatagrams @ network.udp.noports count of udp noports @ network.udp.inerrors count of udp inerrors @ network.udp.outdatagrams count of udp outdatagrams @ network.udp.recvbuferrors count of udp receive buffer errors @ network.udp.sndbuferrors count of udp send buffer errors @ network.udp.incsumerrors count of udp in checksum errors @ network.udplite.indatagrams count of udplite indatagrams @ network.udplite.noports count of udplite noports @ network.udplite.inerrors count of udplite inerrors @ network.udplite.outdatagrams count of udplite outdatagrams @ network.udplite.recvbuferrors count of udplite receive buffer errors @ network.udplite.sndbuferrors count of udplite send buffer errors @ network.udplite.incsumerrors count of udplite in checksum errors @ pmda.uname identity and type of current system Identity and type of current system. The concatenation of the values returned from utsname(2), also similar to uname -a. See also the kernel.uname.* metrics @ pmda.version build version of Linux PMDA @ hinv.map.cpu_num logical to physical CPU mapping for each CPU @ hinv.map.cpu_node logical CPU to NUMA node mapping for each CPU @ hinv.machine machine name, IP35 if SGI SNIA, else simply linux @ hinv.cpu.clock clock rate in Mhz for each CPU as reported by /proc/cpuinfo @ hinv.cpu.vendor manafacturer of each CPU as reported by /proc/cpuinfo @ hinv.cpu.model model number of each CPU as reported by /proc/cpuinfo @ hinv.cpu.model_name model name of each CPU as reported by /proc/cpuinfo @ hinv.cpu.stepping stepping of each CPU as reported by /proc/cpuinfo @ hinv.cpu.cache primary cache size of each CPU as reported by /proc/cpuinfo @ hinv.cpu.bogomips bogo mips rating for each CPU as reported by /proc/cpuinfo @ kernel.all.hz value of HZ (jiffies/second) for the currently running kernel @ kernel.all.uptime time the current kernel has been running @ kernel.all.idletime time the current kernel has been idle since boot @ kernel.all.lastpid most recently allocated process id @ kernel.all.runnable total number of processes in the (per-CPU) run queues @ kernel.all.nprocs total number of processes (lightweight) @ mem.slabinfo.objects.active number of active objects in each cache @ mem.slabinfo.objects.total total number of objects in each cache @ mem.slabinfo.objects.size size of individual objects of each cache @ mem.slabinfo.slabs.active number of active slabs comprising each cache @ mem.slabinfo.slabs.total total number of slabs comprising each cache @ mem.slabinfo.slabs.pages_per_slab number of pages in each slab @ mem.slabinfo.slabs.objects_per_slab number of objects in each slab @ mem.slabinfo.slabs.total_size total number of bytes allocated for active objects in each slab @ ipc.sem.max_semmap maximum number of entries in a semaphore map (from semctl(..,IPC_INFO,..)) @ ipc.sem.max_semid maximum number of semaphore identifiers (from semctl(..,IPC_INFO,..)) @ ipc.sem.max_sem maximum number of semaphores in system (from semctl(..,IPC_INFO,..)) @ ipc.sem.num_undo number of undo structures in system (from semctl(..,IPC_INFO,..)) @ ipc.sem.max_perid maximum number of semaphores per identifier (from semctl(..,IPC_INFO,..)) @ ipc.sem.max_ops maximum number of operations per semop call (from semctl(..,IPC_INFO,..)) @ ipc.sem.max_undoent maximum number of undo entries per process (from semctl(..,IPC_INFO,..)) @ ipc.sem.sz_semundo size of struct sem_undo (from semctl(..,IPC_INFO,..)) @ ipc.sem.max_semval semaphore maximum value (from semctl(..,IPC_INFO,..)) @ ipc.sem.max_exit adjust on exit maximum value (from semctl(..,IPC_INFO,..)) @ ipc.msg.sz_pool size of message pool in kilobytes (from msgctl(..,IPC_INFO,..)) @ ipc.msg.mapent number of entries in a message map (from msgctl(..,IPC_INFO,..)) @ ipc.msg.max_msgsz maximum size of a message in bytes (from msgctl(..,IPC_INFO,..)) @ ipc.msg.max_defmsgq default maximum size of a message queue (from msgctl(..,IPC_INFO,..)) @ ipc.msg.max_msgqid maximum number of message queue identifiers (from msgctl(..,IPC_INFO,..)) @ ipc.msg.max_msgseg message segment size (from msgctl(..,IPC_INFO,..)) @ ipc.msg.num_smsghdr number of system message headers (from msgctl(..,IPC_INFO,..)) @ ipc.msg.max_seg maximum number of message segments (from msgctl(..,IPC_INFO,..)) @ ipc.shm.max_segsz maximum shared segment size in bytes (from shmctl(..,IPC_INFO,..)) @ ipc.shm.min_segsz minimum shared segment size in bytes (from shmctl(..,IPC_INFO,..)) @ ipc.shm.max_seg maximum number of shared segments in system (from shmctl(..,IPC_INFO,..)) @ ipc.shm.max_segproc maximum number of shared segments per process (from shmctl(..,IPC_INFO,..)) @ ipc.shm.max_shmsys maximum amount of shared memory in system in pages (from shmctl(..,IPC_INFO,..)) @ vfs.files.count number of in-use file structures @ vfs.files.free number of available file structures @ vfs.files.max hard maximum on number of file structures @ vfs.inodes.count number of in-use inode structures @ vfs.inodes.free number of available inode structures @ vfs.dentry.count number of in-use dentry structures @ vfs.dentry.free number of available dentry structures @ sysfs.kernel.uevent_seqnum counter of the number of uevents processed by the udev subsystem pcp-3.8.12ubuntu1/src/pmdas/linux/proc_scsi.c0000664000000000000000000001135012272262501015764 0ustar /* * Linux Scsi Devices Cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "proc_scsi.h" static char diskname[64]; static char tapename[64]; static char cdromname[64]; int refresh_proc_scsi(proc_scsi_t *scsi) { char buf[1024]; char name[1024]; int i; int n; FILE *fp; char *sp; static int have_devfs = -1; static int next_id = -1; if (next_id < 0) { /* one trip initialization */ next_id = 0; scsi->nscsi = 0; scsi->scsi = (scsi_entry_t *)malloc(sizeof(scsi_entry_t)); /* scsi indom */ scsi->scsi_indom->it_numinst = 0; scsi->scsi_indom->it_set = (pmdaInstid *)malloc(sizeof(pmdaInstid)); /* devfs naming convention */ have_devfs = access("/dev/.devfsd", F_OK) == 0; if (have_devfs) { strcpy(diskname, "scsi/host%d/bus%d/target%d/lun%d/disc"); strcpy(tapename, "st0"); strcpy(cdromname, "scd0"); } else { strcpy(diskname, "sda"); strcpy(tapename, "st0"); strcpy(cdromname, "scd0"); } } if ((fp = fopen("/proc/scsi/scsi", "r")) == (FILE *)NULL) return -oserror(); while (fgets(buf, sizeof(buf), fp) != NULL) { scsi_entry_t x = { 0 }; if (strncmp(buf, "Host:", 5) != 0) continue; n = sscanf(buf, "Host: scsi%d Channel: %d Id: %d Lun: %d", &x.dev_host, &x.dev_channel, &x.dev_id, &x.dev_lun); if (n != 4) continue; for (i=0; i < scsi->nscsi; i++) { if (scsi->scsi[i].dev_host == x.dev_host && scsi->scsi[i].dev_channel == x.dev_channel && scsi->scsi[i].dev_id == x.dev_id && scsi->scsi[i].dev_lun == x.dev_lun) break; } if (i == scsi->nscsi) { scsi->nscsi++; scsi->scsi = (scsi_entry_t *)realloc(scsi->scsi, scsi->nscsi * sizeof(scsi_entry_t)); memcpy(&scsi->scsi[i], &x, sizeof(scsi_entry_t)); scsi->scsi[i].id = next_id++; /* scan for the Vendor: and Type: strings */ while (fgets(buf, sizeof(buf), fp) != NULL) { if ((sp = strstr(buf, "Type:")) != (char *)NULL) { if (sscanf(sp, "Type: %s", name) == 1) scsi->scsi[i].dev_type = strdup(name); else scsi->scsi[i].dev_type = strdup("unknown"); break; } } if (strcmp(scsi->scsi[i].dev_type, "Direct-Access") == 0) { if (have_devfs) { scsi->scsi[i].dev_name = (char *)malloc(64); sprintf(scsi->scsi[i].dev_name, diskname, scsi->scsi[i].dev_host, scsi->scsi[i].dev_channel, scsi->scsi[i].dev_id, scsi->scsi[i].dev_lun); } else { scsi->scsi[i].dev_name = strdup(diskname); diskname[2]++; /* sd[a-z] bump to next disk device name */ } } else if (strcmp(scsi->scsi[i].dev_type, "Sequential-Access") == 0) { scsi->scsi[i].dev_name = strdup(tapename); tapename[2]++; /* st[0-9] bump to next tape device name */ } else if (strcmp(scsi->scsi[i].dev_type, "CD-ROM") == 0) { scsi->scsi[i].dev_name = strdup(cdromname); cdromname[3]++; /* scd[0-9] bump to next CDROM device name */ } else if (strcmp(scsi->scsi[i].dev_type, "Processor") == 0) scsi->scsi[i].dev_name = strdup("SCSI Controller"); else scsi->scsi[i].dev_name = strdup("Unknown SCSI device"); sprintf(name, "scsi%d:%d:%d:%d %s", scsi->scsi[i].dev_host, scsi->scsi[i].dev_channel, scsi->scsi[i].dev_id, scsi->scsi[i].dev_lun, scsi->scsi[i].dev_type); scsi->scsi[i].namebuf = strdup(name); #if PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { fprintf(stderr, "refresh_proc_scsi: add host=scsi%d channel=%d id=%d lun=%d type=%s\n", scsi->scsi[i].dev_host, scsi->scsi[i].dev_channel, scsi->scsi[i].dev_id, scsi->scsi[i].dev_lun, scsi->scsi[i].dev_type); } #endif } } /* refresh scsi indom */ if (scsi->scsi_indom->it_numinst != scsi->nscsi) { scsi->scsi_indom->it_numinst = scsi->nscsi; scsi->scsi_indom->it_set = (pmdaInstid *)realloc(scsi->scsi_indom->it_set, scsi->nscsi * sizeof(pmdaInstid)); memset(scsi->scsi_indom->it_set, 0, scsi->nscsi * sizeof(pmdaInstid)); } for (i=0; i < scsi->nscsi; i++) { scsi->scsi_indom->it_set[i].i_inst = scsi->scsi[i].id; scsi->scsi_indom->it_set[i].i_name = scsi->scsi[i].namebuf; } /* * success */ fclose(fp); return 0; } pcp-3.8.12ubuntu1/src/pmdas/linux/proc_net_rpc.c0000664000000000000000000001270712272262501016464 0ustar /* * Linux /proc/net_rpc metrics cluster * * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "proc_net_rpc.h" int refresh_proc_net_rpc(proc_net_rpc_t *proc_net_rpc) { char buf[4096]; FILE *fp; char *p; int i; memset(proc_net_rpc, 0, sizeof(proc_net_rpc_t)); /* * client stats */ if ((fp = fopen("/proc/net/rpc/nfs", "r")) == (FILE *)NULL) { proc_net_rpc->client.errcode = -oserror(); } else { proc_net_rpc->client.errcode = 0; while (fgets(buf, sizeof(buf), fp) != NULL) { if (strncmp(buf, "net", 3) == 0) sscanf(buf, "net %u %u %u %u", &proc_net_rpc->client.netcnt, &proc_net_rpc->client.netudpcnt, &proc_net_rpc->client.nettcpcnt, &proc_net_rpc->client.nettcpconn); else if (strncmp(buf, "rpc", 3) == 0) sscanf(buf, "rpc %u %u %u", &proc_net_rpc->client.rpccnt, &proc_net_rpc->client.rpcretrans, &proc_net_rpc->client.rpcauthrefresh); else if (strncmp(buf, "proc2", 5) == 0) { if ((p = strtok(buf, " ")) != NULL) p = strtok(NULL, " "); for (i=0; p && i < NR_RPC_COUNTERS; i++) { if ((p = strtok(NULL, " ")) == NULL) break; proc_net_rpc->client.reqcounts[i] = strtoul(p, (char **)NULL, 10); } } else if (strncmp(buf, "proc3", 5) == 0) { if ((p = strtok(buf, " ")) != NULL) p = strtok(NULL, " "); for (i=0; p && i < NR_RPC3_COUNTERS; i++) { if ((p = strtok(NULL, " ")) == NULL) break; proc_net_rpc->client.reqcounts3[i] = strtoul(p, (char **)NULL, 10); } } else if (strncmp(buf, "proc4", 5) == 0) { if ((p = strtok(buf, " ")) != NULL) p = strtok(NULL, " "); for (i=0; p && i < NR_RPC4_CLI_COUNTERS; i++) { if ((p = strtok(NULL, " ")) == NULL) break; proc_net_rpc->client.reqcounts4[i] = strtoul(p, (char **)NULL, 10); } } } fclose(fp); } /* * server stats */ if ((fp = fopen("/proc/net/rpc/nfsd", "r")) == (FILE *)NULL) { proc_net_rpc->server.errcode = -oserror(); } else { proc_net_rpc->server.errcode = 0; while (fgets(buf, sizeof(buf), fp) != NULL) { if (strncmp(buf, "rc", 2) == 0) sscanf(buf, "rc %u %u %u %u %u %u %u %u %u", &proc_net_rpc->server.rchits, &proc_net_rpc->server.rcmisses, &proc_net_rpc->server.rcnocache, &proc_net_rpc->server.fh_cached, &proc_net_rpc->server.fh_valid, &proc_net_rpc->server.fh_fixup, &proc_net_rpc->server.fh_lookup, &proc_net_rpc->server.fh_stale, &proc_net_rpc->server.fh_concurrent); else if (strncmp(buf, "fh", 2) == 0) sscanf(buf, "fh %u %u %u %u %u", &proc_net_rpc->server.fh_stale, &proc_net_rpc->server.fh_lookup, &proc_net_rpc->server.fh_anon, &proc_net_rpc->server.fh_nocache_dir, &proc_net_rpc->server.fh_nocache_nondir); else if (strncmp(buf, "io", 2) == 0) sscanf(buf, "io %u %u", &proc_net_rpc->server.io_read, &proc_net_rpc->server.io_write); else if (strncmp(buf, "th", 2) == 0) sscanf(buf, "th %u %u", &proc_net_rpc->server.th_cnt, &proc_net_rpc->server.th_fullcnt); else if (strncmp(buf, "net", 3) == 0) sscanf(buf, "net %u %u %u %u", &proc_net_rpc->server.netcnt, &proc_net_rpc->server.netudpcnt, &proc_net_rpc->server.nettcpcnt, &proc_net_rpc->server.nettcpconn); else if (strncmp(buf, "rpc", 3) == 0) sscanf(buf, "rpc %u %u %u", &proc_net_rpc->server.rpccnt, &proc_net_rpc->server.rpcerr, /* always the sum of the following three fields */ &proc_net_rpc->server.rpcbadfmt); else if (strncmp(buf, "proc2", 5) == 0) { if ((p = strtok(buf, " ")) != NULL) p = strtok(NULL, " "); for (i=0; p && i < NR_RPC_COUNTERS; i++) { if ((p = strtok(NULL, " ")) == NULL) break; proc_net_rpc->server.reqcounts[i] = strtoul(p, (char **)NULL, 10); } } else if (strncmp(buf, "proc3", 5) == 0) { if ((p = strtok(buf, " ")) != NULL) p = strtok(NULL, " "); for (i=0; p && i < NR_RPC3_COUNTERS; i++) { if ((p = strtok(NULL, " ")) == NULL) break; proc_net_rpc->server.reqcounts3[i] = strtoul(p, (char **)NULL, 10); } } else if (strncmp(buf, "proc4ops", 8) == 0) { if ((p = strtok(buf, " ")) != NULL) p = strtok(NULL, " "); /* Inst 0 is NULL count (below) */ for (i=1; p && i < NR_RPC4_SVR_COUNTERS; i++) { if ((p = strtok(NULL, " ")) == NULL) break; proc_net_rpc->server.reqcounts4[i] = strtoul(p, (char **)NULL, 10); } } else if (strncmp(buf, "proc4", 5) == 0) { if ((strtok(buf, " ")) != NULL && (strtok(NULL, " ")) != NULL && (p = strtok(NULL, " ")) != NULL) { /* 3rd token is NULL count */ proc_net_rpc->server.reqcounts4[0] = strtoul(p, (char **)NULL, 10); } } } fclose(fp); } if (proc_net_rpc->client.errcode == 0 && proc_net_rpc->server.errcode == 0) return 0; return -1; } pcp-3.8.12ubuntu1/src/pmdas/linux/getinfo.h0000664000000000000000000000113112272262501015434 0ustar /* * Copyright (c) 2010 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ extern char *get_distro_info(void); pcp-3.8.12ubuntu1/src/pmdas/linux/proc_net_snmp.h0000664000000000000000000000755212272262521016666 0ustar /* * Copyright (c) 2013-2014 Red Hat. * Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #define SNMP_MAX_COLUMNS 64 /* arbitrary upper bound */ #define SNMP_PERLINE 16 /* see net/ipv4/proc.c */ #define SNMP_MAX_ICMPMSG_TYPESTR 8 /* longest name for type */ #define NR_ICMPMSG_COUNTERS 256 /* half of __ICMPMSG_MIB_MAX from kernel */ enum { _PM_SNMP_IP_FORWARDING = 0, _PM_SNMP_IP_DEFAULTTTL, _PM_SNMP_IP_INRECEIVES, _PM_SNMP_IP_INHDRERRORS, _PM_SNMP_IP_INADDRERRORS, _PM_SNMP_IP_FORWDATAGRAMS, _PM_SNMP_IP_INUNKNOWNPROTOS, _PM_SNMP_IP_INDISCARDS, _PM_SNMP_IP_INDELIVERS, _PM_SNMP_IP_OUTREQUESTS, _PM_SNMP_IP_OUTDISCARDS, _PM_SNMP_IP_OUTNOROUTES, _PM_SNMP_IP_REASMTIMEOUT, _PM_SNMP_IP_REASMREQDS, _PM_SNMP_IP_REASMOKS, _PM_SNMP_IP_REASMFAILS, _PM_SNMP_IP_FRAGOKS, _PM_SNMP_IP_FRAGFAILS, _PM_SNMP_IP_FRAGCREATES, _PM_SNMP_IP_NFIELDS /* must be last */ }; enum { _PM_SNMP_ICMP_INMSGS = 0, _PM_SNMP_ICMP_INERRORS, _PM_SNMP_ICMP_INCSUMERRORS, _PM_SNMP_ICMP_INDESTUNREACHS, _PM_SNMP_ICMP_INTIMEEXCDS, _PM_SNMP_ICMP_INPARMPROBS, _PM_SNMP_ICMP_INSRCQUENCHS, _PM_SNMP_ICMP_INREDIRECTS, _PM_SNMP_ICMP_INECHOS, _PM_SNMP_ICMP_INECHOREPS, _PM_SNMP_ICMP_INTIMESTAMPS, _PM_SNMP_ICMP_INTIMESTAMPREPS, _PM_SNMP_ICMP_INADDRMASKS, _PM_SNMP_ICMP_INADDRMASKREPS, _PM_SNMP_ICMP_OUTMSGS, _PM_SNMP_ICMP_OUTERRORS, _PM_SNMP_ICMP_OUTDESTUNREACHS, _PM_SNMP_ICMP_OUTTIMEEXCDS, _PM_SNMP_ICMP_OUTPARMPROBS, _PM_SNMP_ICMP_OUTSRCQUENCHS, _PM_SNMP_ICMP_OUTREDIRECTS, _PM_SNMP_ICMP_OUTECHOS, _PM_SNMP_ICMP_OUTECHOREPS, _PM_SNMP_ICMP_OUTTIMESTAMPS, _PM_SNMP_ICMP_OUTTIMESTAMPREPS, _PM_SNMP_ICMP_OUTADDRMASKS, _PM_SNMP_ICMP_OUTADDRMASKREPS, _PM_SNMP_ICMP_NFIELDS /* must be last */ }; enum { _PM_SNMP_ICMPMSG_INTYPE = 0, _PM_SNMP_ICMPMSG_OUTTYPE = NR_ICMPMSG_COUNTERS, _PM_SNMP_ICMPMSG_NFIELDS = (NR_ICMPMSG_COUNTERS*2) }; enum { _PM_SNMP_TCP_RTOALGORITHM = 0, _PM_SNMP_TCP_RTOMIN, _PM_SNMP_TCP_RTOMAX, _PM_SNMP_TCP_MAXCONN, _PM_SNMP_TCP_ACTIVEOPENS, _PM_SNMP_TCP_PASSIVEOPENS, _PM_SNMP_TCP_ATTEMPTFAILS, _PM_SNMP_TCP_ESTABRESETS, _PM_SNMP_TCP_CURRESTAB, _PM_SNMP_TCP_INSEGS, _PM_SNMP_TCP_OUTSEGS, _PM_SNMP_TCP_RETRANSSEGS, _PM_SNMP_TCP_INERRS, _PM_SNMP_TCP_OUTRSTS, _PM_SNMP_TCP_INCSUMERRORS, _PM_SNMP_TCP_NFIELDS /* must be last */ }; enum { _PM_SNMP_UDP_INDATAGRAMS = 0, _PM_SNMP_UDP_NOPORTS, _PM_SNMP_UDP_INERRORS, _PM_SNMP_UDP_OUTDATAGRAMS, _PM_SNMP_UDP_RECVBUFERRORS, _PM_SNMP_UDP_SNDBUFERRORS, _PM_SNMP_UDP_INCSUMERRORS, _PM_SNMP_UDP_NFIELDS /* must be last */ }; enum { _PM_SNMP_UDPLITE_INDATAGRAMS = 0, _PM_SNMP_UDPLITE_NOPORTS, _PM_SNMP_UDPLITE_INERRORS, _PM_SNMP_UDPLITE_OUTDATAGRAMS, _PM_SNMP_UDPLITE_RECVBUFERRORS, _PM_SNMP_UDPLITE_SNDBUFERRORS, _PM_SNMP_UDPLITE_INCSUMERRORS, _PM_SNMP_UDPLITE_NFIELDS /* must be last */ }; typedef struct { __uint64_t ip[_PM_SNMP_IP_NFIELDS]; __uint64_t icmp[_PM_SNMP_ICMP_NFIELDS]; __uint64_t icmpmsg[_PM_SNMP_ICMPMSG_NFIELDS]; __uint64_t tcp[_PM_SNMP_TCP_NFIELDS]; __uint64_t udp[_PM_SNMP_UDP_NFIELDS]; __uint64_t udplite[_PM_SNMP_UDPLITE_NFIELDS]; } proc_net_snmp_t; extern int refresh_proc_net_snmp(proc_net_snmp_t *); pcp-3.8.12ubuntu1/src/pmdas/postfix/0000775000000000000000000000000012272262620014173 5ustar pcp-3.8.12ubuntu1/src/pmdas/postfix/Remove0000664000000000000000000000127412272262501015355 0ustar #! /bin/sh # # Copyright (c) 2009 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the postfix PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=postfix pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/postfix/pmdapostfix.pl0000664000000000000000000001513112272262501017065 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2009-2010 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; use Time::HiRes qw ( time ); use vars qw( $pmda ); use vars qw( %caches ); use vars qw( %logstats ); my @logfiles = ( '/var/log/mail.log', '/var/log/maillog' ); my $logfile; my $qshape = 'qshape -b 10 -t 5'; my $refresh = 5.0; # 5 seconds between qshape refreshes my $cached = 0; my $postfix_queues_indom = 0; my @postfix_queues_dom = ( 0 => 'total', 1 => '0-5 mins', 2 => '5-10 mins', 3 => '10-20 mins', 4 => '20-40 mins', 5 => '40-80 mins', 6 => '80-160 mins', 7 => '160-320 mins', 8 => '320-640 mins', 9 => '640-1280 mins', 10=> '1280+ mins', ); my $postfix_sent_indom = 1; my @postfix_sent_dom = ( 0 => 'smtp', 1 => 'local', ); my $postfix_received_indom = 2; my @postfix_received_dom = ( 0 => 'local', 1 => 'smtp', ); sub postfix_do_refresh { QUEUE: foreach my $qname ("maildrop", "incoming", "hold", "active", "deferred") { unless (open(PIPE, "$qshape $qname |")) { $pmda->log("couldn't execute '$qshape $qname'"); next QUEUE; } while() { last if (/^[\t ]*TOTAL /); } close PIPE; unless (/^[\t ]*TOTAL /) { $pmda->log("malformed output for '$qshape $qname': $_"); next QUEUE; } s/^[\t ]*//; s/[\t ]+/ /g; my @items = split(/ /); $caches{$qname}{0} = $items[1]; $caches{$qname}{1} = $items[2]; $caches{$qname}{2} = $items[3]; $caches{$qname}{3} = $items[4]; $caches{$qname}{4} = $items[5]; $caches{$qname}{5} = $items[6]; $caches{$qname}{6} = $items[7]; $caches{$qname}{7} = $items[8]; $caches{$qname}{8} = $items[9]; $caches{$qname}{9} = $items[10]; $caches{$qname}{10} = $items[11]; } } sub postfix_log_parser { ( undef, $_ ) = @_; if (/status=sent/) { return unless (/ postfix\//); my $relay = ""; if (/relay=([^,]+)/o) { $relay = $1; } if ($relay !~ /\[/o) { # if we are about to define a new instance, let's add it to the # domain as well my $idx = 0; my $key; my %tmp = @postfix_sent_dom; foreach $key (sort keys %tmp) { last if ($relay eq $tmp{$key}); $idx += 1; } if ((2 * $idx) == @postfix_sent_dom) { push(@postfix_sent_dom, $idx=>$relay); $pmda->replace_indom($postfix_sent_indom, \@postfix_sent_dom); } $logstats{"sent"}{$idx} += 1; } else { $logstats{"sent"}{0} += 1; } } elsif (/smtpd.*client=/) { $logstats{"received"}{1} += 1; } elsif (/pickup.*(sender|uid)=/) { $logstats{"received"}{0} += 1; } } sub postfix_fetch_callback { my ($cluster, $item, $inst) = @_; my $metric_name = pmda_pmid_name($cluster, $item); my $now = time; #$pmda->log("postfix_fetch_callback $metric_name $cluster:$item ($inst)\n"); if (!defined($metric_name)) { return (PM_ERR_PMID, 0); } if ($cluster == 0) { my $qname; if ($now - $cached > $refresh) { postfix_do_refresh(); $cached = $now; } $qname = $metric_name; $qname =~ s/^postfix\.queues\.//; return (PM_ERR_AGAIN, 0) unless defined($caches{$qname}); return ($caches{$qname}{$inst}, 1); } elsif ($cluster == 1) { my $dir = $metric_name; $dir =~ s/^postfix\.//; return (PM_ERR_AGAIN, 0) unless defined($logstats{$dir}); return (PM_ERR_AGAIN, 0) unless defined($logstats{$dir}{$inst}); return ($logstats{$dir}{$inst}, 1); } return (PM_ERR_PMID, 0); } $pmda = PCP::PMDA->new('postfix', 103); $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U32, $postfix_queues_indom, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postfix.queues.maildrop', '', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_U32, $postfix_queues_indom, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postfix.queues.incoming', '', ''); $pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U32, $postfix_queues_indom, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postfix.queues.hold', '', ''); $pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U32, $postfix_queues_indom, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postfix.queues.active', '', ''); $pmda->add_metric(pmda_pmid(0,4), PM_TYPE_U32, $postfix_queues_indom, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postfix.queues.deferred', '', ''); $pmda->add_metric(pmda_pmid(1,0), PM_TYPE_U32, $postfix_sent_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postfix.sent', '', ''); $pmda->add_metric(pmda_pmid(1,1), PM_TYPE_U32, $postfix_received_indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postfix.received', '', ''); $logstats{"sent"}{0} = 0; $logstats{"received"}{0} = 0; $logstats{"received"}{1} = 0; foreach my $file ( @logfiles ) { if ( -r $file ) { $logfile = $file; } } die 'No Postfix log file found' unless defined($logfile); $pmda->add_indom($postfix_queues_indom, \@postfix_queues_dom, '', ''); $pmda->add_indom($postfix_sent_indom, \@postfix_sent_dom, '', ''); $pmda->add_indom($postfix_received_indom, \@postfix_received_dom, '', ''); $pmda->add_tail($logfile, \&postfix_log_parser, 0); $pmda->set_fetch_callback(\&postfix_fetch_callback); $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdapostfix - Postfix performance metrics domain agent (PMDA) =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports mail queue sizes as reported by qshape(1), as well as aggregate statistics collected from mail.log. =head1 INSTALLATION If you want access to the names and values for the Postfix performance metrics, do the following as root: # cd $PCP_PMDAS_DIR/postfix # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/postfix # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/postfix/Install installation script for the B agent =item $PCP_PMDAS_DIR/postfix/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/postfix.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1) and qshape(1). pcp-3.8.12ubuntu1/src/pmdas/postfix/Install0000664000000000000000000000155012272262501015523 0ustar #! /bin/sh # # Copyright (c) 2009 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the postfix PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=postfix perl_opt=true daemon_opt=false forced_restart=false which qshape >/dev/null 2>&1 if test $? -ne 0; then echo "Postfix qshape utility is not installed" exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/postfix/GNUmakefile0000664000000000000000000000236212272262501016246 0ustar #!gmake # # Copyright (c) 2009 Josef 'Jeff' Sipek # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = postfix PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/aix/0000775000000000000000000000000012272262620013260 5ustar pcp-3.8.12ubuntu1/src/pmdas/aix/data.c0000664000000000000000000003566112272262501014346 0ustar /* * Data structures that define metrics and control the AIX PMDA * * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "common.h" #include /* * List of instance domains ... we expect the *_INDOM macros * to index into this table. */ pmdaIndom indomtab[] = { { DISK_INDOM, 0, NULL }, { CPU_INDOM, 0, NULL }, { NETIF_INDOM, 0, NULL } }; int indomtab_sz = sizeof(indomtab) / sizeof(indomtab[0]); pmdaMetric *metrictab; method_t methodtab[] = { { cpu_total_init, cpu_total_prefetch, cpu_total_fetch }, // M_CPU_TOTAL { cpu_init, cpu_prefetch, cpu_fetch }, // M_CPU { disk_total_init, disk_total_prefetch, disk_total_fetch }, // M_DISK_TOTAL { disk_init, disk_prefetch, disk_fetch }, // M_DISK { netif_init, netif_prefetch, netif_fetch } // M_NETIF // M_NETBUF - TODO // M_PROTO - TODO // M_MEM_TOTAL - TODO }; int methodtab_sz = sizeof(methodtab) / sizeof(methodtab[0]); #define CPU_OFF(field) ((int)&((perfstat_cpu_t *)0)->field) #define CPU_TOTAL_OFF(field) ((int)&((perfstat_cpu_total_t *)0)->field) #define DISK_OFF(field) ((int)&((perfstat_disk_t *)0)->field) #define DISK_TOTAL_OFF(field) ((int)&((perfstat_disk_total_t *)0)->field) #define NETIF_OFF(field) ((int)&((perfstat_netinterface_t *)0)->field) /* * all metrics supported in this PMDA - one table entry for each metric */ metricdesc_t metricdesc[] = { /* kernel.all.cpu.idle */ { { PMDA_PMID(0,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU_TOTAL, CPU_TOTAL_OFF(idle) }, /* kernel.all.cpu.user */ { { PMDA_PMID(0,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU_TOTAL, CPU_TOTAL_OFF(user) }, /* kernel.all.cpu.sys */ { { PMDA_PMID(0,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU_TOTAL, CPU_TOTAL_OFF(sys) }, /* kernel.all.cpu.wait.total */ { { PMDA_PMID(0,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU_TOTAL, CPU_TOTAL_OFF(wait) }, /* kernel.percpu.cpu.idle */ { { PMDA_PMID(0,4), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU, CPU_OFF(idle) }, /* kernel.percpu.cpu.user */ { { PMDA_PMID(0,5), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU, CPU_OFF(user) }, /* kernel.percpu.cpu.sys */ { { PMDA_PMID(0,6), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU, CPU_OFF(sys) }, /* kernel.percpu.cpu.wait.total */ { { PMDA_PMID(0,7), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU, CPU_OFF(wait) }, /* kernel.all.readch */ { { PMDA_PMID(0,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU_TOTAL, CPU_TOTAL_OFF(readch) }, /* kernel.all.writech */ { { PMDA_PMID(0,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU_TOTAL, CPU_TOTAL_OFF(readch) }, /* kernel.all.io.softintrs */ { { PMDA_PMID(0,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU_TOTAL, CPU_TOTAL_OFF(softintrs) }, /* kernel.percpu.readch */ { { PMDA_PMID(0,11), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU, CPU_OFF(readch) }, /* kernel.percpu.writech */ { { PMDA_PMID(0,12), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU, CPU_OFF(writech) }, /* kernel.percpu.cpu.intr */ { { PMDA_PMID(0,13), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU, OFF_NOVALUES }, /* kernel.all.io.bread */ { { PMDA_PMID(0,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(bread) }, /* kernel.all.io.bwrite */ { { PMDA_PMID(0,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(bwrite) }, /* kernel.all.io.lread */ { { PMDA_PMID(0,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(lread) }, /* kernel.all.io.lwrite */ { { PMDA_PMID(0,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(lwrite) }, /* kernel.percpu.io.bread */ { { PMDA_PMID(0,18), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(bread) }, /* kernel.percpu.io.bwrite */ { { PMDA_PMID(0,19), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(bwrite) }, /* kernel.percpu.io.lread */ { { PMDA_PMID(0,20), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(lread) }, /* kernel.percpu.io.lwrite */ { { PMDA_PMID(0,21), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(lwrite) }, /* kernel.all.syscall */ { { PMDA_PMID(0,22), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(syscall) }, /* kernel.all.pswitch */ { { PMDA_PMID(0,23), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(pswitch) }, /* kernel.percpu.syscall */ { { PMDA_PMID(0,24), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(syscall) }, /* kernel.percpu.pswitch */ { { PMDA_PMID(0,25), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(pswitch) }, /* kernel.all.io.phread */ { { PMDA_PMID(0,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(phread) }, /* kernel.all.io.phwrite */ { { PMDA_PMID(0,27), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(phwrite) }, /* kernel.all.io.devintrs */ { { PMDA_PMID(0,28), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(devintrs) }, /* kernel.percpu.io.phread */ { { PMDA_PMID(0,29), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(phread) }, /* kernel.percpu.io.phwrite */ { { PMDA_PMID(0,30), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(phwrite) }, /* kernel.all.cpu.intr */ { { PMDA_PMID(0,31), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_CPU_TOTAL, OFF_NOVALUES }, /* kernel.all.trap */ { { PMDA_PMID(0,32), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(traps) }, /* kernel.all.sysexec */ { { PMDA_PMID(0,33), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(sysexec) }, /* kernel.all.sysfork */ { { PMDA_PMID(0,34), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(sysfork) }, /* kernel.all.io.namei */ { { PMDA_PMID(0,35), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(namei) }, /* kernel.all.sysread */ { { PMDA_PMID(0,36), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(sysread) }, /* kernel.all.syswrite */ { { PMDA_PMID(0,37), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(syswrite) }, /* hinv.ncpu_cfg */ { { PMDA_PMID(0,38), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(ncpus_cfg) }, /* kernel.percpu.sysexec */ { { PMDA_PMID(0,39), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(sysexec) }, /* kernel.percpu.sysfork */ { { PMDA_PMID(0,40), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(sysfork) }, /* kernel.percpu.io.namei */ { { PMDA_PMID(0,41), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(namei) }, /* kernel.percpu.sysread */ { { PMDA_PMID(0,42), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(sysread) }, /* kernel.percpu.syswrite */ { { PMDA_PMID(0,43), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU, CPU_OFF(syswrite) }, /* disk.all.read -- not available */ { { PMDA_PMID(0,44), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_DISK_TOTAL, OFF_NOVALUES }, /* disk.all.write -- not available */ { { PMDA_PMID(0,45), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_DISK_TOTAL, OFF_NOVALUES }, /* disk.all.total */ { { PMDA_PMID(0,46), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_DISK_TOTAL, DISK_TOTAL_OFF(xfers) }, /* disk.all.read_bytes */ { { PMDA_PMID(0,47), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_MBYTE, 0, 0) }, M_DISK_TOTAL, DISK_TOTAL_OFF(rblks) }, /* disk.all.write_bytes */ { { PMDA_PMID(0,48), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_MBYTE, 0, 0) }, M_DISK_TOTAL, DISK_TOTAL_OFF(wblks) }, /* disk.all.total_bytes */ { { PMDA_PMID(0,49), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_MBYTE, 0, 0) }, M_DISK_TOTAL, OFF_DERIVED }, /* disk.dev.read -- not available */ { { PMDA_PMID(0,50), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_DISK, OFF_NOVALUES }, /* disk.dev.write -- not available */ { { PMDA_PMID(0,51), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_DISK, OFF_NOVALUES }, /* disk.dev.total */ { { PMDA_PMID(0,52), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_DISK, DISK_OFF(xfers) }, /* disk.dev.read_bytes */ { { PMDA_PMID(0,53), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_MBYTE, 0, 0) }, M_DISK, DISK_OFF(rblks) }, /* disk.dev.write_bytes */ { { PMDA_PMID(0,54), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_MBYTE, 0, 0) }, M_DISK, DISK_OFF(wblks) }, /* disk.dev.total_bytes */ { { PMDA_PMID(0,55), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_MBYTE, 0, 0) }, M_DISK, OFF_DERIVED }, /* hinv.ncpu */ { { PMDA_PMID(0,56), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_CPU_TOTAL, CPU_TOTAL_OFF(ncpus) }, /* hinv.ndisk */ { { PMDA_PMID(0,57), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_DISK_TOTAL, DISK_TOTAL_OFF(number) }, /* hinv.nnetif */ { { PMDA_PMID(0,58), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NETIF, OFF_DERIVED }, /* network.interface.in.packets */ { { PMDA_PMID(0,59), PM_TYPE_U64, NETIF_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NETIF, NETIF_OFF(ipackets) }, /* network.interface.in.bytes */ { { PMDA_PMID(0,60), PM_TYPE_U64, NETIF_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NETIF, NETIF_OFF(ibytes) }, /* network.interface.in.errors */ { { PMDA_PMID(0,61), PM_TYPE_U64, NETIF_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NETIF, NETIF_OFF(ierrors) }, /* network.interface.out.packets */ { { PMDA_PMID(0,62), PM_TYPE_U64, NETIF_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NETIF, NETIF_OFF(opackets) }, /* network.interface.out.bytes */ { { PMDA_PMID(0,63), PM_TYPE_U64, NETIF_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NETIF, NETIF_OFF(obytes) }, /* network.interface.out.errors */ { { PMDA_PMID(0,64), PM_TYPE_U64, NETIF_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NETIF, NETIF_OFF(oerrors) }, /* network.interface.total.packets */ { { PMDA_PMID(0,65), PM_TYPE_U64, NETIF_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NETIF, OFF_DERIVED }, /* network.interface.total.bytes */ { { PMDA_PMID(0,66), PM_TYPE_U64, NETIF_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NETIF, OFF_DERIVED } /* remember to add trailing comma before adding more entries ... */ }; int metrictab_sz = sizeof(metricdesc) / sizeof(metricdesc[0]); void init_data(int domain) { int i; int serial; __pmID_int *ip; __pmInDom_int *iip; /* * Create the PMDA's metrictab[] version of the per-metric table. * * Also do domain initialization for each pmid and indom element of * the metricdesc[] table ... the PMDA table is fixed up in * libpcp_pmda */ if ((metrictab = (pmdaMetric *)malloc(metrictab_sz * sizeof(pmdaMetric))) == NULL) { fprintf(stderr, "init_data: Error: malloc metrictab [%d] failed: %s\n", metrictab_sz * sizeof(pmdaMetric), osstrerror()); exit(1); } for (i = 0; i < metrictab_sz; i++) { metrictab[i].m_user = &metricdesc[i]; metrictab[i].m_desc = metricdesc[i].md_desc; ip = (__pmID_int *)&metricdesc[i].md_desc.pmid; ip->domain = domain; if (metricdesc[i].md_desc.indom != PM_INDOM_NULL) { serial = metricdesc[i].md_desc.indom; iip = (__pmInDom_int *)&metricdesc[i].md_desc.indom; iip->serial = serial; iip->pad = 0; iip->domain = domain; } } /* * initialize each of the methods */ for (i = 0; i < methodtab_sz; i++) { methodtab[i].m_init(1); } } pcp-3.8.12ubuntu1/src/pmdas/aix/pmns.network0000664000000000000000000000050412272262501015645 0ustar network { interface } network.interface { in out total } network.interface.in { packets AIX:0:59 bytes AIX:0:60 errors AIX:0:61 } network.interface.out { packets AIX:0:62 bytes AIX:0:63 errors AIX:0:64 } network.interface.total { packets AIX:0:65 bytes AIX:0:66 } pcp-3.8.12ubuntu1/src/pmdas/aix/pmns.hinv0000664000000000000000000000013012272262501015113 0ustar hinv { ncpu AIX:0:56 ncpu_cfg AIX:0:38 ndisk AIX:0:57 nnetif AIX:0:58 } pcp-3.8.12ubuntu1/src/pmdas/aix/pmns.kernel0000664000000000000000000000216412272262501015440 0ustar kernel { all percpu } kernel.all { cpu io trap AIX:0:32 pswitch AIX:0:23 syscall AIX:0:22 sysexec AIX:0:33 sysfork AIX:0:34 sysread AIX:0:36 syswrite AIX:0:37 readch AIX:0:8 writech AIX:0:9 } kernel.all.cpu { idle AIX:0:0 user AIX:0:1 sys AIX:0:2 intr AIX:0:31 wait } kernel.all.cpu.wait { total AIX:0:3 } kernel.all.io { bread AIX:0:14 bwrite AIX:0:15 lread AIX:0:16 lwrite AIX:0:17 phread AIX:0:26 phwrite AIX:0:27 devintrs AIX:0:28 softintrs AIX:0:10 namei AIX:0:35 } kernel.percpu { cpu io pswitch AIX:0:25 syscall AIX:0:24 sysexec AIX:0:39 sysfork AIX:0:40 sysread AIX:0:42 syswrite AIX:0:43 readch AIX:0:11 writech AIX:0:12 } kernel.percpu.cpu { idle AIX:0:4 user AIX:0:5 sys AIX:0:6 intr AIX:0:13 wait } kernel.percpu.cpu.wait { total AIX:0:7 } kernel.percpu.io { bread AIX:0:18 bwrite AIX:0:19 lread AIX:0:20 lwrite AIX:0:21 phread AIX:0:29 phwrite AIX:0:30 namei AIX:0:41 } pcp-3.8.12ubuntu1/src/pmdas/aix/pmns.disk0000664000000000000000000000047712272262501015117 0ustar disk { all dev } disk.all { read AIX:0:44 write AIX:0:45 total AIX:0:46 read_bytes AIX:0:47 write_bytes AIX:0:48 total_bytes AIX:0:49 } disk.dev { read AIX:0:50 write AIX:0:51 total AIX:0:52 read_bytes AIX:0:53 write_bytes AIX:0:54 total_bytes AIX:0:55 } pcp-3.8.12ubuntu1/src/pmdas/aix/netif.c0000664000000000000000000001230112272262501014524 0ustar /* * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "common.h" static int nnetif; static int nnetif_alloc; static int *fetched; static perfstat_netinterface_t *netifstat; void netif_init(int first) { perfstat_id_t id; int i; if (!first) /* TODO ... not sure if/when we'll use this re-init hook */ return; nnetif = perfstat_netinterface(NULL, NULL, sizeof(perfstat_netinterface_t), 0); if ((fetched = (int *)malloc(nnetif * sizeof(int))) == NULL) { fprintf(stderr, "netif_init: fetched malloc[%d] failed: %s\n", nnetif * sizeof(int), osstrerror()); exit(1); } if ((netifstat = (perfstat_netinterface_t *)malloc(nnetif * sizeof(perfstat_netinterface_t))) == NULL) { fprintf(stderr, "netif_init: netifstat malloc[%d] failed: %s\n", nnetif * sizeof(perfstat_netinterface_t), osstrerror()); exit(1); } nnetif_alloc = nnetif; /* * set up instance domain */ strcpy(id.name, ""); nnetif = perfstat_netinterface(&id, netifstat, sizeof(perfstat_netinterface_t), nnetif_alloc); indomtab[NETIF_INDOM].it_numinst = nnetif; indomtab[NETIF_INDOM].it_set = (pmdaInstid *)malloc(nnetif * sizeof(pmdaInstid)); if (indomtab[NETIF_INDOM].it_set == NULL) { fprintf(stderr, "netif_init: indomtab malloc[%d] failed: %s\n", nnetif * sizeof(pmdaInstid), osstrerror()); exit(1); } for (i = 0; i < nnetif; i++) { indomtab[NETIF_INDOM].it_set[i].i_inst = i; indomtab[NETIF_INDOM].it_set[i].i_name = strdup(netifstat[i].name); } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "netif_init: nnetif=%d\n", nnetif); } #endif } void netif_prefetch(void) { int i; for (i = 0; i < nnetif_alloc; i++) fetched[i] = 0; } static __uint64_t netif_derived(pmdaMetric *mdesc, int inst) { pmID pmid; __pmID_int *ip = (__pmID_int *)&pmid; __uint64_t val; pmid = mdesc->m_desc.pmid; ip->domain = 0; switch (pmid) { case PMDA_PMID(0,58): /* hinv.nnetif */ val = nnetif; break; case PMDA_PMID(0,65): /* network.interface.total.packets */ val = netifstat[inst].ipackets + netifstat[inst].opackets; break; case PMDA_PMID(0,66): /* network.interface.total.bytes */ val = netifstat[inst].ibytes + netifstat[inst].obytes; break; default: fprintf(stderr, "netif_derived: Botch: no method for pmid %s\n", pmIDStr(mdesc->m_desc.pmid)); val = 0; break; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "netif_derived: pmid %s inst %d val %llu\n", pmIDStr(mdesc->m_desc.pmid), inst, val); } #endif return val; } int netif_fetch(pmdaMetric *mdesc, int inst, pmAtomValue *atom) { int offset; if (fetched[inst] == 0) { int sts; int i; perfstat_id_t id; strcpy(id.name, ""); sts = perfstat_netinterface(&id, netifstat, sizeof(perfstat_netinterface_t), nnetif_alloc); /* TODO ... * - if sts != nnetif, the number of network interfaces has changed, * need to set fetched[i] to -1 for the missing ones * - is sts > nnetif possible? worse, if the number of network * interfaces is > nnetif_alloc what should we do? * - possibly reshape the instance domain? * - error handling? */ for (i = 0; i < nnetif; i++) { fetched[i] = 1; } } /* hinv.nnetif is a singular metric ... so no "instance" for this one */ if (inst != PM_IN_NULL && fetched[inst] != 1) return 0; offset = ((metricdesc_t *)mdesc->m_user)->md_offset; if (offset == OFF_NOVALUES) return 0; if (mdesc->m_desc.type == PM_TYPE_U64) { if (offset == OFF_DERIVED) atom->ull = netif_derived(mdesc, inst); else { __uint64_t *ullp; ullp = (__uint64_t *)&((char *)&netifstat[inst])[offset]; atom->ull = *ullp; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "netif_fetch: pmid %s inst %d val %llu\n", pmIDStr(mdesc->m_desc.pmid), inst, atom->ull); } #endif } else { if (offset == OFF_DERIVED) atom->ul = (__uint32_t)netif_derived(mdesc, inst); else { __uint32_t *ulp; ulp = (__uint32_t *)&((char *)&netifstat[inst])[offset]; atom->ul = *ulp; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "netif_fetch: pmid %s inst %d val %lu\n", pmIDStr(mdesc->m_desc.pmid), inst, atom->ul); } #endif } return 1; } pcp-3.8.12ubuntu1/src/pmdas/aix/GNUmakefile0000664000000000000000000000367312272262501015341 0ustar # # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = aix DOMAIN = AIX CMDTARGET = pmdaaix LIBTARGET = pmda_aix.so PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) CONF_LINE = "aix 80 dso aix_init $(PMDADIR)/$(LIBTARGET)" CFILES = aix.c data.c disk_total.c disk.c cpu_total.c cpu.c netif.c LLDLIBS = $(PCP_PMDALIB) -lperfstat PMNS = pmns.disk pmns.kernel pmns.mem pmns.network pmns.hinv LSRCFILES = $(PMNS) help root common.h LDIRT = *.log *.dir *.pag root_aix domain.h default: build-me ifeq "$(TARGET_OS)" "aix" build-me: common.h root_aix domain.h $(CMDTARGET) $(LIBTARGET) help.dir help.pag @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi install: build-me $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 644 domain.h help.dir help.pag $(PMDADIR) $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(PMDADIR) $(INSTALL) -m 644 root_aix $(PCP_VAR_DIR)/pmns/root_aix else build-me: install: endif $(OBJECTS): common.h include $(BUILDRULES) default_pcp : default install_pcp : install help.dir help.pag: help root_aix $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_aix -v 2 -o help < help root_aix: ../../pmns/stdpmid rm -f root_aix sed -e 's;;"../../pmns/stdpmid";' root_aix domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/aix/root0000664000000000000000000000035312272262501014165 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { kernel disk mem network hinv } #include "pmns.kernel" #include "pmns.disk" #include "pmns.mem" #include "pmns.network" #include "pmns.hinv" pcp-3.8.12ubuntu1/src/pmdas/aix/common.h0000664000000000000000000000541612272262501014725 0ustar /* * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "./domain.h" typedef long long longlong_t; // TODO nuke for AIX typedef unsigned long long u_longlong_t; // TODO nuke for AIX build typedef unsigned char uchar; // TODO nuke for AIX build #include /* * libperfstat method controls * * md_method choices (see below) ... must be contiguous integers so * we can index directly into method[] */ #define M_CPU_TOTAL 0 #define M_CPU 1 #define M_DISK_TOTAL 2 #define M_DISK 3 #define M_NETIF 4 #define M_NETBUF 5 // TODO #define M_PROTO 6 // TODO #define M_MEM_TOTAL 7 // TODO /* * special values for offset */ #define OFF_NOVALUES -2 #define OFF_DERIVED -1 typedef struct { void (*m_init)(int); void (*m_prefetch)(void); int (*m_fetch)(pmdaMetric *, int, pmAtomValue *); } method_t; extern method_t methodtab[]; extern int methodtab_sz; extern void init_data(int); extern void cpu_total_init(int); extern void cpu_total_prefetch(void); extern int cpu_total_fetch(pmdaMetric *, int, pmAtomValue *); extern void cpu_init(int); extern void cpu_prefetch(void); extern int cpu_fetch(pmdaMetric *, int, pmAtomValue *); extern void disk_total_init(int); extern void disk_total_prefetch(void); extern int disk_total_fetch(pmdaMetric *, int, pmAtomValue *); extern void disk_init(int); extern void disk_prefetch(void); extern int disk_fetch(pmdaMetric *, int, pmAtomValue *); extern void netif_init(int); extern void netif_prefetch(void); extern int netif_fetch(pmdaMetric *, int, pmAtomValue *); /* * metric descriptions */ typedef struct { pmDesc md_desc; // PMDA's idea of the semantics int md_method; // specific stats method int md_offset; // offset into stats structure } metricdesc_t; extern metricdesc_t metricdesc[]; extern pmdaMetric *metrictab; extern int metrictab_sz; #define DISK_INDOM 0 #define CPU_INDOM 1 #define NETIF_INDOM 2 extern pmdaIndom indomtab[]; extern int indomtab_sz; pcp-3.8.12ubuntu1/src/pmdas/aix/cpu.c0000664000000000000000000001143412272262501014214 0ustar /* * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "common.h" static int ncpu; static int ncpu_alloc; static int *fetched; static perfstat_cpu_t *cpustat; void cpu_init(int first) { perfstat_id_t id; int i; if (!first) /* TODO ... not sure if/when we'll use this re-init hook */ return; ncpu = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0); if ((fetched = (int *)malloc(ncpu * sizeof(int))) == NULL) { fprintf(stderr, "cpu_init: fetched malloc[%d] failed: %s\n", ncpu * sizeof(int), osstrerror()); exit(1); } if ((cpustat = (perfstat_cpu_t *)malloc(ncpu * sizeof(perfstat_cpu_t))) == NULL) { fprintf(stderr, "cpu_init: cpustat malloc[%d] failed: %s\n", ncpu * sizeof(perfstat_cpu_t), osstrerror()); exit(1); } ncpu_alloc = ncpu; /* * set up instance domain */ strcpy(id.name, ""); ncpu = perfstat_cpu(&id, cpustat, sizeof(perfstat_cpu_t), ncpu_alloc); indomtab[CPU_INDOM].it_numinst = ncpu; indomtab[CPU_INDOM].it_set = (pmdaInstid *)malloc(ncpu * sizeof(pmdaInstid)); if (indomtab[CPU_INDOM].it_set == NULL) { fprintf(stderr, "cpu_init: indomtab malloc[%d] failed: %s\n", ncpu * sizeof(pmdaInstid), osstrerror()); exit(1); } for (i = 0; i < ncpu; i++) { indomtab[CPU_INDOM].it_set[i].i_inst = i; indomtab[CPU_INDOM].it_set[i].i_name = strdup(cpustat[i].name); } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "cpu_init: ncpu=%d\n", ncpu); } #endif } void cpu_prefetch(void) { int i; for (i = 0; i < ncpu_alloc; i++) fetched[i] = 0; } static __uint64_t cpu_derived(pmdaMetric *mdesc, int inst) { pmID pmid; __pmID_int *ip = (__pmID_int *)&pmid; __uint64_t val; pmid = mdesc->m_desc.pmid; ip->domain = 0; switch (pmid) { default: fprintf(stderr, "cpu_derived: Botch: no method for pmid %s\n", pmIDStr(mdesc->m_desc.pmid)); val = 0; break; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "cpu_derived: pmid %s inst %d val %llu\n", pmIDStr(mdesc->m_desc.pmid), inst, val); } #endif return val; } int cpu_fetch(pmdaMetric *mdesc, int inst, pmAtomValue *atom) { int offset; if (fetched[inst] == 0) { int sts; int i; perfstat_id_t id; strcpy(id.name, ""); sts = perfstat_cpu(&id, cpustat, sizeof(perfstat_cpu_t), ncpu_alloc); /* TODO ... * - if sts != ncpu, the number of CPUs has changed, need to set * fetched[i] to -1 for the missing ones * - is sts > ncpu possible? worse, if the number of cpus is > * ncpu_alloc what should we do? * - possibly reshape the instance domain? * - error handling? */ for (i = 0; i < ncpu; i++) { fetched[i] = 1; } } if (fetched[inst] != 1) return 0; offset = ((metricdesc_t *)mdesc->m_user)->md_offset; if (offset == OFF_NOVALUES) return 0; if (mdesc->m_desc.type == PM_TYPE_U64) { if (offset == OFF_DERIVED) atom->ull = cpu_derived(mdesc, inst); else { __uint64_t *ullp; ullp = (__uint64_t *)&((char *)&cpustat[inst])[offset]; atom->ull = *ullp; } if (mdesc->m_desc.units.scaleTime == PM_TIME_MSEC) { /* assumed to be CPU time */ atom->ull *= 1000 / HZ; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "cpu_fetch: pmid %s inst %d val %llu\n", pmIDStr(mdesc->m_desc.pmid), inst, atom->ull); } #endif } else { if (offset == OFF_DERIVED) atom->ul = (__uint32_t)cpu_derived(mdesc, inst); else { __uint32_t *ulp; ulp = (__uint32_t *)&((char *)&cpustat[inst])[offset]; atom->ul = *ulp; } if (mdesc->m_desc.units.scaleTime == PM_TIME_MSEC) { /* assumed to be CPU time */ atom->ul *= 1000 / HZ; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "cpu_fetch: pmid %s inst %d val %lu\n", pmIDStr(mdesc->m_desc.pmid), inst, atom->ul); } #endif } return 1; } pcp-3.8.12ubuntu1/src/pmdas/aix/disk_total.c0000664000000000000000000000621712272262501015565 0ustar /* * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "common.h" static perfstat_disk_total_t diskstat; static int fetched; void disk_total_init(int first) { if (!first) /* TODO ... not sure if/when we'll use this re-init hook */ return; } void disk_total_prefetch(void) { int i; fetched = 0; } static __uint64_t disk_total_derived(pmdaMetric *mdesc, int inst) { pmID pmid; __pmID_int *ip = (__pmID_int *)&pmid; __uint64_t val; pmid = mdesc->m_desc.pmid; ip->domain = 0; switch (pmid) { case PMDA_PMID(0,49): /* disk.all.total_bytes */ val = diskstat.rblks + diskstat.wblks; break; default: fprintf(stderr, "disk_total_derived: Botch: no method for pmid %s\n", pmIDStr(mdesc->m_desc.pmid)); val = 0; break; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "disk_total_derived: pmid %s inst %d val %llu\n", pmIDStr(mdesc->m_desc.pmid), inst, val); } #endif return val; } int disk_total_fetch(pmdaMetric *mdesc, int inst, pmAtomValue *atom) { int offset; if (fetched == 0) { int sts; sts = perfstat_disk_total(NULL, &diskstat, sizeof(perfstat_disk_total_t), 1); if (sts != 1) { /* TODO - how to find/decode errors? */ fprintf(stderr, "perfstat_disk_total: failed %s\n", osstrerror()); fetched = -1; } else fetched = 1; } if (fetched != 1) return 0; offset = ((metricdesc_t *)mdesc->m_user)->md_offset; if (offset == OFF_NOVALUES) return 0; if (mdesc->m_desc.type == PM_TYPE_U64) { if (offset == OFF_DERIVED) atom->ull = disk_total_derived(mdesc, inst); else { __uint64_t *ullp; ullp = (__uint64_t *)&((char *)&diskstat)[offset]; atom->ull = *ullp; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "disk_total_fetch: pmid %s inst %d val %llu\n", pmIDStr(mdesc->m_desc.pmid), inst, atom->ull); } #endif } else { if (offset == OFF_DERIVED) atom->ul = (__uint32_t)disk_total_derived(mdesc, inst); else { __uint32_t *ulp; ulp = (__uint32_t *)&((char *)&diskstat)[offset]; atom->ul = *ulp; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "disk_total_fetch: pmid %s inst %d val %lu\n", pmIDStr(mdesc->m_desc.pmid), inst, atom->ul); } #endif } return 1; } pcp-3.8.12ubuntu1/src/pmdas/aix/cpu_total.c0000664000000000000000000000643312272262501015422 0ustar /* * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "common.h" #include static perfstat_cpu_total_t cpustat; static int fetched; void cpu_total_init(int first) { if (!first) /* TODO ... not sure if/when we'll use this re-init hook */ return; } void cpu_total_prefetch(void) { int i; fetched = 0; } static __uint64_t cpu_total_derived(pmdaMetric *mdesc, int inst) { pmID pmid; __pmID_int *ip = (__pmID_int *)&pmid; __uint64_t val; pmid = mdesc->m_desc.pmid; ip->domain = 0; switch (pmid) { default: fprintf(stderr, "cpu_total_derived: Botch: no method for pmid %s\n", pmIDStr(mdesc->m_desc.pmid)); val = 0; break; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "cpu_total_derived: pmid %s inst %d val %llu\n", pmIDStr(mdesc->m_desc.pmid), inst, val); } #endif return val; } int cpu_total_fetch(pmdaMetric *mdesc, int inst, pmAtomValue *atom) { int offset; if (fetched == 0) { int sts; sts = perfstat_cpu_total(NULL, &cpustat, sizeof(perfstat_cpu_total_t), 1); if (sts != 1) { /* TODO - how to find/decode errors? */ fprintf(stderr, "perfstat_cpu_total: failed %s\n", osstrerror()); fetched = -1; } else fetched = 1; } if (fetched != 1) return 0; offset = ((metricdesc_t *)mdesc->m_user)->md_offset; if (offset == OFF_NOVALUES) return 0; if (mdesc->m_desc.type == PM_TYPE_U64) { if (offset == OFF_DERIVED) atom->ull = cpu_total_derived(mdesc, inst); else { __uint64_t *ullp; ullp = (__uint64_t *)&((char *)&cpustat)[offset]; atom->ull = *ullp; } if (mdesc->m_desc.units.scaleTime == PM_TIME_MSEC) { /* assumed to be CPU time */ atom->ull *= 1000 / HZ; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "cpu_total_fetch: pmid %s inst %d val %llu\n", pmIDStr(mdesc->m_desc.pmid), inst, atom->ull); } #endif } else { if (offset == OFF_DERIVED) atom->ul = (__uint32_t)cpu_total_derived(mdesc, inst); else { __uint32_t *ulp; ulp = (__uint32_t *)&((char *)&cpustat)[offset]; atom->ul = *ulp; } if (mdesc->m_desc.units.scaleTime == PM_TIME_MSEC) { /* assumed to be CPU time */ atom->ul *= 1000 / HZ; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "cpu_total_fetch: pmid %s inst %d val %lu\n", pmIDStr(mdesc->m_desc.pmid), inst, atom->ul); } #endif } return 1; } pcp-3.8.12ubuntu1/src/pmdas/aix/aix.c0000664000000000000000000000614412272262501014210 0ustar /* * AIX PMDA * * Collect performance data from the AIX kernel using libperfstat for * the most part. * * Copyright (c) 2012 Red Hat. * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "common.h" static int _isDSO = 1; static char mypath[MAXPATHLEN]; static char *username; /* * wrapper for pmdaFetch which primes the methods ready for * the next fetch * ... real callback is fetch_callback() */ static int aix_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i; // TODO: this should only fetch metrics from "pmidlist" for (i = 0; i < methodtab_sz; i++) { methodtab[i].m_prefetch(); } return pmdaFetch(numpmid, pmidlist, resp, pmda); } /* * callback provided to pmdaFetch */ static int aix_fetch_callback(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { metricdesc_t *mdp; mdp = (metricdesc_t *)mdesc->m_user; return methodtab[mdp->md_method].m_fetch(mdesc, inst, atom); } /* * Initialise the agent (both daemon and DSO). */ void aix_init(pmdaInterface *dp) { if (_isDSO) { int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "aix" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_3, "AIX DSO", mypath); } else { __pmSetProcessIdentity(username); } if (dp->status != 0) return; dp->version.two.fetch = aix_fetch; pmdaSetFetchCallBack(dp, aix_fetch_callback); init_data(dp->domain); pmdaInit(dp, indomtab, indomtab_sz, metrictab, metrictab_sz); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int c, err = 0; int sep = __pmPathSeparator(); pmdaInterface desc; _isDSO = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(mypath, sizeof(mypath), "%s%c" "aix" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&desc, PMDA_INTERFACE_3, pmProgname, AIX, "aix.log", mypath); while ((c = pmdaGetOpt(argc, argv, "D:d:l:U:?", &desc, &err)) != EOF) { switch(c) { case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&desc); aix_init(&desc); pmdaConnect(&desc); pmdaMain(&desc); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/aix/disk.c0000664000000000000000000001172012272262501014355 0ustar /* * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "common.h" static int ndisk; static int ndisk_alloc; static int *fetched; static perfstat_disk_t *diskstat; void disk_init(int first) { perfstat_id_t id; int i; if (!first) /* TODO ... not sure if/when we'll use this re-init hook */ return; ndisk = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0); if ((fetched = (int *)malloc(ndisk * sizeof(int))) == NULL) { fprintf(stderr, "disk_init: fetched malloc[%d] failed: %s\n", ndisk * sizeof(int), osstrerror()); exit(1); } if ((diskstat = (perfstat_disk_t *)malloc(ndisk * sizeof(perfstat_disk_t))) == NULL) { fprintf(stderr, "disk_init: diskstat malloc[%d] failed: %s\n", ndisk * sizeof(perfstat_disk_t), osstrerror()); exit(1); } ndisk_alloc = ndisk; /* * set up instance domain */ strcpy(id.name, ""); ndisk = perfstat_disk(&id, diskstat, sizeof(perfstat_disk_t), ndisk_alloc); indomtab[DISK_INDOM].it_numinst = ndisk; indomtab[DISK_INDOM].it_set = (pmdaInstid *)malloc(ndisk * sizeof(pmdaInstid)); if (indomtab[DISK_INDOM].it_set == NULL) { fprintf(stderr, "disk_init: indomtab malloc[%d] failed: %s\n", ndisk * sizeof(pmdaInstid), osstrerror()); exit(1); } for (i = 0; i < ndisk; i++) { indomtab[DISK_INDOM].it_set[i].i_inst = i; indomtab[DISK_INDOM].it_set[i].i_name = strdup(diskstat[i].name); } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "disk_init: ndisk=%d\n", ndisk); } #endif } void disk_prefetch(void) { int i; for (i = 0; i < ndisk_alloc; i++) fetched[i] = 0; } static __uint64_t disk_derived(pmdaMetric *mdesc, int inst) { pmID pmid; __pmID_int *ip = (__pmID_int *)&pmid; __uint64_t val; pmid = mdesc->m_desc.pmid; ip->domain = 0; switch (pmid) { case PMDA_PMID(0,55): /* disk.dev.total_bytes */ val = diskstat[inst].rblks + diskstat[inst].wblks; break; default: fprintf(stderr, "disk_derived: Botch: no method for pmid %s\n", pmIDStr(mdesc->m_desc.pmid)); val = 0; break; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "disk_derived: pmid %s inst %d val %llu\n", pmIDStr(mdesc->m_desc.pmid), inst, val); } #endif return val; } int disk_fetch(pmdaMetric *mdesc, int inst, pmAtomValue *atom) { int offset; if (fetched[inst] == 0) { int sts; int i; perfstat_id_t id; strcpy(id.name, ""); sts = perfstat_disk(&id, diskstat, sizeof(perfstat_disk_t), ndisk_alloc); /* TODO ... * - if sts != ndisk, the number of disks has changed, need to set * fetched[i] to -1 for the missing ones * - is sts > ndisk possible? worse, if the number of disks is > * ndisk_alloc what should we do? * - possibly reshape the instance domain? * - error handling? */ for (i = 0; i < ndisk; i++) { fetched[i] = 1; } } if (fetched[inst] != 1) return 0; offset = ((metricdesc_t *)mdesc->m_user)->md_offset; if (offset == OFF_NOVALUES) return 0; if (mdesc->m_desc.type == PM_TYPE_U64) { if (offset == OFF_DERIVED) atom->ull = disk_derived(mdesc, inst); else { __uint64_t *ullp; ullp = (__uint64_t *)&((char *)&diskstat[inst])[offset]; atom->ull = *ullp; } if (mdesc->m_desc.units.scaleTime == PM_TIME_MSEC) { /* assumed to be CPU time */ atom->ull *= 1000 / HZ; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "disk_fetch: pmid %s inst %d val %llu\n", pmIDStr(mdesc->m_desc.pmid), inst, atom->ull); } #endif } else { if (offset == OFF_DERIVED) atom->ul = (__uint32_t)disk_derived(mdesc, inst); else { __uint32_t *ulp; ulp = (__uint32_t *)&((char *)&diskstat[inst])[offset]; atom->ul = *ulp; } if (mdesc->m_desc.units.scaleTime == PM_TIME_MSEC) { /* assumed to be CPU time */ atom->ul *= 1000 / HZ; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "disk_fetch: pmid %s inst %d val %lu\n", pmIDStr(mdesc->m_desc.pmid), inst, atom->ul); } #endif } return 1; } pcp-3.8.12ubuntu1/src/pmdas/aix/help0000664000000000000000000000406212272262501014133 0ustar # # Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # AIX PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ kernel.all.cpu.idle TODO @ kernel.all.cpu.user TODO @ kernel.all.cpu.sys TODO @ kernel.all.cpu.wait.total TODO @ kernel.percpu.cpu.user TODO @ kernel.percpu.cpu.idle TODO @ kernel.percpu.cpu.sys TODO @ kernel.percpu.cpu.wait.total TODO @ disk.all.read TODO @ disk.all.write TODO @ disk.all.total TODO @ disk.all.read_bytes TODO @ disk.all.write_bytes TODO @ disk.all.total_bytes TODO @ disk.dev.read TODO @ disk.dev.write TODO @ disk.dev.total TODO @ disk.dev.read_bytes TODO @ disk.dev.write_bytes TODO @ disk.dev.total_bytes TODO @ network.interface.in.packets TODO @ network.interface.in.bytes TODO @ network.interface.in.errors TODO @ network.interface.out.packets TODO @ network.interface.out.bytes TODO @ network.interface.out.errors TODO @ network.interface.total.packets TODO @ network.interface.total.bytes TODO pcp-3.8.12ubuntu1/src/pmdas/aix/pmns.mem0000664000000000000000000000001012272262501014722 0ustar mem { } pcp-3.8.12ubuntu1/src/pmdas/solaris/0000775000000000000000000000000012272262620014153 5ustar pcp-3.8.12ubuntu1/src/pmdas/solaris/data.c0000664000000000000000000017021612272262501015235 0ustar /* * Data structures that define metrics and control the Solaris PMDA * * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2010 Max Matveev. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "common.h" #include "netmib2.h" #include #include #ifndef ARRAY_SIZE #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) #endif method_t methodtab[] = { { "sysinfo", sysinfo_init, sysinfo_prefetch, sysinfo_fetch }, { "disk", disk_init, disk_prefetch, disk_fetch }, { "netmib2", netmib2_init, netmib2_refresh, netmib2_fetch }, { "zpool", zpool_init, zpool_refresh, zpool_fetch }, { "zfs", zfs_init, zfs_refresh, zfs_fetch }, { "zpool_vdev", zpool_perdisk_init, zpool_perdisk_refresh, zpool_perdisk_fetch }, { "netlink", netlink_init, netlink_refresh, netlink_fetch }, { "kvm", kvm_init, kvm_refresh, kvm_fetch }, { "zfs_arc", NULL, arcstats_refresh, arcstats_fetch }, { "filesystem", vnops_init, vnops_refresh, vnops_fetch } }; const int methodtab_sz = ARRAY_SIZE(methodtab); static pmdaInstid prefetch_insts[ARRAY_SIZE(methodtab)]; static pmdaInstid loadavg_insts[] = { {1, "1 minute"}, {5, "5 minute"}, {15, "15 minute"} }; pmdaMetric *metrictab; #define SYSINFO_OFF(field) ((ptrdiff_t)&((cpu_stat_t *)0)->cpu_sysinfo.field) #define KSTAT_IO_OFF(field) ((ptrdiff_t)&((kstat_io_t *)0)->field) #define VDEV_OFFSET(field) ((ptrdiff_t)&((vdev_stat_t *)0)->field) #define NM2_UDP_OFFSET(field) ((ptrdiff_t)&(nm2_udp.field)) #define NM2_NETIF_OFFSET(field) ((ptrdiff_t)&((nm2_netif_stats_t *)0)->field) #define FSF_STAT_OFFSET(field) ((ptrdiff_t)&((fsf_stat_t *)0)->field) /* * all metrics supported in this PMDA - one table entry for each metric */ metricdesc_t metricdesc[] = { { "kernel.all.cpu.idle", { PMDA_PMID(SCLR_SYSINFO,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(cpu[CPU_IDLE]) }, { "kernel.all.cpu.user", { PMDA_PMID(SCLR_SYSINFO,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(cpu[CPU_USER]) }, { "kernel.all.cpu.sys", { PMDA_PMID(SCLR_SYSINFO,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(cpu[CPU_KERNEL]) }, { "kernel.all.cpu.wait.total", { PMDA_PMID(SCLR_SYSINFO,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(cpu[CPU_WAIT]) }, { "kernel.percpu.cpu.idle", { PMDA_PMID(SCLR_SYSINFO,4), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(cpu[CPU_IDLE]) }, { "kernel.percpu.cpu.user", { PMDA_PMID(SCLR_SYSINFO,5), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(cpu[CPU_USER]) }, { "kernel.percpu.cpu.sys", { PMDA_PMID(SCLR_SYSINFO,6), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(cpu[CPU_KERNEL]) }, { "kernel.percpu.cpu.wait.total", { PMDA_PMID(SCLR_SYSINFO,7), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(cpu[CPU_WAIT]) }, { "kernel.all.cpu.wait.io", { PMDA_PMID(SCLR_SYSINFO,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(wait[W_IO]) }, { "kernel.all.cpu.wait.pio", { PMDA_PMID(SCLR_SYSINFO,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(wait[W_PIO]) }, { "kernel.all.cpu.wait.swap", { PMDA_PMID(SCLR_SYSINFO,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(wait[W_SWAP]) }, { "kernel.percpu.cpu.wait.io", { PMDA_PMID(SCLR_SYSINFO,11), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(wait[W_IO]) }, { "kernel.percpu.cpu.wait.pio", { PMDA_PMID(SCLR_SYSINFO,12), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(wait[W_PIO]) }, { "kernel.percpu.cpu.wait.swap", { PMDA_PMID(SCLR_SYSINFO,13), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, SYSINFO_OFF(wait[W_SWAP]) }, { "kernel.all.io.bread", { PMDA_PMID(SCLR_SYSINFO,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(bread) }, { "kernel.all.io.bwrite", { PMDA_PMID(SCLR_SYSINFO,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(bwrite) }, { "kernel.all.io.lread", { PMDA_PMID(SCLR_SYSINFO,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(lread) }, { "kernel.all.io.lwrite", { PMDA_PMID(SCLR_SYSINFO,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(lwrite) }, { "kernel.percpu.io.bread", { PMDA_PMID(SCLR_SYSINFO,18), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(bread) }, { "kernel.percpu.io.bwrite", { PMDA_PMID(SCLR_SYSINFO,19), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(bwrite) }, { "kernel.percpu.io.lread", { PMDA_PMID(SCLR_SYSINFO,20), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(lread) }, { "kernel.percpu.io.lwrite", { PMDA_PMID(SCLR_SYSINFO,21), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(lwrite) }, { "kernel.all.syscall", { PMDA_PMID(SCLR_SYSINFO,22), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(syscall) }, { "kernel.all.pswitch", { PMDA_PMID(SCLR_SYSINFO,23), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(pswitch) }, { "kernel.percpu.syscall", { PMDA_PMID(SCLR_SYSINFO,24), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(syscall) }, { "kernel.percpu.pswitch", { PMDA_PMID(SCLR_SYSINFO,25), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(pswitch) }, { "kernel.all.io.phread", { PMDA_PMID(SCLR_SYSINFO,26), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(phread) }, { "kernel.all.io.phwrite", { PMDA_PMID(SCLR_SYSINFO,27), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(phwrite) }, { "kernel.all.io.intr", { PMDA_PMID(SCLR_SYSINFO,28), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(intr) }, { "kernel.percpu.io.phread", { PMDA_PMID(SCLR_SYSINFO,29), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(phread) }, { "kernel.percpu.io.phwrite", { PMDA_PMID(SCLR_SYSINFO,30), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(phwrite) }, { "kernel.percpu.io.intr", { PMDA_PMID(SCLR_SYSINFO,31), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(intr) }, { "kernel.all.trap", { PMDA_PMID(SCLR_SYSINFO,32), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(trap) }, { "kernel.all.sysexec", { PMDA_PMID(SCLR_SYSINFO,33), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(sysexec) }, { "kernel.all.sysfork", { PMDA_PMID(SCLR_SYSINFO,34), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(sysfork) }, { "kernel.all.sysvfork", { PMDA_PMID(SCLR_SYSINFO,35), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(sysvfork) }, { "kernel.all.sysread", { PMDA_PMID(SCLR_SYSINFO,36), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(sysread) }, { "kernel.all.syswrite", { PMDA_PMID(SCLR_SYSINFO,37), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(syswrite) }, { "kernel.percpu.trap", { PMDA_PMID(SCLR_SYSINFO,38), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(trap) }, { "kernel.percpu.sysexec", { PMDA_PMID(SCLR_SYSINFO,39), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(sysexec) }, { "kernel.percpu.sysfork", { PMDA_PMID(SCLR_SYSINFO,40), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(sysfork) }, { "kernel.percpu.sysvfork", { PMDA_PMID(SCLR_SYSINFO,41), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(sysvfork) }, { "kernel.percpu.sysread", { PMDA_PMID(SCLR_SYSINFO,42), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(sysread) }, { "kernel.percpu.syswrite", { PMDA_PMID(SCLR_SYSINFO,43), PM_TYPE_U32, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, SYSINFO_OFF(syswrite) }, { "disk.all.read", { PMDA_PMID(SCLR_DISK,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, KSTAT_IO_OFF(reads) }, { "disk.all.write", { PMDA_PMID(SCLR_DISK,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, KSTAT_IO_OFF(writes) }, { "disk.all.total", { PMDA_PMID(SCLR_DISK,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, -1}, { "disk.all.read_bytes", { PMDA_PMID(SCLR_DISK,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, KSTAT_IO_OFF(nread) }, { "disk.all.write_bytes", { PMDA_PMID(SCLR_DISK,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, KSTAT_IO_OFF(nwritten) }, { "disk.all.total_bytes", { PMDA_PMID(SCLR_DISK,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, -1}, { "disk.dev.read", { PMDA_PMID(SCLR_DISK,10), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, KSTAT_IO_OFF(reads) }, { "disk.dev.write", { PMDA_PMID(SCLR_DISK,11), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, KSTAT_IO_OFF(writes) }, { "disk.dev.total", { PMDA_PMID(SCLR_DISK,12), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, -1}, { "disk.dev.read_bytes", { PMDA_PMID(SCLR_DISK,13), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, KSTAT_IO_OFF(nread) }, { "disk.dev.write_bytes", { PMDA_PMID(SCLR_DISK,14), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, KSTAT_IO_OFF(nwritten) }, { "disk.dev.total_bytes", { PMDA_PMID(SCLR_DISK,15), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, -1}, { "hinv.ncpu", { PMDA_PMID(SCLR_SYSINFO,56), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, -1}, { "hinv.ndisk", { PMDA_PMID(SCLR_DISK,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, -1}, { "hinv.nfilesys", { PMDA_PMID(SCLR_FILESYS,1023), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, -1}, { "pmda.uname", { PMDA_PMID(SCLR_SYSINFO,107), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, -1 }, { "hinv.pagesize", { PMDA_PMID(SCLR_SYSINFO,108), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, -1 }, { "hinv.physmem", { PMDA_PMID(SCLR_SYSINFO,109), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_MBYTE, 0, 0) }, -1 }, { "zpool.capacity", { PMDA_PMID(SCLR_ZPOOL,2), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, VDEV_OFFSET(vs_space) }, { "zpool.used", { PMDA_PMID(SCLR_ZPOOL,3), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, VDEV_OFFSET(vs_alloc) }, { "zpool.checksum_errors", { PMDA_PMID(SCLR_ZPOOL,4), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, VDEV_OFFSET(vs_checksum_errors) }, { "zpool.self_healed", { PMDA_PMID(SCLR_ZPOOL,5), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, VDEV_OFFSET(vs_self_healed) }, { "zpool.in.bytes", { PMDA_PMID(SCLR_ZPOOL,6), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, VDEV_OFFSET(vs_bytes[ZIO_TYPE_READ]) }, { "zpool.in.ops", { PMDA_PMID(SCLR_ZPOOL,7), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, VDEV_OFFSET(vs_ops[ZIO_TYPE_READ]) }, { "zpool.in.errors", { PMDA_PMID(SCLR_ZPOOL,8), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, VDEV_OFFSET(vs_read_errors) }, { "zpool.out.bytes", { PMDA_PMID(SCLR_ZPOOL,9), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, VDEV_OFFSET(vs_bytes[ZIO_TYPE_WRITE]) }, { "zpool.out.ops", { PMDA_PMID(SCLR_ZPOOL,10), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, VDEV_OFFSET(vs_ops[ZIO_TYPE_WRITE]) }, { "zpool.out.errors", { PMDA_PMID(SCLR_ZPOOL,11), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, VDEV_OFFSET(vs_write_errors) }, { "zpool.ops.noops", { PMDA_PMID(SCLR_ZPOOL,12), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, VDEV_OFFSET(vs_ops[ZIO_TYPE_NULL]) }, { "zpool.ops.ioctls", { PMDA_PMID(SCLR_ZPOOL,13), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, VDEV_OFFSET(vs_ops[ZIO_TYPE_WRITE]) }, { "zpool.ops.claims", { PMDA_PMID(SCLR_ZPOOL,14), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, VDEV_OFFSET(vs_ops[ZIO_TYPE_WRITE]) }, { "zpool.ops.frees", { PMDA_PMID(SCLR_ZPOOL,15), PM_TYPE_U64, ZPOOL_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, VDEV_OFFSET(vs_ops[ZIO_TYPE_WRITE]) }, { "zfs.used.total", { PMDA_PMID(SCLR_ZFS,10), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_USED }, { "zfs.available", { PMDA_PMID(SCLR_ZFS,0), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_AVAILABLE }, { "zfs.quota", { PMDA_PMID(SCLR_ZFS,1), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_QUOTA }, { "zfs.reservation", { PMDA_PMID(SCLR_ZFS,2), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_RESERVATION }, { "zfs.compression", { PMDA_PMID(SCLR_ZFS,3), PM_TYPE_DOUBLE, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, ZFS_PROP_COMPRESSRATIO }, { "zfs.copies", { PMDA_PMID(SCLR_ZFS,4), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, ZFS_PROP_COPIES }, { "zfs.used.byme", { PMDA_PMID(SCLR_ZFS,11), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_USEDDS }, { "zfs.used.bysnapshots", { PMDA_PMID(SCLR_ZFS,12), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_USEDSNAP }, { "zfs.used.bychildren", { PMDA_PMID(SCLR_ZFS,13), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_USEDCHILD }, { "network.udp.ipackets", { PMDA_PMID(SCLR_NETIF,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_UDP_OFFSET(ipackets) }, { "network.udp.opackets", { PMDA_PMID(SCLR_NETIF,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_UDP_OFFSET(opackets) }, { "network.udp.ierrors", { PMDA_PMID(SCLR_NETIF,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_UDP_OFFSET(ierrors) }, { "network.udp.oerrors", { PMDA_PMID(SCLR_NETIF,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_UDP_OFFSET(oerrors) }, { "network.interface.mtu", { PMDA_PMID(SCLR_NETIF,0), PM_TYPE_U32, NETIF_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, NM2_NETIF_OFFSET(mtu) }, { "network.interface.in.packets", { PMDA_PMID(SCLR_NETIF,2), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_NETIF_OFFSET(ipackets) }, { "network.interface.in.bytes", { PMDA_PMID(SCLR_NETIF,3), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, NM2_NETIF_OFFSET(ibytes) }, { "network.interface.in.bcasts", { PMDA_PMID(SCLR_NETIF,4), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_NETIF_OFFSET(ibcast) }, { "network.interface.in.mcasts", { PMDA_PMID(SCLR_NETIF,5), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_NETIF_OFFSET(imcast) }, { "network.interface.out.packets", { PMDA_PMID(SCLR_NETIF,9), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_NETIF_OFFSET(opackets) }, { "network.interface.out.bytes", { PMDA_PMID(SCLR_NETIF,10), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, NM2_NETIF_OFFSET(obytes) }, { "network.interface.out.bcasts", { PMDA_PMID(SCLR_NETIF,11), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_NETIF_OFFSET(obcast) }, { "network.interface.out.mcasts", { PMDA_PMID(SCLR_NETIF,12), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_NETIF_OFFSET(omcast) }, { "network.interface.in.errors", { PMDA_PMID(SCLR_NETIF,1), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_NETIF_OFFSET(ierrors) }, { "network.interface.out.errors", { PMDA_PMID(SCLR_NETIF,8), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_NETIF_OFFSET(oerrors) }, { "network.interface.in.drops", { PMDA_PMID(SCLR_NETIF,6), PM_TYPE_U32, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_NETIF_OFFSET(idrops) }, { "network.interface.out.drops", { PMDA_PMID(SCLR_NETIF,13), PM_TYPE_U32, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_NETIF_OFFSET(odrops) }, { "network.interface.in.delivers", { PMDA_PMID(SCLR_NETIF,7), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_NETIF_OFFSET(delivered) }, { "network.udp.noports", { PMDA_PMID(SCLR_NETIF,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_UDP_OFFSET(noports) }, { "network.udp.overflows", { PMDA_PMID(SCLR_NETIF,19), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, NM2_UDP_OFFSET(overflows) }, { "zpool.state", { PMDA_PMID(SCLR_ZPOOL,0), PM_TYPE_STRING, ZPOOL_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, 0 }, { "zpool.state_int", { PMDA_PMID(SCLR_ZPOOL,1), PM_TYPE_U32, ZPOOL_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, 0 }, { "zpool.perdisk.state", { PMDA_PMID(SCLR_ZPOOL_PERDISK,0), PM_TYPE_STRING, ZPOOL_PERDISK_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, VDEV_OFFSET(vs_state) }, { "zpool.perdisk.state_int", { PMDA_PMID(SCLR_ZPOOL_PERDISK,1), PM_TYPE_U32, ZPOOL_PERDISK_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, 0 }, { "zpool.perdisk.checksum_errors", { PMDA_PMID(SCLR_ZPOOL_PERDISK,2), PM_TYPE_U64, ZPOOL_PERDISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, VDEV_OFFSET(vs_checksum_errors) }, { "zpool.perdisk.self_healed", { PMDA_PMID(SCLR_ZPOOL_PERDISK,3), PM_TYPE_U64, ZPOOL_PERDISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, VDEV_OFFSET(vs_self_healed) }, { "zpool.perdisk.in.errors", { PMDA_PMID(SCLR_ZPOOL_PERDISK,4), PM_TYPE_U64, ZPOOL_PERDISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, VDEV_OFFSET(vs_read_errors) }, { "zpool.perdisk.out.errors", { PMDA_PMID(SCLR_ZPOOL_PERDISK,5), PM_TYPE_U64, ZPOOL_PERDISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, VDEV_OFFSET(vs_write_errors) }, { "network.link.in.errors", { PMDA_PMID(SCLR_NETLINK,4), PM_TYPE_U32, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ierrors" }, { "network.link.in.packets", { PMDA_PMID(SCLR_NETLINK,5), PM_TYPE_U64, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ipackets64" }, { "network.link.in.bytes", { PMDA_PMID(SCLR_NETLINK,6), PM_TYPE_U64, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"rbytes64" }, { "network.link.in.bcasts", { PMDA_PMID(SCLR_NETLINK,7), PM_TYPE_U32, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"brdcstrcv" }, { "network.link.in.mcasts", { PMDA_PMID(SCLR_NETLINK,8), PM_TYPE_U32, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"multircv" }, { "network.link.in.nobufs", { PMDA_PMID(SCLR_NETLINK,9), PM_TYPE_U32, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"norcvbuf" }, { "network.link.out.errors", { PMDA_PMID(SCLR_NETLINK,10), PM_TYPE_U32, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"oerrors" }, { "network.link.out.packets", { PMDA_PMID(SCLR_NETLINK,11), PM_TYPE_U64, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"opackets64" }, { "network.link.out.bytes", { PMDA_PMID(SCLR_NETLINK,12), PM_TYPE_U64, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"obytes64" }, { "network.link.out.bcasts", { PMDA_PMID(SCLR_NETLINK,13), PM_TYPE_U32, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"brdcstxmt" }, { "network.link.out.mcasts", { PMDA_PMID(SCLR_NETLINK,14), PM_TYPE_U32, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"multixmt" }, { "network.link.out.nobufs", { PMDA_PMID(SCLR_NETLINK,15), PM_TYPE_U32, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"noxmtbuf" }, { "network.link.collisions", { PMDA_PMID(SCLR_NETLINK,0), PM_TYPE_U32, NETLINK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"collisions" }, { "network.link.state", { PMDA_PMID(SCLR_NETLINK,1), PM_TYPE_U32, NETLINK_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"link_state" }, { "network.link.duplex", { PMDA_PMID(SCLR_NETLINK,2), PM_TYPE_U32, NETLINK_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"link_duplex" }, { "network.link.speed", { PMDA_PMID(SCLR_NETLINK,3), PM_TYPE_U64, NETLINK_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ifspeed" }, { "zfs.recordsize", { PMDA_PMID(SCLR_ZFS,5), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_RECORDSIZE }, { "zfs.refquota", { PMDA_PMID(SCLR_ZFS,6), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_REFQUOTA }, { "zfs.refreservation", { PMDA_PMID(SCLR_ZFS,7), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_REFRESERVATION }, { "zfs.used.byrefreservation", { PMDA_PMID(SCLR_ZFS,14), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_USEDREFRESERV }, { "zfs.referenced", { PMDA_PMID(SCLR_ZFS,8), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_REFERENCED }, { "zfs.nsnapshots", { PMDA_PMID(SCLR_ZFS,9), PM_TYPE_U64, ZFS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, -1 }, { "zfs.snapshot.used", { PMDA_PMID(SCLR_ZFS,15), PM_TYPE_U64, ZFS_SNAP_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_USED }, { "zfs.snapshot.referenced", { PMDA_PMID(SCLR_ZFS,16), PM_TYPE_U64, ZFS_SNAP_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, ZFS_PROP_REFERENCED }, { "zfs.snapshot.compression", { PMDA_PMID(SCLR_ZFS,17), PM_TYPE_DOUBLE, ZFS_SNAP_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, ZFS_PROP_COMPRESSRATIO }, { "kernel.all.load", { PMDA_PMID(SCLR_SYSINFO,135), PM_TYPE_FLOAT, LOADAVG_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, 0 }, { "kernel.fsflush.scanned", { PMDA_PMID(SCLR_FSFLUSH,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, FSF_STAT_OFFSET(fsf_scan) }, { "kernel.fsflush.examined", { PMDA_PMID(SCLR_FSFLUSH,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, FSF_STAT_OFFSET(fsf_examined) }, { "kernel.fsflush.locked", { PMDA_PMID(SCLR_FSFLUSH,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, FSF_STAT_OFFSET(fsf_locked) }, { "kernel.fsflush.modified", { PMDA_PMID(SCLR_FSFLUSH,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, FSF_STAT_OFFSET(fsf_modified) }, { "kernel.fsflush.coalesced", { PMDA_PMID(SCLR_FSFLUSH,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, FSF_STAT_OFFSET(fsf_coalesce) }, { "kernel.fsflush.released", { PMDA_PMID(SCLR_FSFLUSH,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, FSF_STAT_OFFSET(fsf_releases) }, { "kernel.fsflush.time", { PMDA_PMID(SCLR_FSFLUSH,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_NSEC, 0) }, FSF_STAT_OFFSET(fsf_time) }, { "mem.physmem", { PMDA_PMID(SCLR_SYSINFO,136), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, -1}, { "mem.freemem", { PMDA_PMID(SCLR_SYSINFO,137), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, -1}, { "mem.lotsfree", { PMDA_PMID(SCLR_SYSINFO,138), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, -1}, { "mem.availrmem", { PMDA_PMID(SCLR_SYSINFO,139), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, -1}, { "zfs.arc.size", { PMDA_PMID(SCLR_ARCSTATS,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"size"}, { "zfs.arc.min_size", { PMDA_PMID(SCLR_ARCSTATS,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"c_min"}, { "zfs.arc.max_size", { PMDA_PMID(SCLR_ARCSTATS,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"c_max"}, { "zfs.arc.mru_size", { PMDA_PMID(SCLR_ARCSTATS,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"p"}, { "zfs.arc.target_size", { PMDA_PMID(SCLR_ARCSTATS,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"c"}, { "zfs.arc.misses.total", { PMDA_PMID(SCLR_ARCSTATS,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"misses"}, { "zfs.arc.misses.demand_data", { PMDA_PMID(SCLR_ARCSTATS,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"demand_data_misses"}, { "zfs.arc.misses.demand_metadata", { PMDA_PMID(SCLR_ARCSTATS,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"demand_metadata_misses"}, { "zfs.arc.misses.prefetch_data", { PMDA_PMID(SCLR_ARCSTATS,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"prefetch_data_misses"}, { "zfs.arc.misses.prefetch_metadata", { PMDA_PMID(SCLR_ARCSTATS,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"prefetch_metadata_misses"}, { "zfs.arc.hits.total", { PMDA_PMID(SCLR_ARCSTATS,10), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"hits"}, { "zfs.arc.hits.mfu", { PMDA_PMID(SCLR_ARCSTATS,11), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"mfu_hits"}, { "zfs.arc.hits.mru", { PMDA_PMID(SCLR_ARCSTATS,12), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"mru_hits"}, { "zfs.arc.hits.mfu_ghost", { PMDA_PMID(SCLR_ARCSTATS,13), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"mfu_ghost_hits"}, { "zfs.arc.hits.mru_ghost", { PMDA_PMID(SCLR_ARCSTATS,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"mru_ghost_hits"}, { "zfs.arc.hits.demand_data", { PMDA_PMID(SCLR_ARCSTATS,15), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"demand_data_hits"}, { "zfs.arc.hits.demand_metadata", { PMDA_PMID(SCLR_ARCSTATS,16), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"demand_metadata_hits"}, { "zfs.arc.hits.prefetch_data", { PMDA_PMID(SCLR_ARCSTATS,17), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"prefetch_data_hits"}, { "zfs.arc.hits.prefetch_metadata", { PMDA_PMID(SCLR_ARCSTATS,18), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"prefetch_metadata_hits"}, { "pmda.prefetch.time", { PMDA_PMID(4095,0), PM_TYPE_U64, PREFETCH_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_NSEC, 0) }, -1 }, { "pmda.prefetch.count", { PMDA_PMID(4095,1), PM_TYPE_U64, PREFETCH_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, -1 }, { "pmda.metric.time", { PMDA_PMID(4095,2), PM_TYPE_U64, METRIC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_NSEC, 0) }, -1 }, { "pmda.metric.count", { PMDA_PMID(4095,3), PM_TYPE_U64, METRIC_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, -1 }, { "disk.dev.wait.time", { PMDA_PMID(SCLR_DISK,16), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_NSEC, 0) }, KSTAT_IO_OFF(wtime)}, { "disk.dev.wait.count", { PMDA_PMID(SCLR_DISK,17), PM_TYPE_U32, DISK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, KSTAT_IO_OFF(wcnt)}, { "disk.dev.run.time", { PMDA_PMID(SCLR_DISK,18), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_NSEC, 0) }, KSTAT_IO_OFF(rtime)}, { "disk.dev.run.count", { PMDA_PMID(SCLR_DISK,19), PM_TYPE_U32, DISK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, KSTAT_IO_OFF(rcnt)}, { "disk.all.wait.time", { PMDA_PMID(SCLR_DISK,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_NSEC, 0) }, KSTAT_IO_OFF(wtime)}, { "disk.all.wait.count", { PMDA_PMID(SCLR_DISK,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, -1}, { "disk.all.run.time", { PMDA_PMID(SCLR_DISK,8), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_NSEC, 0) }, KSTAT_IO_OFF(rtime)}, { "disk.all.run.count", { PMDA_PMID(SCLR_DISK,9), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, -1}, { "kernel.fs.read_bytes", { PMDA_PMID(SCLR_FILESYS,0), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"read_bytes"}, { "kernel.fs.readdir_bytes", { PMDA_PMID(SCLR_FILESYS,1), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"readdir_bytes"}, { "kernel.fs.write_bytes", { PMDA_PMID(SCLR_FILESYS,2), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"write_bytes"}, { "kernel.fs.vnops.access", { PMDA_PMID(SCLR_FILESYS,3), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"naccess"}, { "kernel.fs.vnops.addmap", {PMDA_PMID(SCLR_FILESYS,4), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"naddmap"}, { "kernel.fs.vnops.close", {PMDA_PMID(SCLR_FILESYS,5), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nclose"}, { "kernel.fs.vnops.cmp", {PMDA_PMID(SCLR_FILESYS,6), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ncmp"}, { "kernel.fs.vnops.create", {PMDA_PMID(SCLR_FILESYS,7), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ncreate"}, { "kernel.fs.vnops.delmap", {PMDA_PMID(SCLR_FILESYS,8), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ndelmap"}, { "kernel.fs.vnops.dispose", {PMDA_PMID(SCLR_FILESYS,9), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ndispose"}, { "kernel.fs.vnops.dump", {PMDA_PMID(SCLR_FILESYS,10), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ndump"}, { "kernel.fs.vnops.dumpctl", {PMDA_PMID(SCLR_FILESYS,11), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ndumpctl"}, { "kernel.fs.vnops.fid", {PMDA_PMID(SCLR_FILESYS,12), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nfid"}, { "kernel.fs.vnops.frlock", {PMDA_PMID(SCLR_FILESYS,13), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nfrlock"}, { "kernel.fs.vnops.fsync", {PMDA_PMID(SCLR_FILESYS,14), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nfsync"}, { "kernel.fs.vnops.getattr", {PMDA_PMID(SCLR_FILESYS,15), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ngetattr"}, { "kernel.fs.vnops.getpage", {PMDA_PMID(SCLR_FILESYS,16), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ngetpage"}, { "kernel.fs.vnops.getsecattr", {PMDA_PMID(SCLR_FILESYS,17), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ngetsecattr"}, { "kernel.fs.vnops.inactive", {PMDA_PMID(SCLR_FILESYS,18), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ninactive"}, { "kernel.fs.vnops.ioctl", {PMDA_PMID(SCLR_FILESYS,19), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nioctl"}, { "kernel.fs.vnops.link", {PMDA_PMID(SCLR_FILESYS,20), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nlink"}, { "kernel.fs.vnops.lookup", {PMDA_PMID(SCLR_FILESYS,21), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nlookup"}, { "kernel.fs.vnops.map", {PMDA_PMID(SCLR_FILESYS,22), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nmap"}, { "kernel.fs.vnops.mkdir", {PMDA_PMID(SCLR_FILESYS,23), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nmkdir"}, { "kernel.fs.vnops.open", {PMDA_PMID(SCLR_FILESYS,24), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nopen"}, { "kernel.fs.vnops.pageio", {PMDA_PMID(SCLR_FILESYS,25), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"npageio"}, { "kernel.fs.vnops.pathconf", {PMDA_PMID(SCLR_FILESYS,26), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"npathconf"}, { "kernel.fs.vnops.poll", {PMDA_PMID(SCLR_FILESYS,27), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"npoll"}, { "kernel.fs.vnops.putpage", {PMDA_PMID(SCLR_FILESYS,28), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nputpage"}, { "kernel.fs.vnops.read", {PMDA_PMID(SCLR_FILESYS,29), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nread"}, { "kernel.fs.vnops.readdir", {PMDA_PMID(SCLR_FILESYS,30), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nreaddir"}, { "kernel.fs.vnops.readlink", {PMDA_PMID(SCLR_FILESYS,31), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nreadlink"}, { "kernel.fs.vnops.realvp", {PMDA_PMID(SCLR_FILESYS,32), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nrealvp"}, { "kernel.fs.vnops.remove", {PMDA_PMID(SCLR_FILESYS,33), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nremove"}, { "kernel.fs.vnops.rename", {PMDA_PMID(SCLR_FILESYS,34), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nrename"}, { "kernel.fs.vnops.rmdir", {PMDA_PMID(SCLR_FILESYS,35), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nrmdir"}, { "kernel.fs.vnops.rwlock", {PMDA_PMID(SCLR_FILESYS,36), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nrwlock"}, { "kernel.fs.vnops.rwunlock", {PMDA_PMID(SCLR_FILESYS,37), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nrwunlock"}, { "kernel.fs.vnops.seek", {PMDA_PMID(SCLR_FILESYS,38), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nseek"}, { "kernel.fs.vnops.setattr", {PMDA_PMID(SCLR_FILESYS,39), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nsetattr"}, { "kernel.fs.vnops.setfl", {PMDA_PMID(SCLR_FILESYS,40), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nsetfl"}, { "kernel.fs.vnops.setsecattr", {PMDA_PMID(SCLR_FILESYS,41), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nsetsecattr"}, { "kernel.fs.vnops.shrlock", {PMDA_PMID(SCLR_FILESYS,42), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nshrlock"}, { "kernel.fs.vnops.space", {PMDA_PMID(SCLR_FILESYS,43), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nspace"}, { "kernel.fs.vnops.symlink", {PMDA_PMID(SCLR_FILESYS,44), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nsymlink"}, { "kernel.fs.vnops.vnevent", {PMDA_PMID(SCLR_FILESYS,45), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nvnevent"}, { "kernel.fs.vnops.write", {PMDA_PMID(SCLR_FILESYS,46), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nwrite"}, { "kernel.fstype.read_bytes", { PMDA_PMID(SCLR_FILESYS,47), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"read_bytes"}, { "kernel.fstype.readdir_bytes", { PMDA_PMID(SCLR_FILESYS,48), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"readdir_bytes"}, { "kernel.fstype.write_bytes", { PMDA_PMID(SCLR_FILESYS,49), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"write_bytes"}, { "kernel.fstype.vnops.access", { PMDA_PMID(SCLR_FILESYS,50), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"naccess"}, { "kernel.fstype.vnops.addmap", {PMDA_PMID(SCLR_FILESYS,51), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"naddmap"}, { "kernel.fstype.vnops.close", {PMDA_PMID(SCLR_FILESYS,52), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nclose"}, { "kernel.fstype.vnops.cmp", {PMDA_PMID(SCLR_FILESYS,53), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ncmp"}, { "kernel.fstype.vnops.create", {PMDA_PMID(SCLR_FILESYS,54), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ncreate"}, { "kernel.fstype.vnops.delmap", {PMDA_PMID(SCLR_FILESYS,55), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ndelmap"}, { "kernel.fstype.vnops.dispose", {PMDA_PMID(SCLR_FILESYS,56), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ndispose"}, { "kernel.fstype.vnops.dump", {PMDA_PMID(SCLR_FILESYS,57), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ndump"}, { "kernel.fstype.vnops.dumpctl", {PMDA_PMID(SCLR_FILESYS,58), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ndumpctl"}, { "kernel.fstype.vnops.fid", {PMDA_PMID(SCLR_FILESYS,59), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nfid"}, { "kernel.fstype.vnops.frlock", {PMDA_PMID(SCLR_FILESYS,60), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nfrlock"}, { "kernel.fstype.vnops.fsync", {PMDA_PMID(SCLR_FILESYS,61), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nfsync"}, { "kernel.fstype.vnops.getattr", {PMDA_PMID(SCLR_FILESYS,62), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ngetattr"}, { "kernel.fstype.vnops.getpage", {PMDA_PMID(SCLR_FILESYS,63), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ngetpage"}, { "kernel.fstype.vnops.getsecattr", {PMDA_PMID(SCLR_FILESYS,64), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ngetsecattr"}, { "kernel.fstype.vnops.inactive", {PMDA_PMID(SCLR_FILESYS,65), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"ninactive"}, { "kernel.fstype.vnops.ioctl", {PMDA_PMID(SCLR_FILESYS,66), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nioctl"}, { "kernel.fstype.vnops.link", {PMDA_PMID(SCLR_FILESYS,67), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nlink"}, { "kernel.fstype.vnops.lookup", {PMDA_PMID(SCLR_FILESYS,68), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nlookup"}, { "kernel.fstype.vnops.map", {PMDA_PMID(SCLR_FILESYS,69), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nmap"}, { "kernel.fstype.vnops.mkdir", {PMDA_PMID(SCLR_FILESYS,70), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nmkdir"}, { "kernel.fstype.vnops.open", {PMDA_PMID(SCLR_FILESYS,71), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nopen"}, { "kernel.fstype.vnops.pageio", {PMDA_PMID(SCLR_FILESYS,72), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"npageio"}, { "kernel.fstype.vnops.pathconf", {PMDA_PMID(SCLR_FILESYS,73), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"npathconf"}, { "kernel.fstype.vnops.poll", {PMDA_PMID(SCLR_FILESYS,74), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"npoll"}, { "kernel.fstype.vnops.putpage", {PMDA_PMID(SCLR_FILESYS,75), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nputpage"}, { "kernel.fstype.vnops.read", {PMDA_PMID(SCLR_FILESYS,76), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nread"}, { "kernel.fstype.vnops.readdir", {PMDA_PMID(SCLR_FILESYS,77), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nreaddir"}, { "kernel.fstype.vnops.readlink", {PMDA_PMID(SCLR_FILESYS,78), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nreadlink"}, { "kernel.fstype.vnops.realvp", {PMDA_PMID(SCLR_FILESYS,79), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nrealvp"}, { "kernel.fstype.vnops.remove", {PMDA_PMID(SCLR_FILESYS,80), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nremove"}, { "kernel.fstype.vnops.rename", {PMDA_PMID(SCLR_FILESYS,81), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nrename"}, { "kernel.fstype.vnops.rmdir", {PMDA_PMID(SCLR_FILESYS,82), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nrmdir"}, { "kernel.fstype.vnops.rwlock", {PMDA_PMID(SCLR_FILESYS,83), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nrwlock"}, { "kernel.fstype.vnops.rwunlock", {PMDA_PMID(SCLR_FILESYS,84), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nrwunlock"}, { "kernel.fstype.vnops.seek", {PMDA_PMID(SCLR_FILESYS,85), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nseek"}, { "kernel.fstype.vnops.setattr", {PMDA_PMID(SCLR_FILESYS,86), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nsetattr"}, { "kernel.fstype.vnops.setfl", {PMDA_PMID(SCLR_FILESYS,87), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nsetfl"}, { "kernel.fstype.vnops.setsecattr", {PMDA_PMID(SCLR_FILESYS,88), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nsetsecattr"}, { "kernel.fstype.vnops.shrlock", {PMDA_PMID(SCLR_FILESYS,89), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nshrlock"}, { "kernel.fstype.vnops.space", {PMDA_PMID(SCLR_FILESYS,90), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nspace"}, { "kernel.fstype.vnops.symlink", {PMDA_PMID(SCLR_FILESYS,91), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nsymlink"}, { "kernel.fstype.vnops.vnevent", {PMDA_PMID(SCLR_FILESYS,92), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nvnevent"}, { "kernel.fstype.vnops.write", {PMDA_PMID(SCLR_FILESYS,93), PM_TYPE_U64, FSTYPE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, (ptrdiff_t)"nwrite"}, { "hinv.cpu.maxclock", {PMDA_PMID(SCLR_SYSINFO,147), PM_TYPE_64, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, -1, 1, 0, PM_TIME_SEC, 6) }, (ptrdiff_t)"clock_MHz"}, { "hinv.cpu.clock", {PMDA_PMID(SCLR_SYSINFO,148), PM_TYPE_U64, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, -1, 1, 0, PM_TIME_SEC, 0) }, (ptrdiff_t)"current_clock_Hz"}, { "hinv.cpu.brand", {PMDA_PMID(SCLR_SYSINFO, 149), PM_TYPE_STRING, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"brand"}, { "hinv.cpu.frequencies", {PMDA_PMID(SCLR_SYSINFO, 150), PM_TYPE_STRING, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"supported_frequencies_Hz"}, { "hinv.cpu.implementation", {PMDA_PMID(SCLR_SYSINFO, 151), PM_TYPE_STRING, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"implementation"}, { "hinv.cpu.chip_id", {PMDA_PMID(SCLR_SYSINFO, 152), PM_TYPE_64, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"chip_id"}, { "hinv.cpu.clog_id", {PMDA_PMID(SCLR_SYSINFO, 153), PM_TYPE_32, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"clog_id"}, { "hinv.cpu.core_id", {PMDA_PMID(SCLR_SYSINFO, 154), PM_TYPE_64, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"core_id"}, { "hinv.cpu.pkg_core_id", {PMDA_PMID(SCLR_SYSINFO, 155), PM_TYPE_64, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"pkg_core_id"}, { "hinv.cpu.cstate", {PMDA_PMID(SCLR_SYSINFO, 156), PM_TYPE_32, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"current_cstate"}, { "hinv.cpu.maxcstates", {PMDA_PMID(SCLR_SYSINFO, 157), PM_TYPE_32, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"supported_max_cstates"}, { "hinv.cpu.ncores", {PMDA_PMID(SCLR_SYSINFO, 158), PM_TYPE_32, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"ncore_per_chip"}, { "hinv.cpu.ncpus", {PMDA_PMID(SCLR_SYSINFO, 159), PM_TYPE_32, CPU_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"ncpu_per_chip"}, { "disk.dev.errors.soft", {PMDA_PMID(SCLR_DISK, 21), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"Soft Errors"}, { "disk.dev.errors.hard", {PMDA_PMID(SCLR_DISK, 22), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"Hard Errors"}, { "disk.dev.errors.transport", {PMDA_PMID(SCLR_DISK, 23), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"Transport Errors"}, { "disk.dev.errors.media", {PMDA_PMID(SCLR_DISK, 24), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"Media Error"}, { "disk.dev.errors.recoverable", {PMDA_PMID(SCLR_DISK, 25), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"Recoverable"}, { "disk.dev.errors.notready", {PMDA_PMID(SCLR_DISK, 26), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"Device Not Ready"}, { "disk.dev.errors.nodevice", {PMDA_PMID(SCLR_DISK, 27), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"No Device"}, { "disk.dev.errors.badrequest", {PMDA_PMID(SCLR_DISK, 28), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"Illegal Request"}, { "disk.dev.errors.pfa", {PMDA_PMID(SCLR_DISK, 29), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE), }, (ptrdiff_t)"Predictive Failure Analysis"}, { "hinv.disk.vendor", {PMDA_PMID(SCLR_DISK, 30), PM_TYPE_STRING, DISK_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"Vendor"}, { "hinv.disk.product", {PMDA_PMID(SCLR_DISK, 31), PM_TYPE_STRING, DISK_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"Product"}, { "hinv.disk.revision", {PMDA_PMID(SCLR_DISK, 32), PM_TYPE_STRING, DISK_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"Revision"}, { "hinv.disk.serial", {PMDA_PMID(SCLR_DISK, 33), PM_TYPE_STRING, DISK_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, (ptrdiff_t)"Serial No"}, { "hinv.disk.capacity", { PMDA_PMID(SCLR_DISK,34), PM_TYPE_U64, DISK_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, (ptrdiff_t)"Size" }, { "hinv.disk.devlink", {PMDA_PMID(SCLR_DISK, 35), PM_TYPE_STRING, DISK_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, -1} /* remember to add trailing comma before adding more entries ... */ }; int metrictab_sz = ARRAY_SIZE(metricdesc); pmdaInstid metric_insts[ARRAY_SIZE(metricdesc)]; /* * List of instance domains ... we expect the *_INDOM macros * to index into this table. */ pmdaIndom indomtab[] = { { DISK_INDOM, 0, NULL }, { CPU_INDOM, 0, NULL }, { NETIF_INDOM, 0, NULL }, { ZPOOL_INDOM, 0, NULL }, { ZFS_INDOM, 0, NULL }, { ZPOOL_PERDISK_INDOM, 0, NULL }, { NETLINK_INDOM}, { ZFS_SNAP_INDOM }, { LOADAVG_INDOM, ARRAY_SIZE(loadavg_insts), loadavg_insts}, { PREFETCH_INDOM, ARRAY_SIZE(prefetch_insts), prefetch_insts}, { METRIC_INDOM, ARRAY_SIZE(metric_insts), metric_insts}, { FILESYS_INDOM }, { FSTYPE_INDOM } }; int indomtab_sz = sizeof(indomtab) / sizeof(indomtab[0]); static kstat_ctl_t *kc; static int kstat_chains_updated; kstat_ctl_t * kstat_ctl_update(void) { if (!kstat_chains_updated) { if (kstat_chain_update(kc) == -1) { kstat_chains_updated = 0; return NULL; } kstat_chains_updated = 1; } return kc; } void kstat_ctl_needs_update(void) { kstat_chains_updated = 0; } void init_data(int domain) { int i; int serial; __pmID_int *ip; /* * set up kstat() handle ... failure is fatal */ if ((kc = kstat_open()) == NULL) { fprintf(stderr, "init_data: kstat_open failed: %s\n", osstrerror()); exit(1); } /* * Create the PMDA's metrictab[] version of the per-metric table. * * Also do domain initialization for each pmid and indom element of * the metricdesc[] table ... the PMDA table is fixed up in * libpcp_pmda */ if ((metrictab = (pmdaMetric *)malloc(metrictab_sz * sizeof(pmdaMetric))) == NULL) { fprintf(stderr, "init_data: Error: malloc metrictab [%d] failed: %s\n", (int)(metrictab_sz * sizeof(pmdaMetric)), osstrerror()); exit(1); } for (i = 0; i < metrictab_sz; i++) { metrictab[i].m_user = &metricdesc[i]; metrictab[i].m_desc = metricdesc[i].md_desc; ip = (__pmID_int *)&metricdesc[i].md_desc.pmid; ip->domain = domain; if (metricdesc[i].md_desc.indom != PM_INDOM_NULL) { serial = metricdesc[i].md_desc.indom; metricdesc[i].md_desc.indom = pmInDom_build(domain, serial); } metric_insts[i].i_inst = i+1; metric_insts[i].i_name = (char *)metricdesc[i].md_name; } /* Bless indoms with our own domain - usually pmdaInit will do it for * us but we need properly setup indoms for pmdaCache which means that * we have to do it ourselves */ for (i = 0; i < indomtab_sz; i++) { __pmindom_int(&indomtab[i].it_indom)->domain = domain; } /* * initialize each of the methods */ for (i = 0; i < methodtab_sz; i++) { if (methodtab[i].m_init) { methodtab[i].m_init(1); } prefetch_insts[i].i_inst = i + 1; prefetch_insts[i].i_name = (char *)methodtab[i].m_name; } } pcp-3.8.12ubuntu1/src/pmdas/solaris/sysinfo.c0000664000000000000000000002157212272262501016016 0ustar /* * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2010 Max Matveev. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "common.h" #include #include typedef struct { int fetched; int err; kstat_t *ksp; cpu_stat_t cpustat; kstat_t *info; int info_is_good; } ctl_t; static int ncpu; static int hz; static long pagesize; static ctl_t *ctl; static char uname_full[SYS_NMLN * 5]; static int nloadavgs; static double loadavgs[3]; void sysinfo_init(int first) { kstat_t *ksp; int i; char buf[10]; /* cpuXXXXX */ kstat_ctl_t *kc; if (!first) /* TODO ... not sure if/when we'll use this re-init hook */ return; if ((kc = kstat_ctl_update()) == NULL) return; for (ncpu = 0; ; ncpu++) { ksp = kstat_lookup(kc, "cpu_stat", ncpu, NULL); if (ksp == NULL) break; if ((ctl = (ctl_t *)realloc(ctl, (ncpu+1) * sizeof(ctl_t))) == NULL) { fprintf(stderr, "sysinfo_init: ctl realloc[%d] @ cpu=%d failed: %s\n", (int)((ncpu+1) * sizeof(ctl_t)), ncpu, osstrerror()); exit(1); } ctl[ncpu].info = kstat_lookup(kc, "cpu_info", ncpu, NULL); ctl[ncpu].ksp = ksp; ctl[ncpu].err = 0; } indomtab[CPU_INDOM].it_numinst = ncpu; indomtab[CPU_INDOM].it_set = (pmdaInstid *)malloc(ncpu * sizeof(pmdaInstid)); /* TODO check? */ for (i = 0; i < ncpu; i++) { indomtab[CPU_INDOM].it_set[i].i_inst = i; snprintf(buf, sizeof(buf), "cpu%d", i); indomtab[CPU_INDOM].it_set[i].i_name = strdup(buf); /* TODO check? */ } hz = (int)sysconf(_SC_CLK_TCK); pagesize = sysconf(_SC_PAGESIZE); #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "sysinfo: ncpu=%d hz=%d\n", ncpu, hz); } #endif } static __uint32_t sysinfo_derived(pmdaMetric *mdesc, int inst) { pmID pmid = mdesc->m_desc.pmid; __pmID_int *ip = (__pmID_int *)&pmid; __uint32_t val; ip->domain = 0; switch (pmid) { case PMDA_PMID(SCLR_SYSINFO,56): /* hinv.ncpu */ if (inst == 0) val = ncpu; else val = 0; break; default: fprintf(stderr, "cpu_derived: Botch: no method for pmid %s\n", pmIDStr(mdesc->m_desc.pmid)); val = 0; break; } #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "cpu_derived: pmid %s inst %d val %d\n", pmIDStr(mdesc->m_desc.pmid), inst, val); } #endif return val; } void sysinfo_prefetch(void) { int i; nloadavgs = -1; for (i = 0; i < ncpu; i++) { ctl[i].fetched = 0; ctl[i].info_is_good = 0; } } int kstat_named_to_pmAtom(const kstat_named_t *kn, pmAtomValue *atom) { static char chardat[sizeof(kn->value.c) + 1]; switch (kn->data_type) { case KSTAT_DATA_UINT64: atom->ull = kn->value.ui64; return 1; case KSTAT_DATA_INT64: atom->ull = kn->value.i64; return 1; case KSTAT_DATA_UINT32: atom->ull = kn->value.ui32; return 1; case KSTAT_DATA_INT32: atom->ull = kn->value.i32; return 1; case KSTAT_DATA_STRING: atom->cp = kn->value.str.addr.ptr; return 1; case KSTAT_DATA_CHAR: memcpy(chardat, kn->value.c, sizeof(kn->value.c)); chardat[sizeof(chardat)-1] = '\0'; atom->cp = chardat; return 1; default: return 0; } } static int kstat_fetch_named(kstat_ctl_t *kc, pmAtomValue *atom, char *metric, int shift_bits) { kstat_t *ks; if ((ks = kstat_lookup(kc, "unix", -1, "system_pages")) != NULL) { kstat_named_t *kn; if (kstat_read(kc, ks, NULL) == -1) return 0; if (((kn = kstat_data_lookup(ks, metric)) != NULL) && kstat_named_to_pmAtom(kn, atom)) { atom->ull = (atom->ull * pagesize) >> shift_bits; return 1; } } return 0; } int kstat_named_to_typed_atom(const kstat_named_t *kn, int pmtype, pmAtomValue *atom) { static char chardat[sizeof(kn->value.c) + 1]; switch (pmtype) { case PM_TYPE_32: if (kn->data_type == KSTAT_DATA_INT32) { atom->l = kn->value.i32; return 1; } break; case PM_TYPE_U32: if (kn->data_type == KSTAT_DATA_UINT32) { atom->ul = kn->value.ui32; return 1; } break; case PM_TYPE_64: if (kn->data_type == KSTAT_DATA_INT64) { atom->ll = kn->value.i64; return 1; } break; case PM_TYPE_U64: if (kn->data_type == KSTAT_DATA_UINT64) { atom->ull = kn->value.ui64; return 1; } break; case PM_TYPE_STRING: switch(kn->data_type) { case KSTAT_DATA_STRING: atom->cp = kn->value.str.addr.ptr; return 1; case KSTAT_DATA_CHAR: memcpy(chardat, kn->value.c, sizeof(kn->value.c)); chardat[sizeof(chardat)-1] = '\0'; atom->cp = chardat; return 1; } break; } return 0; } int sysinfo_fetch(pmdaMetric *mdesc, int inst, pmAtomValue *atom) { __uint64_t ull; int i; int ok; ptrdiff_t offset; struct utsname u; kstat_ctl_t *kc; if ((kc = kstat_ctl_update()) == NULL) return 0; /* Special processing of metrics which notionally belong * to sysinfo category */ switch (pmid_item(mdesc->m_desc.pmid)) { case 109: /* hinv.physmem */ return kstat_fetch_named(kc, atom, "physmem", 20); case 136: /* mem.physmem */ return kstat_fetch_named(kc, atom, "physmem", 10); case 137: /* mem.freemem */ return kstat_fetch_named(kc, atom, "freemem", 10); case 138: /* mem.lotsfree */ return kstat_fetch_named(kc, atom, "lotsfree", 10); case 139: /* mem.availrmem */ return kstat_fetch_named(kc, atom, "availrmem", 10); case 108: /* hinv.pagesize */ atom->ul = pagesize; return 1; case 107: /* pmda.uname */ if (uname(&u) < 0) return 0; snprintf(uname_full, sizeof(uname_full), "%s %s %s %s %s", u.sysname, u.nodename, u.release, u.version, u.machine); atom->cp = uname_full; return 1; case 135: /* kernel.all.load */ if (nloadavgs < 0) { if ((nloadavgs = getloadavg(loadavgs, 3)) < 0) return 0; } switch (inst) { case 1: atom->f = (float)loadavgs[LOADAVG_1MIN]; return nloadavgs > LOADAVG_1MIN; case 5: atom->f = (float)loadavgs[LOADAVG_5MIN]; return nloadavgs > LOADAVG_5MIN; case 15: atom->f = (float)loadavgs[LOADAVG_15MIN]; return nloadavgs > LOADAVG_15MIN; } return PM_ERR_INST; } ok = 1; for (i = 0; i < ncpu; i++) { if (inst == PM_IN_NULL || inst == i) { if (!ctl[i].info_is_good) { ctl[i].info_is_good = (ctl[i].info && (kstat_read(kc, ctl[i].info, NULL) != -1)); } if (ctl[i].fetched == 1) continue; if (kstat_read(kc, ctl[i].ksp, &ctl[i].cpustat) == -1) { if (ctl[i].err == 0) { fprintf(stderr, "Error: sysinfo_fetch(pmid=%s cpu=%d ...)\n", pmIDStr(mdesc->m_desc.pmid), i); fprintf(stderr, "kstat_read(kc=%p, ksp=%p, ...) failed: %s\n", kc, ctl[i].ksp, osstrerror()); } ctl[i].err++; ctl[i].fetched = -1; ok = 0; } else { ctl[i].fetched = 1; if (ctl[i].err != 0) { fprintf(stderr, "Success: sysinfo_fetch(pmid=%s cpu=%d ...) after %d errors as previously reported\n", pmIDStr(mdesc->m_desc.pmid), i, ctl[i].err); ctl[i].err = 0; } } } } if (!ok) return 0; ull = 0; for (i = 0; i < ncpu; i++) { if (inst == PM_IN_NULL || inst == i) { offset = ((metricdesc_t *)mdesc->m_user)->md_offset; if (offset == -1) { ull += sysinfo_derived(mdesc, i); } else if (offset > sizeof(ctl[i].cpustat)) { char *stat = (char *)offset; kstat_named_t *kn; if (!ctl[i].info_is_good) return 0; if ((kn = kstat_data_lookup(ctl[i].info, stat)) == NULL) { fprintf(stderr, "No kstat called %s for CPU %d\n", stat, i); return 0; } return kstat_named_to_typed_atom(kn, mdesc->m_desc.type, atom); } else { /* all the kstat fields are 32-bit unsigned */ __uint32_t *ulp; ulp = (__uint32_t *)&((char *)&ctl[i].cpustat)[offset]; ull += *ulp; #ifdef PCP_DEBUG if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) { /* desperate */ fprintf(stderr, "sysinfo_fetch: pmid %s inst %d val %u\n", pmIDStr(mdesc->m_desc.pmid), i, *ulp); } #endif } } } if (mdesc->m_desc.units.dimTime == 1) { /* sysinfo times are in ticks, and we export as 64-bit msec */ atom->ull = ull * 1000 / hz; } else if (mdesc->m_desc.type == PM_TYPE_U64) { /* export as 64-bit value */ atom->ull = ull; } else { /* else export as a 32-bit */ atom->ul = (__uint32_t)ull; } return 1; } pcp-3.8.12ubuntu1/src/pmdas/solaris/zpool_perdisk.c0000664000000000000000000001616412272262501017211 0ustar /* * Copyright (C) 2009 Max Matveev. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "common.h" struct vdev_stats { int vdev_stats_fresh; vdev_stat_t vds; }; static libzfs_handle_t *zh; static int vdev_added; static char * make_vdev_name(zpool_handle_t *zp, const char *pname, nvlist_t *child) { char *name = NULL; char *cname = zpool_vdev_name(zh, zp, child, B_FALSE); uint_t size; if (cname == NULL) { __pmNotifyErr(LOG_WARNING, "Cannot get the name of %s\'s " "child\n", pname); goto out; } size = strlen(pname) + strlen(cname) + 2; name = malloc(size); if (name == NULL) { __pmNotifyErr(LOG_WARNING, "Cannot allocate memory for %s.%s\n", pname, cname); goto free_out; } snprintf(name, size, "%s.%s", pname, cname); free_out: free(cname); out: return name; } /* * get the names and stats of those vdevs in the pool that are disks and are * either children, cache or spare devices */ static int zp_get_vdevs(zpool_handle_t *zp, char *zpname, nvlist_t *vdt, char ***vdev_names, vdev_stat_t ***vds, int *num) { int rv = 0; uint_t cnt; char **new_vdev_names; vdev_stat_t **new_vds; int nelem = *num; char *name; vdev_stat_t *stats; nvlist_t **children; uint_t nchildren; static const char *prop[] = { ZPOOL_CONFIG_CHILDREN, ZPOOL_CONFIG_L2CACHE, ZPOOL_CONFIG_SPARES }; int i; int j; char *vdev_type; rv = nvlist_lookup_string(vdt, ZPOOL_CONFIG_TYPE, &vdev_type); /* we've found disk, look no further */ if (rv == 0 && strcmp(vdev_type, "disk") == 0) { /* accommodate zpool api changes ... */ #ifdef ZPOOL_CONFIG_VDEV_STATS rv = nvlist_lookup_uint64_array(vdt, ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&stats, &cnt); #else rv = nvlist_lookup_uint64_array(vdt, ZPOOL_CONFIG_STATS, (uint64_t **)&stats, &cnt); #endif if (rv != 0) { __pmNotifyErr(LOG_WARNING, "Cannot get the stats of %s\'s " "child\n", zpname); goto out; } name = make_vdev_name(zp, zpname, vdt); if (name == NULL) { __pmNotifyErr(LOG_WARNING, "Cannot get the name of a %s\'s " "disk\n", zpname); goto out; } nelem++; new_vdev_names = realloc(*vdev_names, nelem * sizeof(*new_vdev_names)); if (new_vdev_names == NULL) { __pmNotifyErr(LOG_WARNING, "Cannot realloc memory for %s\n", name); goto free_out; } new_vdev_names[nelem - 1] = NULL; *vdev_names = new_vdev_names; new_vds = realloc(*vds, nelem * sizeof(*new_vds)); if (new_vds == NULL) { __pmNotifyErr(LOG_WARNING, "Cannot realloc memory for vds %s\n", name); goto free_out; } new_vds[nelem - 1] = stats; new_vdev_names[nelem - 1] = name; *vds = new_vds; *num = nelem; goto out; } /* not a disk, traversing children until we find all the disks */ for (i = 0; i < sizeof(prop) / sizeof(prop[0]); i++) { rv = nvlist_lookup_nvlist_array(vdt, prop[i], &children, &nchildren); if (rv != 0) nchildren = 0; for (j = 0; j < nchildren; j++) { zp_get_vdevs(zp, zpname, children[j], vdev_names, vds, num); } } return 0; out: return rv; free_out: free(name); return rv; } /* * For each zpool, check the leaf vdev names that are disks in the instance * cache, if one is not there then add it to the cache. Regardless if it's the * first time we've seen it or if it was in the cache before refresh the stats */ static int zp_cache_vdevs(zpool_handle_t *zp, void *arg) { nvlist_t *cfg = zpool_get_config(zp, NULL); char *zpname = (char *)zpool_get_name(zp); struct vdev_stats *zps = NULL; pmInDom zpindom = indomtab[ZPOOL_PERDISK_INDOM].it_indom; int rv; int inst; nvlist_t *vdt; int i; char **vdev_names = NULL; vdev_stat_t **vds = NULL; int num = 0; rv = nvlist_lookup_nvlist(cfg, ZPOOL_CONFIG_VDEV_TREE, &vdt); if (rv != 0) { __pmNotifyErr(LOG_ERR, "Cannot get vdev tree for '%s': %d %d\n", zpname, rv, oserror()); goto done; } rv = zp_get_vdevs(zp, zpname, vdt, &vdev_names, &vds, &num); if (rv != 0) { __pmNotifyErr(LOG_WARNING, "Cannot get vdevs for zpool '%s'\n", zpname); goto free_done; } for (i = 0; i < num; i++) { if (vdev_names[i] == NULL) continue; rv = pmdaCacheLookupName(zpindom, vdev_names[i], &inst, (void **)&zps); if (rv != PMDA_CACHE_ACTIVE) { int new_vdev = (zps == NULL); if (rv != PMDA_CACHE_INACTIVE || new_vdev) { zps = malloc(sizeof(*zps)); if (zps == NULL) { __pmNotifyErr(LOG_WARNING, "Cannot allocate memory to hold stats for " "vdev '%s'\n", vdev_names[i]); goto free_done; } } rv = pmdaCacheStore(zpindom, PMDA_CACHE_ADD, vdev_names[i], zps); if (rv < 0) { __pmNotifyErr(LOG_WARNING, "Cannot add '%s' to the cache " "for instance domain %s: %s\n", vdev_names[i], pmInDomStr(zpindom), pmErrStr(rv)); free(zps); goto free_done; } vdev_added += new_vdev; } if (rv >= 0) { memcpy(&zps->vds, vds[i], sizeof(zps->vds)); zps->vdev_stats_fresh = 1; } else { __pmNotifyErr(LOG_ERR, "Cannot get stats for '%s': %d %d\n", vdev_names[i], rv, oserror()); zps->vdev_stats_fresh = 0; } } free_done: for (i = 0; i < num; i++) free(vdev_names[i]); free(vdev_names); free(vds); done: zpool_close(zp); return 0; } void zpool_perdisk_refresh(void) { vdev_added = 0; pmdaCacheOp(indomtab[ZPOOL_PERDISK_INDOM].it_indom, PMDA_CACHE_INACTIVE); zpool_iter(zh, zp_cache_vdevs, NULL); if (vdev_added) { pmdaCacheOp(indomtab[ZPOOL_PERDISK_INDOM].it_indom, PMDA_CACHE_SAVE); } } int zpool_perdisk_fetch(pmdaMetric *pm, int inst, pmAtomValue *atom) { struct vdev_stats *stats; char *vdev_name; metricdesc_t *md = pm->m_user; if (pmdaCacheLookup(indomtab[ZPOOL_PERDISK_INDOM].it_indom, inst, &vdev_name, (void **)&stats) != PMDA_CACHE_ACTIVE) return PM_ERR_INST; if (stats->vdev_stats_fresh) { switch (pmid_item(md->md_desc.pmid)) { case 0: /* zpool.perdisk.state */ atom->cp = zpool_state_to_name(stats->vds.vs_state, stats->vds.vs_aux); break; case 1: /* zpool.perdisk.state_int */ atom->ul = (stats->vds.vs_aux << 8) | stats->vds.vs_state; break; default: memcpy(&atom->ull, ((char *)&stats->vds) + md->md_offset, sizeof(atom->ull)); } } return stats->vdev_stats_fresh; } void zpool_perdisk_init(int first) { if (zh) return; zh = libzfs_init(); if (zh) { pmdaCacheOp(indomtab[ZPOOL_PERDISK_INDOM].it_indom, PMDA_CACHE_LOAD); zpool_iter(zh, zp_cache_vdevs, NULL); pmdaCacheOp(indomtab[ZPOOL_PERDISK_INDOM].it_indom, PMDA_CACHE_SAVE); } } pcp-3.8.12ubuntu1/src/pmdas/solaris/arcstats.c0000664000000000000000000000306512272262501016145 0ustar /* * Copyright (C) 2010 Max Matveev. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Extract information about ZFS' Adjustable Replacement Cache * * The stats are in the sections called "arc_stats" of module zfs */ #include #include "common.h" static kstat_t *arcstats; int arcstats_fresh; void arcstats_refresh(void) { kstat_ctl_t *kc; arcstats_fresh = 0; if ((kc = kstat_ctl_update()) == NULL) return; if ((arcstats = kstat_lookup(kc, "zfs", -1, "arcstats")) != NULL) arcstats_fresh = kstat_read(kc, arcstats, NULL) != -1; } int arcstats_fetch(pmdaMetric *pm, int inst, pmAtomValue *av) { metricdesc_t *md = pm->m_user; char *metric = (char *)md->md_offset; kstat_named_t *kn; if (!arcstats_fresh) return 0; if ((kn = kstat_data_lookup(arcstats, metric)) != NULL) return kstat_named_to_pmAtom(kn, av); return 0; } pcp-3.8.12ubuntu1/src/pmdas/solaris/pmns.network0000664000000000000000000001677412272262501016560 0ustar /* * TODO * * These are the IRIX names, for reference * network.icmp.error * network.icmp.oldshort * network.icmp.oldicmp * network.icmp.badcode * network.icmp.tooshort * network.icmp.checksum * network.icmp.badlen * network.icmp.reflect * network.icmp.inhist.echoreply * network.icmp.inhist.unreach * network.icmp.inhist.sourcequench * network.icmp.inhist.redirect * network.icmp.inhist.echo * network.icmp.inhist.routeradvert * network.icmp.inhist.routersolicit * network.icmp.inhist.timxceed * network.icmp.inhist.paramprob * network.icmp.inhist.tstamp * network.icmp.inhist.tstampreply * network.icmp.inhist.ireq * network.icmp.inhist.ireqreply * network.icmp.inhist.maskreq * network.icmp.inhist.maskreply * network.icmp.outhist.echoreply * network.icmp.outhist.unreach * network.icmp.outhist.sourcequench * network.icmp.outhist.redirect * network.icmp.outhist.echo * network.icmp.outhist.routeradvert * network.icmp.outhist.routersolicit * network.icmp.outhist.timxceed * network.icmp.outhist.paramprob * network.icmp.outhist.tstamp * network.icmp.outhist.tstampreply * network.icmp.outhist.ireq * network.icmp.outhist.ireqreply * network.icmp.outhist.maskreq * network.icmp.outhist.maskreply * network.igmp.rcv_total * network.igmp.rcv_tooshort * network.igmp.rcv_badsum * network.igmp.rcv_queries * network.igmp.rcv_badqueries * network.igmp.rcv_reports * network.igmp.rcv_badreports * network.igmp.rcv_ourreports * network.igmp.snd_reports * network.ip.badhlen * network.ip.badlen * network.ip.badoptions * network.ip.badsum * network.ip.cantforward * network.ip.cantfrag * network.ip.delivered * network.ip.forward * network.ip.fragdropped * network.ip.fragmented * network.ip.fragments * network.ip.fragtimeout * network.ip.localout * network.ip.noproto * network.ip.noroute * network.ip.odropped * network.ip.ofragments * network.ip.reassembled * network.ip.redirect * network.ip.tooshort * network.ip.toosmall * network.ip.badvers * network.ip.rawout * network.ip.strictreassoverlapfrags * network.ip.strictreassgapfrags * network.ip.total * network.tcp.connattempt * network.tcp.accepts * network.tcp.connects * network.tcp.drops * network.tcp.conndrops * network.tcp.closed * network.tcp.segstimed * network.tcp.rttupdated * network.tcp.delack * network.tcp.timeoutdrop * network.tcp.rexmttimeo * network.tcp.persisttimeo * network.tcp.keeptimeo * network.tcp.keepprobe * network.tcp.keepdrops * network.tcp.sndtotal * network.tcp.sndpack * network.tcp.sndbyte * network.tcp.sndrexmitpack * network.tcp.sndrexmitbyte * network.tcp.sndacks * network.tcp.sndprobe * network.tcp.sndurg * network.tcp.sndwinup * network.tcp.sndctrl * network.tcp.sndrst * network.tcp.rcvtotal * network.tcp.rcvpack * network.tcp.rcvbyte * network.tcp.rcvbadsum * network.tcp.rcvbadoff * network.tcp.rcvshort * network.tcp.rcvduppack * network.tcp.rcvdupbyte * network.tcp.rcvpartduppack * network.tcp.rcvpartdupbyte * network.tcp.rcvoopack * network.tcp.rcvoobyte * network.tcp.rcvpackafterwin * network.tcp.rcvbyteafterwin * network.tcp.rcvafterclose * network.tcp.rcvwinprobe * network.tcp.rcvdupack * network.tcp.rcvacktoomuch * network.tcp.rcvackpack * network.tcp.rcvackbyte * network.tcp.rcvwinupd * network.tcp.pcbcachemiss * network.tcp.predack * network.tcp.preddat * network.tcp.pawsdrop * network.tcp.badsyn * network.tcp.listendrop * network.tcp.persistdrop * network.tcp.synpurge * network.udp.ipackets * network.udp.hdrops * network.udp.badsum * network.udp.badlen * network.udp.noport * network.udp.noportbcast * network.udp.fullsock * network.udp.opackets * network.udp.pcbcachemiss * network.interface.collisions * network.interface.mtu * network.interface.noproto * network.interface.baudrate * network.interface.in.errors * network.interface.in.packets * network.interface.in.bytes * network.interface.in.mcasts * network.interface.in.drops * network.interface.out.errors * network.interface.out.packets * network.interface.out.bytes * network.interface.out.mcasts * network.interface.out.drops * network.interface.out.qdrops * network.interface.out.qlength * network.interface.out.qmax * network.interface.total.errors * network.interface.total.packets * network.interface.total.bytes * network.interface.total.mcasts * network.interface.total.drops * network.mbuf.alloc * network.mbuf.typealloc * network.mbuf.clustalloc * network.mbuf.clustfree * network.mbuf.failed * network.mbuf.waited * network.mbuf.drained * network.mbuf.pcb.total * network.mbuf.pcb.bytes * network.mbuf.mcb.total * network.mbuf.mcb.bytes * network.mbuf.mcb.fail * network.mcr.mfc_lookups * network.mcr.mfc_misses * network.mcr.upcalls * network.mcr.no_route * network.mcr.bad_tunnel * network.mcr.cant_tunnel * network.mcr.wrong_if * network.mcr.upq_ovflw * network.mcr.cache_cleanups * network.mcr.drop_sel * network.mcr.q_overflow * network.mcr.pkt2large * network.mcr.upq_sockfull * network.socket.type * network.socket.state * network.st.connattempt * network.st.accepts * network.st.connects * network.st.drops * network.st.connfails * network.st.closed * network.st.txtotal * network.st.datatxtotal * network.st.rxtotal * network.st.datarxtotal * network.st.cksumbad * network.st.oototal * network.st.keyrejects * network.st.txrejects * network.st.rxrejects * network.st.slotdrops * network.is.in_window * network.is.in_underflow * network.is.in_overlap * network.is.up_disordered * network.is.up_ordered * network.is.outq_full * network.is.outq_wakeups * network.is.outq_drains * network.is.reorder_wakeups * network.is.reorder_drains * network.is.drain_underflow * network.is.drain_loop * network.is.drain_empty * network.is.window_stalls * network.is.window_flush_null * network.is.window_seqno_fixup * network.is.window_flush_skipped * network.is.window_flush_nlinks * network.is.link_quota_oflows * network.is.link_empty_headers * network.is.link_header_allocs * network.is.link_soft_cksums * network.is.link_sync_seqno * network.is.err_bad_version * network.is.err_input_no_link */ network { interface link udp } network.interface { in out mtu SOLARIS:SCLR_NETIF:0 } network.interface.in { errors SOLARIS:SCLR_NETIF:1 packets SOLARIS:SCLR_NETIF:2 bytes SOLARIS:SCLR_NETIF:3 bcasts SOLARIS:SCLR_NETIF:4 mcasts SOLARIS:SCLR_NETIF:5 drops SOLARIS:SCLR_NETIF:6 delivers SOLARIS:SCLR_NETIF:7 } network.interface.out { errors SOLARIS:SCLR_NETIF:8 packets SOLARIS:SCLR_NETIF:9 bytes SOLARIS:SCLR_NETIF:10 bcasts SOLARIS:SCLR_NETIF:11 mcasts SOLARIS:SCLR_NETIF:12 drops SOLARIS:SCLR_NETIF:13 } network.udp { ipackets SOLARIS:SCLR_NETIF:14 opackets SOLARIS:SCLR_NETIF:15 ierrors SOLARIS:SCLR_NETIF:16 oerrors SOLARIS:SCLR_NETIF:17 noports SOLARIS:SCLR_NETIF:18 overflows SOLARIS:SCLR_NETIF:19 } network.link { in out collisions SOLARIS:SCLR_NETLINK:0 state SOLARIS:SCLR_NETLINK:1 duplex SOLARIS:SCLR_NETLINK:2 speed SOLARIS:SCLR_NETLINK:3 } network.link.in { errors SOLARIS:SCLR_NETLINK:4 packets SOLARIS:SCLR_NETLINK:5 bytes SOLARIS:SCLR_NETLINK:6 bcasts SOLARIS:SCLR_NETLINK:7 mcasts SOLARIS:SCLR_NETLINK:8 nobufs SOLARIS:SCLR_NETLINK:9 } network.link.out { errors SOLARIS:SCLR_NETLINK:10 packets SOLARIS:SCLR_NETLINK:11 bytes SOLARIS:SCLR_NETLINK:12 bcasts SOLARIS:SCLR_NETLINK:13 mcasts SOLARIS:SCLR_NETLINK:14 nobufs SOLARIS:SCLR_NETLINK:15 } pcp-3.8.12ubuntu1/src/pmdas/solaris/zpool.c0000664000000000000000000000763412272262501015472 0ustar /* * Copyright (C) 2009 Max Matveev. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "common.h" struct zpool_stats { int vdev_stats_fresh; vdev_stat_t vds; }; static libzfs_handle_t *zh; static int zp_added; /* * For each zpool check the name in the instance cache, if it's not there then * add it to the cache. Regardless if it's the first time we've seen this one * or if it was in the cache before refresh the stats */ static int zp_cache_pool(zpool_handle_t *zp, void *arg) { nvlist_t *cfg = zpool_get_config(zp, NULL); char *zpname = (char *)zpool_get_name(zp); struct zpool_stats *zps = NULL; pmInDom zpindom = indomtab[ZPOOL_INDOM].it_indom; uint_t cnt = 0; vdev_stat_t *vds; int rv; int inst; nvlist_t *vdt; if ((rv = pmdaCacheLookupName(zpindom, zpname, &inst, (void **)&zps)) != PMDA_CACHE_ACTIVE) { int newpool = (zps == NULL); if (rv != PMDA_CACHE_INACTIVE || zps == NULL) { zps = malloc(sizeof(*zps)); if (zps == NULL) { __pmNotifyErr(LOG_WARNING, "Cannot allocate memory to hold stats for " "zpool '%s'\n", zpname); goto done; } } rv = pmdaCacheStore(zpindom, PMDA_CACHE_ADD, zpname, zps); if (rv < 0) { __pmNotifyErr(LOG_WARNING, "Cannot add '%s' to the cache " "for instance domain %s: %s\n", zpname, pmInDomStr(zpindom), pmErrStr(rv)); free(zps); goto done; } zp_added += newpool; } rv = nvlist_lookup_nvlist(cfg, ZPOOL_CONFIG_VDEV_TREE, &vdt); if (rv != 0) { __pmNotifyErr(LOG_ERR, "Cannot get vdev tree for '%s': %d %d\n", zpname, rv, oserror()); zps->vdev_stats_fresh = 0; } else { /* accommodate zpool api changes ... */ #ifdef ZPOOL_CONFIG_VDEV_STATS rv = nvlist_lookup_uint64_array(vdt, ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vds, &cnt); #else rv = nvlist_lookup_uint64_array(vdt, ZPOOL_CONFIG_STATS, (uint64_t **)&vds, &cnt); #endif if (rv == 0) { memcpy(&zps->vds, vds, sizeof(zps->vds)); zps->vdev_stats_fresh = 1; } else { __pmNotifyErr(LOG_ERR, "Cannot get zpool stats for '%s': %d %d\n", zpname, rv, oserror()); zps->vdev_stats_fresh = 0; } } done: zpool_close(zp); return 0; } void zpool_refresh(void) { zp_added = 0; pmdaCacheOp(indomtab[ZPOOL_INDOM].it_indom, PMDA_CACHE_INACTIVE); zpool_iter(zh, zp_cache_pool, NULL); if (zp_added) { pmdaCacheOp(indomtab[ZPOOL_INDOM].it_indom, PMDA_CACHE_SAVE); } } int zpool_fetch(pmdaMetric *pm, int inst, pmAtomValue *atom) { struct zpool_stats *zps; char *zpname; metricdesc_t *md = pm->m_user; if (pmdaCacheLookup(indomtab[ZPOOL_INDOM].it_indom, inst, &zpname, (void **)&zps) != PMDA_CACHE_ACTIVE) return PM_ERR_INST; if (zps->vdev_stats_fresh) { switch (pmid_item(md->md_desc.pmid)) { case 0: /* zpool.state */ atom->cp = zpool_state_to_name(zps->vds.vs_state, zps->vds.vs_aux); break; case 1: /* zpool.state_int */ atom->ul = (zps->vds.vs_aux << 8) | zps->vds.vs_state; break; default: memcpy(&atom->ull, ((char *)&zps->vds) + md->md_offset, sizeof(atom->ull)); } } return zps->vdev_stats_fresh; } void zpool_init(int first) { if (zh) return; zh = libzfs_init(); if (zh) { pmdaCacheOp(indomtab[ZPOOL_INDOM].it_indom, PMDA_CACHE_LOAD); zpool_iter(zh, zp_cache_pool, NULL); pmdaCacheOp(indomtab[ZPOOL_INDOM].it_indom, PMDA_CACHE_SAVE); } } pcp-3.8.12ubuntu1/src/pmdas/solaris/pmns.hinv0000664000000000000000000000164712272262501016024 0ustar hinv { ncpu SOLARIS:SCLR_SYSINFO:56 ndisk SOLARIS:SCLR_DISK:20 nfilesys SOLARIS:SCLR_FILESYS:1023 pagesize SOLARIS:SCLR_SYSINFO:108 physmem SOLARIS:SCLR_SYSINFO:109 cpu disk } hinv.cpu { maxclock SOLARIS:SCLR_SYSINFO:147 clock SOLARIS:SCLR_SYSINFO:148 brand SOLARIS:SCLR_SYSINFO:149 frequencies SOLARIS:SCLR_SYSINFO:150 implementation SOLARIS:SCLR_SYSINFO:151 chip_id SOLARIS:SCLR_SYSINFO:152 clog_id SOLARIS:SCLR_SYSINFO:153 core_id SOLARIS:SCLR_SYSINFO:154 pkg_core_id SOLARIS:SCLR_SYSINFO:155 cstate SOLARIS:SCLR_SYSINFO:156 maxcstates SOLARIS:SCLR_SYSINFO:157 ncores SOLARIS:SCLR_SYSINFO:158 ncpus SOLARIS:SCLR_SYSINFO:159 } hinv.disk { vendor SOLARIS:SCLR_DISK:30 product SOLARIS:SCLR_DISK:31 revision SOLARIS:SCLR_DISK:32 serial SOLARIS:SCLR_DISK:33 capacity SOLARIS:SCLR_DISK:34 devlink SOLARIS:SCLR_DISK:35 } pcp-3.8.12ubuntu1/src/pmdas/solaris/pmns.kernel0000664000000000000000000001227712272262501016341 0ustar kernel { all percpu fsflush fs fstype } kernel.all { cpu io trap SOLARIS:SCLR_SYSINFO:32 pswitch SOLARIS:SCLR_SYSINFO:23 syscall SOLARIS:SCLR_SYSINFO:22 sysexec SOLARIS:SCLR_SYSINFO:33 sysfork SOLARIS:SCLR_SYSINFO:34 sysvfork SOLARIS:SCLR_SYSINFO:35 sysread SOLARIS:SCLR_SYSINFO:36 syswrite SOLARIS:SCLR_SYSINFO:37 load SOLARIS:SCLR_SYSINFO:135 } kernel.all.cpu { idle SOLARIS:SCLR_SYSINFO:0 user SOLARIS:SCLR_SYSINFO:1 sys SOLARIS:SCLR_SYSINFO:2 wait } kernel.all.cpu.wait { total SOLARIS:SCLR_SYSINFO:3 io SOLARIS:SCLR_SYSINFO:8 pio SOLARIS:SCLR_SYSINFO:9 swap SOLARIS:SCLR_SYSINFO:10 } kernel.all.io { bread SOLARIS:SCLR_SYSINFO:14 bwrite SOLARIS:SCLR_SYSINFO:15 lread SOLARIS:SCLR_SYSINFO:16 lwrite SOLARIS:SCLR_SYSINFO:17 phread SOLARIS:SCLR_SYSINFO:26 phwrite SOLARIS:SCLR_SYSINFO:27 intr SOLARIS:SCLR_SYSINFO:28 } kernel.percpu { cpu io trap SOLARIS:SCLR_SYSINFO:38 pswitch SOLARIS:SCLR_SYSINFO:25 syscall SOLARIS:SCLR_SYSINFO:24 sysexec SOLARIS:SCLR_SYSINFO:39 sysfork SOLARIS:SCLR_SYSINFO:40 sysvfork SOLARIS:SCLR_SYSINFO:41 sysread SOLARIS:SCLR_SYSINFO:42 syswrite SOLARIS:SCLR_SYSINFO:43 } kernel.percpu.cpu { idle SOLARIS:SCLR_SYSINFO:4 user SOLARIS:SCLR_SYSINFO:5 sys SOLARIS:SCLR_SYSINFO:6 wait } kernel.percpu.cpu.wait { total SOLARIS:SCLR_SYSINFO:7 io SOLARIS:SCLR_SYSINFO:11 pio SOLARIS:SCLR_SYSINFO:12 swap SOLARIS:SCLR_SYSINFO:13 } kernel.percpu.io { bread SOLARIS:SCLR_SYSINFO:18 bwrite SOLARIS:SCLR_SYSINFO:19 lread SOLARIS:SCLR_SYSINFO:20 lwrite SOLARIS:SCLR_SYSINFO:21 phread SOLARIS:SCLR_SYSINFO:29 phwrite SOLARIS:SCLR_SYSINFO:30 intr SOLARIS:SCLR_SYSINFO:31 } kernel.fsflush { scanned SOLARIS:SCLR_FSFLUSH:0 examined SOLARIS:SCLR_FSFLUSH:1 locked SOLARIS:SCLR_FSFLUSH:2 modified SOLARIS:SCLR_FSFLUSH:3 coalesced SOLARIS:SCLR_FSFLUSH:4 released SOLARIS:SCLR_FSFLUSH:5 time SOLARIS:SCLR_FSFLUSH:6 } kernel.fs { vnops read_bytes SOLARIS:SCLR_FILESYS:0 readdir_bytes SOLARIS:SCLR_FILESYS:1 write_bytes SOLARIS:SCLR_FILESYS:2 } kernel.fs.vnops { access SOLARIS:SCLR_FILESYS:3 addmap SOLARIS:SCLR_FILESYS:4 close SOLARIS:SCLR_FILESYS:5 cmp SOLARIS:SCLR_FILESYS:6 create SOLARIS:SCLR_FILESYS:7 delmap SOLARIS:SCLR_FILESYS:8 dispose SOLARIS:SCLR_FILESYS:9 dump SOLARIS:SCLR_FILESYS:10 dumpctl SOLARIS:SCLR_FILESYS:11 fid SOLARIS:SCLR_FILESYS:12 frlock SOLARIS:SCLR_FILESYS:13 fsync SOLARIS:SCLR_FILESYS:14 getattr SOLARIS:SCLR_FILESYS:15 getpage SOLARIS:SCLR_FILESYS:16 getsecattr SOLARIS:SCLR_FILESYS:17 inactive SOLARIS:SCLR_FILESYS:18 ioctl SOLARIS:SCLR_FILESYS:19 link SOLARIS:SCLR_FILESYS:20 lookup SOLARIS:SCLR_FILESYS:21 map SOLARIS:SCLR_FILESYS:22 mkdir SOLARIS:SCLR_FILESYS:23 open SOLARIS:SCLR_FILESYS:24 pageio SOLARIS:SCLR_FILESYS:25 pathconf SOLARIS:SCLR_FILESYS:26 poll SOLARIS:SCLR_FILESYS:27 putpage SOLARIS:SCLR_FILESYS:28 read SOLARIS:SCLR_FILESYS:29 readdir SOLARIS:SCLR_FILESYS:30 readlink SOLARIS:SCLR_FILESYS:31 realvp SOLARIS:SCLR_FILESYS:32 remove SOLARIS:SCLR_FILESYS:33 rename SOLARIS:SCLR_FILESYS:34 rmdir SOLARIS:SCLR_FILESYS:35 rwlock SOLARIS:SCLR_FILESYS:36 rwunlock SOLARIS:SCLR_FILESYS:37 seek SOLARIS:SCLR_FILESYS:38 setattr SOLARIS:SCLR_FILESYS:39 setfl SOLARIS:SCLR_FILESYS:40 setsecattr SOLARIS:SCLR_FILESYS:41 shrlock SOLARIS:SCLR_FILESYS:42 space SOLARIS:SCLR_FILESYS:43 symlink SOLARIS:SCLR_FILESYS:44 vnevent SOLARIS:SCLR_FILESYS:45 write SOLARIS:SCLR_FILESYS:46 } kernel.fstype { vnops read_bytes SOLARIS:SCLR_FILESYS:47 readdir_bytes SOLARIS:SCLR_FILESYS:48 write_bytes SOLARIS:SCLR_FILESYS:49 } kernel.fstype.vnops { access SOLARIS:SCLR_FILESYS:50 addmap SOLARIS:SCLR_FILESYS:51 close SOLARIS:SCLR_FILESYS:52 cmp SOLARIS:SCLR_FILESYS:53 create SOLARIS:SCLR_FILESYS:54 delmap SOLARIS:SCLR_FILESYS:55 dispose SOLARIS:SCLR_FILESYS:56 dump SOLARIS:SCLR_FILESYS:57 dumpctl SOLARIS:SCLR_FILESYS:58 fid SOLARIS:SCLR_FILESYS:59 frlock SOLARIS:SCLR_FILESYS:60 fsync SOLARIS:SCLR_FILESYS:61 getattr SOLARIS:SCLR_FILESYS:62 getpage SOLARIS:SCLR_FILESYS:63 getsecattr SOLARIS:SCLR_FILESYS:64 inactive SOLARIS:SCLR_FILESYS:65 ioctl SOLARIS:SCLR_FILESYS:66 link SOLARIS:SCLR_FILESYS:67 lookup SOLARIS:SCLR_FILESYS:68 map SOLARIS:SCLR_FILESYS:69 mkdir SOLARIS:SCLR_FILESYS:70 open SOLARIS:SCLR_FILESYS:71 pageio SOLARIS:SCLR_FILESYS:72 pathconf SOLARIS:SCLR_FILESYS:73 poll SOLARIS:SCLR_FILESYS:74 putpage SOLARIS:SCLR_FILESYS:75 read SOLARIS:SCLR_FILESYS:76 readdir SOLARIS:SCLR_FILESYS:77 readlink SOLARIS:SCLR_FILESYS:78 realvp SOLARIS:SCLR_FILESYS:79 remove SOLARIS:SCLR_FILESYS:80 rename SOLARIS:SCLR_FILESYS:81 rmdir SOLARIS:SCLR_FILESYS:82 rwlock SOLARIS:SCLR_FILESYS:83 rwunlock SOLARIS:SCLR_FILESYS:84 seek SOLARIS:SCLR_FILESYS:85 setattr SOLARIS:SCLR_FILESYS:86 setfl SOLARIS:SCLR_FILESYS:87 setsecattr SOLARIS:SCLR_FILESYS:88 shrlock SOLARIS:SCLR_FILESYS:89 space SOLARIS:SCLR_FILESYS:90 symlink SOLARIS:SCLR_FILESYS:91 vnevent SOLARIS:SCLR_FILESYS:92 write SOLARIS:SCLR_FILESYS:93 } pcp-3.8.12ubuntu1/src/pmdas/solaris/kvm.c0000664000000000000000000000272212272262501015115 0ustar /* * Copyright (C) 2009 Max Matveev. All Rights Reserved * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "common.h" static kvm_t *kvm; struct nlist kvm_names[] = { {.n_name = "fsf_total"}, {.n_name = NULL} }; fsf_stat_t s = {0}; static int fresh; void kvm_init(int ignore) { kvm = kvm_open(NULL, NULL, NULL, O_RDONLY, "pmdasolaris"); if (kvm && kvm_nlist(kvm, kvm_names)) fprintf(stderr, "Cannot extract addresses\n"); } void kvm_refresh(void) { fresh = kvm && (kvm_kread(kvm, kvm_names[0].n_value, &s, sizeof(s)) == sizeof(s)); } int kvm_fetch(pmdaMetric *pm, int inst, pmAtomValue *v) { metricdesc_t *md = pm->m_user; char *p = (char *)&s; if (!fresh) return 0; memcpy(&v->ull, p + md->md_offset, sizeof(v->ull)); return 1; } pcp-3.8.12ubuntu1/src/pmdas/solaris/pmns.disk0000664000000000000000000000212112272262501015776 0ustar disk { all dev } disk.all { read SOLARIS:SCLR_DISK:0 write SOLARIS:SCLR_DISK:1 total SOLARIS:SCLR_DISK:2 read_bytes SOLARIS:SCLR_DISK:3 write_bytes SOLARIS:SCLR_DISK:4 total_bytes SOLARIS:SCLR_DISK:5 wait run } disk.all.wait { time SOLARIS:SCLR_DISK:6 count SOLARIS:SCLR_DISK:7 } disk.all.run { time SOLARIS:SCLR_DISK:8 count SOLARIS:SCLR_DISK:9 } disk.dev { read SOLARIS:SCLR_DISK:10 write SOLARIS:SCLR_DISK:11 total SOLARIS:SCLR_DISK:12 read_bytes SOLARIS:SCLR_DISK:13 write_bytes SOLARIS:SCLR_DISK:14 total_bytes SOLARIS:SCLR_DISK:15 wait run errors } disk.dev.wait { time SOLARIS:SCLR_DISK:16 count SOLARIS:SCLR_DISK:17 } disk.dev.run { time SOLARIS:SCLR_DISK:18 count SOLARIS:SCLR_DISK:19 } disk.dev.errors { soft SOLARIS:SCLR_DISK:21 hard SOLARIS:SCLR_DISK:22 transport SOLARIS:SCLR_DISK:23 media SOLARIS:SCLR_DISK:24 recoverable SOLARIS:SCLR_DISK:25 notready SOLARIS:SCLR_DISK:26 nodevice SOLARIS:SCLR_DISK:27 badrequest SOLARIS:SCLR_DISK:28 pfa SOLARIS:SCLR_DISK:29 } pcp-3.8.12ubuntu1/src/pmdas/solaris/vnops.c0000664000000000000000000001276512272262501015475 0ustar /* * Copyright (C) 2010 Max Matveev. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* kstat has counters for vnode operations for each filesystem. * * Unfortunately the counters for mounted fileystems are mixed with counters * for the filesystem types and there is no obvious way to distinguish * between the two except by trying to convert the kstat's name to the number * and see if works */ #include #include #include #include #include "common.h" struct mountpoint { struct mountpoint *next; dev_t dev; char mountpoint[]; }; static struct mountpoint *mountpoints; static struct timespec mtime; /* NB! The order of entires in mountopoints list is important: * lofs mounts use the same device number but appear later * in /etc/mnttab then the target filesystem - keeping the * order the same as /etc/mnttab means that more "logical" * mountpoints are reported, in particular the counters * for "/" are not reported as /lib/libc.so.1 */ static void cache_mnttab(void) { FILE *f; struct mnttab m; struct mountpoint *mp; struct stat sb; struct mountpoint **tail = &mountpoints; if (stat("/etc/mnttab", &sb) < 0) return; if (mountpoints && (sb.st_mtim.tv_sec == mtime.tv_sec) && (sb.st_mtim.tv_nsec == mtime.tv_nsec)) return; if ((f = fopen("/etc/mnttab", "r")) == NULL) return; for (mp = mountpoints; mp; mp = mountpoints) { mountpoints = mp->next; free(mp); } while(getmntent(f, &m) == 0) { char *devop= hasmntopt(&m, "dev"); if (devop) { char *end; dev_t d = strtoul(devop+4, &end, 16); if ((end != devop+4) && (*end != '\0')) { fprintf(stderr, "Bogus device number %s for filesystem %s\n", devop+4, m.mnt_mountp); continue; } mp = malloc(sizeof(*mp) + strlen(m.mnt_mountp) + 1); if (mp == NULL) { fprintf(stderr, "Cannot allocate memory for cache entry of %s\n", m.mnt_mountp); continue; } mp->next = NULL; mp->dev = d; strcpy(mp->mountpoint, m.mnt_mountp); *tail = mp; tail = &mp->next; } } fclose(f); mtime = sb.st_mtim; } static const char * mountpoint_bydev(dev_t dev) { int i; for (i=0; i < 2; i++) { struct mountpoint *mp = mountpoints; while(mp) { if (mp->dev == dev) return mp->mountpoint; mp = mp->next; } cache_mnttab(); } return NULL; } int vnops_fetch(pmdaMetric *pm, int inst, pmAtomValue *av) { char *fsname; metricdesc_t *md = pm->m_user; kstat_t *k; char *stat = (char *)md->md_offset; if (pmid_item(pm->m_desc.pmid) == 1023) { /* hinv.nfilesys */ int sts; sts = pmdaCacheOp(indomtab[FILESYS_INDOM].it_indom, PMDA_CACHE_SIZE_ACTIVE); if (sts < 0) return 0; else { av->ul = sts; return 1; } } if (pmdaCacheLookup(pm->m_desc.indom, inst, &fsname, (void **)&k) != PMDA_CACHE_ACTIVE) return PM_ERR_INST; if (k) { kstat_named_t *kn = kstat_data_lookup(k, stat); if (kn == NULL) { fprintf(stderr, "No kstat called %s for %s\n", stat, fsname); return 0; } return kstat_named_to_typed_atom(kn, pm->m_desc.type, av); } return 0; } static void vnops_update_stats(int fetch) { kstat_t *k; kstat_ctl_t *kc = kstat_ctl_update(); if (kc == NULL) return; for (k = kc->kc_chain; k != NULL; k = k->ks_next) { int rv; kstat_t *cached; const char *key; dev_t dev; char *end; pmInDom indom; if (strcmp(k->ks_module, "unix") || strncmp(k->ks_name, "vopstats_", sizeof("vopstats_")-1)) continue; key = k->ks_name + 9; dev = strtoul(key, &end, 16); if ((end != key) && (*end == '\0')) { indom = indomtab[FILESYS_INDOM].it_indom; if ((key = mountpoint_bydev(dev)) == NULL) continue; } else { indom = indomtab[FSTYPE_INDOM].it_indom; } if (pmdaCacheLookupName(indom, key, &rv, (void **)&cached) != PMDA_CACHE_ACTIVE) { rv = pmdaCacheStore(indom, PMDA_CACHE_ADD, key, k); if (rv < 0) { __pmNotifyErr(LOG_WARNING, "Cannot create instance for " "filesystem '%s': %s\n", key, pmErrStr(rv)); continue; } } if (fetch) kstat_read(kc, k, NULL); } } void vnops_refresh(void) { pmdaCacheOp(indomtab[FILESYS_INDOM].it_indom, PMDA_CACHE_INACTIVE); pmdaCacheOp(indomtab[FSTYPE_INDOM].it_indom, PMDA_CACHE_INACTIVE); vnops_update_stats(1); pmdaCacheOp(indomtab[FILESYS_INDOM].it_indom, PMDA_CACHE_SAVE); pmdaCacheOp(indomtab[FSTYPE_INDOM].it_indom, PMDA_CACHE_SAVE); } void vnops_init(int first) { pmdaCacheOp(indomtab[FILESYS_INDOM].it_indom, PMDA_CACHE_LOAD); pmdaCacheOp(indomtab[FSTYPE_INDOM].it_indom, PMDA_CACHE_LOAD); vnops_update_stats(0); pmdaCacheOp(indomtab[FILESYS_INDOM].it_indom, PMDA_CACHE_SAVE); pmdaCacheOp(indomtab[FSTYPE_INDOM].it_indom, PMDA_CACHE_SAVE); } pcp-3.8.12ubuntu1/src/pmdas/solaris/GNUmakefile0000664000000000000000000000447312272262501016233 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = solaris DOMAIN = SOLARIS PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) PMDAINIT = solaris_init CMDTARGET = pmdasolaris LIBTARGET = pmda_solaris.so CONF_LINE = "solaris 75 dso $(PMDAINIT) $(PMDADIR)/$(LIBTARGET)" CFILES = solaris.c data.c sysinfo.c disk.c zpool.c zfs.c \ zpool_perdisk.c netmib2.c netlink.c kvm.c arcstats.c vnops.c BARE_NS = disk kernel mem network hinv zpool zfs zpool_perdisk PMNS = $(BARE_NS:%=pmns.%) LSRCFILES = $(PMNS) help root common.h clusters.h netmib2.h HELPTARGETS = help.dir help.pag VERSION_SCRIPT = exports LDIRT = domain.h *.log $(HELPTARGETS) root_solaris LLDLIBS = $(PCP_PMDALIB) -lkstat -lzfs -lnvpair -lkvm -ldevinfo default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "solaris" build-me: root_solaris domain.h $(LIBTARGET) $(CMDTARGET) $(HELPTARGETS) @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi install: build-me $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 644 domain.h $(HELPTARGETS) $(PMDADIR) $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(PMDADIR) $(INSTALL) -m 644 root_solaris $(PCP_VAR_DIR)/pmns/root_solaris else build-me: install: endif default_pcp : default install_pcp : install $(OBJECTS): common.h $(HELPTARGETS): help root_solaris $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_solaris -v 2 -o help < help root_solaris: ../../pmns/stdpmid $(PMNS) root rm -f root_solaris sed -e 's;;"../../pmns/stdpmid";' root_solaris domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) $(VERSION_SCRIPT): $(VERSION_SCRIPT_MAKERULE) $(LIBTARGET): $(VERSION_SCRIPT) pcp-3.8.12ubuntu1/src/pmdas/solaris/netmib2.c0000664000000000000000000001676612272262501015675 0ustar /* * Copyright (C) 2009 Max Matveev. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* Extract network-related information from the kernel using MIB2 * interfaces. MIB2 structures are described by RFC 4113, 4293, * 4001. IPv6 specific MIB structures are described in RFC 2465, 2466. */ #include #include #include #include #include #include #include "common.h" #include "netmib2.h" static int afd = -1; static int data_valid; static int netif_added; nm2_udp_stats_t nm2_udp; static nm2_netif_stats_t * netif_cache_inst(const char *ifname) { pmInDom indom = indomtab[NETIF_INDOM].it_indom; nm2_netif_stats_t *ist; int rv; if (pmdaCacheLookupName(indom, ifname, &rv, (void **)&ist) != PMDA_CACHE_ACTIVE) { ist = malloc(sizeof(*ist)); if (ist == NULL) { __pmNotifyErr(LOG_WARNING, "Out of memory for stats on network interface '%s'\n", ifname); return NULL; } rv = pmdaCacheStore(indom, PMDA_CACHE_ADD, ifname, ist); if (rv < 0) { __pmNotifyErr(LOG_WARNING, "Cannot create instance for '%s': %s\n", ifname, pmErrStr(rv)); free(ist); return NULL; } netif_added++; } return ist; } static void ipv4_stats (const void *data, int sz) { const mib2_ipAddrEntry_t *ipa = data; while (sz > 0) { nm2_netif_stats_t *ist = netif_cache_inst(ipa->ipAdEntIfIndex.o_bytes); if (ist) { ist->mtu = ipa->ipAdEntInfo.ae_mtu; /* We get byte count and other stuff from Traffic stats */ } sz -= sizeof(*ipa); ipa++; } } static void ipv4_ifstats(const void *data, int sz) { const mib2_ipIfStatsEntry_t *ips = data; nm2_udp.noports = 0; nm2_udp.overflows = 0; while (sz > 0) { /* index 0 is a pseudo-interface */ if (ips->ipIfStatsIfIndex) { nm2_netif_stats_t *ist; char name[64]; if ((if_indextoname(ips->ipIfStatsIfIndex, name) != NULL) && ((ist = netif_cache_inst(name)) != NULL)) { ist->ibytes = ips->ipIfStatsHCInOctets; ist->obytes = ips->ipIfStatsHCOutOctets; ist->ipackets = ips->ipIfStatsHCInReceives; ist->opackets = ips->ipIfStatsHCOutTransmits; ist->imcast = ips->ipIfStatsHCInMcastPkts; ist->omcast = ips->ipIfStatsHCOutMcastPkts; ist->ibcast = ips->ipIfStatsHCInBcastPkts; ist->obcast = ips->ipIfStatsHCOutBcastPkts; ist->delivered = ips->ipIfStatsHCInDelivers; ist->idrops = ips->ipIfStatsInDiscards; ist->odrops = ips->ipIfStatsOutDiscards; ist->ierrors = + (uint64_t)ips->ipIfStatsInHdrErrors + ips->ipIfStatsInTooBigErrors + ips->ipIfStatsInNoRoutes + ips->ipIfStatsInAddrErrors + ips->ipIfStatsInUnknownProtos + ips->ipIfStatsInTruncatedPkts; ist->oerrors = ips->ipIfStatsOutFragFails; } } nm2_udp.noports += ips->udpNoPorts; nm2_udp.overflows += ips->udpInOverflows; sz -= sizeof(*ips); ips++; } } void netmib2_refresh(void) { struct strbuf ctrl; struct opthdr *oh; uint64_t buf[64]; /* Arbitrary size, just large enough to fit req + opthdr */ struct T_optmgmt_req *omreq = (struct T_optmgmt_req *)buf; struct T_optmgmt_ack *omack = (struct T_optmgmt_ack *)buf; omreq->PRIM_type = T_SVR4_OPTMGMT_REQ; omreq->OPT_offset = sizeof (*omreq); omreq->OPT_length = sizeof (*oh); omreq->MGMT_flags = T_CURRENT; oh = (struct opthdr *)(omreq + 1); oh->level = /*EXPER_IP_AND_TESTHIDDEN*/MIB2_IP; oh->name = 0; oh->len = 0; ctrl.buf = (char *)buf; ctrl.len = omreq->OPT_length + omreq->OPT_offset; data_valid = 0; if (putmsg(afd, &ctrl, NULL, 0) == -1) { __pmNotifyErr(LOG_ERR, "Failed to push message down stream: %s\n", osstrerror()); return; } oh = (struct opthdr *)(omack + 1); ctrl.maxlen = sizeof(buf); netif_added = 0; for (;;) { int flags = 0; struct strbuf data; int rv; rv = getmsg(afd, &ctrl, NULL, &flags); if (rv < 0) { __pmNotifyErr(LOG_ERR, "netmib2: failed to get a response: %s\n", osstrerror()); break; } if ((rv == 0) && (ctrl.len >= sizeof(*omack)) && (omack->PRIM_type == T_OPTMGMT_ACK) && (omack->MGMT_flags == T_SUCCESS) && (oh->len == 0)) { data_valid = 1; break; } if ((rv != MOREDATA) || (ctrl.len < sizeof(*omack)) || (omack->PRIM_type != T_OPTMGMT_ACK) || (omack->MGMT_flags != T_SUCCESS)) { __pmNotifyErr(LOG_ERR, "netmib2: Unexpected message received\n"); break; } memset(&data, 0, sizeof(data)); data.buf = malloc(oh->len); if (data.buf == NULL) { __pmNotifyErr(LOG_ERR, "netmib2: Out of memory\n"); break; } data.maxlen = oh->len; flags = 0; rv = getmsg(afd, NULL, &data, &flags); if (rv) { __pmNotifyErr(LOG_ERR, "net2mib: Failed to get additional data: %s\n", osstrerror()); break; } switch (oh->level) { case MIB2_IP: switch(oh->name) { case 0: /* Overall statistic */ break; case MIB2_IP_ADDR: ipv4_stats(data.buf, data.len); break; case MIB2_IP_TRAFFIC_STATS: ipv4_ifstats(data.buf, data.len); break; } break; case MIB2_IP6: break; case MIB2_UDP: if (oh->name == 0) { mib2_udp_t *m2u = (mib2_udp_t *)data.buf; #ifdef EXPER_IP_AND_TESTHIDDEN nm2_udp.ipackets = m2u->udpHCInDatagrams; nm2_udp.opackets = m2u->udpHCOutDatagrams; #else nm2_udp.ipackets = m2u->udpInDatagrams; nm2_udp.opackets = m2u->udpOutDatagrams; #endif nm2_udp.ierrors = m2u->udpInErrors; nm2_udp.oerrors = m2u->udpOutErrors; } break; case MIB2_TCP: break; } free(data.buf); } if (netif_added) { pmdaCacheOp(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_SAVE); } } int netmib2_fetch(pmdaMetric *pm, int inst, pmAtomValue *av) { char *fsname; metricdesc_t *md = pm->m_user; char *ist; if (pm->m_desc.indom == PM_INDOM_NULL) { switch (pm->m_desc.type) { case PM_TYPE_U32: av->ul = *(uint32_t *)md->md_offset; return 1; case PM_TYPE_U64: av->ull = *(uint64_t *)md->md_offset; return 1; } return PM_ERR_APPVERSION; } if (pmdaCacheLookup(indomtab[NETIF_INDOM].it_indom, inst, &fsname, (void **)&ist) != PMDA_CACHE_ACTIVE) return PM_ERR_INST; if (ist) { switch (pm->m_desc.type) { case PM_TYPE_U32: av->ul = *(uint32_t *)(ist + md->md_offset); return 1; case PM_TYPE_U64: av->ull = *(uint64_t *)(ist + md->md_offset); return 1; } return PM_ERR_APPVERSION; } /* Even if we've copied the values don't admit they're good unless * the update was problem-free. */ return data_valid; } void netmib2_init(int first) { char *mods[] = {"tcp", "udp", "icmp"}; int i; if (afd >= 0) return; afd = open("/dev/arp", O_RDWR); if (afd < 0) { __pmNotifyErr(LOG_ERR, "Cannot open /dev/arp: %s\n", osstrerror()); return; } for (i = 0; i < 3; i++ ) { if (ioctl(afd, I_PUSH, mods[i]) < 0) { __pmNotifyErr(LOG_ERR, "Cannot push %s into /dev/arp: %s\n", mods[i], osstrerror()); close(afd); afd = -1; return; } } pmdaCacheOp(indomtab[NETIF_INDOM].it_indom, PMDA_CACHE_LOAD); netmib2_refresh(); } pcp-3.8.12ubuntu1/src/pmdas/solaris/root0000664000000000000000000000100512272262501015053 0ustar /* * fake "root" for validating the local PMNS subtree */ #include #include "clusters.h" root { kernel disk mem network hinv zpool zfs pmda } pmda { uname SOLARIS:0:107 prefetch metric } pmda.prefetch { time SOLARIS:4095:0 count SOLARIS:4095:1 } pmda.metric { time SOLARIS:4095:2 count SOLARIS:4095:3 } #include "pmns.kernel" #include "pmns.disk" #include "pmns.mem" #include "pmns.network" #include "pmns.hinv" #include "pmns.zpool" #include "pmns.zfs" #include "pmns.zpool_perdisk" pcp-3.8.12ubuntu1/src/pmdas/solaris/common.h0000664000000000000000000000755112272262501015622 0ustar /* * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __PMDASOLARIS_COMMON_H #define __PMDASOLARIS_COMMON_H #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include "clusters.h" #include #include typedef struct { const char *m_name; void (*m_init)(int); void (*m_prefetch)(void); int (*m_fetch)(pmdaMetric *, int, pmAtomValue *); int m_fetched; uint64_t m_elapsed; uint64_t m_hits; } method_t; extern method_t methodtab[]; extern const int methodtab_sz; extern void init_data(int); extern void sysinfo_init(int); extern void sysinfo_prefetch(void); extern int sysinfo_fetch(pmdaMetric *, int, pmAtomValue *); extern void disk_init(int); extern void disk_prefetch(void); extern int disk_fetch(pmdaMetric *, int, pmAtomValue *); void zpool_init(int); void zpool_refresh(void); int zpool_fetch(pmdaMetric *, int, pmAtomValue *); void zfs_init(int); void zfs_refresh(void); int zfs_fetch(pmdaMetric *, int, pmAtomValue *); void zpool_perdisk_init(int); void zpool_perdisk_refresh(void); int zpool_perdisk_fetch(pmdaMetric *, int, pmAtomValue *); void netlink_init(int); void netlink_refresh(void); int netlink_fetch(pmdaMetric *, int, pmAtomValue *); void kvm_init(int); void kvm_refresh(void); int kvm_fetch(pmdaMetric *, int, pmAtomValue *); void arcstats_refresh(void); int arcstats_fetch(pmdaMetric *, int, pmAtomValue *); void vnops_init(int); void vnops_refresh(void); int vnops_fetch(pmdaMetric *, int, pmAtomValue *); /* * metric descriptions */ typedef struct { const char *md_name; pmDesc md_desc; // PMDA's idea of the semantics ptrdiff_t md_offset; // offset into kstat stats structure uint64_t md_elapsed; uint64_t md_hits; } metricdesc_t; extern metricdesc_t metricdesc[]; extern pmdaMetric *metrictab; extern int metrictab_sz; #define DISK_INDOM 0 #define CPU_INDOM 1 #define NETIF_INDOM 2 #define ZPOOL_INDOM 3 #define ZFS_INDOM 4 #define ZPOOL_PERDISK_INDOM 5 #define NETLINK_INDOM 6 #define ZFS_SNAP_INDOM 7 #define LOADAVG_INDOM 8 #define PREFETCH_INDOM 9 #define METRIC_INDOM 10 #define FILESYS_INDOM 11 #define FSTYPE_INDOM 12 extern pmdaIndom indomtab[]; extern int indomtab_sz; /* * kstat() control */ kstat_ctl_t *kstat_ctl_update(void); void kstat_ctl_needs_update(void); int kstat_named_to_pmAtom(const kstat_named_t *, pmAtomValue *); int kstat_named_to_typed_atom(const kstat_named_t *, int, pmAtomValue *); /* Snarfed from usr/src/uts/common/fs/fsflush.c in OpenSolaris source tree */ typedef struct { ulong_t fsf_scan; /* number of pages scanned */ ulong_t fsf_examined; /* number of page_t's actually examined, can */ /* be less than fsf_scan due to large pages */ ulong_t fsf_locked; /* pages we actually page_lock()ed */ ulong_t fsf_modified; /* number of modified pages found */ ulong_t fsf_coalesce; /* number of page coalesces done */ ulong_t fsf_time; /* nanoseconds of run time */ ulong_t fsf_releases; /* number of page_release() done */ } fsf_stat_t; #endif pcp-3.8.12ubuntu1/src/pmdas/solaris/solaris.c0000664000000000000000000001231412272262501015772 0ustar /* * Solaris PMDA * * Collect performance data from the Solaris kernel using kstat() for * the most part. * * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2010 Max Matveev. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include "common.h" static int _isDSO = 1; static char mypath[MAXPATHLEN]; /* * wrapper for pmdaFetch which primes the methods ready for * the next fetch * ... real callback is fetch_callback() */ static int solaris_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i; kstat_ctl_needs_update(); for (i = 0; i < methodtab_sz; i++) { methodtab[i].m_fetched = 0; } return pmdaFetch(numpmid, pmidlist, resp, pmda); } /* * callback provided to pmdaFetch */ static int solaris_fetch_callback(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { metricdesc_t *mdp = (metricdesc_t *)mdesc->m_user; int cluster = pmid_cluster(mdesc->m_desc.pmid); method_t *m = methodtab + cluster; hrtime_t start; int rv; __pmID_int *id = __pmid_int(&mdesc->m_desc.pmid); if (cluster == 4095) { switch (id->item) { case 0: /* pmda.prefetch.time */ if ((inst <= 0) || (inst > methodtab_sz+1)) return PM_ERR_INST; atom->ull = methodtab[inst-1].m_elapsed; return 1; case 1: /* pmda.prefetch.count */ if ((inst <= 0) || (inst > methodtab_sz+1)) return PM_ERR_INST; atom->ull = methodtab[inst-1].m_hits; return 1; case 2: /* pmda.metric.time */ if ((inst <= 0) || (inst > metrictab_sz+1)) return PM_ERR_INST; atom->ull = metricdesc[inst-1].md_elapsed; return 1; case 3: /* pmda.metric.count */ if ((inst <= 0) || (inst > metrictab_sz+1)) return PM_ERR_INST; atom->ull = metricdesc[inst-1].md_hits; return 1; default: return PM_ERR_PMID; } } else if (cluster >= methodtab_sz) { return PM_ERR_PMID; } if (!m->m_fetched && m->m_prefetch) { start = gethrtime(); m->m_prefetch(); m->m_elapsed = gethrtime() - start; m->m_hits++; m->m_fetched = 1; } start = gethrtime(); rv = m->m_fetch(mdesc, inst, atom); mdp->md_elapsed = gethrtime() - start; mdp->md_hits++; return rv; } /* * Initialise the agent (both daemon and DSO). */ void __PMDA_INIT_CALL solaris_init(pmdaInterface *dp) { if (_isDSO) { int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "solaris" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_3, "Solaris DSO", mypath); } if (dp->status != 0) return; dp->version.two.fetch = solaris_fetch; pmdaSetFetchCallBack(dp, solaris_fetch_callback); init_data(dp->domain); pmdaInit(dp, indomtab, indomtab_sz, metrictab, metrictab_sz); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -N namespace verify consistency of internal metrics with the namespace\n", stderr); exit(1); } static void checkname(const char *mname) { int i; for (i = 0; i < metrictab_sz; i++) { if (strcmp(mname, metricdesc[i].md_name) == 0) return; } printf ("Cannot find %s in the code\n", mname); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int err = 0; int sep = __pmPathSeparator(); pmdaInterface desc; int c; char *namespace = NULL; _isDSO = 0; __pmSetProgname(argv[0]); snprintf(mypath, sizeof(mypath), "%s%c" "solaris" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&desc, PMDA_INTERFACE_3, pmProgname, SOLARIS, "solaris.log", mypath); while ((c = pmdaGetOpt(argc, argv, "N:D:d:l:?", &desc, &err)) != EOF) { switch (c) { case 'N': namespace = optarg; break; default: err++; break; } } if (err) usage(); if (namespace) { if (pmLoadNameSpace(namespace)) exit(1); for (c = 0; c < metrictab_sz; c++) { char *name; int e; __pmID_int *id = __pmid_int(&metricdesc[c].md_desc.pmid); id->domain = desc.domain; if ((e = pmNameID(metricdesc[c].md_desc.pmid, &name)) != 0) { printf ("Cannot find %s(%s) in %s: %s\n", metricdesc[c].md_name, pmIDStr(metricdesc[c].md_desc.pmid), namespace, pmErrStr(e)); } else { if (strcmp(name, metricdesc[c].md_name)) { printf ("%s is %s in the %s but %s in code\n", pmIDStr(metricdesc[c].md_desc.pmid), name, namespace,metricdesc[c].md_name); } } } pmTraversePMNS("", checkname); exit (0); } pmdaOpenLog(&desc); solaris_init(&desc); pmdaConnect(&desc); pmdaMain(&desc); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/solaris/pmns.zfs0000664000000000000000000000255412272262501015660 0ustar zfs { arc used snapshot available SOLARIS:SCLR_ZFS:0 quota SOLARIS:SCLR_ZFS:1 reservation SOLARIS:SCLR_ZFS:2 compression SOLARIS:SCLR_ZFS:3 copies SOLARIS:SCLR_ZFS:4 recordsize SOLARIS:SCLR_ZFS:5 refquota SOLARIS:SCLR_ZFS:6 refreservation SOLARIS:SCLR_ZFS:7 referenced SOLARIS:SCLR_ZFS:8 nsnapshots SOLARIS:SCLR_ZFS:9 } zfs.used { total SOLARIS:SCLR_ZFS:10 byme SOLARIS:SCLR_ZFS:11 bysnapshots SOLARIS:SCLR_ZFS:12 bychildren SOLARIS:SCLR_ZFS:13 byrefreservation SOLARIS:SCLR_ZFS:14 } zfs.snapshot { used SOLARIS:SCLR_ZFS:15 referenced SOLARIS:SCLR_ZFS:16 compression SOLARIS:SCLR_ZFS:17 } zfs.arc { size SOLARIS:SCLR_ARCSTATS:0 min_size SOLARIS:SCLR_ARCSTATS:1 max_size SOLARIS:SCLR_ARCSTATS:2 mru_size SOLARIS:SCLR_ARCSTATS:3 target_size SOLARIS:SCLR_ARCSTATS:4 hits misses } zfs.arc.misses { total SOLARIS:SCLR_ARCSTATS:5 demand_data SOLARIS:SCLR_ARCSTATS:6 demand_metadata SOLARIS:SCLR_ARCSTATS:7 prefetch_data SOLARIS:SCLR_ARCSTATS:8 prefetch_metadata SOLARIS:SCLR_ARCSTATS:9 } zfs.arc.hits { total SOLARIS:SCLR_ARCSTATS:10 mfu SOLARIS:SCLR_ARCSTATS:11 mru SOLARIS:SCLR_ARCSTATS:12 mfu_ghost SOLARIS:SCLR_ARCSTATS:13 mru_ghost SOLARIS:SCLR_ARCSTATS:14 demand_data SOLARIS:SCLR_ARCSTATS:15 demand_metadata SOLARIS:SCLR_ARCSTATS:16 prefetch_data SOLARIS:SCLR_ARCSTATS:17 prefetch_metadata SOLARIS:SCLR_ARCSTATS:18 } pcp-3.8.12ubuntu1/src/pmdas/solaris/zfs.c0000664000000000000000000001063112272262501015120 0ustar /* * Copyright (C) 2009 Max Matveev. All Rights Reserved * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "common.h" static libzfs_handle_t *zh; static int zf_added; struct zfs_data { zfs_handle_t *zh; uint64_t nsnaps; }; /* * For each filesystem or snapshot check if the name is in the * corresponding instance cache. If it's not there then add it to the * cache. If we've cached the new instance then we keep the zfs_handle * which we've received in the argument, otherwise we need to close it * - zfs_iter_root() expects that from us. * * For filesystems iterate over their snapshots and update snapshot * count which is stored in the cached data for the instances in ZFS_INDOM * domain. */ static int zfs_cache_inst(zfs_handle_t *zf, void *arg) { const char *fsname = zfs_get_name(zf); pmInDom zfindom; int inst, rv; struct zfs_data *zdata = NULL; uint64_t *snapcnt = arg; switch (zfs_get_type(zf)) { case ZFS_TYPE_FILESYSTEM: zfindom = indomtab[ZFS_INDOM].it_indom; break; case ZFS_TYPE_SNAPSHOT: (*snapcnt)++; zfindom = indomtab[ZFS_SNAP_INDOM].it_indom; break; default: zfs_close(zf); return 0; } if ((rv = pmdaCacheLookupName(zfindom, fsname, &inst, (void **)&zdata)) == PMDA_CACHE_ACTIVE) { zfs_close(zf); zfs_refresh_properties(zdata->zh); zf = zdata->zh; } else if ((rv == PMDA_CACHE_INACTIVE) && zdata) { rv = pmdaCacheStore(zfindom, PMDA_CACHE_ADD, fsname, zdata); if (rv < 0) { __pmNotifyErr(LOG_WARNING, "Cannot reactivate cached data for '%s': %s\n", fsname, pmErrStr(rv)); zfs_close(zf); return 0; } zfs_close(zf); zfs_refresh_properties(zdata->zh); zf = zdata->zh; } else { if ((zdata = calloc(1, sizeof(*zdata))) == NULL) { __pmNotifyErr(LOG_WARNING, "Out of memory for data of %s\n", fsname); zfs_close(zf); return 0; } zdata->zh = zf; rv = pmdaCacheStore(zfindom, PMDA_CACHE_ADD, fsname, zdata); if (rv < 0) { __pmNotifyErr(LOG_WARNING, "Cannot cache data for '%s': %s\n", fsname, pmErrStr(rv)); zfs_close(zf); return 0; } zf_added++; } zfs_iter_filesystems(zf, zfs_cache_inst, NULL); if (zfs_get_type(zf) == ZFS_TYPE_FILESYSTEM) { zdata->nsnaps = 0; zfs_iter_snapshots(zf, zfs_cache_inst, &zdata->nsnaps); } return 0; } void zfs_refresh(void) { zf_added = 0; pmdaCacheOp(indomtab[ZFS_INDOM].it_indom, PMDA_CACHE_INACTIVE); pmdaCacheOp(indomtab[ZFS_SNAP_INDOM].it_indom, PMDA_CACHE_INACTIVE); zfs_iter_root(zh, zfs_cache_inst, NULL); if (zf_added) { pmdaCacheOp(indomtab[ZFS_INDOM].it_indom, PMDA_CACHE_SAVE); pmdaCacheOp(indomtab[ZFS_SNAP_INDOM].it_indom, PMDA_CACHE_SAVE); } } int zfs_fetch(pmdaMetric *pm, int inst, pmAtomValue *atom) { char *fsname; metricdesc_t *md = pm->m_user; struct zfs_data *zdata; uint64_t v; if (pmdaCacheLookup(pm->m_desc.indom, inst, &fsname, (void **)&zdata) != PMDA_CACHE_ACTIVE) return PM_ERR_INST; if (md->md_offset == -1) { /* nsnapshot */ atom->ull = zdata->nsnaps; return 1; } v = zfs_prop_get_int(zdata->zh, md->md_offset); /* Special processing - compression ratio is in precent, we export * it as multiplier */ switch (md->md_offset) { case ZFS_PROP_COMPRESSRATIO: atom->d = v / 100.0; break; default: atom->ull = v; break; } return 1; } void zfs_init(int first) { if (zh) return; zh = libzfs_init(); if (zh) { pmdaCacheOp(indomtab[ZFS_INDOM].it_indom, PMDA_CACHE_LOAD); pmdaCacheOp(indomtab[ZFS_SNAP_INDOM].it_indom, PMDA_CACHE_LOAD); zfs_iter_root(zh, zfs_cache_inst, &first); pmdaCacheOp(indomtab[ZFS_INDOM].it_indom, PMDA_CACHE_SAVE); pmdaCacheOp(indomtab[ZFS_SNAP_INDOM].it_indom, PMDA_CACHE_SAVE); } } pcp-3.8.12ubuntu1/src/pmdas/solaris/clusters.h0000664000000000000000000000063712272262501016174 0ustar #ifndef __PMDA_SOLARIS_CLUSTERS_H #define __PMDA_SOLARIS_CLUSTERS_H /* * PMID cluster numbers * * Clusters are used to index method[] table and shall be contigious */ #define SCLR_SYSINFO 0 #define SCLR_DISK 1 #define SCLR_NETIF 2 #define SCLR_ZPOOL 3 #define SCLR_ZFS 4 #define SCLR_ZPOOL_PERDISK 5 #define SCLR_NETLINK 6 #define SCLR_FSFLUSH 7 #define SCLR_ARCSTATS 8 #define SCLR_FILESYS 9 #endif pcp-3.8.12ubuntu1/src/pmdas/solaris/pmns.zpool_perdisk0000664000000000000000000000047112272262501017736 0ustar zpool.perdisk { state SOLARIS:SCLR_ZPOOL_PERDISK:0 state_int SOLARIS:SCLR_ZPOOL_PERDISK:1 checksum_errors SOLARIS:SCLR_ZPOOL_PERDISK:2 self_healed SOLARIS:SCLR_ZPOOL_PERDISK:3 in out } zpool.perdisk.in { errors SOLARIS:SCLR_ZPOOL_PERDISK:4 } zpool.perdisk.out { errors SOLARIS:SCLR_ZPOOL_PERDISK:5 } pcp-3.8.12ubuntu1/src/pmdas/solaris/netlink.c0000664000000000000000000000614612272262501015770 0ustar /* * Copyright (C) 2010 Max Matveev. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* Extract per-link network information via kstat. * * Link stats are in the sections called "link" and the stat name * is the same as the link names */ #include #include "common.h" int netlink_fetch(pmdaMetric *pm, int inst, pmAtomValue *av) { char *lname; metricdesc_t *md = pm->m_user; kstat_t *k; char *stat = (char *)md->md_offset; if (pmdaCacheLookup(indomtab[NETLINK_INDOM].it_indom, inst, &lname, (void **)&k) != PMDA_CACHE_ACTIVE) return PM_ERR_INST; if (k) { kstat_named_t *kn = kstat_data_lookup(k, stat); if (kn == NULL) { fprintf(stderr, "No kstat called %s for %s\n", stat, lname); return 0; } switch (pm->m_desc.type) { case PM_TYPE_32: if (kn->data_type == KSTAT_DATA_INT32) { av->l = kn->value.i32; return 1; } break; case PM_TYPE_U32: if (kn->data_type == KSTAT_DATA_UINT32) { av->ul = kn->value.ui32; return 1; } break; case PM_TYPE_64: if (kn->data_type == KSTAT_DATA_INT64) { av->ll = kn->value.i64; return 1; } break; case PM_TYPE_U64: if (kn->data_type == KSTAT_DATA_UINT64) { av->ull = kn->value.ui64; return 1; } break; } } return 0; } void netlink_update_stats(int fetch) { kstat_t *k; kstat_ctl_t *kc; pmInDom indom = indomtab[NETLINK_INDOM].it_indom; if ((kc = kstat_ctl_update()) == NULL) return; for (k = kc->kc_chain; k != NULL; k = k->ks_next) { if (strcmp(k->ks_module, "link") == 0) { int rv; kstat_t *cached; if (pmdaCacheLookupName(indom, k->ks_name, &rv, (void **)&cached) != PMDA_CACHE_ACTIVE) { rv = pmdaCacheStore(indom, PMDA_CACHE_ADD, k->ks_name, k); if (rv < 0) { __pmNotifyErr(LOG_WARNING, "Cannot create instance for " "network link '%s': %s\n", k->ks_name, pmErrStr(rv)); continue; } } if (fetch) kstat_read(kc, k, NULL); } } } void netlink_refresh(void) { pmdaCacheOp(indomtab[NETLINK_INDOM].it_indom, PMDA_CACHE_INACTIVE); netlink_update_stats(1); pmdaCacheOp(indomtab[NETLINK_INDOM].it_indom, PMDA_CACHE_SAVE); } void netlink_init(int first) { pmdaCacheOp(indomtab[NETLINK_INDOM].it_indom, PMDA_CACHE_LOAD); netlink_update_stats(0); pmdaCacheOp(indomtab[NETLINK_INDOM].it_indom, PMDA_CACHE_SAVE); } pcp-3.8.12ubuntu1/src/pmdas/solaris/disk.c0000664000000000000000000002402312272262501015250 0ustar /* * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2010 Max Matveev. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "common.h" #include #define SOLARIS_PMDA_TRACE (DBG_TRACE_APPL0|DBG_TRACE_APPL2) typedef struct { int fetched; int err; kstat_t *ksp; kstat_io_t iostat; kstat_t *sderr; int sderr_fresh; } ctl_t; static di_devlink_handle_t devlink_hndl = DI_LINK_NIL; static di_node_t di_root = DI_NODE_NIL; static ctl_t * getDiskCtl(pmInDom dindom, const char *name) { ctl_t *ctl = NULL; int inst; int rv = pmdaCacheLookupName(dindom,name, &inst, (void **)&ctl); if (rv == PMDA_CACHE_ACTIVE) return ctl; if ((rv == PMDA_CACHE_INACTIVE) && ctl) { rv = pmdaCacheStore(dindom, PMDA_CACHE_ADD, name, ctl); if (rv < 0) { __pmNotifyErr(LOG_WARNING, "Cannot reactivate cached data for disk '%s': %s\n", name, pmErrStr(rv)); return NULL; } } else { if ((ctl = (ctl_t *)calloc(1, sizeof(ctl_t))) == NULL) { __pmNotifyErr(LOG_WARNING, "Out of memory to keep state for disk '%s'\n", name); return NULL; } rv = pmdaCacheStore(dindom, PMDA_CACHE_ADD, name, ctl); if (rv < 0) { __pmNotifyErr(LOG_WARNING, "Cannot cache data for disk '%s': %s\n", name, pmErrStr(rv)); free(ctl); return NULL; } } return ctl; } static void disk_walk_chains(pmInDom dindom) { kstat_t *ksp; kstat_ctl_t *kc; if ((kc = kstat_ctl_update()) == NULL) return; for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { ctl_t *ctl; if ((strcmp(ksp->ks_class, "disk") == 0) && (ksp->ks_type == KSTAT_TYPE_IO)) { if ((ctl = getDiskCtl(dindom, ksp->ks_name)) == NULL) continue; ctl->ksp = ksp; ctl->fetched = 0; } else if (strcmp(ksp->ks_class, "device_error") == 0) { char *comma; char modname[KSTAT_STRLEN]; strcpy(modname, ksp->ks_name); if ((comma = strchr(modname, ',')) == NULL) continue; *comma = '\0'; if ((ctl = getDiskCtl(dindom, modname)) == NULL) continue; ctl->sderr = ksp; ctl->sderr_fresh = 0; } } } void disk_init(int first) { pmInDom dindom = indomtab[DISK_INDOM].it_indom; if (!first) /* TODO ... not sure if/when we'll use this re-init hook */ return; pmdaCacheOp(dindom, PMDA_CACHE_LOAD); disk_walk_chains(dindom); pmdaCacheOp(dindom, PMDA_CACHE_SAVE); } void disk_prefetch(void) { if (di_root != DI_NODE_NIL) { di_fini(di_root); di_root = DI_NODE_NIL; } if (devlink_hndl != DI_LINK_NIL) { di_devlink_fini(&devlink_hndl); devlink_hndl = DI_LINK_NIL; } pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_INACTIVE); disk_walk_chains(indomtab[DISK_INDOM].it_indom); pmdaCacheOp(indomtab[DISK_INDOM].it_indom, PMDA_CACHE_SAVE); } static __uint64_t disk_derived(pmdaMetric *mdesc, int inst, const kstat_io_t *iostat) { pmID pmid; __pmID_int *ip = (__pmID_int *)&pmid; __uint64_t val; pmid = mdesc->m_desc.pmid; ip->domain = 0; // from kstat_io_t ... // // u_longlong_t nread; /* number of bytes read */ // u_longlong_t nwritten; /* number of bytes written */ // uint_t reads; /* number of read operations */ // uint_t writes; /* number of write operations */ // switch (pmid) { case PMDA_PMID(SCLR_DISK,2): /* disk.all.total */ case PMDA_PMID(SCLR_DISK,12): /* disk.dev.total */ val = iostat->reads + iostat->writes; break; case PMDA_PMID(SCLR_DISK,5): /* disk.all.total_bytes */ case PMDA_PMID(SCLR_DISK,15): /* disk.dev.total_bytes */ val = iostat->nread + iostat->nwritten; break; /* iostat->wcnt and iostat->rcnt are 32 bit intergers, * these two metrics must be derived because the metrics * are using 64 bit integers to avoid overflows during * accumultion */ case PMDA_PMID(SCLR_DISK,7): /* disk.all.wait.count */ val = iostat->wcnt; break; case PMDA_PMID(SCLR_DISK,9): /* disk.all.run.time */ val = iostat->rcnt; break; default: fprintf(stderr, "disk_derived: Botch: no method for pmid %s\n", pmIDStr(mdesc->m_desc.pmid)); val = 0; break; } #ifdef PCP_DEBUG if ((pmDebug & SOLARIS_PMDA_TRACE) == SOLARIS_PMDA_TRACE) { /* desperate */ fprintf(stderr, "disk_derived: pmid %s inst %d val %llu\n", pmIDStr(mdesc->m_desc.pmid), inst, (unsigned long long)val); } #endif return val; } static int fetch_disk_data(kstat_ctl_t *kc, const pmdaMetric *mdesc, ctl_t *ctl, const char *diskname) { if (ctl->fetched == 1) return 1; if (ctl->ksp == NULL) return 0; if ((kstat_read(kc, ctl->ksp, &ctl->iostat) == -1)) { if (ctl->err == 0) { __pmNotifyErr(LOG_WARNING, "Error: disk_fetch(pmid=%s disk=%s ...) - " "kstat_read(kc=%p, ksp=%p, ...) failed: %s\n", pmIDStr(mdesc->m_desc.pmid), diskname, kc, ctl->ksp, osstrerror()); } ctl->err++; ctl->fetched = -1; return 0; } ctl->fetched = 1; if (ctl->err != 0) { __pmNotifyErr(LOG_INFO, "Success: disk_fetch(pmid=%s disk=%s ...) " "after %d errors as previously reported\n", pmIDStr(mdesc->m_desc.pmid), diskname, ctl->err); ctl->err = 0; } return 1; } static int get_devlink_path(di_devlink_t devlink, void *arg) { const char **p = arg; *p = di_devlink_path(devlink); return DI_WALK_TERMINATE; } static int fetch_disk_devlink(const kstat_t *ksp, pmAtomValue *atom) { di_node_t n; if (di_root == DI_NODE_NIL) { if ((di_root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) return 0; } if (devlink_hndl == DI_LINK_NIL) { if ((devlink_hndl = di_devlink_init(NULL, DI_MAKE_LINK)) == DI_LINK_NIL) return 0; } if ((n = di_drv_first_node(ksp->ks_module, di_root)) == DI_NODE_NIL) { #ifdef PCP_DEBUG if ((pmDebug & SOLARIS_PMDA_TRACE) == SOLARIS_PMDA_TRACE) { fprintf(stderr,"No nodes for %s: %s\n", ksp->ks_name, osstrerror()); } #endif return 0; } do { if (di_instance(n) == ksp->ks_instance) { di_minor_t minor = di_minor_next(n, DI_MINOR_NIL); char *path; char *devlink = NULL; if (minor == DI_MINOR_NIL) { #ifdef PCP_DEBUG if ((pmDebug & SOLARIS_PMDA_TRACE) == SOLARIS_PMDA_TRACE) { fprintf (stderr, "No minors of %s: %s\n", ksp->ks_name, osstrerror()); } #endif return 0; } path = di_devfs_minor_path(minor); di_devlink_walk(devlink_hndl, NULL, path, 0, &devlink, get_devlink_path); di_devfs_path_free(path); if (devlink) { atom->cp = devlink; return 1; } return 0; } n = di_drv_next_node(n); } while (n != DI_NODE_NIL); return 0; } static int get_instance_value(pmdaMetric *mdesc, pmInDom dindom, int inst, pmAtomValue *atom) { ctl_t *ctl; char *diskname; uint64_t ull; ptrdiff_t offset = ((metricdesc_t *)mdesc->m_user)->md_offset; kstat_ctl_t *kc; if ((kc = kstat_ctl_update()) == NULL) return 0; if (pmdaCacheLookup(dindom, inst, &diskname, (void **)&ctl) != PMDA_CACHE_ACTIVE) { #ifdef PCP_DEBUG if ((pmDebug & SOLARIS_PMDA_TRACE) == SOLARIS_PMDA_TRACE) { fprintf(stderr, "Unexpected cache result - instance %d " "is not active in disk indom cache\n", inst); } #endif return 0; } if (offset == -1) { if (pmid_item(mdesc->m_desc.pmid) == 35) { /* hinv.disk.devlink */ return fetch_disk_devlink(ctl->ksp, atom); } if (!fetch_disk_data(kc, mdesc, ctl, diskname)) return 0; ull = disk_derived(mdesc, inst, &ctl->iostat); } else if (offset > sizeof(ctl->iostat)) { /* device_error */ if (ctl->sderr) { kstat_named_t *kn; char * m = (char *)offset; if (!ctl->sderr_fresh) { ctl->sderr_fresh = (kstat_read(kc, ctl->sderr, NULL) != -1); if (!ctl->sderr_fresh) return 0; } if ((kn = kstat_data_lookup(ctl->sderr, m)) == NULL) { #ifdef PCP_DEBUG if ((pmDebug & SOLARIS_PMDA_TRACE) == SOLARIS_PMDA_TRACE) fprintf(stderr, "No %s in %s\n", m, diskname); #endif return 0; } return kstat_named_to_pmAtom(kn, atom); } return 0; } else { char *iop = ((char *)&ctl->iostat) + offset; if (!fetch_disk_data(kc, mdesc, ctl, diskname)) return 0; if (mdesc->m_desc.type == PM_TYPE_U64) { __uint64_t *ullp = (__uint64_t *)iop; ull = *ullp; #ifdef PCP_DEBUG if ((pmDebug & SOLARIS_PMDA_TRACE) == SOLARIS_PMDA_TRACE) { /* desperate */ fprintf(stderr, "disk_fetch: pmid %s inst %d val %llu\n", pmIDStr(mdesc->m_desc.pmid), inst, (unsigned long long)*ullp); } #endif } else { __uint32_t *ulp = (__uint32_t *)iop; ull = *ulp; #ifdef PCP_DEBUG if ((pmDebug & SOLARIS_PMDA_TRACE) == SOLARIS_PMDA_TRACE) { /* desperate */ fprintf(stderr, "disk_fetch: pmid %s inst %d val %u\n", pmIDStr(mdesc->m_desc.pmid), inst, *ulp); } #endif } } if (mdesc->m_desc.type == PM_TYPE_U64) { /* export as 64-bit value */ atom->ull += ull; } else { /* else export as a 32-bit */ atom->ul += (__uint32_t)ull; } return 1; } int disk_fetch(pmdaMetric *mdesc, int inst, pmAtomValue *atom) { int i; pmInDom dindom = indomtab[DISK_INDOM].it_indom; if (pmid_item(mdesc->m_desc.pmid) == 20) { /* hinv.ndisk */ i = pmdaCacheOp(dindom, PMDA_CACHE_SIZE_ACTIVE); if (i < 0) { return 0; } else { atom->ul = i; return 1; } } memset(atom, 0, sizeof(*atom)); if (inst == PM_IN_NULL) { pmdaCacheOp(dindom,PMDA_CACHE_WALK_REWIND); while ((i = pmdaCacheOp(dindom, PMDA_CACHE_WALK_NEXT)) != -1) { if (get_instance_value(mdesc, dindom, i, atom) == 0) return 0; } return 1; } return get_instance_value(mdesc, dindom, inst, atom); } pcp-3.8.12ubuntu1/src/pmdas/solaris/help0000664000000000000000000012033712272262501015032 0ustar # # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Solaris PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ kernel.all.cpu.idle Amount of time CPUs were idle @ kernel.all.cpu.user Amount of time spent executing userspace tasks @ kernel.all.cpu.sys Amount of time spent executing kernel code @ kernel.all.cpu.wait.total Amount of time CPU spent waiting for events @ kernel.percpu.cpu.user Amount of time spent executing userspace tasks by each CPU @ kernel.percpu.cpu.idle Amount of time each CPU was idle @ kernel.percpu.cpu.sys Amount of time each CPU spent executing kernel code @ kernel.percpu.cpu.wait.total Amount of time each CPU spent waiting for events @ disk.all.read Number of read requests aggregated across all disks @ disk.all.write Number of write requests aggregated across all disks @ disk.all.total Number of IO requests aggregated across all disks @ disk.all.read_bytes Number of bytes read from all disks @ disk.all.write_bytes Number of bytes written to all disk @ disk.all.total_bytes Number of bytes transferred to and from all disks @ disk.dev.read Number of read requests for each individual disk @ disk.dev.write Number of write requests for each individual disk @ disk.dev.total Number of IO requests for each individual disk @ disk.dev.read_bytes Number of bytes read from each individual disk @ disk.dev.write_bytes Number of bytes written to each individual disk @ disk.dev.total_bytes Number of bytes transferred to and from each individual disk @ network.interface.mtu Maximum Transmission Unit of a network interface Maximum Transmision Unit is the largest size of IP datagram which can be transferred over the data link. @ network.interface.in.bytes Number of bytes received by a network interface @ network.interface.in.errors Number of receive errors per network interface Number of receive errors per network interface. The errors counted towards this metric are: IP header errors, packets larger then the link MTU, packets delivered to the unknown address, packets sent to the unknown IP protocol, truncated packets, packets discarded due to not having a route for the destination. @ network.interface.in.drops Number of packets droped by a network interface Number of packets discared due to lack of space during the input processing. @ network.interface.in.delivers Number of packets delivered to ULPs Number of packets delivered for further processing by the upper-layer protocols. @ network.interface.in.bcasts Number of broadcast packets received by a network interface @ network.interface.in.packets Number of IP packets received by a network interface @ network.interface.in.mcasts Number of multicast packets received by a network interface @ network.interface.out.packets Number of packets sent by a network interface @ network.interface.out.bytes Number of bytes sent by a network interface @ network.interface.out.errors Number of send errors per network interface @ network.interface.out.bcasts Number of broadcast packets sent by a network interface @ network.interface.out.mcasts Number of multicast packets sent by a network interface @ network.interface.out.drops Number of packets discared by a network interface Number of packets discared due to lack of space during the output processing. @ network.udp.ipackets Number of UDP packets received @ network.udp.opackets Number of UDP packets sent @ network.udp.ierrors Number of receive errors in UDP processing @ network.udp.oerrors Number of send erros in UDP processing @ network.udp.noports Number of UDP packets received on unknown UDP port Number of UDP packets received for which here is no port can be found. This counter is reported on the per-interface basis and aggregated by the PMDA. @ network.udp.overflows Number of UDP packets droped due to queue overflow Number of UDP packets droped due to queue overflow. This counter is reported on the per-interface basis and aggregated by the PMDA. @zpool.capacity Total capacity of a zpool in bytes @zpool.used Total space used on a pool @zpool.checksum_errors Number of checksum errors per zpool @zpool.self_healed Number of bytes healed @zpool.in.bytes Counter of bytes read from a zpool @zpool.out.bytes Counter of bytes written to a zpool @zpool.in.ops Counter of reads per zpool @zpool.out.ops Counter of writes per zpool @zpool.in.errors Counter of read errors per zpool @zpool.out.errors Counter of write errors per zpool @zpool.state Current state of zpool @zpool.state_int vs_aux << 8 | vs_state @zfs.available Amount of space available to the dataset The amount of space available to the dataset (a filesystem, a snapshot or a volume) and all its children. This is usually the amount of space available in the zpool which houses the dataset. @zfs.used.total Amount of space used by the dataset and its children The amount of space consumed by the filesystem, snapshot or volume and all its children. This amount does not include any reservation made by the dataset itself but do include the reservation of the children. @zfs.used.byme Amount of space used by the dataset itself. This amount exclude any space used by the children of this dataset or any of its snapshots. @zfs.used.bysnapshots Amount of space used by the snapshots of the dataset The amount of space consumed by the snapshots of this dataset. @zfs.used.bychildren Amount of space used by decendents of the dataset The amount of space consumed by all the decendants of this dataset. @zfs.quota Maximum amount of space a dataset can use Quotas are used to restrict the growth of the datasets. If the quota is set to 0 then the size of the dataset is limited only by the size of the pool which houses this dataset. @zfs.reservation Minimum amount of space guaranteed to a dataset The amount of space which dataset and its decendents are guaranteed to be available for them to use. This amount of taken off the quota of the parent of the dataset. @zfs.compression Compression ratio of the dataset Compression ratio is expressed as multiplier. To estimate how much data will be used by the uncompressed data multiply the amount of space used by the dataset by the compression ratio. @zfs.copies Number of redundant copies of data The number of redundant copies does not include any copies made as part of the pool redundancy. @zfs.recordsize Recommendend block size for files in filesystems By using recommended block size applications which deal with fixed size records can improve I/O performance. @zfs.used.byrefreservation Space used by refreservation The amount of space used by a refreservation set on this filesystem, which would be freed if the refreservation was removed. @zfs.refreservation Minimum amount of space guaranteed to a filesystem The minimum amount of space guaranteed to a dataset, not including its descendents. Unlike reservation refreservation is counted towards the total used space of a dataset. @zfs.refquota Amount of space a filesystem can consume The hard limit on the amount of space a filesystem but not its descendants can consume from the pool. @zfs.referenced Amount of space referenced by the filesystem The amount of data that is accessible by the filesystem. The data may be shared with other datasets in the pool. @zfs.nsnapshots Number of snapshots in the filesystem @zfs.snapshot.compression Compression ratio of the data in the snapshot Compression ratio is expressed as multiplier. To estimate how much data will be used by the uncompressed data multiply the amount of space used by the snapshot by the compression ratio. @zfs.snapshot.used Amount of space used by the snapshot @zfs.snapshot.referenced Amount of space referenced by the snapshot The amount of data that is accessible by the snapshot. The data may be shared with other datasets in the filesystem. @zpool.perdisk.state Current state per disk in zpool @zpool.perdisk.state_int vs_aux << 8 | vs_state @zpool.perdisk.checksum_errors Number of checksum errors per disk in zpool @zpool.perdisk.self_healed Number of bytes healed per disk in zpool @zpool.perdisk.in.errors Counter of read errors per disk in zpool @zpool.perdisk.out.errors Counter of write errors per disk in zpool @network.link.in.errors Number of input errors per link Counts input errors per link @network.link.in.packets Numbe of datagrams received by a link @network.link.in.bytes Number of bytes received by a link Counts number of bytes received by a link. For the physical links this is the raw counter of bytes received, for the aggregated links this is the number of bytes received by all links in the aggregation group @network.link.in.bcasts Number of broadcast datagrams received by a link @network.link.in.mcasts Number of multicast datagrams Counts multicast datagram recieved by a link. @network.link.in.nobufs Number of inpit packets discared Counts number of packets discared because of failure to allocate buffers @network.link.out.errors Number of output errors per link @network.link.out.packets Number of packets sent from a link @network.link.out.bytes Number of bytes sent from a link @network.link.out.bcasts Number of broadcast datagrams sent from a link @network.link.out.mcasts Number of multicast datagrams sent from a link @network.link.out.nobufs Number of output packets discared Counts number of packets discared because of failure to allocate buffers @network.link.collisions Number of collisions detected per link @network.link.state Link state 1 - Link is up, 2 - Link is down, 0 - unknown state @network.link.duplex Link duplex 1 - Half duplex, 2 - Full duplex @network.link.speed Link speed in bytes per second @hinv.pagesize Memory page size The memory page size of the running kernel in bytes. @hinv.physmem Total physical system memory Total physical system memory size rounded down to the nearest page size boundary @pmda.uname identity and type of current system Identity and type of current system. The concatenation of the values returned from utsname(2), also similar to uname -a. @kernel.fsflush.scanned Number of pages scanned by fsflush daemon @kernel.fsflush.examined Number of pages examined by fsflush daemon @kernel.fsflush.coalesced Number of pages coalesced into larger page @kernel.fsflush.modified Number of modified pages written to disk @kernel.fsflush.locked Number of pages locked by fsflush daemon Pages which were considered to be on interest for further examination are locked before deciding if they could be coalesced, released or flushed to disk. @kernel.fsflush.released Number of free pages released by fsflush daemon @kernel.fsflush.time Amount of time fsflush daemon spent doing its work @mem.physmem Total physical system memory Total physical system memory size rounded down to the nearest page size boundary. This metric is the same as hinv.physmem but uses different units. @mem.freemem Amount of free memory in the system @mem.lotsfree Paging theshold If freemem fails below the lostfree threshold then paging out daemon starts its activity. Default value for lotsfree is 1/64 of physical memory or 512K (which ever is larger). @mem.availrmem Amount of resident memory in the system @kernel.all.io.bread Physical block reads across all CPUs This metric is only updated if reading or writing to UFS mounted filesystems, reads and writes to ZFS do not update this metric. @kernel.all.io.bwrite Physical block writes across all CPUs This metric is only updated if reading or writing to UFS mounted filesystems, reads and writes to ZFS do not update this metric. @kernel.all.io.lread Logical block reads across all CPUs This metric is only updated if reading or writing to UFS mounted filesystems, reads and writes to ZFS do not update this metric. @kernel.all.io.lwrite Logical block writes across all CPUs This metric is only updated if reading or writing to UFS mounted filesystems, reads and writes to ZFS do not update this metric. @kernel.all.io.phread Raw I/O reads across all CPUs @kernel.all.io.phwrite Raw I/O writes across all CPUs @kernel.all.io.intr Device interrupts across all CPUs @kernel.percpu.io.bread Physical block reads This metric is only updated if reading or writing to UFS mounted filesystems, reads and writes to ZFS do not update this metric. @kernel.percpu.io.bwrite Physical block writes This metric is only updated if reading or writing to UFS mounted filesystems, reads and writes to ZFS do not update this metric. @kernel.percpu.io.lread Logical block reads This metric is only updated if reading or writing to UFS mounted filesystems, reads and writes to ZFS do not update this metric. @kernel.percpu.io.lwrite Logical block writes This metric is only updated if reading or writing to UFS mounted filesystems, reads and writes to ZFS do not update this metric. @kernel.percpu.io.phread Raw I/O reads @kernel.percpu.io.phwrite Raw I/O writes @kernel.percpu.io.intr Device interrupts @hinv.ncpu Number of CPUs in the system @hinv.ndisk Number of disks in the system @kernel.all.trap Traps across all CPUs @kernel.all.pswitch Context switches across all CPUs @kernel.all.syscall Total number of system calls across all CPUs @kernel.all.sysexec Total number of calls from exec(2) family across all CPUs @kernel.all.sysfork Total number of new processes created across all CPUs @kernel.all.sysvfork Total number of new processes created across all CPUs Unlike fork vfork does not copy all the virtual memory of the parent process into the child process and is mostly used to create new system context for execve(2). vfork(2) calls are not counted towards kernel.all.sysfork. @kernel.all.sysread Total number of system calls from read(2) family across all CPUs @kernel.all.syswrite Total number of system calls from write (2) family across all CPUs @kernel.percpu.trap Traps on each CPUs @kernel.percpu.pswitch Context switches on each CPUs @kernel.percpu.syscall Total number of system calls on each CPU @kernel.percpu.sysexec Total number of calls from exec(2) family on each CPU @kernel.percpu.sysfork Total number of new processes created on each CPU @kernel.percpu.sysvfork Total number of new processes created on each CPU Unlike fork vfork does not copy all the virtual memory of the parent process into the child process and is mostly used to create new system context for execve(2). vfork(2) calls are not counted towards kernel.percpu.sysfork. @kernel.percpu.sysread Total number of system calls from read(2) family on each CPU @kernel.percpu.syswrite Total number of system calls from write (2) family on each CPU @kernel.all.load Classic load average for 1, 5 and 15 minute intervals @kernel.all.cpu.wait.io Time spent waiting for I/O across all CPUs This metric is not updated by OpenSolaris kernel. @kernel.all.cpu.wait.pio Time spent wait for polled I/O across all CPUs This metric is not updated by OpenSolaris kernel. @kernel.all.cpu.wait.swap Time spent wait for swap across all CPUs This metric is not updated by OpenSolaris kernel. @kernel.percpu.cpu.wait.io Time spent waiting for I/O on per-CPU basis This metric is not updated by OpenSolaris kernel. @kernel.percpu.cpu.wait.pio Time spent waiting for polled I/O on per-CPU basis This metric is not updated by OpenSolaris kernel. @kernel.percpu.cpu.wait.swap Time spent waiting swap on per-CPU basis This metric is not updated by OpenSolaris kernel. @zfs.arc.size Total amount of memory used by ZFS ARC @zfs.arc.min_size Lower limit of them amount of memory for ZFS ARC @zfs.arc.max_size Upper limit of the amount of memory for ZFS ARC The default is to use 7/8 of total physical memory. @zfs.arc.mru_size Amount of memory used by the most recently used pages @zfs.arc.target_size "Ideal" size of the cached based on aging @zfs.arc.hits.total Number of times data is found in the cache @zfs.arc.hits.mfu Number of times data is found in the most frequently used buffers @zfs.arc.hits.mru Number of times data is found in the most recently used buffers @zfs.arc.hits.mfu_ghost Number of times MFU ghost buffer is accessed A ghost buffer is a buffer which is no longer cached but is still linked into the hash. @zfs.arc.hits.mru_ghost Number of times MRU ghost buffer is accessed A ghost buffer is a buffer which is no longer cached but is still linked into the hash. @zfs.arc.hits.demand_data Number of times file data is found in the cache ARC statistics provide separate counters for demand vs prefetch and data vs metadata accesses: demand is a result of the direct request for a particular data, prefetch is a result of speculative request for a particular data. @zfs.arc.hits.demand_metadata Number of times filesystem metadata is found in the cache ARC statistics provide separate counters for demand vs prefetch and data vs metadata accesses: demand is a result of the direct request for a particular data, prefetch is a result of speculative request for a particular data. @zfs.arc.hits.prefetch_data Number of times speculative request for data is satisfied from the cache ARC statistics provide separate counters for demand vs prefetch and data vs metadata accesses: demand is a result of the direct request for a particular data, prefetch is a result of speculative request for a particular data. @zfs.arc.hits.prefetch_metadata Number of times speculative request for metadata is satisfied from the cache ARC statistics provide separate counters for demand vs prefetch and data vs metadata accesses: demand is a result of the direct request for a particular data, prefetch is a result of speculative request for a particular data. @zfs.arc.misses.total Number of times the data is not found in the cache @zfs.arc.misses.demand_data Number of times file data is not found in the cache ARC statistics provide separate counters for demand vs prefetch and data vs metadata accesses: demand is a result of the direct request for a particular data, prefetch is a result of speculative request for a particular data. @zfs.arc.misses.demand_metadata Number of times filesystem metadata is not found in the cache ARC statistics provide separate counters for demand vs prefetch and data vs metadata accesses: demand is a result of the direct request for a particular data, prefetch is a result of speculative request for a particular data. @zfs.arc.misses.prefetch_data Number of times speculatively accessed file data is not found in the cache ARC statistics provide separate counters for demand vs prefetch and data vs metadata accesses: demand is a result of the direct request for a particular data, prefetch is a result of speculative request for a particular data. @zfs.arc.misses.prefetch_metadata Number of times speculatively accessed filesystem metadata is not found in the cache ARC statistics provide separate counters for demand vs prefetch and data vs metadata accesses: demand is a result of the direct request for a particular data, prefetch is a result of speculative request for a particular data. @pmda.prefetch.time Amount of time spent extracting information about a group of metrics Each metric belongs to a prefetch group. When a client asks for the metric to be fetched the information for the group must be extracted from the kernel. @pmda.prefetch.count Number of times each group of metrics was updated @pmda.metric.time Amount of time spent extracting information about individual metrics Requesting multiple instances of the same metrics counts against the metric itself and not against the individual instances @pmda.metric.count Number of times individual metrics have been fetched Requesting multiple instances of the same metrics counts as multiple hits against the metric itself @disk.all.wait.time Amount of time IO requests spent waiting for service Amount of time IO transactions spent waiting to be serviced, i.e. the transaction has been accepted for processing but for which the processing has not yet begun. Each transaction waiting for processing adds to to the total time which means that if multiple transactions are waiting then total time for the sampling interval may be larger then the interval. @disk.dev.wait.time Amount of time IO requests spent waiting for service Amount of time IO transactions spent waiting to be serviced, i.e. the transaction has been accepted for processing but for which the processing has not yet begun. Each transaction waiting for processing adds to to the total time which means that if multiple transactions are waiting then total time for the sampling interval may be larger then the interval. @disk.all.wait.count Number of transactions waiting to be serviced Number of transactions accepted for processing but for which the processing has not yet begun. @disk.dev.wait.count Number of transactions waiting to be serviced Number of transactions accepted for processing but for which the processing has not yet begun. @disk.all.run.time Amount of time spent processing IO requests @disk.dev.run.time Amount of time spent processing IO requests @disk.all.run.count Number of transactions being processed @disk.dev.run.count Number of transactions being processed # from i86pc/os/cpuid.c # /* # * 8bit APIC IDs on dual core Pentiums # * look like this: # * # * +-----------------------+------+------+ # * | Physical Package ID | MC | HT | # * +-----------------------+------+------+ # * <------- chipid --------> # * <------- coreid ---------------> # * <--- clogid --> # * <------> # * pkgcoreid # * # * Where the number of bits necessary to # * represent MC and HT fields together equals # * to the minimum number of bits necessary to # * store the value of cpi->cpi_ncpu_per_chip. # * Of those bits, the MC part uses the number # * of bits necessary to store the value of # * cpi->cpi_ncore_per_chip. # */ # @hinv.cpu.brand Marketing name of CPU @hinv.cpu.clock Current CPU clock frequency On CPUs which support dynamic clock frequency changes current clock frequency could differ from the nominal ("maximum") clock frequency specified by the manufacturer. @hinv.cpu.maxclock Maximum clock frequency supported by CPU Nominal CPU clock frequency as specified by the manufacturer. @hinv.cpu.frequencies List of clock frequencies supported by CPU @hinv.cpu.implementation Details of CPU implementation @hinv.cpu.chip_id Chip or Socket identifier of the CPU Logical CPUs can share single chip identifier @hinv.cpu.clog_id Logical core identifier Logical cores identifier combines identifiers of the CPU core and virtual CPU identifier (aka hyperthread identifier). @hinv.cpu.core_id CPU core identifier CPU core identifire combines chip identifier and per-chip core identifier. If cores support more the one virtual CPU per core then same core identifier is shared across several virtual CPUs. @hinv.cpu.pkg_core_id Per-chip core identifier This identifier is used to identify individual cores within the package. If a core support more the one virtual CPU per core then same core identifier is shared across several virtual CPUs. @hinv.cpu.cstate Current CPU idle state @hinv.cpu.maxcstates Maximum number of idle state supported by the CPU Information about cstate is available in kstat(1m). @hinv.cpu.ncores Number of CPU cores per physical chip @hinv.cpu.ncpus Number of virtual CPUs per physical chip @disk.dev.errors.soft Number of soft errors per device @disk.dev.errors.hard Number of hard errors per device @disk.dev.errors.transport Number of transport errors per device @disk.dev.errors.media Number of media errors per device @disk.dev.errors.recoverable Number of recoverable errors per device @disk.dev.errors.notready Number of times device reported as not ready @disk.dev.errors.nodevice Number of times device was found missing @disk.dev.errors.badrequest Number of illegal requests per device @disk.dev.errors.pfa Number of times failure prediction threshold has been exceeded @hinv.disk.vendor Device Vendor Can be reported as ATA if SATA device is behind SAS expander @hinv.disk.product Device name Vendor's device name (up-to 16 characters long) @hinv.disk.revision Device Revision @hinv.disk.serial Device Serial Number @hinv.disk.capacity Device Capacity For removable devices capacity of the media is reported. @kernel.fs.vnops.access Number of VOP_ACCESS calls per filesystem VOP_ACCESS is used by access(2) system call. @kernel.fs.vnops.addmap Number of VOP_ADDMAP calls per filesystem VOP_ADDMAP is used to manage reference counting of the vnode used by mmap(2) operations. @kernel.fs.vnops.close Number of VOP_CLOSE calls per filesystem VOP_CLOSE is called every time a close(2) system call is called @kernel.fs.vnops.cmp Number of VOP_CMP calls per filesystem VOP_CMP is used to check if two vnodes are "equal" to each other, i.e. both refer to the same filesystem object. @kernel.fs.vnops.create Number of VOP_CREATE calls per filesystem VOP_CREATE is used to create regular files and device or FIFO nodes. @kernel.fs.vnops.delmap Number of VOP_DELMAP calls VOP_DELMAP is used to destroy a previously created memory-mapped region of a file. @kernel.fs.vnops.dispose Number ot VOP_DISPOSE calls per filesystem VOP_DISPOSE is used to dispose(free or invalidate) of a page associated with a file. @kernel.fs.vnops.dump Number of VOP_DUMP calls per filesystem VOP_DUMP is used to transfer data from the frozen kernel directly to the dump device @kernel.fs.vnops.dumpctl Number of VOP_DUMPCTL calls per filesystem VOP_DUMPCTL sets up context used by VOP_DUMP call. It is used to allocate, free or search for data blocks on the dump device. @kernel.fs.vnops.fid Number of VOP_FID calls per filesystem VOP_FID is used to get file identifier which can be used instead of the file name in some operations. NFS server is one known user of this vnode operation. @kernel.fs.vnops.frlock Number of VOP_FRLOCK calls per filesystem VOP_FRLOCK is used to implement file record locking used by flock(2) @kernel.fs.vnops.fsync Number of VOP_FSYNC calls per filesystem VOP_FSYNC is used to implement fsync(2) system call which flushes data for a specific file to disk. @kernel.fs.vnops.getattr Number of VOP_GETATTR calls per filesystem VOP_GETATTR is used to extract vnode attributes. It use used as part of many system calls which manipulate file attributes, e.g. chmod(2), stat(2), utimes(2) etc. @kernel.fs.vnops.getpage Number of VOP_GETPAGE calls per filesystem VOP_GETPAGE is used to allocate pages (could be several at a time) to cover a region in a file. @kernel.fs.vnops.getsecattr Number of VOP_GETSECATTR calls per filesystem VOP_GETSECATTR used to extract ACL entires associated with a file. @kernel.fs.vnops.inactive Number of VOP_INACTIVE calls per filesystem VOP_INACTIVE is used to destroy vnode before it is removed from the cache or reused. @kernel.fs.vnops.ioctl Number of VOP_IOCTL calls per filesystem VOP_IOCTL is used to implement ioctl(2) system call. @kernel.fs.vnops.link Number of VOP_LINK calls per filesystem VOP_LINK is used to implement support for hard links @kernel.fs.vnops.lookup Number of VOP_LOOKUP calls per filesystem VOP_LOOKUP is used to translate filename to vnode. @kernel.fs.vnops.map Number of VOP_MAP calls per filesystem VOP_MAP is used to create a new memory-mapped region of a file @kernel.fs.vnops.mkdir Number of VOP_MKDIR calls per filesystem VOP_MKDIR is used to create directories @kernel.fs.vnops.open Number of VOP_OPEN calls per filesystem VOP_OPEN is called every time open(2) system call is called. @kernel.fs.vnops.pageio Number of VOP_PAGEIO calls per filesystem VOP_PAGEIO is similar to VOP_GETPAGE and VOP_PUTPAGE and can be used when either of the other two are less efficient, e.g. in the case when pages will be reused after the IO is done. @kernel.fs.vnops.pathconf Number of VOP_PATHCONF calls per filesystem VOP_PATHCONF is used to obtain information about filesystem's parameters reported by pathconf(2) system call @kernel.fs.vnops.poll Number of VOP_POLL calls per filesystem VOP_POLL is used to implement pool(2) system call @kernel.fs.vnops.putpage Number of VOP_PUTPAGE calls per filesystem VOP_PUTPAGE is used to release pages which have been used to hold data from a file @kernel.fs.vnops.read Number of VOP_READ calls per filesystem VOP_READ is used to implement read(2) system call @kernel.fs.vnops.readdir Number of VOP_READDIR calls per filesystem VOP_READDIR is used to read directory entries @kernel.fs.vnops.readlink Number of VOP_READLINK calls per filesystem VOP_READLINK is used to read the information about the target of the symbolic link @kernel.fs.vnops.realvp Number of VOP_REALVP calls per filesystem VOP_REALVP is used to traverse stacking filesystems and extract information about the vnode which refers to the "real" filesystem object. @kernel.fs.vnops.remove Number of VOP_REMOVE calls per filesystem VOP_REMOVE is used to remove entires from a directory. @kernel.fs.vnops.rename Number of VOP_RENAME calls per filesystem VOP_RENAME is used to implement rename(2) system call @kernel.fs.vnops.rmdir Number of VOP_RMDIR calls per filesystem VOP_RMDIR is used to implement rmdir(2) system call @kernel.fs.vnops.rwlock Number of VOP_RWLOCK calls per filesystem VOP_RWLOCK and VOP_RWUNLOCK are used to protect access to vnode data. @kernel.fs.vnops.rwunlock Number of VOP_RWUNLOCK calls per filesystem VOP_RWLOCK and VOP_RWUNLOCK are used to protect access to vnode data. @kernel.fs.vnops.seek Number of VOP_SEEK calls per filesystem VOP_SEEK is used by lseek(2). Because vnodes can be shared across multiple instances of vfile VOP_SEEK does not usually change the position of the file pointer, it instead used to verify the offset before it is changed. @kernel.fs.vnops.setattr Number of VOP_SETATTR calls per filesystem VOP_SETATTR is used to change vnode attributes which are modified by system calls like chmod(2), chown(2), utimes(2) etc. @kernel.fs.vnops.setfl Number of VOP_SETFL calls per filesystem VOP_SETFL is used to implement fcntl(2) F_SETFL option. Currently only sockfs pseudo filesystem is implementing this vnode operation. @kernel.fs.vnops.setsecattr Number of VOP_SETSECATTR calls per filesystem VOP_SETSECATTR is used to change ACL entries @kernel.fs.vnops.shrlock Number of VOP_SHRLOCK calls per filesystem VOP_SHRLOCK is usually used to implement CIFS and NLMv3 shared reservations. @kernel.fs.vnops.space Number of VOP_SPACE calls per filesystem VOP_SPACE is used to provide optimized support for growing and shrinking the files. F_FREESP option of fcntl(2) is using this vnode operation to implment ftruncate(3c) function. @kernel.fs.vnops.symlink Number of VOP_SYMLINK calls per filesystem VOP_SYMLINK is used to create symbolic links. @kernel.fs.vnops.vnevent Number of VOP_VNEVENT calls per filesystem VIP_VNEVENT is used to check if a filesystem support vnode event notifications for operations which change the names of the files. @kernel.fs.vnops.write Number of VOP_WRITE calls per filesystem VOP_WRITE is used to implement write(2) system call @kernel.fs.read_bytes Number of bytes read from a specific filesystem @kernel.fs.readdir_bytes Number of bytes containting directory entires read from a specific filesystem @kernel.fs.write_bytes Number of bytes written to a specific filesystem @kernel.fstype.vnops.access Number of VOP_ACCESS calls for all filesystems of a given type VOP_ACCESS is used by access(2) system call. @kernel.fstype.vnops.addmap Number of VOP_ADDMAP calls for all filesystems of a given type VOP_ADDMAP is used to manage reference counting of the vnode used by mmap(2) operations. @kernel.fstype.vnops.close Number of VOP_CLOSE calls for the specific filesystem VOP_CLOSE is called every time a close(2) system call is called @kernel.fstype.vnops.cmp Number of VOP_CMP calls for the specific filesystem VOP_CMP is used to check if two vnodes are "equal" to each other, i.e. both refer to the same filesystem object. @kernel.fstype.vnops.create Number of VOP_CREATE calls for all filesystems of a given type VOP_CREATE is used to create regular files and device or FIFO nodes. @kernel.fstype.vnops.delmap Number of VOP_DELMAP was called VOP_DELMAP is used to destroy a previously created memory-mapped region of a file. @kernel.fstype.vnops.dispose Number ot VOP_DISPOSE calls for all filesystems of a given type VOP_DISPOSE is used to dispose(free or invalidate) of a page associated with a file. @kernel.fstype.vnops.dump Number of VOP_DUMP calls for all filesystems of a given type VOP_DUMP is used to transfer data from the frozen kernel directly to the dump device @kernel.fstype.vnops.dumpctl Number of VOP_DUMPCTL calls for all filesystems of a given type VOP_DUMPCTL sets up context used by VOP_DUMP call. It is used to allocate, free or search for data blocks on the dump device. @kernel.fstype.vnops.fid Number of VOP_FID calls for all filesystems of a given type VOP_FID is used to get file identifier which can be used instead of the file name in some operations. NFS server is one known user of this vnode operation. @kernel.fstype.vnops.frlock Number of time VOP_FRLOCK calls for all filesystems of a given type VOP_FRLOCK is used to implement file record locking used by flock(2) @kernel.fstype.vnops.fsync Number of VOP_FSYNC calls for all filesystems of a given type VOP_FSYNC is used to implement fsync(2) system call which flushes data for a specific file to disk. @kernel.fstype.vnops.getattr Number of VOP_GETATTR calls for all filesystems of a given type VOP_GETATTR is used to extract vnode attributes. It use used as part of many system calls which manipulate file attributes, e.g. chmod(2), stat(2), utimes(2) etc. @kernel.fstype.vnops.getpage Number of VOP_GETPAGE calls for all filesystems of a given type VOP_GETPAGE is used to allocate pages (could be several at a time) to cover a region in a file. @kernel.fstype.vnops.getsecattr Number of VOP_GETSECATTR calls for all filesystems of a given type VOP_GETSECATTR used to extract ACL entires associated with a file. @kernel.fstype.vnops.inactive Number of VOP_INACTIVE calls for all filesystems of a given type VOP_INACTIVE is used to destroy vnode before it is removed from the cache or reused. @kernel.fstype.vnops.ioctl Number of VOP_IOCTL calls for all filesystems of a given type VOP_IOCTL is used to implement ioctl(2) system call. @kernel.fstype.vnops.link Number of VOP_LINK calls for all filesystems of a given type VOP_LINK is used to implement support for hard links @kernel.fstype.vnops.lookup Number of VOP_LOOKUP calls for all filesystems of a given type VOP_LOOKUP is used to translate filename to vnode. @kernel.fstype.vnops.map Number of VOP_MAP calls for all filesystems of a given type VOP_MAP is used to create a new memory-mapped region of a file @kernel.fstype.vnops.mkdir Number of VOP_MKDIR calls for all filesystems of a given type VOP_MKDIR is used to create directories @kernel.fstype.vnops.open Number of VOP_OPEN calls for all filesystems of a given type VOP_OPEN is called every time open(2) system call is called. @kernel.fstype.vnops.pageio Number of VOP_PAGEIO calls for all filesystems of a given type VOP_PAGEIO is similar to VOP_GETPAGE and VOP_PUTPAGE and can be used when either of the other two are less efficient, e.g. in the case when pages will be reused after the IO is done. @kernel.fstype.vnops.pathconf Number of VOP_PATHCONF calls for all filesystems of a given type VOP_PATHCONF is used to obtain information about filesystem's parameters reported by pathconf(2) system call @kernel.fstype.vnops.poll Number of VOP_POLL calls for all filesystems of a given type VOP_POLL is used to implement pool(2) system call @kernel.fstype.vnops.putpage Number of VOP_PUTPAGE calls for all filesystems of a given type VOP_PUTPAGE is used to release pages which have been used to hold data from a file @kernel.fstype.vnops.read Number of VOP_READ calls for all filesystems of a given type VOP_READ is used to implement read(2) system call @kernel.fstype.vnops.readdir Number of VOP_READDIR calls for all filesystems of a given type VOP_READDIR is used to read directory entries @kernel.fstype.vnops.readlink Number of VOP_READLINK calls for all filesystems of a given type VOP_READLINK is used to read the information about the target of the symbolic link @kernel.fstype.vnops.realvp Number of VOP_REALVP calls for all filesystems of a given type VOP_REALVP is used to traverse stacking filesystems and extract information about the vnode which refers to the "real" filesystem object. @kernel.fstype.vnops.remove Number of VOP_REMOVE calls for all filesystems of a given type VOP_REMOVE is used to remove entires from a directory. @kernel.fstype.vnops.rename Number of VOP_RENAME calls for all filesystems of a given type VOP_RENAME is used to implement rename(2) system call @kernel.fstype.vnops.rmdir Number of VOP_RMDIR calls for all filesystems of a given type VOP_RMDIR is used to implement rmdir(2) system call @kernel.fstype.vnops.rwlock Number of VOP_RWLOCK calls for all filesystems of a given type VOP_RWLOCK and VOP_RWUNLOCK are used to protect access to vnode data. @kernel.fstype.vnops.rwunlock Number of VOP_RWUNLOCK calls for all filesystems of a given type VOP_RWLOCK and VOP_RWUNLOCK are used to protect access to vnode data. @kernel.fstype.vnops.seek Number of VOP_SEEK calls for all filesystems of a given type VOP_SEEK is used by lseek(2). Because vnodes can be shared across multiple instances of vfile VOP_SEEK does not usually change the position of the file pointer, it instead used to verify the offset before it is changed. @kernel.fstype.vnops.setattr Number of VOP_SETATTR calls for all filesystems of a given type VOP_SETATTR is used to change vnode attributes which are modified by system calls like chmod(2), chown(2), utimes(2) etc. @kernel.fstype.vnops.setfl Number of VOP_SETFL calls for all filesystems of a given type VOP_SETFL is used to implement fcntl(2) F_SETFL option. Currently only sockfs pseudo filesystem is implementing this vnode operation. @kernel.fstype.vnops.setsecattr Number of VOP_SETSECATTR calls for all filesystems of a given type VOP_SETSECATTR is used to change ACL entries @kernel.fstype.vnops.shrlock Number of VOP_SHRLOCK calls for all filesystems of a given type VOP_SHRLOCK is usually used to implement CIFS and NLMv3 shared reservations. @kernel.fstype.vnops.space Number of VOP_SPACE calls for all filesystems of a given type VOP_SPACE is used to provide optimized support for growing and shrinking the files. F_FREESP option of fcntl(2) is using this vnode operation to implment ftruncate(3c) function. @kernel.fstype.vnops.symlink Number of VOP_SYMLINK calls for all filesystems of a given type VOP_SYMLINK is used to create symbolic links. @kernel.fstype.vnops.vnevent Number of VOP_VNEVENT calls for all filesystems of a given type VIP_VNEVENT is used to check if a filesystem support vnode event notifications for operations which change the names of the files. @kernel.fstype.vnops.write Number of VOP_WRITE calls for all filesystems of a given type VOP_WRITE is used to implement write(2) system call @kernel.fstype.read_bytes Bytes read from all filesystems of a given type @kernel.fstype.readdir_bytes Bytes read for directory entries from all filesystems of a given type @kernel.fstype.write_bytes Bytes written to all filesystems of a given type @hinv.disk.devlink Disk name in the descriptive format Solaris uses symbolic links under /dev to provide access to device nodes via "descriptive" names like /dev/dsk/cXtYdZsN. This metrics provides a translation from a "descriptive" name to instances in the disk instance domain. The name is always the name of the first minor device for a particular disk and includes the slice information. NOTE! Fetching this metric is expensive - several system calls are made to fetch each instance. pcp-3.8.12ubuntu1/src/pmdas/solaris/netmib2.h0000664000000000000000000000277312272262501015673 0ustar /* * Copyright (C) 2009 Max Matveev. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __PMDA_SOLARIS_NETMIB2_H #define __PMDA_SOLARIS_NETMIB2_H typedef struct nm2_udp_stats { uint64_t ipackets; uint64_t opackets; int32_t ierrors; int32_t oerrors; uint32_t noports; uint32_t overflows; } nm2_udp_stats_t; extern nm2_udp_stats_t nm2_udp; typedef struct nm2_netif_stats { uint64_t ipackets; uint64_t opackets; uint64_t ibytes; uint64_t obytes; uint64_t delivered; uint64_t imcast; uint64_t omcast; uint64_t ibcast; uint64_t obcast; uint64_t ierrors; uint64_t oerrors; int32_t idrops; int32_t odrops; int mtu; } nm2_netif_stats_t; void netmib2_init(int); void netmib2_refresh(void); int netmib2_fetch(pmdaMetric *, int, pmAtomValue *); #endif pcp-3.8.12ubuntu1/src/pmdas/solaris/pmns.mem0000664000000000000000000000320112272262501015622 0ustar /* * TODO * * These are the IRIX names, for reference * mem.freemem * mem.availsmem * mem.availrmem * mem.ravailrmem * mem.bufmem * mem.physmem * mem.dchunkpages * mem.pmapmem * mem.strmem * mem.chunkpages * mem.dpages * mem.emptymem * mem.freeswap * mem.halloc * mem.heapmem * mem.hfree * mem.hovhd * mem.hunused * mem.zfree * mem.zonemem * mem.zreq * mem.iclean * mem.bsdnet * mem.palloc * mem.unmodfl * mem.unmodsw * mem.min_file_pages * mem.min_free_pages * mem.bufs.fs_metadata * mem.bufs.fs_data * mem.bufs.empty * mem.bufs.inact * mem.fault.prot.total * mem.fault.prot.cow * mem.fault.prot.steal * mem.fault.addr.total * mem.fault.addr.cache * mem.fault.addr.demand * mem.fault.addr.file * mem.fault.addr.swap * mem.tlb.flush * mem.tlb.invalid * mem.tlb.rfault * mem.tlb.sync * mem.tlb.tfault * mem.tlb.purge * mem.tlb.idnew * mem.tlb.idwrap * mem.tlb.kvmwrap * mem.paging.reclaim * mem.system.sptalloc * mem.system.sptfree * mem.system.sptclean * mem.system.sptdirty * mem.system.sptintrans * mem.system.sptaged * mem.system.sptbp * mem.system.sptheap * mem.system.sptzone * mem.system.sptpt * mem.lpage.faults * mem.lpage.allocs * mem.lpage.downgrade * mem.lpage.page_splits * mem.lpage.basesize * mem.lpage.maxsize * mem.lpage.maxenabled * mem.lpage.enabled * mem.lpage.coalesce.scans * mem.lpage.coalesce.success * mem.util.kernel * mem.util.fs_ctl * mem.util.fs_dirty * mem.util.fs_clean * mem.util.free * mem.util.user */ mem { physmem SOLARIS:SCLR_SYSINFO:136 freemem SOLARIS:SCLR_SYSINFO:137 lotsfree SOLARIS:SCLR_SYSINFO:138 availrmem SOLARIS:SCLR_SYSINFO:139 } pcp-3.8.12ubuntu1/src/pmdas/solaris/pmns.zpool0000664000000000000000000000106512272262501016215 0ustar zpool { state SOLARIS:SCLR_ZPOOL:0 state_int SOLARIS:SCLR_ZPOOL:1 capacity SOLARIS:SCLR_ZPOOL:2 used SOLARIS:SCLR_ZPOOL:3 checksum_errors SOLARIS:SCLR_ZPOOL:4 self_healed SOLARIS:SCLR_ZPOOL:5 perdisk in out ops } zpool.in { bytes SOLARIS:SCLR_ZPOOL:6 ops SOLARIS:SCLR_ZPOOL:7 errors SOLARIS:SCLR_ZPOOL:8 } zpool.out { bytes SOLARIS:SCLR_ZPOOL:9 ops SOLARIS:SCLR_ZPOOL:10 errors SOLARIS:SCLR_ZPOOL:11 } zpool.ops { noops SOLARIS:SCLR_ZPOOL:12 ioctls SOLARIS:SCLR_ZPOOL:13 claims SOLARIS:SCLR_ZPOOL:14 frees SOLARIS:SCLR_ZPOOL:15 } pcp-3.8.12ubuntu1/src/pmdas/named/0000775000000000000000000000000012272262620013563 5ustar pcp-3.8.12ubuntu1/src/pmdas/named/Remove0000775000000000000000000000125512272262501014747 0ustar #!/bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the named PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=named pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/named/Install0000775000000000000000000000170012272262501015113 0ustar #!/bin/sh # # Copyright (c) 2012 Red Hat. # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the named PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=named perl_opt=true daemon_opt=false forced_restart=true d="/var/named/data" f="named_stats.txt" if test ! -f "$d/$f" -a ! -f "/var/named/chroot/$d/$f" then echo "named does not appear to be exporting statistics (no $d/$f found)" exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/named/GNUmakefile0000664000000000000000000000234612272262501015640 0ustar #!gmake # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = named PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/named/pmdanamed.pl0000664000000000000000000001324412272262501016050 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; my $pmda = PCP::PMDA->new('named', 100); my @paths = ( '/var/named/chroot/var/named/data', '/var/named/data' ); my $filename = 'named_stats.txt'; my $statscmd = 'rdnc stats'; # writes to $paths/$filename my ( $statsdir, $statsfile ); my $interval = 10; # time (in seconds) between runs of $statscmd my %values; # hash with all values mapped to metric names sub named_update { #$pmda->log('Updating values in named statistics file'); system 'rndc', 'stats'; } # Parser formats (PMDA internal numbering scheme): # 0: not yet known what ondisk format is # 1: bind 8,9.[0-4] (<=rhel5.5) # 2: bind 9.5+ (>=rhel5.6) my $version = 0; sub named_parser { ( undef, $_ ) = @_; #$pmda->log("named_parser got line: $_"); if (m|^\+\+\+ Statistics Dump \+\+\+ \(\d+\)$|) { $version = 1; # all observed formats have this } elsif (m|^\+\+ Incoming Requests \+\+$|) { $version = 2; # but, new format has this also. } if ($version == 2) { if (m|^\s+(\d+) responses sent$|) { $values{'named.nameserver.responses.sent'} = $1; } elsif (m|^\s+(\d+) IPv4 requests received$|) { $values{'named.nameserver.requests.IPv4'} = $1; } elsif (m|^\s+(\d+) queries resulted in successful answer$|) { $values{'named.nameserver.queries.successful'} = $1; } elsif (m|^\s+(\d+) queries resulted in authoritative answer$|) { $values{'named.nameserver.queries.authoritative'} = $1; } elsif (m|^\s+(\d+) queries resulted in non authoritative answer$|) { $values{'named.nameserver.queries.non_authoritative'} = $1; } elsif (m|^\s+(\d+) queries resulted in nxrrset$|) { $values{'named.nameserver.queries.nxrrset'} = $1; } elsif (m|^\s+(\d+) queries resulted in NXDOMAIN$|) { $values{'named.nameserver.queries.nxdomain'} = $1; } elsif (m|^\s+(\d+) queries caused recursion$|) { $values{'named.nameserver.queries.recursion'} = $1; } } elsif ($version == 1) { if (m|^success (\d+)$|) { $values{'named.success'} = $1; } elsif (m|^referral (\d+)$|) { $values{'named.referral'} = $1; } elsif (m|^nxrrset (\d+)$|) { $values{'named.nxrrset'} = $1; } elsif (m|^nxdomain (\d+)$|) { $values{'named.nxdomain'} = $1; } elsif (m|^recursion (\d+)$|) { $values{'named.recursion'} = $1; } elsif (m|^failure (\d+)$|) { $values{'named.failure'} = $1; } } } sub named_metrics { my $id = 0; open STATS, $statsfile || die "Cannot open statistics file: $statsfile\n"; while () { named_parser(undef, $_); } close STATS; $pmda->add_metric(pmda_pmid(0,$id++), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'named.interval', 'Time interval between invocations of rndc stats command', ''); foreach my $key (sort keys %values) { $pmda->add_metric(pmda_pmid(0,$id++), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), $key, '', ''); #$pmda->log("named_metrics adding $key metric"); } } sub named_fetch_callback { my ($cluster, $item, $inst) = @_; if ($inst != PM_IN_NULL) { return (PM_ERR_INST, 0); } if ($cluster != 0) { return (PM_ERR_PMID, 0); } if ($item == 0) { return ($interval, 1); } my $metric_name = pmda_pmid_name($cluster, $item); my $value = $values{$metric_name}; #$pmda->log("named_fetch_callback for $metric_name: $cluster.$item"); return ($value, 1) if (defined($value)); return (PM_ERR_PMID, 0); } # PMDA starts here foreach $statsdir ( @paths ) { $statsfile = $statsdir . '/' . $filename; last if ( -f $statsfile ); } die "Cannot find a valid named statistics file\n" unless -f $statsfile; named_update(); # push some values into the statistics file $pmda->set_fetch_callback(\&named_fetch_callback); $pmda->add_tail($statsfile, \&named_parser, 0); $pmda->add_timer($interval, \&named_update, 0); $pmda->set_user('named'); named_metrics(); # fetch/parse the stats file, create metrics $pmda->run; =pod =head1 NAME pmdanamed - BIND (named) PMDA =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from the BIND DNS server. Further details on BIND can be found at http://isc.org/. =head1 INSTALLATION If you want access to the names and values for the named performance metrics, do the following as root: # cd $PCP_PMDAS_DIR/named # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/named # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item /var/named/data/named_stats.txt statistics file showing values exported from named =item /var/named/chroot/var/named/data/named_stats.txt chroot variant of statistics file showing values exported from named =item $PCP_PMDAS_DIR/named/Install installation script for the B agent =item $PCP_PMDAS_DIR/named/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/named.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1), named.conf(5), named(8). pcp-3.8.12ubuntu1/src/pmdas/postgresql/0000775000000000000000000000000012272262620014702 5ustar pcp-3.8.12ubuntu1/src/pmdas/postgresql/pmdapostgresql.pl0000664000000000000000000015426612272262501020320 0ustar # # Copyright (c) 2011 Nathan Scott. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; use DBI; my $database = 'dbi:Pg:dbname=postgres'; my $username = 'postgres'; my $password = ''; # DBI parameter, typically unused for postgres # Configuration files for overriding the above settings for my $file ( '/etc/pcpdbi.conf', # system defaults (lowest priority) pmda_config('PCP_PMDAS_DIR') . '/postgresql/postgresql.conf', './postgresql.conf' ) { # current directory (high priority) eval `cat $file` unless ! -f $file; } use vars qw( $pmda $dbh ); my $pm_in_null = PM_IN_NULL; my $all_rel_indom = 0; my @all_rel_instances; my $sys_rel_indom = 1; my @sys_rel_instances; my $user_rel_indom = 2; my @user_rel_instances; my $process_indom = 3; my @process_instances; my $function_indom = 4; my @function_instances; my $database_indom = 5; my @database_instances; my $all_index_indom = 6; my @all_index_instances; my $sys_index_indom = 7; my @sys_index_instances; my $user_index_indom = 8; my @user_index_instances; my $all_seq_indom = 9; my @all_seq_instances; my $sys_seq_indom = 10; my @sys_seq_instances; my $user_seq_indom = 11; my @user_seq_instances; my $replicant_indom = 12; my @replicant_instances; # hash of hashes holding DB handle, last values, and min version indexed by table name my %tables_by_name = ( pg_stat_activity => { handle => undef, values => {}, version => undef }, pg_stat_bgwriter => { handle => undef, values => {}, version => undef }, pg_stat_database => { handle => undef, values => {}, version => undef }, pg_stat_database_conflicts => { handle => undef, values => {}, version => 9.1 }, pg_stat_replication => { handle => undef, values => {}, version => 9.1 }, pg_stat_all_tables => { handle => undef, values => {}, version => undef }, pg_stat_sys_tables => { handle => undef, values => {}, version => undef }, pg_stat_user_tables => { handle => undef, values => {}, version => undef }, pg_stat_all_indexes => { handle => undef, values => {}, version => undef }, pg_stat_sys_indexes => { handle => undef, values => {}, version => undef }, pg_stat_user_indexes => { handle => undef, values => {}, version => undef }, pg_statio_all_tables => { handle => undef, values => {}, version => undef }, pg_statio_sys_tables => { handle => undef, values => {}, version => undef }, pg_statio_user_tables => { handle => undef, values => {}, version => undef }, pg_statio_all_indexes => { handle => undef, values => {}, version => undef }, pg_statio_sys_indexes => { handle => undef, values => {}, version => undef }, pg_statio_user_indexes => { handle => undef, values => {}, version => undef }, pg_statio_all_sequences => { handle => undef, values => {}, version => undef }, pg_statio_sys_sequences => { handle => undef, values => {}, version => undef }, pg_statio_user_sequences => { handle => undef, values => {}, version => undef }, pg_stat_user_functions => { handle => undef, values => {}, version => undef }, pg_stat_xact_user_functions => { handle => undef, values => {}, version => 9.1 }, pg_stat_xact_all_tables => { handle => undef, values => {}, version => 9.1 }, pg_stat_xact_sys_tables => { handle => undef, values => {}, version => 9.1 }, pg_stat_xact_user_tables => { handle => undef, values => {}, version => 9.1 }, pg_active => { handle => undef, values => {}, version => undef, sql => 'select pg_is_in_recovery(), pg_current_xlog_location()' }, pg_recovery => { handle => undef, values => {}, version => undef, sql => 'select pg_is_in_recovery(), pg_last_xlog_receive_location(), pg_last_xlog_replay_location()' }, ); # hash of hashes holding setup and refresh function, indexed by PMID cluster my %tables_by_cluster = ( '0' => { name => 'pg_stat_activity', setup => \&setup_activity, indom => $process_indom, refresh => \&refresh_activity }, '1' => { name => 'pg_stat_bgwriter', setup => \&setup_bgwriter, indom => PM_INDOM_NULL, refresh => \&refresh_bgwriter }, '2' => { name => 'pg_stat_database', setup => \&setup_database, indom => $database_indom, refresh => \&refresh_database }, '3' => { name => 'pg_stat_user_functions', setup => \&setup_user_functions, indom => $function_indom, refresh => \&refresh_user_functions }, '4' => { name => 'pg_stat_xact_user_functions', setup => \&setup_xact_user_functions, indom => $function_indom, refresh => \&refresh_user_functions }, # identical refresh routine '5' => { name => 'pg_stat_database_conflicts', setup => \&setup_database_conflicts, indom => $database_indom, refresh => \&refresh_database }, # identical refresh routine '6' => { name => 'pg_stat_replication', setup => \&setup_replication, indom => $replicant_indom, refresh => \&refresh_replication }, '7' => { name => 'pg_active', setup => \&setup_active_functions, indom => PM_INDOM_NULL, refresh => \&refresh_active_functions }, '8' => { name => 'pg_recovery', setup => \&setup_recovery_functions, indom => PM_INDOM_NULL, refresh => \&refresh_recovery_functions }, '10' => { name => 'pg_stat_all_tables', setup => \&setup_stat_tables, indom => $all_rel_indom, params => 'all_tables', refresh => \&refresh_all_tables }, '11' => { name => 'pg_stat_sys_tables', setup => \&setup_stat_tables, indom => $sys_rel_indom, params => 'sys_tables', refresh => \&refresh_sys_tables }, '12' => { name => 'pg_stat_user_tables', setup => \&setup_stat_tables, indom => $user_rel_indom, params => 'user_tables', refresh => \&refresh_user_tables }, '13' => { name => 'pg_stat_all_indexes', setup => \&setup_stat_indexes, indom => $all_index_indom, params => 'all_indexes', refresh => \&refresh_all_indexes }, '14' => { name => 'pg_stat_sys_indexes', setup => \&setup_stat_indexes, params => 'sys_indexes', indom => $sys_index_indom, refresh => \&refresh_sys_indexes }, '15' => { name => 'pg_stat_user_indexes', setup => \&setup_stat_indexes, indom => $user_index_indom, params => 'user_indexes', refresh => \&refresh_user_indexes }, '16' => { name => 'pg_stat_xact_all_tables', setup => \&setup_stat_xact_tables, indom => $all_rel_indom, params => 'all_tables', refresh => \&refresh_xact_all_tables }, '17' => { name => 'pg_stat_xact_sys_tables', setup => \&setup_stat_xact_tables, indom => $sys_rel_indom, params => 'sys_tables', refresh => \&refresh_xact_sys_tables }, '18' => { name => 'pg_stat_xact_user_tables', setup => \&setup_stat_xact_tables, indom => $user_rel_indom, params => 'user_tables', refresh => \&refresh_xact_user_tables }, '30' => { name => 'pg_statio_all_tables', setup => \&setup_statio_tables, indom => $all_rel_indom, params => 'all_tables', refresh => \&refresh_io_all_tables }, '31' => { name => 'pg_statio_sys_tables', setup => \&setup_statio_tables, indom => $sys_rel_indom, params => 'sys_tables', refresh => \&refresh_io_sys_tables }, '32' => { name => 'pg_statio_user_tables', setup => \&setup_statio_tables, indom => $user_rel_indom, params => 'user_tables', refresh => \&refresh_io_user_tables }, '33' => { name => 'pg_statio_all_indexes', setup => \&setup_statio_indexes, indom => $all_index_indom, params => 'all_indexes', refresh => \&refresh_io_all_indexes }, '34' => { name => 'pg_statio_sys_indexes', setup => \&setup_statio_indexes, indom => $sys_index_indom, params => 'sys_indexes', refresh => \&refresh_io_all_indexes }, '35' => { name => 'pg_statio_user_indexes', setup => \&setup_statio_indexes, indom => $user_index_indom, params => 'user_indexes', refresh => \&refresh_io_all_indexes }, '36' => { name => 'pg_statio_all_sequences', setup => \&setup_statio_sequences, indom => $all_seq_indom, params => 'all_sequences', refresh => \&refresh_io_all_sequences }, '37' => { name => 'pg_statio_sys_sequences', setup => \&setup_statio_sequences, indom => $sys_seq_indom, params => 'sys_sequences', refresh => \&refresh_io_sys_sequences }, '38' => { name => 'pg_statio_user_sequences', setup => \&setup_statio_sequences, params => 'user_sequences', indom => $user_seq_indom, refresh => \&refresh_io_user_sequences }, ); sub postgresql_version_query { my $handle = $dbh->prepare("select VERSION()"); if (defined($handle->execute())) { my $result = $handle->fetchall_arrayref(); return 0 unless defined($result); my $version = $result->[0][0]; $version =~ s/^PostgreSQL (\d+\.\d+)\.\d+ .*/$1/g; return $version; } return 0; } sub postgresql_connection_setup { if (!defined($dbh)) { $dbh = DBI->connect($database, $username, $password, {AutoCommit => 1, pg_bool_tf => 0}); if (defined($dbh)) { $pmda->log("PostgreSQL connection established"); my $version = postgresql_version_query(); foreach my $key (keys %tables_by_name) { my $minversion = $tables_by_name{$key}{version}; my $sqlquery = $tables_by_name{$key}{sql}; my $query; $minversion = 0 unless defined($minversion); if ($minversion > $version) { $pmda->log("Skipping table $key, not supported on $version"); } elsif (defined($sqlquery)) { $query = $dbh->prepare($sqlquery); } else { $query = $dbh->prepare("select * from $key"); } $tables_by_name{$key}{handle} = $query unless !defined($query); } } } } sub postgresql_indoms_setup { $all_rel_indom = $pmda->add_indom($all_rel_indom, \@all_rel_instances, 'Instance domain for PostgreSQL relations, all tables', ''); $sys_rel_indom = $pmda->add_indom($sys_rel_indom, \@sys_rel_instances, 'Instance domain for PostgreSQL relations, system tables', ''); $user_rel_indom = $pmda->add_indom($user_rel_indom, \@user_rel_instances, 'Instance domain for PostgreSQL relations, user tables', ''); $function_indom = $pmda->add_indom($function_indom, \@function_instances, 'Instance domain exporting PostgreSQL user functions', ''); $process_indom = $pmda->add_indom($process_indom, \@process_instances, 'Instance domain exporting each PostgreSQL client process', ''); $database_indom = $pmda->add_indom($database_indom, \@database_instances, 'Instance domain exporting each PostgreSQL database', ''); $replicant_indom = $pmda->add_indom($replicant_indom, \@replicant_instances, 'Instance domain exporting PostgreSQL replication processes', ''); $all_index_indom = $pmda->add_indom($all_index_indom, \@all_index_instances, 'Instance domain for PostgreSQL indexes, all tables', ''); $sys_index_indom = $pmda->add_indom($sys_index_indom, \@sys_index_instances, 'Instance domain for PostgreSQL indexes, system tables', ''); $user_index_indom = $pmda->add_indom($user_index_indom, \@user_index_instances, 'Instance domain for PostgreSQL indexes, user tables', ''); $all_seq_indom = $pmda->add_indom($all_seq_indom, \@all_seq_instances, 'Instance domain for PostgreSQL sequences, all tables', ''); $sys_seq_indom = $pmda->add_indom($sys_seq_indom, \@sys_seq_instances, 'Instance domain for PostgreSQL sequences, system tables', ''); $user_seq_indom = $pmda->add_indom($user_seq_indom, \@user_seq_instances, 'Instance domain for PostgreSQL sequences, user tables', ''); } sub postgresql_metrics_setup { foreach my $cluster (sort (keys %tables_by_cluster)) { my $setup = $tables_by_cluster{"$cluster"}{setup}; my $indom = $tables_by_cluster{"$cluster"}{indom}; &$setup($cluster, $indom, $tables_by_cluster{"$cluster"}{params}); } } sub postgresql_refresh { my ($cluster) = @_; my $name = $tables_by_cluster{"$cluster"}{name}; my $refresh = $tables_by_cluster{"$cluster"}{refresh}; &$refresh($tables_by_name{$name}); } sub postgresql_fetch_callback { my ($cluster, $item, $inst) = @_; my $metric_name = pmda_pmid_name($cluster, $item); my ($key, $value, $valueref, @columns ); return (PM_ERR_PMID, 0) unless defined($metric_name); $key = $metric_name; $key =~ s/^postgresql\./pg_/; $key =~ s/\.[a-zA-Z0-9_]*$//; $key =~ s/\./_/g; # $pmda->log("fetch_cb $metric_name $cluster:$item ($inst) - $key"); $valueref = $tables_by_name{$key}{values}{"$inst"}; if (!defined($valueref)) { return (PM_ERR_INST, 0) unless ($inst == PM_IN_NULL); return (PM_ERR_VALUE, 0); } @columns = @$valueref; $value = $columns[$item]; return (PM_ERR_APPVERSION, 0) unless defined($value); return ($value, 1); } # # Refresh routines - one per table (cluster) - format database query # result set for later use by the generic fetch callback routine. # sub refresh_results { my $tableref = shift; my %table = %$tableref; my ( $handle, $valuesref ) = ( $table{handle}, $table{values} ); my %values = %$valuesref; %values = (); # clear any previous values if (defined($dbh) && defined($handle)) { if (defined($handle->execute())) { return $handle->fetchall_arrayref(); } $table{handle} = undef; } return undef; } sub refresh_activity { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @process_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $process_instances[($i*2)] = "$result->[$i][2]"; $tableref = $result->[$i]; $process_instances[($i*2)+1] = "$tableref->[2] $tableref->[5]"; # 9.0 does not have client_hostname, deal with that first splice @$tableref, 7, 0, (undef) unless (@$tableref > 13); # special case needed for 'client_*' columns (6 -> 8), may be null for my $j (6 .. 8) { # for each special case column $tableref->[$j] = '' unless (defined($tableref->[$j])); } $table{values}{$instid} = $tableref; } } $pmda->replace_indom($process_indom, \@process_instances); } sub refresh_replication { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @replicant_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $replicant_instances[($i*2)] = "$result->[$i][2]"; $replicant_instances[($i*2)+1] = "$result->[$i][2] $result->[$i][5]"; # special case needed for 'client_*' columns (4 -> 5) for my $j (4 .. 5) { # for each special case column $result->[$i][$j] = '' unless (defined($result->[$i][$j])); } $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($replicant_indom, \@replicant_instances); } sub refresh_bgwriter { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; $table{values}{"$pm_in_null"} = \@{$result->[0]} unless (!defined($result)); } sub refresh_active_functions { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; # Results from SQL (2 values; 2nd may well contain undef): # select pg_is_in_recovery(), pg_current_xlog_location(), # We need to split out the log identifier and log record offset in the # final value, and save separately into the cached result table. # if (defined($result)) { my $arrayref = $result->[0]; my @values = @$arrayref; my @massaged = ( $values[0], undef,undef ); my $moffset = 1; # index for @massaged array if (defined($values[1])) { my @pieces = split /\//, $values[1]; $massaged[$moffset++] = hex($pieces[0]); $massaged[$moffset++] = hex($pieces[1]); } $table{values}{"$pm_in_null"} = \@massaged; } } sub refresh_recovery_functions { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; # Results from SQL (3 values; 3rd,4th may well contain undef): # select pg_is_in_recovery(), # pg_last_xlog_receive_location(), pg_last_xlog_replay_location() # We need to split out the log identifier and log record offset in the # final values, and save separately into the cached result table. # if (defined($result)) { my $arrayref = $result->[0]; my @values = @$arrayref; my @massaged = ( $values[0], undef,undef, undef,undef ); my $moffset = 1; # index for @massaged array foreach my $voffset (1..2) { # index for @values array if (defined($values[$voffset])) { my @pieces = split /\//, $values[$voffset]; $massaged[$moffset++] = hex($pieces[0]); $massaged[$moffset++] = hex($pieces[1]); } } $table{values}{"$pm_in_null"} = \@massaged; } } sub refresh_database { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @database_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $database_instances[($i*2)] = $result->[$i][0]; $database_instances[($i*2)+1] = $result->[$i][1]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($database_indom, \@database_instances); } sub refresh_user_functions { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @function_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $function_instances[($i*2)] = $result->[$i][0]; $function_instances[($i*2)+1] = $result->[$i][2]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($function_indom, \@function_instances); } sub refresh_all_tables { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @all_rel_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $all_rel_instances[($i*2)] = $result->[$i][0]; $all_rel_instances[($i*2)+1] = $result->[$i][2]; # special case needed for 'last_*' columns (13 -> 16) for my $j (13 .. 16) { # for each special case column $result->[$i][$j] = '' unless (defined($result->[$i][$j])); } $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($all_rel_indom, \@all_rel_instances); } sub refresh_sys_tables { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @sys_rel_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $sys_rel_instances[($i*2)] = $result->[$i][0]; $sys_rel_instances[($i*2)+1] = $result->[$i][2]; # special case needed for 'last_*' columns (13 -> 16) for my $j (13 .. 16) { # for each special case column $result->[$i][$j] = '' unless (defined($result->[$i][$j])); } $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($sys_rel_indom, \@sys_rel_instances); } sub refresh_user_tables { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @user_rel_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $user_rel_instances[($i*2)] = $result->[$i][0]; $user_rel_instances[($i*2)+1] = $result->[$i][2]; # special case needed for 'last_*' columns (13 -> 16) for my $j (13 .. 16) { # for each special case column $result->[$i][$j] = '' unless (defined($result->[$i][$j])); } $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($user_rel_indom, \@user_rel_instances); } sub refresh_xact_all_tables { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @all_rel_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $all_rel_instances[($i*2)] = $result->[$i][0]; $all_rel_instances[($i*2)+1] = $result->[$i][2]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($all_rel_indom, \@all_rel_instances); } sub refresh_xact_sys_tables { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @sys_rel_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $sys_rel_instances[($i*2)] = $result->[$i][0]; $sys_rel_instances[($i*2)+1] = $result->[$i][2]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($sys_rel_indom, \@sys_rel_instances); } sub refresh_xact_user_tables { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @user_rel_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $user_rel_instances[($i*2)] = $result->[$i][0]; $user_rel_instances[($i*2)+1] = $result->[$i][2]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($user_rel_indom, \@user_rel_instances); } sub refresh_all_indexes { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @all_index_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $all_index_instances[($i*2)] = $result->[$i][1]; $all_index_instances[($i*2)+1] = $result->[$i][4]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($all_index_indom, \@all_index_instances); } sub refresh_sys_indexes { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @sys_index_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $sys_index_instances[($i*2)] = $result->[$i][1]; $sys_index_instances[($i*2)+1] = $result->[$i][4]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($sys_index_indom, \@sys_index_instances); } sub refresh_user_indexes { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @user_index_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $user_index_instances[($i*2)] = $result->[$i][1]; $user_index_instances[($i*2)+1] = $result->[$i][4]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($user_index_indom, \@user_index_instances); } sub refresh_io_all_tables { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @all_rel_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $all_rel_instances[($i*2)] = $result->[$i][0]; $all_rel_instances[($i*2)+1] = $result->[$i][2]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($all_rel_indom, \@all_rel_instances); } sub refresh_io_sys_tables { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @sys_rel_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $sys_rel_instances[($i*2)] = $result->[$i][0]; $sys_rel_instances[($i*2)+1] = $result->[$i][2]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($sys_rel_indom, \@sys_rel_instances); } sub refresh_io_user_tables { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @user_rel_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $user_rel_instances[($i*2)] = $result->[$i][0]; $user_rel_instances[($i*2)+1] = $result->[$i][2]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($user_rel_indom, \@user_rel_instances); } sub refresh_io_all_indexes { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @all_index_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $all_index_instances[($i*2)] = $result->[$i][1]; $all_index_instances[($i*2)+1] = $result->[$i][4]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($all_index_indom, \@all_index_instances); } sub refresh_io_sys_indexes { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @sys_index_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $sys_index_instances[($i*2)] = $result->[$i][1]; $sys_index_instances[($i*2)+1] = $result->[$i][4]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($sys_index_indom, \@sys_index_instances); } sub refresh_io_user_indexes { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @user_index_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $user_index_instances[($i*2)] = $result->[$i][1]; $user_index_instances[($i*2)+1] = $result->[$i][4]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($user_index_indom, \@user_index_instances); } sub refresh_io_all_sequences { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @all_seq_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $all_seq_instances[($i*2)] = $result->[$i][0]; $all_seq_instances[($i*2)+1] = $result->[$i][2]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($all_seq_indom, \@all_seq_instances); } sub refresh_io_sys_sequences { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @sys_seq_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $sys_seq_instances[($i*2)] = $result->[$i][0]; $sys_seq_instances[($i*2)+1] = $result->[$i][2]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($sys_seq_indom, \@sys_seq_instances); } sub refresh_io_user_sequences { my $tableref = shift; my $result = refresh_results($tableref); my %table = %$tableref; @user_seq_instances = (); # refresh indom too if (defined($result)) { for my $i (0 .. $#{$result}) { # for each row (instance) returned my $instid = $user_seq_instances[($i*2)] = $result->[$i][0]; $user_seq_instances[($i*2)+1] = $result->[$i][2]; $table{values}{$instid} = $result->[$i]; } } $pmda->replace_indom($user_seq_indom, \@user_seq_instances); } # # Setup routines - one per cluster, add metrics to PMDA # # For help text, see # http://www.postgresql.org/docs/9.2/static/monitoring-stats.html # # and the Postgres Licence: # Portions Copyright (c) 1996-2012, The PostgreSQL Global Development Group # # Portions Copyright (c) 1994, The Regents of the University of California # # Permission to use, copy, modify, and distribute this software # and its documentation for any purpose, without fee, and without a # written agreement is hereby granted, provided that the above copyright # notice and this paragraph and the following two paragraphs appear in # all copies. # # IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY # FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, # INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND # ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE # PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY # OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, # UPDATES, ENHANCEMENTS, OR MODIFICATIONS # sub setup_activity { my ($cluster, $indom) = @_; # indom: procpid + application_name $pmda->add_metric(pmda_pmid($cluster,0), PM_TYPE_U32, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.datid', 'OID of the database this backend is connected to', ''); $pmda->add_metric(pmda_pmid($cluster,1), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.datname', 'Name of the database this backend is connected to', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_U32, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.usesysid', 'OID of the user logged into this backend', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.usename', 'Name of the user logged into this backend', ''); $pmda->add_metric(pmda_pmid($cluster,5), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.application_name', 'Name of the application that is connected to this backend', ''); $pmda->add_metric(pmda_pmid($cluster,6), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.client_addr', 'Client IP address', 'IP address of the client connected to this backend. If this field is null, it indicates either that the client is connected via a Unix socket on the server machine or that this is an internal process such as autovacuum.'); $pmda->add_metric(pmda_pmid($cluster,7), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.client_hostname', 'Host name of the connected client', 'Client host name is derived from reverse DNS lookup of postgresql.stat.activity.client_addr. This field will only be non-null for IP connections, and only when log_hostname is enabled.'); $pmda->add_metric(pmda_pmid($cluster,8), PM_TYPE_U32, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.client_port', 'Client TCP port number', 'TCP port number that the client is using for communication with this backend. Value will be -1 if a Unix socket is used.'); $pmda->add_metric(pmda_pmid($cluster,9), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.backend_start', 'Time when this process was started', 'Time when this client process connected to the server.'); $pmda->add_metric(pmda_pmid($cluster,10), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.xact_start', 'Transaction start time', 'Time when this process' . "'" . ' current transaction was started. The value will be null if no transaction is active. If the current query is the first of its transaction, value is equal to postgresql.stat.activity.query_start.'); $pmda->add_metric(pmda_pmid($cluster,11), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.query_start', 'Query start time', 'Time when the currently active query was started, or if state is not active, when the last query was started'); $pmda->add_metric(pmda_pmid($cluster,12), PM_TYPE_32, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.waiting', 'True if this backend is currently waiting on a lock', ''); $pmda->add_metric(pmda_pmid($cluster,13), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.activity.current_query', 'Most recent query', 'Text of this backend' . "'" . 's most recent query. If state is active this field shows the currently executing query. In all other states, it shows the last query that was executed.'); } sub setup_replication { my ($cluster, $indom) = @_; # indom: procpid + application_name $pmda->add_metric(pmda_pmid($cluster,1), PM_TYPE_U32, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.usesysid', 'OID of the user logged into this WAL sender process', ''); $pmda->add_metric(pmda_pmid($cluster,2), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.usename', 'Name of the user logged into this WAL sender process', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.application_name', 'Name of the application that is connected to this WAL sender', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.client_addr', 'WAL client IP address', 'IP address of the client connected to this WAL sender. If this field is null, it indicates that the client is connected via a Unix socket on the server machine.'); $pmda->add_metric(pmda_pmid($cluster,5), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.client_hostname', 'WAL client host name', 'Host name of the connected client, as reported by a reverse DNS lookup of postgresql.stat.replication.client_addr. This field will only be non-null for IP connections, and only when log_hostname is enabled.'); $pmda->add_metric(pmda_pmid($cluster,6), PM_TYPE_U32, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.client_port', 'WAL client TCP port', 'TCP port number that the client is using for communication with this WAL sender, or -1 if a Unix socket is used.'); $pmda->add_metric(pmda_pmid($cluster,7), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.backend_start', 'Time when when the client connected to this WAL sender', ''); $pmda->add_metric(pmda_pmid($cluster,8), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.state', 'Current WAL sender state', ''); $pmda->add_metric(pmda_pmid($cluster,9), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.sent_location', 'Last transaction log position sent on this connection', ''); $pmda->add_metric(pmda_pmid($cluster,10), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.write_location', 'Last transaction log position written to disk by this standby server', ''); $pmda->add_metric(pmda_pmid($cluster,11), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.flush_location', 'Last transaction log position flushed to disk by this standby server', ''); $pmda->add_metric(pmda_pmid($cluster,12), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.replay_location', 'Last transaction log position replayed into the database on this standby server', ''); $pmda->add_metric(pmda_pmid($cluster,13), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.sync_priority', 'Priority of this standby server for being chosen as the synchronous standby', ''); $pmda->add_metric(pmda_pmid($cluster,14), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.replication.sync_state', 'Synchronous state of this standby server', ''); } sub setup_stat_xact_tables { my ($cluster, $indom, $tables) = @_; # indom: relid + relname $pmda->add_metric(pmda_pmid($cluster,1), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.stat.xact.$tables.schemaname", 'Name of the schema that this table is in', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.xact.$tables.seq_scan", '', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.xact.$tables.seq_tup_read", '', ''); $pmda->add_metric(pmda_pmid($cluster,5), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.xact.$tables.idx_scan", '', ''); $pmda->add_metric(pmda_pmid($cluster,6), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.xact.$tables.idx_tup_fetch", 'Number of rows fetched by queries in this database', ''); $pmda->add_metric(pmda_pmid($cluster,7), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.xact.$tables.n_tup_ins", '', ''); $pmda->add_metric(pmda_pmid($cluster,8), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.xact.$tables.n_tup_upd", '', ''); $pmda->add_metric(pmda_pmid($cluster,9), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.xact.$tables.n_tup_del", '', ''); $pmda->add_metric(pmda_pmid($cluster,10), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.xact.$tables.n_tup_hot_upd", '', ''); } sub setup_stat_tables { my ($cluster, $indom, $tables) = @_; # indom: relid + relname $pmda->add_metric(pmda_pmid($cluster,1), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.schemaname", '', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.seq_scan", '', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.seq_tup_read", '', ''); $pmda->add_metric(pmda_pmid($cluster,5), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.idx_scan", '', ''); $pmda->add_metric(pmda_pmid($cluster,6), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.idx_tup_fetch", '', ''); $pmda->add_metric(pmda_pmid($cluster,7), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.n_tup_ins", '', ''); $pmda->add_metric(pmda_pmid($cluster,8), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.n_tup_upd", '', ''); $pmda->add_metric(pmda_pmid($cluster,9), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.n_tup_del", '', ''); $pmda->add_metric(pmda_pmid($cluster,10), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.n_tup_hot_upd", '', ''); $pmda->add_metric(pmda_pmid($cluster,11), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.n_live_tup", '', ''); $pmda->add_metric(pmda_pmid($cluster,12), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.n_dead_tup", '', ''); $pmda->add_metric(pmda_pmid($cluster,13), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.last_vacuum", '', ''); $pmda->add_metric(pmda_pmid($cluster,14), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.last_autovacuum", '', ''); $pmda->add_metric(pmda_pmid($cluster,15), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.last_analyze", '', ''); $pmda->add_metric(pmda_pmid($cluster,16), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.stat.$tables.last_autoanalyze", '', ''); } sub setup_bgwriter { my ($cluster, $indom) = @_; $pmda->add_metric(pmda_pmid($cluster,0), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.bgwriter.checkpoints_timed', '', ''); $pmda->add_metric(pmda_pmid($cluster,1), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.bgwriter.checkpoints_req', '', ''); $pmda->add_metric(pmda_pmid($cluster,2), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.bgwriter.buffers_checkpoints', '', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.bgwriter.buffers_clean', '', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.bgwriter.maxwritten_clean', '', ''); $pmda->add_metric(pmda_pmid($cluster,5), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.bgwriter.buffers_backend', '', ''); $pmda->add_metric(pmda_pmid($cluster,6), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.bgwriter.buffers_alloc', '', ''); } sub setup_active_functions { my ($cluster, $indom) = @_; $pmda->add_metric(pmda_pmid($cluster,0), PM_TYPE_U32, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.active.is_in_recovery', '', ''); $pmda->add_metric(pmda_pmid($cluster,1), PM_TYPE_U64, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.active.xlog_current_location_log_id', '', ''); $pmda->add_metric(pmda_pmid($cluster,2), PM_TYPE_U64, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.active.xlog_current_location_offset', '', ''); } sub setup_recovery_functions { my ($cluster, $indom) = @_; $pmda->add_metric(pmda_pmid($cluster,0), PM_TYPE_U32, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.recovery.is_in_recovery', '', ''); $pmda->add_metric(pmda_pmid($cluster,1), PM_TYPE_U64, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.recovery.xlog_receive_location_log_id', '', ''); $pmda->add_metric(pmda_pmid($cluster,2), PM_TYPE_U64, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.recovery.xlog_receive_location_offset', '', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_U64, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.recovery.xlog_replay_location_log_id', '', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_U64, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.recovery.xlog_replay_location_offset', '', ''); } sub setup_database_conflicts { my ($cluster, $indom) = @_; # indom: datid + datname $pmda->add_metric(pmda_pmid($cluster,2), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database_conflicts.tablespace', '', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database_conflicts.lock', '', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database_conflicts.snapshot', '', ''); $pmda->add_metric(pmda_pmid($cluster,5), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database_conflicts.bufferpin', '', ''); $pmda->add_metric(pmda_pmid($cluster,6), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database_conflicts.deadlock', '', ''); } sub setup_database { my ($cluster, $indom) = @_; # indom: datid + datname $pmda->add_metric(pmda_pmid($cluster,2), PM_TYPE_U32, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.database.numbackends', '', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database.xact_commit', '', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database.xact_rollback', '', ''); $pmda->add_metric(pmda_pmid($cluster,5), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database.blks_read', '', ''); $pmda->add_metric(pmda_pmid($cluster,6), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database.blks_hit', '', ''); $pmda->add_metric(pmda_pmid($cluster,7), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database.tup_returned', '', ''); $pmda->add_metric(pmda_pmid($cluster,8), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database.tup_fetched', '', ''); $pmda->add_metric(pmda_pmid($cluster,9), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database.tup_inserted', '', ''); $pmda->add_metric(pmda_pmid($cluster,10), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database.tup_updated', '', ''); $pmda->add_metric(pmda_pmid($cluster,11), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database.tup_deleted', '', ''); $pmda->add_metric(pmda_pmid($cluster,12), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'postgresql.stat.database.conflicts', '', ''); $pmda->add_metric(pmda_pmid($cluster,13), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.database.stats_reset', '', ''); } sub setup_stat_indexes { my ($cluster, $indom, $indexes) = @_; $pmda->add_metric(pmda_pmid($cluster,0), PM_TYPE_32, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.stat.$indexes.relid", '', ''); $pmda->add_metric(pmda_pmid($cluster,2), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.stat.$indexes.schemaname", '', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.stat.$indexes.relname", '', ''); $pmda->add_metric(pmda_pmid($cluster,5), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.stat.$indexes.idx_scan", '', ''); $pmda->add_metric(pmda_pmid($cluster,6), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.stat.$indexes.idx_tup_read", '', ''); $pmda->add_metric(pmda_pmid($cluster,7), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.stat.$indexes.idx_tup_fetch", '', ''); } sub setup_statio_tables { my ($cluster, $indom, $tables) = @_; $pmda->add_metric(pmda_pmid($cluster,1), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.statio.$tables.schemaname", '', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.statio.$tables.heap_blks_read", '', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.statio.$tables.heap_blks_hit", '', ''); $pmda->add_metric(pmda_pmid($cluster,5), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.statio.$tables.idx_blks_read", '', ''); $pmda->add_metric(pmda_pmid($cluster,6), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.statio.$tables.idx_blks_hit", '', ''); $pmda->add_metric(pmda_pmid($cluster,7), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.statio.$tables.toast_blks_read", '', ''); $pmda->add_metric(pmda_pmid($cluster,8), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.statio.$tables.toast_blks_hit", '', ''); $pmda->add_metric(pmda_pmid($cluster,9), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.statio.$tables.tidx_blks_read", '', ''); $pmda->add_metric(pmda_pmid($cluster,10), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.statio.$tables.tidx_blks_hit", '', ''); } sub setup_statio_indexes { my ($cluster, $indom, $indexes) = @_; # indom: indexrelid + indexrelname $pmda->add_metric(pmda_pmid($cluster,0), PM_TYPE_32, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.statio.$indexes.relid", '', ''); $pmda->add_metric(pmda_pmid($cluster,2), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.statio.$indexes.schemaname", '', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.statio.$indexes.relname", '', ''); $pmda->add_metric(pmda_pmid($cluster,5), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.statio.$indexes.idx_blks_read", '', ''); $pmda->add_metric(pmda_pmid($cluster,6), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.statio.$indexes.idx_blks_hit", '', ''); } sub setup_statio_sequences { my ($cluster, $indom, $sequences) = @_; # indom: relid + relname $pmda->add_metric(pmda_pmid($cluster,1), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), "postgresql.statio.$sequences.schemaname", '', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.statio.$sequences.blks_read", '', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_U32, $indom, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), "postgresql.statio.$sequences.blks_hit", '', ''); } sub setup_xact_user_functions { my ($cluster, $indom) = @_; # indom: funcid + funcname $pmda->add_metric(pmda_pmid($cluster,1), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.xact.user_functions.schemaname', '', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_U64, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), 'postgresql.stat.xact.user_functions.calls', '', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_U64, $indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'postgresql.stat.xact.user_functions.total_time', '', ''); $pmda->add_metric(pmda_pmid($cluster,5), PM_TYPE_U64, $indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'postgresql.stat.xact.user_functions.self_time', '', ''); } sub setup_user_functions { my ($cluster, $indom) = @_; # indom: funcid + funcname $pmda->add_metric(pmda_pmid($cluster,1), PM_TYPE_STRING, $indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'postgresql.stat.user_functions.schemaname', '', ''); $pmda->add_metric(pmda_pmid($cluster,3), PM_TYPE_U64, $indom, PM_SEM_COUNTER, pmda_units(0,0,0,0,0,0), 'postgresql.stat.user_functions.calls', '', ''); $pmda->add_metric(pmda_pmid($cluster,4), PM_TYPE_U64, $indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'postgresql.stat.user_functions.total_time', '', ''); $pmda->add_metric(pmda_pmid($cluster,5), PM_TYPE_U64, $indom, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_MSEC,0), 'postgresql.stat.user_functions.self_time', '', ''); } # # Main PMDA thread of execution starts here - setup metrics and callbacks # drop root priveleges, then call PMDA 'run' routine to talk to pmcd. # $pmda = PCP::PMDA->new('postgresql', 110); postgresql_metrics_setup(); postgresql_indoms_setup(); $pmda->set_fetch_callback(\&postgresql_fetch_callback); $pmda->set_fetch(\&postgresql_connection_setup); $pmda->set_refresh(\&postgresql_refresh); $pmda->set_user('postgres'); $pmda->run; =pod =head1 NAME pmdapostgresql - PostgreSQL database PMDA =head1 DESCRIPTION B is a Performance Co-Pilot PMDA which extracts live performance data from a running PostgreSQL database. =head1 INSTALLATION B uses a configuration file from (in this order): =over =item * /etc/pcpdbi.conf =item * $PCP_PMDAS_DIR/postgresql/postgresql.conf =back This file can contain overridden values (Perl code) for the settings listed at the start of pmdapostgresql.pl, namely: =over =item * database name (see DBI(3) for details) =item * database username =back Once this is setup, you can access the names and values for the postgresql performance metrics by doing the following as root: # cd $PCP_PMDAS_DIR/postgresql # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/postgresql # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item /etc/pcpdbi.conf configuration file for all PCP database monitors =item $PCP_PMDAS_DIR/postgresql/postgresql.conf configuration file for B =item $PCP_PMDAS_DIR/postgresql/Install installation script for the B agent =item $PCP_PMDAS_DIR/postgresql/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/postgresql.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1), pmdadbping.pl(1) and DBI(3). pcp-3.8.12ubuntu1/src/pmdas/postgresql/Remove0000775000000000000000000000127012272262501016063 0ustar #! /bin/sh # # Copyright (c) 2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the PostgreSQL PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=postgresql pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/postgresql/Install0000775000000000000000000000176212272262501016242 0ustar #! /bin/sh # # Copyright (c) 2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the PostgreSQL PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=postgresql perl_opt=true daemon_opt=false forced_restart=true perl -e "use DBI" 2>/dev/null if test $? -ne 0; then echo "Perl database interface (DBI) is not installed" exit 1 fi perl -e "use DBD::Pg" 2>/dev/null if test $? -ne 0; then echo "Postgres database driver (DBD::Pg) is not installed" exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/postgresql/pmlogconf.summary0000664000000000000000000000041012272262501020276 0ustar #pmlogconf-setup 2.0 ident postgresql summary information probe postgresql.stat.all_tables.seq_scan ? include : exclude postgresql.stat.database postgresql.stat.all_tables postgresql.stat.all_indexes postgresql.statio.all_tables postgresql.statio.all_indexes pcp-3.8.12ubuntu1/src/pmdas/postgresql/GNUmakefile0000664000000000000000000000262112272262501016753 0ustar #!gmake # # Copyright (c) 2011 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = postgresql PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl pmlogconf.summary ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif LDIRT = domain.h root pmns *.log $(MAN_PAGES) default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) $(INSTALL) -m 755 -d $(PCP_VAR_DIR)/config/pmlogconf/$(IAM) $(INSTALL) -m 644 pmlogconf.summary $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)/summary default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/trace/0000775000000000000000000000000012272262620013575 5ustar pcp-3.8.12ubuntu1/src/pmdas/trace/app3.c0000664000000000000000000001050312272262501014601 0ustar /* * Copyright (c) 1997-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * app3.c * * Parallel program to demonstrate use of the PCP trace performance metrics * domain agent (PMDA(3)). This agent needs to be installed before metrics * can be made available via the performance metrics namespace (PMNS(4)), * and the Performance Metrics Collector Daemon (PMCD(1)). * * Once this program is running, the trace PMDA metrics & instances can be * viewed through PCP monitor tools such as pmchart(1), pmgadgets(1), and * pmview(1). To view the help text associated with each of these metrics, * use: * $ pminfo -tT trace */ #include #include #include #include #include #include #include #include #include #define IO_UPPER_LIMIT 1000 /* I/O ops */ #define CPU_UPPER_LIMIT 0xffff /* iterations */ #define TIME_UPPER_LIMIT 10 /* seconds */ static void * pio_sucker(void *); static void * pcpu_sucker(void *); static void * ptime_sucker(void *); static char *prog; int main(int argc, char **argv) { int i; pthread_t p[3]; prog = argv[0]; pthread_create(p, NULL, pio_sucker, NULL); pthread_create(p+1, NULL, pcpu_sucker, NULL); pthread_create(p+2, NULL, ptime_sucker, NULL); for (i=0; i < 3; i++) { wait(NULL); fprintf(stderr, "%s: reaped sproc #%d\n", prog, i); } exit(0); } static void * pcpu_sucker(void *dummy) { int i, j, loops, sts; double array[100]; long iterations; for (loops = 0; loops < 10; loops++) { if ((sts = pmtracebegin("pcpu_sucker")) < 0) { fprintf(stderr, "%s: pcpu_sucker begin (%d): %s\n", prog, sts, pmtraceerrstr(sts)); return NULL; } iterations = lrand48() % CPU_UPPER_LIMIT; memset((void *)array, 0, 100*sizeof(double)); for (i = 0; i < iterations; i++) for (j = 0; j < 100; j++) array[j] = (double)(j*iterations); if ((sts = pmtraceend("pcpu_sucker")) < 0) { fprintf(stderr, "%s: pcpu_sucker end (%d): %s\n", prog, sts, pmtraceerrstr(sts)); return NULL; } } fprintf(stderr, "%s: finished %d cpu-bound iterations.\n", prog, loops); return NULL; } static void * ptime_sucker(void *dummy) { long seconds; int loops, sts; for (loops = 0; loops < 10; loops++) { if ((sts = pmtracebegin("ptime_sucker")) < 0) { fprintf(stderr, "%s: ptime_sucker start (%d): %s\n", prog, sts, pmtraceerrstr(sts)); return NULL; } seconds = lrand48() % TIME_UPPER_LIMIT; sleep((unsigned int)seconds); if ((sts = pmtraceend("ptime_sucker")) < 0) { fprintf(stderr, "%s: ptime_sucker end (%d): %s\n", prog, sts, pmtraceerrstr(sts)); return NULL; } } fprintf(stderr, "%s: finished %d timer iterations.\n", prog, loops); return NULL; } static void * pio_sucker(void *dummy) { long characters; FILE *foo; int i, loops, sts; for (loops = 0; loops < 10; loops++) { if ((sts = pmtracebegin("pio_sucker")) < 0) { fprintf(stderr, "%s: pio_sucker start (%d): %s\n", prog, sts, pmtraceerrstr(sts)); return NULL; } if ((foo = fopen("/dev/null", "rw")) == NULL) { fprintf(stderr, "%s: pio_sucker can't open /dev/null.\n", prog); return NULL; } characters = lrand48() % IO_UPPER_LIMIT; for (i = 0; i < characters; i++) { fgetc(foo); fputc('!', foo); } fclose(foo); if ((sts = pmtraceend("pio_sucker")) < 0) { fprintf(stderr, "%s: pio_sucker end (%d): %s\n", prog, sts, pmtraceerrstr(sts)); return NULL; } } fprintf(stderr, "%s: finished %d io-bound iterations.\n", prog, loops); return NULL; } pcp-3.8.12ubuntu1/src/pmdas/trace/app1.c0000664000000000000000000000547612272262501014614 0ustar /* * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * app1.c * * Simple program to demonstrate use of the PCP trace performance metrics * domain agent (PMDA(3)). This agent needs to be installed before metrics * can be made available via the performance metrics namespace (PMNS(4)), * and the Performance Metrics Collector Daemon (PMCD(1)). * * Once this program is running, the trace PMDA metrics & instances can be * viewed through PCP monitor tools such as pmchart(1), pmgadgets(1), and * pmview(1). To view the help text associated with each of these metrics, * use: * $ pminfo -tT trace */ #include #include #include #include int main(int argc, char **argv) { int sts; char *prog; prog = argv[0]; sts = pmtracestate(PMTRACE_STATE_API|PMTRACE_STATE_COMMS|PMTRACE_STATE_PDU); fprintf(stderr, "%s: start: %s (state=0x%x)\n", prog, pmtraceerrstr(0), sts); /* force call to all library symbols */ if ((sts = pmtracebegin("simple")) < 0) { fprintf(stderr, "%s: pmtracebegin error: %s\n", prog, pmtraceerrstr(sts)); exit(1); } if (sleep(2) != 0) { fprintf(stderr, "%s: sleep prematurely awaken\n", prog); pmtraceabort("simple"); } if ((sts = pmtraceend("simple")) < 0) { fprintf(stderr, "%s: pmtraceend error: %s\n", prog, pmtraceerrstr(sts)); exit(1); } if ((sts = pmtracebegin("ascanbe")) < 0) { fprintf(stderr, "%s: pmtracebegin error: %s\n", prog, pmtraceerrstr(sts)); exit(1); } sleep(1); if ((sts = pmtraceend("ascanbe")) < 0) { fprintf(stderr, "%s: pmtraceend error: %s\n", prog, pmtraceerrstr(sts)); exit(1); } if ((sts = pmtraceobs("observe", 101.0)) < 0) { fprintf(stderr, "%s: pmtraceobs error: %s\n", prog, pmtraceerrstr(sts)); exit(1); } if ((sts = pmtracecounter("counter", 101.1)) < 0) { fprintf(stderr, "%s: pmtracecounter error: %s\n", prog, pmtraceerrstr(sts)); exit(1); } if ((sts = pmtracepoint("imouttahere")) < 0) { fprintf(stderr, "%s: pmtracepoint error: %s\n", prog, pmtraceerrstr(sts)); exit(1); } exit(0); } pcp-3.8.12ubuntu1/src/pmdas/trace/fapp1.f0000664000000000000000000000611012272262501014747 0ustar program fapp1 C Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. C C This program is free software; you can redistribute it and/or modify it C under the terms of the GNU General Public License as published by the C Free Software Foundation; either version 2 of the License, or (at your C option) any later version. C C This program is distributed in the hope that it will be useful, but C WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY C or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License C for more details. C C You should have received a copy of the GNU General Public License along C with this program; if not, write to the Free Software Foundation, Inc., C 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA C fapp1.f C C Simple program to demonstrate use of the PCP trace performance metrics C domain agent (PMDA(3)). This agent needs to be installed before metrics C can be made available via the performance metrics namespace (PMNS(4)), C and the Performance Metrics Collector Daemon (PMCD(1)). C C Once this program is running, the trace PMDA metrics & instances can be C viewed through PCP monitor tools such as pmchart(1), pmgadgets(1), and C pmview(1). To view the help text associated with each of these metrics, C use: C $ pminfo -tT trace C C The pmtracestate constants are defined in /usr/include/pcp/trace.h C external pmtracebegin, pmtraceend, pmtracepoint, pmtraceerrstr, pmtracestate integer pmtracebegin, pmtraceend, pmtracepoint integer sts integer debug character*5 prog character*40 emesg real*8 value integer dbg_noagent, dbg_api, dbg_comms, dbg_pdu parameter (dbg_noagent = 1, dbg_api = 2, dbg_comms = 4, dbg_pdu = 8) prog='fapp1' C Addition below is the equivalent to the C 'logical or' operator as C trace API constants are all disjoint and the high bit is never set. debug = (dbg_api + dbg_comms + dbg_pdu) call pmtracestate(debug) sts = pmtracebegin('simple') if (sts .lt. 0) then call pmtraceerrstr(sts, emesg) print *,prog,': pmtracebegin error: ',emesg stop 1 endif call sleep(2) sts = pmtraceend('simple') if (sts .lt. 0) then call pmtraceerrstr(sts, emesg) print *,prog,': pmtraceend error: ',emesg stop 1 endif sts = pmtracebegin('ascanbe') if (sts .lt. 0) then call pmtraceerrstr(sts, emesg) print *,prog,': pmtracebegin error: ',emesg stop 1 endif call sleep(1) sts = pmtraceend('ascanbe') if (sts .lt. 0) then call pmtraceerrstr(sts, emesg) print *,prog,': pmtraceend error: ',emesg stop 1 endif sts = pmtracepoint('imouttahere') if (sts .lt. 0) then call pmtraceerrstr(sts, emesg) print *,prog,': pmtracepoint error: ',emesg stop 1 endif value = 340.5 sts = pmtraceobs('end point', value) if (sts .lt. 0) then call pmtraceerrstr(sts, emesg) print *,prog,': pmtraceobs error: ',emesg stop 1 endif value = 340.6 sts = pmtracecounter('new end point', value) if (sts .lt. 0) then call pmtraceerrstr(sts, emesg) print *,prog,': pmtracecounter error: ',emesg stop 1 endif end pcp-3.8.12ubuntu1/src/pmdas/trace/README0000664000000000000000000000330512272262501014454 0ustar Trace PMDA ========== This PMDA exports application-level transaction and event statistics. The PMDA needs to be used in conjunction with the pcp_trace library, which provides the pmtracebegin, pmtraceend, pmtracepoint, ... functions to user-level programs. For information about the use of the pcp_trace dynamic library and its function call interface, see pmdatrace(1) and pmdatrace(3). Also, the example programs - $PCP_VAR_DIR/demos/trace/*.c are useful as starting points. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT trace Installation ============ + # cd $PCP_PMDAS_DIR/trace + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options. If you choose the "default" installation, appropriate values will be assigned to those parameters that control the customization of the PMDA. Otherwise consult the pmdatrace(1) man page for a description of the customization parameters. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/trace # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/trace.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/trace/README.demos0000664000000000000000000000406612272262501015567 0ustar sample pcp_trace applications ============================= pmtrace is a sample application that uses the pcp_trace interface to send trace data to the trace PMDA (Performance Metrics Domain Agent). The binary is shipped as part of pcp and should be installed in $PCP_BIN_DIR/pmtrace. A pmtrace(1) man page is available. The source is shipped as part of pcp as well and is installed in $PCP_DEMOS_DIR/trace. If you have the C compiler installed, the source and Makefile in this directory may be used to create a functionally equivalent binary, simply by entering the command % make pmtrace The source in pmtrace.c demonstrates many of the trace services. The C interface ( pmtrace.c, app1.c, app2.c, and app3.c ) =============== The default Makefile rules build the C applications only, so these applications can be built simply by using the command % make The Fortran Interface ( fapp1.f ) ===================== To build the sample Fortran program, using either the f77 or f90 compilers, use one of these commands % make fortran77 % make fortran90 The Java Interface ( japp1.java ) ================== To build the sample Java program, and provided you have the java compiler installed, use the command % make java Setting the environment variable $CLASSPATH to include the full path to the trace.class file (/usr/java/classes/com/sgi/pcp) allows the application to compile and run successfuly. To run the demo application, after compilation type % java japp1 which passes the compiled class file into the java interpreter for subsequent execution. The pcp_trace "stub" library ============================ To ensure that applications linked with the pcp_trace library are not locked into being SGI-specific, a "stub" library which has all of the pcp_trace entry points defined and simple debug switching enabled, is provided (stub.c). This shared library can be built using % make -f Makefile.stub and is intended to be simple to port to other platforms. Related manual pages ==================== pmdatrace(1), pmtrace(1), and pmdatrace(3). pcp-3.8.12ubuntu1/src/pmdas/trace/Makefile.proto0000664000000000000000000000300212272262501016370 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # SHELL = /bin/sh CC = cc JC = javac F77C = f77 F90C = f90 TARGETS = app1 app2 app3 fapp1.f77 fapp1.f90 pmtrace japp1.class CDEMOS = app1 app2 app3 pmtrace F77DEMO = fapp1.f77 F90DEMO = fapp1.f90 JDEMO = japp1.class CFLAGS = -DPMTRACE_DEBUG -I$(PCP_INC_DIR) FFLAGS = JFLAGS = default: $(CDEMOS) fortran77: $(F77DEMO) fortran90: $(F90DEMO) java: $(JDEMO) pmtrace: pmtrace.c rm -f $@ $(CC) $(CFLAGS) -o $@ pmtrace.c -lpcp -lpcp_trace app1: app1.c rm -f $@ $(CC) $(CFLAGS) -o $@ app1.c -lpcp -lpcp_trace app2: app2.c rm -f $@ $(CC) $(CFLAGS) -o $@ app2.c -lpcp -lpcp_trace app3: app3.c rm -f $@ $(CC) $(CFLAGS) -o $@ app3.c -lpcp -lpcp_trace PTHREAD_LIB DLOPEN_LIB MATH_LIB fapp1.77: fapp1.f rm -f $@ $(F77C) $(FFLAGS) -o $@ fapp1.f -lpcp -lpcp_trace fapp1.90: fapp1.f rm -f $@ $(F90C) $(FFLAGS) -o $@ fapp1.f -lpcp -lpcp_trace japp1.class: japp1.java rm -f $@ $(JC) $(JFLAGS) japp1.java clean: rm -f *.o clobber: clean rm -f $(TARGETS) pcp-3.8.12ubuntu1/src/pmdas/trace/Remove0000664000000000000000000000200712272262501014752 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the Trace PMDA # # Get standard environment . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=trace # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/trace/stub.c0000664000000000000000000000640012272262501014714 0ustar /* * stub.c - libpcp_trace stubs * * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include int __pmstate = 0; int pmtracebegin(const char *tag) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtracebegin: start of transaction '%s'\n", tag); #endif return 0; } int pmtraceend(const char *tag) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtraceend: end of transaction '%s'\n", tag); #endif return 0; } int pmtraceabort(const char *tag) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtraceabort: transaction '%s' aborted\n", tag); #endif return 0; } int pmtraceobs(const char *label, double value) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtraceobs: observation '%s', value=%f\n", label, value); #endif return 0; } int pmtracecounter(const char *label, double value) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtracecounter: counter '%s', value=%f\n", label, value); #endif return 0; } int pmtracepoint(const char *label) { #ifdef PMTRACE_DEBUG if (__pmstate & PMTRACE_STATE_API) fprintf(stderr, "pmtracepoint: trace point '%s' reached\n", label); #endif return 0; } int pmtracestate(int code) { return(__pmstate |= code); } char * pmtraceerrstr(int code) { static const struct { int code; char *msg; } errtab[] = { { PMTRACE_ERR_TAGNAME, "Invalid tag name - tag names cannot be NULL" }, { PMTRACE_ERR_INPROGRESS, "Transaction is already in progress - cannot begin" }, { PMTRACE_ERR_NOPROGRESS, "Transaction is not currently in progress - cannot end" }, { PMTRACE_ERR_NOSUCHTAG, "Transaction tag was not successfully initialised" }, { PMTRACE_ERR_TAGTYPE, "Tag is already in use for a different type of tracing" }, { PMTRACE_ERR_TAGLENGTH, "Tag name is too long (maximum 256 characters)" }, { PMTRACE_ERR_IPC, "IPC protocol failure" }, { PMTRACE_ERR_ENVFORMAT, "Unrecognised environment variable format" }, { PMTRACE_ERR_TIMEOUT, "Application timed out connecting to the PMDA" }, { PMTRACE_ERR_VERSION, "Incompatible versions between application and PMDA" }, { PMTRACE_ERR_PERMISSION, "Cannot connect to PMDA - permission denied" }, { PMTRACE_ERR_CONNLIMIT, "Cannot connect to PMDA - connection limit reached" }, { 0, "" } }; if ((code < 0) && (code > -PMTRACE_ERR_BASE)) /* catch intro(2) errors */ return strerror(-code); else if (code == 0) return "No error"; else { int i; for (i=0; errtab[i].code; i++) { if (errtab[i].code == code) return errtab[i].msg; } } return "Unknown error code"; } pcp-3.8.12ubuntu1/src/pmdas/trace/Install0000664000000000000000000001520412272262501015126 0ustar #! /bin/sh # # Copyright (c) 1997,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the Trace PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=trace pmda_interface=2 forced_restart=false # Override interactive dialog from pmdaSetup in pmdaproc.sh # __choose_mode() { echo "Installing the \"$iam\" Performance Metrics Domain Agent (PMDA) ..." echo } numeric=0 getnumeric() { if [ "X$2" = "X" ] then numeric=0 elif [ "X`expr 0 + $2 2>/dev/null`" != "X$2" ] then echo "-- Sorry, $1 must be numeric (not $2) --" return 1 else numeric=$2 fi return 0 } getunits() { metric_name=$1 option_name=$2 # Default dimension and scale values # dimspace=0 dimtime=0 dimcount=0 scalespace=0 scaletime=0 scalecount=0 cat - </dev/null [ $? -ne 1 -a $numeric -ne 0 ] && args="-T $numeric" echo $PCP_ECHO_PROG $PCP_ECHO_N "Number of buckets [5]? ""$PCP_ECHO_C" read value getnumeric 'Number of buckets' $value >/dev/null [ $? -ne 1 -a $numeric -ne 0 ] && args="$args -N $numeric" echo $PCP_ECHO_PROG $PCP_ECHO_N "Port number for client connections [4323]? ""$PCP_ECHO_C" read value getnumeric 'Port number' $value >/dev/null [ $? -ne 1 -a $numeric -ne 0 ] && args="$args -I $numeric" getunits trace.observe.value -U getunits trace.counter.value -V while true do access="" echo $PCP_ECHO_PROG $PCP_ECHO_N "Client host access - (A)llow/(D)isallow [Enter to complete install]? ""$PCP_ECHO_C" read access access=`echo $access | tr -d ' '` [ "X$access" = "X" ] && break case $access in A|a|Allow|allow) echo $PCP_ECHO_PROG $PCP_ECHO_N "Host specification (IP mask/Enter to cancel): ""$PCP_ECHO_C" read access access=`echo $access | tr -d ' '` if [ "X$access" != "X" ] then maxconns="" echo $PCP_ECHO_PROG $PCP_ECHO_N "Maximum number of connections from $access (Enter for no limit): ""$PCP_ECHO_C" read maxconns maxconns=`echo $maxconns | tr -d ' '` [ "X$maxconns" = "X" ] && maxconns=0 args="$args"" -A ""allow:$access:$maxconns" fi;; D|d|Disallow|disallow) echo $PCP_ECHO_PROG $PCP_ECHO_N "Host specification (IP mask/Enter to cancel): ""$PCP_ECHO_C" read access access=`echo $access | tr -d ' '` [ "X$access" != "X" ] && args="$args"" -A ""disallow:$access";; *) echo 'Try again, "'$access'" not supported.';; esac done echo fi # for debugging the PMDA, uncomment this line ... # #args="-D appl0,appl1,pdu $args" # Do it ... # pmdaInstall echo Note: some warnings are expected until trace API calls are made - refer to echo " the man pages for pmtrace(1) and pmdatrace(3) for further details." exit 0 pcp-3.8.12ubuntu1/src/pmdas/trace/src/0000775000000000000000000000000012272262620014364 5ustar pcp-3.8.12ubuntu1/src/pmdas/trace/src/trace.c0000664000000000000000000010343712272262501015634 0ustar /* * Copyright (c) 1997-2000 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include "data.h" #include "trace_dev.h" static pmdaIndom indomtab[] = { /* list of trace metric instance domains */ #define TRANSACT_INDOM 0 { TRANSACT_INDOM, 0, NULL }, /* dynamically updated */ #define POINT_INDOM 1 { POINT_INDOM, 0, NULL }, /* dynamically updated */ #define OBSERVE_INDOM 2 { OBSERVE_INDOM, 0, NULL }, /* dynamically updated */ #define COUNTER_INDOM 3 { COUNTER_INDOM, 0, NULL }, /* dynamically updated */ }; static int transacts; /* next instance# to allocate */ static int points; /* next instance# to allocate */ static int counters; /* next instance# to allocate */ static int observes; /* next instance# to allocate */ static int tsortflag; /* need sort on next request? */ static int psortflag; /* need sort on next request? */ static int csortflag; /* need sort on next request? */ static int osortflag; /* need sort on next request? */ /* all metrics supported in this PMDA - one table entry for each */ static pmdaMetric metrictab[] = { /* transact.count */ { NULL, { PMDA_PMID(0,0), PM_TYPE_U64, TRANSACT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1, 0,0,PM_COUNT_ONE)} }, /* transact.rate */ { NULL, { PMDA_PMID(0,1), PM_TYPE_FLOAT, TRANSACT_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,-1,1, 0,PM_TIME_SEC,PM_COUNT_ONE)} }, /* transact.ave_time */ { NULL, { PMDA_PMID(0,2), PM_TYPE_FLOAT, TRANSACT_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,-1, 0,PM_TIME_SEC,PM_COUNT_ONE)} }, /* transact.min_time */ { NULL, { PMDA_PMID(0,3), PM_TYPE_FLOAT, TRANSACT_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0, 0,PM_TIME_SEC,0)} }, /* transact.max_time */ { NULL, { PMDA_PMID(0,4), PM_TYPE_FLOAT, TRANSACT_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0, 0,PM_TIME_SEC,0)} }, /* transact.total_time */ { NULL, { PMDA_PMID(0,5), PM_TYPE_DOUBLE, TRANSACT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0, 0,PM_TIME_SEC,0)} }, /* point.count */ { NULL, { PMDA_PMID(0,6), PM_TYPE_U64, POINT_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1, 0,0,PM_COUNT_ONE)} }, /* point.rate */ { NULL, { PMDA_PMID(0,7), PM_TYPE_FLOAT, POINT_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,-1,1, 0,PM_TIME_SEC,PM_COUNT_ONE)} }, /* observe.count */ { NULL, { PMDA_PMID(0,8), PM_TYPE_U64, OBSERVE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1, 0,0,PM_COUNT_ONE)} }, /* observe.rate */ { NULL, { PMDA_PMID(0,9), PM_TYPE_FLOAT, OBSERVE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,-1,1, 0,PM_TIME_SEC,PM_COUNT_ONE)} }, /* observe.value */ { NULL, { PMDA_PMID(0,10), PM_TYPE_DOUBLE, OBSERVE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0, 0,0,0)} }, /* this may be modified at startup */ /* control.timespan */ { NULL, { PMDA_PMID(0,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,1,0, 0,PM_TIME_SEC,0)} }, /* control.interval */ { NULL, { PMDA_PMID(0,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,1,0, 0,PM_TIME_SEC,0)} }, /* control.buckets */ { NULL, { PMDA_PMID(0,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0, 0,0,0)} }, /* control.port */ { NULL, { PMDA_PMID(0,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0, 0,0,0)} }, /* control.reset */ { NULL, { PMDA_PMID(0,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0, 0,0,0)} }, /* control.debug */ { NULL, { PMDA_PMID(0,16), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0, 0,0,0) }, }, /* counter.count */ { NULL, { PMDA_PMID(0,17), PM_TYPE_U64, COUNTER_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1, 0,0,PM_COUNT_ONE) }, }, /* counter.rate */ { NULL, { PMDA_PMID(0,18), PM_TYPE_FLOAT, COUNTER_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,-1,1, 0,PM_TIME_SEC,PM_COUNT_ONE) }, }, /* counter.value */ { NULL, { PMDA_PMID(0,19), PM_TYPE_DOUBLE, COUNTER_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,0, 0,0,0) }, }, /* this may be modified at startup */ }; extern void __pmdaStartInst(pmInDom indom, pmdaExt *pmda); extern int ctlport; extern unsigned int rbufsize; extern struct timeval timespan; extern struct timeval interval; static ringbuf_t ringbuf; /* *THE* ring buffer of trace data */ static hashtable_t summary; /* globals + recent ringbuf summary */ static hashtable_t history; /* holds every instance seen so far */ static unsigned int rpos; /* `working' buffer, within ringbuf */ static unsigned int dosummary = 1; /* summary refreshed this interval? */ static unsigned int tindomsize = 0; /* updated local to fetch only */ static unsigned int pindomsize = 0; /* updated local to fetch only */ static unsigned int oindomsize = 0; /* updated local to fetch only */ static unsigned int cindomsize = 0; /* updated local to fetch only */ /* note: {t,p,o,c}indomsize are only valid when dosummary equals zero */ /* allow configuration of trace.observe.value/trace.counter.value units */ static int updateValueUnits(const char *str, int offset) { int units[6], i, sts = 0; char *s, *sptr, *endp; if ((sptr = strdup(str)) == NULL) return -oserror(); s = sptr; for (i = 0; i < 6; i++) { if ((s = strtok((i==0 ? sptr : NULL), ",")) == NULL) { fprintf(stderr, "%s: token parse error in string \"%s\"\n", pmProgname, str); sts = -1; goto leaving; } units[i] = (int)strtol(s, &endp, 10); if (*endp) { fprintf(stderr, "%s: integer parse error for substring \"%s\"\n", pmProgname, s); sts = -1; goto leaving; } } /* update table entry for this value metric */ metrictab[offset].m_desc.units.dimSpace = units[0]; metrictab[offset].m_desc.units.dimTime = units[1]; metrictab[offset].m_desc.units.dimCount = units[2]; metrictab[offset].m_desc.units.scaleSpace = units[3]; metrictab[offset].m_desc.units.scaleTime = units[4]; metrictab[offset].m_desc.units.scaleCount = units[5]; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "%s: value metric units updated using \"%s\"\n" "dimSpace=%d, dimTime=%d, dimCount=%d, scaleSpace=%d, " "scaleTime=%d, scaleCount=%d\n", pmProgname, str, units[0], units[1], units[2], units[3], units[4], units[5]); } #endif leaving: if (sptr != NULL) free(sptr); return sts; } int updateObserveValue(const char *str) { return updateValueUnits(str, 10); } int updateCounterValue(const char *str) { return updateValueUnits(str, 19); } static int compareInstance(const void *a, const void *b) { pmdaInstid *aa = (pmdaInstid *)a; pmdaInstid *bb = (pmdaInstid *)b; return aa->i_inst - bb->i_inst; } /* * sort reset instance domains to be friendly to pmclients * (only PMDA knows when optimal time to sort these infrequently-changing sets) */ static void indomSortCheck(void) { if (tsortflag) { qsort(indomtab[TRANSACT_INDOM].it_set, indomtab[TRANSACT_INDOM].it_numinst, sizeof(pmdaInstid), compareInstance); tsortflag = 0; } if (psortflag) { qsort(indomtab[POINT_INDOM].it_set, indomtab[POINT_INDOM].it_numinst, sizeof(pmdaInstid), compareInstance); psortflag = 0; } if (osortflag) { qsort(indomtab[OBSERVE_INDOM].it_set, indomtab[OBSERVE_INDOM].it_numinst, sizeof(pmdaInstid), compareInstance); osortflag = 0; } if (csortflag) { qsort(indomtab[COUNTER_INDOM].it_set, indomtab[COUNTER_INDOM].it_numinst, sizeof(pmdaInstid), compareInstance); csortflag = 0; } } /* * wrapper for pmdaInstance which we need to ensure is called with the * _sorted_ contents of the instance domain. */ static int traceInstance(pmInDom indom, int foo, char *bar, __pmInResult **iresp, pmdaExt *pmda) { indomSortCheck(); return pmdaInstance(indom, foo, bar, iresp, pmda); } /* * `summary' table deletion may add to the `history' table. */ void summarydel(void *a) { hashdata_t *k = (hashdata_t *)a; instdata_t check; check.tag = k->tag; check.type = k->tracetype; check.instid = k->id; if (__pmhashlookup(&history, check.tag, &check) == NULL) { if (__pmhashinsert(&history, check.tag, &check) < 0) __pmNotifyErr(LOG_ERR, "history table insert failure - '%s' " "instance will not maintain its instance number.", check.tag); } if (k != NULL) free(k); /* don't free k->tag - its in the history table */ } /* * Processes data from pcp_trace-linked client programs. * * Return negative only on fd-related errors, as that connection will * later be closed. Other errors - report in log file but continue. */ int readData(int clientfd, int *protocol) { __pmTracePDU *result; double data; hashdata_t newhash; hashdata_t *hptr; hashdata_t hash; char *tag; int type, taglen, sts; int freeflag=0; if ((sts = __pmtracegetPDU(clientfd, TRACE_TIMEOUT_NEVER, &result)) < 0) { __pmNotifyErr(LOG_ERR, "bogus PDU read - %s", pmtraceerrstr(sts)); return -1; } else if (sts == TRACE_PDU_DATA) { if ((sts = __pmtracedecodedata(result, &tag, &taglen, &type, protocol, &data)) < 0) return -1; if (type < TRACE_FIRST_TYPE || type > TRACE_LAST_TYPE) { __pmNotifyErr(LOG_ERR, "unknown trace type for '%s' (%d)", tag, type); free(tag); return -1; } newhash.tag = tag; newhash.taglength = taglen; newhash.tracetype = type; } else if (sts == 0) { /* client has exited - cleanup in mainloop */ return -1; } else { /* unknown PDU type - bail & later kill connection */ __pmNotifyErr(LOG_ERR, "unknown PDU - expected data PDU" " (not type #%d)", sts); return -1; } /* * First, update the global summary table with this new data */ if ((hptr = __pmhashlookup(&summary, tag, &newhash)) == NULL) { instdata_t check, *iptr; int size, index, indom; check.tag = newhash.tag; check.type = newhash.tracetype; if ((iptr = __pmhashlookup(&history, check.tag, &check)) != NULL) { newhash.id = iptr->instid; /* reuse pre-reset instance ID */ if (iptr->type == TRACE_TYPE_TRANSACT) tsortflag++; else if (iptr->type == TRACE_TYPE_POINT) psortflag++; else if (iptr->type == TRACE_TYPE_COUNTER) csortflag++; else /*(iptr->type == TRACE_TYPE_OBSERVE)*/ osortflag++; } else if (type == TRACE_TYPE_TRANSACT) newhash.id = ++transacts; else if (type == TRACE_TYPE_POINT) newhash.id = ++points; else if (type == TRACE_TYPE_COUNTER) newhash.id = ++counters; else /* TRACE_TYPE_OBSERVE */ newhash.id = ++observes; newhash.txcount = -1; /* first time since reset or start */ newhash.padding = 0; newhash.realcount = 1; newhash.realtime = data; newhash.fd = clientfd; newhash.txmin = newhash.txmax = data; newhash.txsum = data; hptr = &newhash; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "'%s' is new to the summary table!", hptr->tag); #endif if (__pmhashinsert(&summary, hptr->tag, hptr) < 0) { __pmNotifyErr(LOG_ERR, "summary table insert failure - '%s' " "data ignored", hptr->tag); free(hptr->tag); return -1; } /* also update the instance domain */ if (hptr->tracetype == TRACE_TYPE_TRANSACT) indom = TRANSACT_INDOM; else if (hptr->tracetype == TRACE_TYPE_POINT) indom = POINT_INDOM; else if (hptr->tracetype == TRACE_TYPE_COUNTER) indom = COUNTER_INDOM; else /*(hptr->tracetype == TRACE_TYPE_OBSERVE)*/ indom = OBSERVE_INDOM; #ifdef DESPERATE /* walk the indom table - if we find this new tag in it already, then * something is badly busted. */ for (sts = 0; sts < indomtab[indom].it_numinst; sts++) { if (strcmp(indomtab[indom].it_set[sts].i_name, hptr->tag) == 0) { fprintf(stderr, "'%s' (inst=%d, type=%d) entry in indomtab already!!!\n", hptr->tag, indomtab[indom].it_set[sts].i_inst, hptr->tracetype); abort(); } } #endif index = indomtab[indom].it_numinst; size = (index+1)*(int)sizeof(pmdaInstid); if ((indomtab[indom].it_set = (pmdaInstid *) realloc(indomtab[indom].it_set, size)) == NULL) { __pmNotifyErr(LOG_ERR, "dropping instance '%s': %s", hptr->tag, osstrerror()); free(hptr->tag); return -1; } indomtab[indom].it_set[index].i_inst = hptr->id; indomtab[indom].it_set[index].i_name = hptr->tag; indomtab[indom].it_numinst++; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "Updated indom #%d:\n", indom); for (index=0; index < indomtab[indom].it_numinst; index++) fprintf(stderr, " Instance %d='%s'\n", indomtab[indom].it_set[index].i_inst, indomtab[indom].it_set[index].i_name); } #endif } else { /* update an existing entry */ freeflag++; /* wont need tag afterwards, so mark for deletion */ if (hptr->taglength != newhash.taglength) { __pmNotifyErr(LOG_ERR, "hash table update failure - '%s' " "data ignored (bad tag length)", tag); free(newhash.tag); return -1; } else { /* update existing entries free running counter */ hptr->realcount++; if (hptr->tracetype == TRACE_TYPE_TRANSACT) hptr->realtime += data; /* keep running total of time attributed to transactions */ else if (hptr->tracetype == TRACE_TYPE_COUNTER) hptr->txsum = data; /* counters are 'permanent' and immediately available */ else if (hptr->tracetype == TRACE_TYPE_OBSERVE) hptr->txsum = data; /* observations are 'permanent' and immediately available */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "'%s' real count updated (%d)", hptr->tag, (int)hptr->realcount); #endif } } /* * Next, update the current ring buffer entry with new trace data */ if ((hptr = __pmhashlookup(ringbuf.ring[rpos].stats, tag, &newhash)) == NULL) { hash.tag = strdup(tag); hash.tracetype = type; hash.id = 0; /* the ring buffer is never used to resolve indoms */ hash.padding = 0; hash.realcount = 1; hash.realtime = data; hash.taglength = (unsigned int)taglen; hash.fd = clientfd; hash.txcount = 1; hash.txmin = hash.txmax = data; hash.txsum = data; hptr = &hash; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "fresh interval data on fd=%d rpos=%d " "('%s': len=%d type=%d value=%d)", clientfd, rpos, hash.tag, taglen, type, (int)data); #endif if (__pmhashinsert(ringbuf.ring[rpos].stats, hash.tag, hptr) < 0) { __pmNotifyErr(LOG_ERR, "ring buffer insert failure - '%s' " "data ignored", hash.tag); free(hash.tag); return -1; } } else { /* update existing entry */ hptr->txcount++; if (hptr->tracetype == TRACE_TYPE_TRANSACT) { if (data < hptr->txmin) hptr->txmin = data; if (data > hptr->txmax) hptr->txmax = data; hptr->txsum += data; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "Updating data on fd=%d ('%s': type=%d " "count=%d min=%f max=%f sum=%f)", clientfd, hptr->tag, hptr->tracetype, hptr->txcount, hptr->txmin, hptr->txmax, hptr->txsum); #endif } if (freeflag) { free(newhash.tag); newhash.tag = NULL; } return hptr->tracetype; } static void clearTable(hashtable_t *t, void *entry) { hashdata_t *h = (hashdata_t *)entry; h->txcount = -1; /* flag as out-of-date */ } /* * Goes off at set time interval. The old `tail' becomes the new `head' * of the ring buffer & is marked as currently in-progess (and this data * is not exported until the next timer event). */ void timerUpdate(void) { /* summary table must be reset for next fetch */ if (dosummary == 0) { __pmhashtraverse(&summary, clearTable); dosummary = 1; } if (ringbuf.ring[rpos].working == 0) { __pmNotifyErr(LOG_ERR, "buffered I/O error - ignoring timer event"); return; } ringbuf.ring[rpos].working = 0; if (rpos == rbufsize-1) rpos = 0; /* return to start of buffer */ else rpos++; __pmhashtrunc(ringbuf.ring[rpos].stats); /* new working set */ ringbuf.ring[rpos].working = 1; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "Alarm - working buffer is now %d/%d", rpos+1, rbufsize); #endif } static void summariseDataAux(hashtable_t *t, void *entry) { hashdata_t *hptr; hashdata_t *base = (hashdata_t *)entry; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "summariseDataAux: looking up '%s'", base->tag); #endif /* update summary hash table */ if ((hptr = __pmhashlookup(&summary, base->tag, base)) == NULL) __pmNotifyErr(LOG_ERR, "summariseDataAux: entry in ring buffer, " "but not summary ('%s')", base->tag); else { /* update an existing summary */ if (hptr->tracetype == TRACE_TYPE_TRANSACT) { if (hptr->txcount == -1) { /* reset coz flagged as out-of-date */ tindomsize++; hptr->txcount = base->txcount; hptr->txmin = base->txmin; hptr->txmax = base->txmax; hptr->txsum = base->txsum; } else { hptr->txcount += base->txcount; if (base->txmin < hptr->txmin) hptr->txmin = base->txmin; if (base->txmax > hptr->txmax) hptr->txmax = base->txmax; hptr->txsum += base->txsum; } } else { if (hptr->txcount == -1) { /* reset coz flagged as out-of-date */ if (hptr->tracetype == TRACE_TYPE_POINT) pindomsize++; else if (hptr->tracetype == TRACE_TYPE_COUNTER) cindomsize++; else if (hptr->tracetype == TRACE_TYPE_OBSERVE) oindomsize++; else { __pmNotifyErr(LOG_ERR, "bogus trace type - skipping '%s'", hptr->tag); return; } hptr->txcount = base->txcount; } else { hptr->txcount += base->txcount; } } } } /* * Create the summary hash table, as well as the instance list for * this set of intervals. */ static void summariseData(void) { int count; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "summariseData: resummarising"); #endif /* initialise counters */ tindomsize = pindomsize = oindomsize = 0; /* create the new summary table */ for (count=0; count < rbufsize; count++) { if (ringbuf.ring[count].working == 1) continue; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "ring buffer table %d/%d has %d entries.\n", count, rbufsize, ringbuf.ring[count].stats->entries); #endif __pmhashtraverse(ringbuf.ring[count].stats, summariseDataAux); } /* summary now holds correct data for the rest of this interval */ dosummary = 0; } /* * Try to keep trace fetching similar to libpcp_pmda pmdaFetch() * we need a different way to get at the instances though * so, we can still use __pmdaStartInst, but trace iterator * is a bit different. */ static pmdaInstid * nextTraceInst(pmdaExt *pmda) { static pmdaInstid in = { PM_INDOM_NULL, NULL }; pmdaInstid *iptr = NULL; if (pmda->e_singular == 0) { /* PM_INDOM_NULL ... just the one value */ iptr = ∈ pmda->e_singular = -1; } if (pmda->e_ordinal >= 0) { int j; for (j = pmda->e_ordinal; j < pmda->e_idp->it_numinst; j++) { if (__pmInProfile(pmda->e_idp->it_indom, pmda->e_prof, pmda->e_idp->it_set[j].i_inst)) { iptr = &pmda->e_idp->it_set[j]; pmda->e_ordinal = j+1; break; } } } return iptr; } static int auxFetch(int inst, __pmID_int *idp, char *tag, pmAtomValue *atom) { if (inst != PM_IN_NULL && idp->cluster != 0) return PM_ERR_INST; /* transaction, point, counter and observe trace values and control data */ if (idp->cluster == 0) { hashdata_t hash; hashdata_t *hptr; hash.tag = tag; switch (idp->item) { case 0: /* trace.transact.count */ hash.tracetype = TRACE_TYPE_TRANSACT; if ((hptr = __pmhashlookup(&summary, hash.tag, &hash)) == NULL) return PM_ERR_INST; atom->ull = hptr->realcount; break; case 1: /* trace.transact.rate */ hash.tracetype = TRACE_TYPE_TRANSACT; if ((hptr = __pmhashlookup(&summary, hash.tag, &hash)) == NULL) return PM_ERR_INST; if (hptr->txcount < 0) /* not in current time period */ return 0; atom->f = (float)((double)hptr->txcount/(double)timespan.tv_sec); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) __pmNotifyErr(LOG_DEBUG, "rate=%f=%f/%f('%s')\n", (float)atom->f, (double)hptr->txcount, (double)timespan.tv_sec, tag); #endif break; case 2: /* trace.transact.ave_time */ hash.tracetype = TRACE_TYPE_TRANSACT; if ((hptr = __pmhashlookup(&summary, hash.tag, &hash)) == NULL) return PM_ERR_INST; if (hptr->txcount < 0) /* not in current time period */ return 0; else if (hptr->txcount == 0) atom->f = 0; else { atom->f = (float)((double)hptr->txsum/(double)hptr->txcount); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) __pmNotifyErr(LOG_DEBUG, "ave_time=%f=%f/%f('%s')\n", (float)atom->f, (double)hptr->txsum, (double)hptr->txcount, tag); #endif } break; case 3: /* trace.transact.min_time */ hash.tracetype = TRACE_TYPE_TRANSACT; if ((hptr = __pmhashlookup(&summary, hash.tag, &hash)) == NULL) return PM_ERR_INST; if (hptr->txcount < 0) /* not in current time period */ return 0; atom->f = (float)hptr->txmin; break; case 4: /* trace.transact.max_time */ hash.tracetype = TRACE_TYPE_TRANSACT; if ((hptr = __pmhashlookup(&summary, hash.tag, &hash)) == NULL) return PM_ERR_INST; if (hptr->txcount < 0) /* not in current time period */ return 0; atom->f = (float)hptr->txmax; break; case 5: /* trace.transact.total_time */ hash.tracetype = TRACE_TYPE_TRANSACT; if ((hptr = __pmhashlookup(&summary, hash.tag, &hash)) == NULL) return PM_ERR_INST; atom->d = hptr->realtime; break; case 6: /* trace.point.count */ hash.tracetype = TRACE_TYPE_POINT; if ((hptr = __pmhashlookup(&summary, hash.tag, &hash)) == NULL) return PM_ERR_INST; atom->ull = hptr->realcount; break; case 7: /* trace.point.rate */ hash.tracetype = TRACE_TYPE_POINT; if ((hptr = __pmhashlookup(&summary, hash.tag, &hash)) == NULL) return PM_ERR_INST; if (hptr->txcount < 0) /* not in current time period */ return 0; atom->f = (float)((double)hptr->txcount/(double)timespan.tv_sec); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) __pmNotifyErr(LOG_DEBUG, "rate=%f=%f/%f('%s')\n", (float)atom->f, (double)hptr->txcount, (double)timespan.tv_sec, tag); #endif break; case 8: /* trace.observe.count */ case 17: /* trace.counter.count */ hash.tracetype = (idp->item == 8)? TRACE_TYPE_OBSERVE : TRACE_TYPE_COUNTER; if ((hptr = __pmhashlookup(&summary, hash.tag, &hash)) == NULL) return PM_ERR_INST; atom->ull = hptr->realcount; break; case 9: /* trace.observe.rate */ case 18: /* trace.counter.rate */ hash.tracetype = (idp->item == 9)? TRACE_TYPE_OBSERVE : TRACE_TYPE_COUNTER; if ((hptr = __pmhashlookup(&summary, hash.tag, &hash)) == NULL) return PM_ERR_INST; if (hptr->txcount < 0) /* not in current time period */ return 0; atom->f = (float)((double)hptr->txcount/(double)timespan.tv_sec); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) __pmNotifyErr(LOG_DEBUG, "rate=%f=%f/%f('%s')\n", (float)atom->f, (double)hptr->txcount, (double)timespan.tv_sec, tag); #endif break; case 10: /* trace.observe.value */ case 19: /* trace.counter.value */ hash.tracetype = (idp->item == 10)? TRACE_TYPE_OBSERVE : TRACE_TYPE_COUNTER; if ((hptr = __pmhashlookup(&summary, hash.tag, &hash)) == NULL) return PM_ERR_INST; atom->d = hptr->txsum; break; case 11: /* trace.control.timespan */ atom->ul = timespan.tv_sec; break; case 12: /* trace.control.interval */ atom->ul = interval.tv_sec; break; case 13: /* trace.control.buckets */ atom->ul = rbufsize-1; break; case 14: /* trace.control.port */ atom->ul = ctlport; break; case 15: /* trace.control.reset */ atom->ul = 1; break; case 16: /* trace.control.debug */ atom->ul = pmDebug; break; default: return PM_ERR_PMID; } } else return PM_ERR_PMID; return 1; } static int getIndomSize(__pmID_int *pmidp) { int size; if (pmidp->cluster != 0) return 1; switch (pmidp->item) { case 0: /* uses summary's real counters (transact) */ case 5: size = indomtab[TRANSACT_INDOM].it_numinst; break; case 1: case 2: case 3: case 4: /* susceptible to ring buffer updates */ size = tindomsize; break; case 6: /* uses summary's real counters (point) */ size = indomtab[POINT_INDOM].it_numinst; break; case 7: /* susceptible to ring buffer updates */ size = pindomsize; break; case 8: case 10: /* uses summary's real counters & data (obs) */ size = indomtab[OBSERVE_INDOM].it_numinst; break; case 9: /* susceptible to ring buffer updates */ size = oindomsize; break; case 17: case 19: /* uses summary's real counters & data (ctr) */ size = indomtab[COUNTER_INDOM].it_numinst; break; case 18: /* susceptible to ring buffer updates */ size = cindomsize; break; default: size = 0; } return size; } static int traceFetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { static int maxnpmids = 0; static pmResult *res = NULL; pmValueSet *vset; pmDesc *dp; __pmID_int *pmidp; pmdaMetric *metap; pmAtomValue atom; pmdaInstid *ins; pmdaInstid noinst = { PM_IN_NULL, NULL }; int numval; int sts, i, j, need; indomSortCheck(); pmda->e_idp = indomtab; if (numpmid > maxnpmids) { if (res != NULL) free(res); /* (numpmid - 1) because there's room for one valueSet in a pmResult */ need = (int)sizeof(pmResult) + (numpmid-1)*(int)sizeof(pmValueSet *); if ((res = (pmResult *) malloc(need)) == NULL) { return -oserror(); } maxnpmids = numpmid; } res->timestamp.tv_sec = 0; res->timestamp.tv_usec = 0; res->numpmid = numpmid; for (i = 0; i < numpmid; i++) { dp = NULL; metap = NULL; pmidp = (__pmID_int *)&pmidlist[i]; if (pmda->e_direct) { if (pmidp->item < pmda->e_nmetrics && pmidlist[i] == pmda->e_metrics[pmidp->item].m_desc.pmid) { metap = &pmda->e_metrics[pmidp->item]; dp = &(metap->m_desc); } } else { /* search for it */ for (j = 0; j < pmda->e_nmetrics; j++) { if (pmidlist[i] == pmda->e_metrics[j].m_desc.pmid) { metap = &pmda->e_metrics[j]; dp = &(metap->m_desc); break; } } } if (dp == NULL) { __pmNotifyErr(LOG_ERR, "traceFetch: Requested metric %s is not " "defined", pmIDStr(pmidlist[i])); numval = PM_ERR_PMID; } else if (dp->indom != PM_INDOM_NULL) { /* * Only summarise when you have to, so check if data has * already been summarised within this interval. */ if (dosummary == 1) summariseData(); numval = getIndomSize(pmidp); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "instance domain for %s numval=%d", pmIDStr(dp->pmid), numval); #endif } else numval = 1; /* Must use individual malloc()s because of pmFreeResult() */ if (numval >= 1) res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet)+ (numval - 1)*sizeof(pmValue)); else res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet)- sizeof(pmValue)); if (vset == NULL) { if ((res->numpmid = i) > 0) __pmFreeResultValues(res); return -oserror(); } vset->pmid = pmidlist[i]; vset->numval = numval; vset->valfmt = PM_VAL_INSITU; if (vset->numval <= 0) continue; if (dp->indom == PM_INDOM_NULL) ins = &noinst; else { __pmdaStartInst(dp->indom, pmda); ins = nextTraceInst(pmda); } j = 0; do { if (ins == NULL) { __pmNotifyErr(LOG_ERR, "bogus instance ignored (pmid=%s)", pmIDStr(dp->pmid)); if ((res->numpmid = i) > 0) __pmFreeResultValues(res); return PM_ERR_INST; } if (j == numval) { numval++; res->vset[i] = vset = (pmValueSet *)realloc(vset, sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue)); if (vset == NULL) { if ((res->numpmid = i) > 0) __pmFreeResultValues(res); return -oserror(); } } vset->vlist[j].inst = ins->i_inst; if ((sts = auxFetch(ins->i_inst, pmidp, ins->i_name, &atom)) < 0) { if (sts == PM_ERR_PMID) __pmNotifyErr(LOG_ERR, "unknown PMID requested - '%s'", pmIDStr(dp->pmid)); else if (sts == PM_ERR_INST) __pmNotifyErr(LOG_ERR, "unknown instance requested - %d " "(pmid=%s)", ins->i_inst, pmIDStr(dp->pmid)); else __pmNotifyErr(LOG_ERR, "fetch error (pmid=%s): %s", pmIDStr(dp->pmid), pmErrStr(sts)); } else if (sts == 0) { /* not current, so don't use */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "Instance is dated %s (pmid=%s)", ins->i_name, pmIDStr(dp->pmid)); #endif } else if ((sts = __pmStuffValue(&atom, &vset->vlist[j], dp->type)) == PM_ERR_TYPE) __pmNotifyErr(LOG_ERR, "bad desc type (%d) for metric %s", dp->type, pmIDStr(dp->pmid)); else if (sts >= 0) { vset->valfmt = sts; j++; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "Instance is good! %s (pmid=%s)", ins->i_name, pmIDStr(dp->pmid)); #endif } } while (dp->indom != PM_INDOM_NULL && (ins = nextTraceInst(pmda)) != NULL); if (j == 0) vset->numval = sts; else vset->numval = j; } *resp = res; return 0; } static int traceStore(pmResult *result, pmdaExt *pmda) { int i, j; int sts = 0; pmValueSet *vsp = NULL; __pmID_int *pmidp = NULL; pmAtomValue av; extern int afid; extern void alarming(int, void *); for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; pmidp = (__pmID_int *)&vsp->pmid; if (pmidp->cluster != 0) return PM_ERR_PMID; if (pmidp->item == 15) { /* trace.control.reset */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "resetting trace metrics"); #endif /* reset the interval timer */ if (afid >= 0) { __pmAFunregister(afid); if ((afid = __pmAFregister(&interval, NULL, alarming)) < 0) { __pmNotifyErr(LOG_ERR, "__pmAFregister failed"); exit(1); } } /* reset summary and ring buffer hash tables */ __pmhashtrunc(&summary); for (j = 0; j < rbufsize; j++) { __pmhashtrunc(ringbuf.ring[j].stats); ringbuf.ring[j].numstats = 0; } /* clear all the instance domain entries */ if (indomtab[TRANSACT_INDOM].it_set) { free(indomtab[TRANSACT_INDOM].it_set); indomtab[TRANSACT_INDOM].it_set = NULL; } if (indomtab[OBSERVE_INDOM].it_set) { free(indomtab[OBSERVE_INDOM].it_set); indomtab[OBSERVE_INDOM].it_set = NULL; } if (indomtab[COUNTER_INDOM].it_set) { free(indomtab[COUNTER_INDOM].it_set); indomtab[COUNTER_INDOM].it_set = NULL; } if (indomtab[POINT_INDOM].it_set) { free(indomtab[POINT_INDOM].it_set); indomtab[POINT_INDOM].it_set = NULL; } indomtab[TRANSACT_INDOM].it_numinst = 0; indomtab[COUNTER_INDOM].it_numinst = 0; indomtab[OBSERVE_INDOM].it_numinst = 0; indomtab[POINT_INDOM].it_numinst = 0; tindomsize = pindomsize = oindomsize = 0; /* definately need to recompute the summary next fetch */ dosummary = 1; __pmNotifyErr(LOG_INFO, "PMDA reset"); } else if (pmidp->item == 16) { /* trace.control.debug */ if (vsp->numval != 1 || vsp->valfmt != PM_VAL_INSITU) sts = PM_ERR_CONV; else if (sts >= 0 && ((sts = pmExtractValue(vsp->valfmt, &vsp->vlist[0], PM_TYPE_32, &av, PM_TYPE_32)) >= 0)) { if (pmDebug != av.l) { pmDebug = av.l; __pmNotifyErr(LOG_INFO, "debug level set to %d", pmDebug); debuglibrary(pmDebug); } } } else sts = PM_ERR_PMID; } return sts; } /* * Initialise the agent */ void traceInit(pmdaInterface *dp) { int rsize, sts; if (dp->status != 0) return; dp->version.two.fetch = traceFetch; dp->version.two.store = traceStore; dp->version.two.instance = traceInstance; dp->version.two.ext->e_direct = 0; pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), metrictab, sizeof(metrictab)/sizeof(metrictab[0])); /* initialise ring buffer */ rsize = (int)(sizeof(statlist_t) * rbufsize); if ((ringbuf.ring = (statlist_t *)malloc(rsize)) == NULL) { __pmNotifyErr(LOG_ERR, "failed during ring buffer initialise: %s", osstrerror()); exit(1); } for (rsize=0; rsize < rbufsize; rsize++) { if ((ringbuf.ring[rsize].stats = (hashtable_t *) malloc(sizeof(hashtable_t))) == NULL) { __pmNotifyErr(LOG_ERR, "ring buffer initialise failed: %s", osstrerror()); exit(1); } if ((sts = __pmhashinit(ringbuf.ring[rsize].stats, 0, sizeof(hashdata_t), datacmp, datadel)) < 0) { __pmNotifyErr(LOG_ERR, "ring buffer initialisation failed: %s", osstrerror()); exit(1); } ringbuf.ring[rsize].working = 0; } rpos = 0; ringbuf.ring[rpos].working = 1; /* initialise summary & associated instance domain */ indomtab[TRANSACT_INDOM].it_numinst = 0; indomtab[TRANSACT_INDOM].it_set = NULL; indomtab[POINT_INDOM].it_numinst = 0; indomtab[POINT_INDOM].it_set = NULL; dp->version.two.ext->e_idp = indomtab; if ((sts = __pmhashinit(&summary, 0, sizeof(hashdata_t), datacmp, summarydel)) < 0) { __pmNotifyErr(LOG_ERR, "summary table initialisation failed: %s", osstrerror()); exit(1); } /* initialise list of reserved instance domains (for store recovery) */ if ((sts = __pmhashinit(&history, 0, sizeof(instdata_t), instcmp, instdel)) < 0) { __pmNotifyErr(LOG_ERR, "history table initialisation failed: %s", osstrerror()); exit(1); } } pcp-3.8.12ubuntu1/src/pmdas/trace/src/data.c0000664000000000000000000000517712272262501015451 0ustar /* * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "pmapi.h" #include "impl.h" #include "data.h" int instcmp(void *a, void *b) { instdata_t *aa = (instdata_t *)a; instdata_t *bb = (instdata_t *)b; if (aa == NULL || bb == NULL) return 0; if (aa->type != bb->type) return 0; return !strcmp(aa->tag, bb->tag); } void instdel(void *a) { instdata_t *k = (instdata_t *)a; if (k != NULL) { if (k->tag != NULL) free(k->tag); free(k); } } void instprint(__pmHashTable *t, void *e) { instdata_t *i = (instdata_t *)e; __pmNotifyErr(LOG_DEBUG, "Instance history table entry\n" "Name: '%s'\n type: %d\n inst: %d\n", i->tag, i->type, i->instid); } int datacmp(void *a, void *b) { hashdata_t *aa = (hashdata_t *)a; hashdata_t *bb = (hashdata_t *)b; if (aa == NULL || bb == NULL) return 0; if (aa->tracetype != bb->tracetype) return 0; return !strcmp(aa->tag, bb->tag); } void datadel(void *a) { hashdata_t *k = (hashdata_t *)a; if (k != NULL) { if (k->tag != NULL) free(k->tag); free(k); } } void dataprint(__pmHashTable *t, void *e) { hashdata_t *h = (hashdata_t *)e; __pmNotifyErr(LOG_DEBUG, "PMDA hash table entry\n" "Name: '%s'\n filedes: %d\n" " type: %d\n length: %d\n" " padding: %d\n count: %d\n" " txmin: %f\n txmax: %f\n" " txsum: %f\nSize: %d\n" "-----------\n", h->tag, h->fd, h->tracetype, h->taglength, h->padding, (int)h->txcount, h->txmin, h->txmax, h->txsum, (int)sizeof(*h)); } #ifdef PCP_DEBUG void debuglibrary(int flag) { extern int __pmstate; int state; state = pmtracestate(0); if (flag & DBG_TRACE_APPL0) state |= PMTRACE_STATE_COMMS; if (flag & DBG_TRACE_PDU) state |= PMTRACE_STATE_PDU; if (flag & DBG_TRACE_PDUBUF) state |= PMTRACE_STATE_PDUBUF; if (flag == 0) __pmstate = 0; else pmtracestate(state); } #endif pcp-3.8.12ubuntu1/src/pmdas/trace/src/client.h0000664000000000000000000000254112272262501016013 0ustar /* * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef CLIENT_H #define CLIENT_H typedef struct { int fd; /* socket descriptor */ __pmSockAddr *addr; /* address of client */ struct { /* connection status */ unsigned int connected : 1; /* client connected */ unsigned int version : 8; /* client pdu version */ unsigned int protocol : 1; /* synchronous or not */ unsigned int padding :22; /* currently unused */ } status; unsigned int denyOps; } client_t; extern client_t *acceptClient(int); extern void deleteClient(client_t *); extern void showClients(void); #endif /* CLIENT_H */ pcp-3.8.12ubuntu1/src/pmdas/trace/src/comms.h0000664000000000000000000000163512272262501015656 0ustar /* * Copyright (c) 1997-2001 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef COMMS_H #define COMMS_H #define TR_OP_NONE 0x0 #define TR_OP_SEND 0x1 #define TR_OP_ALL 0x1 #endif /* COMMS_H */ pcp-3.8.12ubuntu1/src/pmdas/trace/src/client.c0000664000000000000000000000755612272262501016021 0ustar /* * Copyright (c) 2012-2013 Red Hat. * Copyright (c) 1997-2001 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "trace_dev.h" #include "client.h" #include "comms.h" extern fd_set fds; int nclients; /* number of entries in array */ int maxfd; /* largest fd currently in use */ client_t *clients; /* array of clients */ #define MIN_CLIENTS_ALLOC 8 static int clientsize; static int newClient(void); client_t * acceptClient(int reqfd) { int i, fd; __pmSockLen addrlen; i = newClient(); addrlen = __pmSockAddrSize(); fd = __pmAccept(reqfd, clients[i].addr, &addrlen); if (fd == -1) { __pmNotifyErr(LOG_ERR, "acceptClient(%d) accept: %s", reqfd, netstrerror()); return NULL; } if (fd > maxfd) maxfd = fd; FD_SET(fd, &fds); clients[i].fd = fd; clients[i].status.connected = 1; clients[i].status.padding = 0; clients[i].status.protocol = 1; /* sync */ return &clients[i]; } static int newClient(void) { int i, j; for (i = 0; i < nclients; i++) if (!clients[i].status.connected) break; if (i == clientsize) { clientsize = clientsize ? clientsize * 2 : MIN_CLIENTS_ALLOC; clients = (client_t *) realloc(clients, sizeof(client_t)*clientsize); if (clients == NULL) __pmNoMem("newClient", sizeof(client_t)*clientsize, PM_FATAL_ERR); for (j = i; j < clientsize; j++) clients[j].addr = NULL; } clients[i].addr = __pmSockAddrAlloc(); if (clients[i].addr == NULL) __pmNoMem("newClient", __pmSockAddrSize(), PM_FATAL_ERR); if (i >= nclients) nclients = i + 1; return i; } void deleteClient(client_t *cp) { int i; for (i = 0; i < nclients; i++) if (cp == &clients[i]) break; if (i == nclients) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { __pmNotifyErr(LOG_ERR, "deleteClient: tried to delete non-existent client"); } #endif return; } if (cp->fd != -1) { __pmtracenomoreinput(cp->fd); FD_CLR(cp->fd, &fds); close(cp->fd); } if (cp->fd == maxfd) { maxfd = -1; for (i = 0; i < nclients; i++) if (clients[i].fd > maxfd) maxfd = clients[i].fd; } __pmSockAddrFree(cp->addr); cp->addr = NULL; cp->status.connected = 0; cp->status.padding = 0; cp->status.protocol = 1; /* sync */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "deleteClient: client removed (fd=%d)", cp->fd); #endif cp->fd = -1; } void showClients(void) { int i; fprintf(stderr, "%s: %d connected clients:\n", pmProgname, nclients); fprintf(stderr, " fd type conn client connection from\n" " == ===== ==== ======================\n"); for (i=0; i < nclients; i++) { char *hostName; char *hostAddr; fprintf(stderr, " %3d", clients[i].fd); fprintf(stderr, " %s ", clients[i].status.protocol == 1 ? "sync ":"async"); fprintf(stderr, "%s ", clients[i].status.connected == 1 ? "up ":"down"); hostName = __pmGetNameInfo(clients[i].addr); if (hostName == NULL) { hostAddr = __pmSockAddrToString(clients[i].addr); fprintf(stderr, "%s", hostAddr); free(hostAddr); } else { fprintf(stderr, "%-40.40s", hostName); free(hostName); } if (clients[i].denyOps != 0) { fprintf(stderr, " "); if (clients[i].denyOps & TR_OP_SEND) fprintf(stderr, "send "); } fputc('\n', stderr); } fputc('\n', stderr); } pcp-3.8.12ubuntu1/src/pmdas/trace/src/GNUmakefile0000664000000000000000000000261212272262501016435 0ustar # # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../../.. include $(TOPDIR)/src/include/builddefs TARGETS = trace$(EXECSUFFIX) CFILES = trace.c client.c comms.c data.c pmda.c HFILES = data.h client.h comms.h LCFLAGS = -I$(TOPDIR)/src/libpcp_trace/src LLDFLAGS= -L$(TOPDIR)/src/libpcp_trace/src LLDLIBS = -lpcp_trace $(PCP_PMDALIB) IAM = trace DOMAIN = TRACE PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LDIRT = *.log *.dir *.pag domain.h $(TARGETS) default: build-me include $(BUILDRULES) ifneq "$(TARGET_OS)" "mingw" build-me: $(TARGETS) install: build-me $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) $(INSTALL) -m 644 domain.h $(PMDADIR)/domain.h else build-me: install: endif $(IAM)$(EXECSUFFIX): $(OBJECTS) comms.o trace.o pmda.o: domain.h domain.h: ../../../pmns/stdpmid $(DOMAIN_MAKERULE) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmdas/trace/src/pmda.c0000664000000000000000000001361312272262501015453 0ustar /* * Trace PMDA - process level transaction monitoring for libpcp_trace processes * * Copyright (c) 2012 Red Hat. * Copyright (c) 1997-2000 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include "trace.h" #include "trace_dev.h" #include "comms.h" #define DEFAULT_TIMESPAN 60 /* one minute */ #define DEFAULT_BUFSIZE 5 /* twelve second update */ struct timeval timespan = { DEFAULT_TIMESPAN, 0 }; struct timeval interval; unsigned int rbufsize = DEFAULT_BUFSIZE; int ctlport = -1; char *ctlsock; static char mypath[MAXPATHLEN]; static char *username; extern void traceInit(pmdaInterface *dispatch); extern void traceMain(pmdaInterface *dispatch); extern int updateObserveValue(const char *); extern int updateCounterValue(const char *); extern void debuglibrary(int); static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\ \n\ Options:\n\ -d domain use domain (numeric) for metrics domain of PMDA\n\ -l logfile write log into logfile rather than using default file\n\ -A access host based access control\n\ -I port expect programs to connect on given inet port (number/name)\n\ -M username user account to run under (default \"pcp\")\n\ -N buckets number of historical data buffers maintained\n\ -T period time over which samples are considered (default 60 seconds)\n\ -U units export observation values using the given units\n\ -V units export counter values using the given units\n", pmProgname); exit(1); } static char * squash(char *str, int *offset) { char *hspec = NULL; char *p = str; int i = 0; hspec = strdup(str); /* make sure we have space */ *offset = 0; while (isspace((int)*p)) { p++; (*offset)++; } while (p && *p != ':' && *p != '\0') { hspec[i++] = *p; p++; } hspec[i] = '\0'; *offset += i; return hspec; } static int parseAuth(char *spec) { static int first = 1; int offset, maxconn, specops = TR_OP_ALL, denyops; char *p, *endnum; if (first) { if (__pmAccAddOp(TR_OP_SEND) < 0) { __pmNotifyErr(LOG_ERR, "failed to add send auth operation"); return -1; } first = 0; } if (strncasecmp(spec, "disallow:", 9) == 0) { p = squash(&spec[9], &offset); if (p == NULL || p[0] == '\0') { fprintf(stderr, "%s: invalid disallow (%s)\n", pmProgname, spec); if (p) free(p); return -1; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "deny: host '%s'\n", p); #endif denyops = TR_OP_SEND; if (__pmAccAddHost(p, specops, denyops, 0) < 0) __pmNotifyErr(LOG_ERR, "failed to add authorisation (%s)", p); free(p); } else if (strncasecmp(spec, "allow:", 6) == 0) { p = squash(&spec[6], &offset); if (p == NULL || p[0] == '\0') { fprintf(stderr, "%s: invalid allow (%s)\n", pmProgname, spec); if (p) free(p); return -1; } offset += 7; maxconn = (int)strtol(&spec[offset], &endnum, 10); if (*endnum != '\0' || maxconn < 0) { fprintf(stderr, "%s: bogus max connection in '%s'\n", pmProgname, &spec[offset]); free(p); return -1; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "allow: host '%s', maxconn=%d\n", p, maxconn); #endif denyops = TR_OP_NONE; if (__pmAccAddHost(p, specops, denyops, maxconn) < 0) __pmNotifyErr(LOG_ERR, "failed to add authorisation (%s)", p); free(p); } else { fprintf(stderr, "%s: access spec is invalid (%s)\n", pmProgname, spec); return -1; } return 0; } int main(int argc, char **argv) { pmdaInterface dispatch; char *endnum; int err = 0; int sep = __pmPathSeparator(); int c = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(mypath, sizeof(mypath), "%s%c" "trace" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_2, pmProgname, TRACE, "trace.log", mypath); /* need - port, as well as time interval and time span for averaging */ while ((c = pmdaGetOpt(argc, argv, "A:D:d:I:l:T:M:N:U:V:?", &dispatch, &err)) != EOF) { switch(c) { case 'A': if (parseAuth(optarg) < 0) err++; /* add optarg to access control list */ break; case 'I': ctlport = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0' || ctlport < 0) ctlsock = optarg; break; case 'M': username = optarg; break; case 'N': rbufsize = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0' || rbufsize < 1) { fprintf(stderr, "%s: -N requires a positive number.\n", pmProgname); err++; } break; case 'T': if (pmParseInterval(optarg, ×pan, &endnum) < 0) { fprintf(stderr, "%s: -T requires a time interval: %s\n", pmProgname, endnum); free(endnum); err++; } break; case 'U': if (updateObserveValue(optarg) < 0) err++; break; case 'V': if (updateCounterValue(optarg) < 0) err++; break; default: err++; } } if (err) usage(); interval.tv_sec = (int)(timespan.tv_sec / rbufsize); interval.tv_usec = (long)((timespan.tv_sec % rbufsize) * 1000000); rbufsize++; /* reserve space for the `working' buffer */ #ifdef PCP_DEBUG debuglibrary(pmDebug); #endif pmdaOpenLog(&dispatch); __pmSetProcessIdentity(username); traceInit(&dispatch); pmdaConnect(&dispatch); traceMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/trace/src/comms.c0000664000000000000000000001712612272262501015653 0ustar /* * Copyright (c) 2012-2013 Red Hat. All Rights Reserved. * Copyright (c) 1997-2001 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "trace.h" #include "trace_dev.h" #include "domain.h" #include "client.h" #include "comms.h" extern struct timeval interval; extern int readData(int, int *); extern void timerUpdate(void); extern int maxfd; extern int nclients; extern client_t *clients; extern int ctlport; /* control port number */ static int ctlfd; /* fd for control port */ static int pmcdfd; /* fd for pmcd */ void alarming(int, void *); static void hangup(int); static int getcport(void); /* currently in-use fd mask */ fd_set fds; /* the AF event number */ int afid = -1; void traceMain(pmdaInterface *dispatch) { client_t *cp; fd_set readyfds; int nready, i, pdutype, sts, protocol; ctlfd = getcport(); pmcdfd = __pmdaInFd(dispatch); maxfd = (ctlfd > pmcdfd) ? (ctlfd):(pmcdfd); FD_ZERO(&fds); FD_SET(ctlfd, &fds); FD_SET(pmcdfd, &fds); signal(SIGHUP, hangup); /* arm interval timer */ if ((afid = __pmAFregister(&interval, NULL, alarming)) < 0) { __pmNotifyErr(LOG_ERR, "error registering asynchronous event handler"); exit(1); } for (;;) { memcpy(&readyfds, &fds, sizeof(readyfds)); nready = select(maxfd+1, &readyfds, NULL, NULL, NULL); if (nready == 0) continue; else if (nready < 0) { if (neterror() != EINTR) { __pmNotifyErr(LOG_ERR, "select failure: %s", netstrerror()); exit(1); } continue; } __pmAFblock(); if (FD_ISSET(pmcdfd, &readyfds)) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "processing pmcd request [fd=%d]", pmcdfd); #endif if (__pmdaMainPDU(dispatch) < 0) { __pmAFunblock(); exit(1); /* fatal if we lose pmcd */ } } /* handle request on control port */ if (FD_ISSET(ctlfd, &readyfds)) { if ((cp = acceptClient(ctlfd)) != NULL) { sts = __pmAccAddClient(cp->addr, &cp->denyOps); if (sts == PM_ERR_PERMISSION) sts = PMTRACE_ERR_PERMISSION; else if (sts == PM_ERR_CONNLIMIT) sts = PMTRACE_ERR_CONNLIMIT; else if (sts >= 0) sts = TRACE_PDU_VERSION; __pmtracesendack(cp->fd, sts); if (sts < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { char *hostAddr = __pmSockAddrToString(cp->addr); __pmNotifyErr(LOG_DEBUG, "client %s [fd=%d]: connect refused, denyOps=0x%x: %s", hostAddr, cp->fd, cp->denyOps, pmtraceerrstr(sts)); free(hostAddr); } #endif deleteClient(cp); } else { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { char *hostAddr = __pmSockAddrToString(cp->addr); __pmNotifyErr(LOG_DEBUG, "client %s [fd=%d]: new connection, denyOps=0x%x", hostAddr, cp->fd, cp->denyOps); free(hostAddr); } #endif ; } } } for (i = 0; i < nclients; i++) { if (!clients[i].status.connected) continue; if (clients[i].denyOps & TR_OP_SEND) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { char *hostAddr = __pmSockAddrToString(clients[i].addr); __pmNotifyErr(LOG_DEBUG, "client %s [fd=%d]: send denied, denyOps=0x%x", hostAddr, clients[i].fd, clients[i].denyOps); free(hostAddr); } #endif __pmtracesendack(clients[i].fd, PMTRACE_ERR_PERMISSION); __pmAccDelClient(clients[i].addr); deleteClient(&clients[i]); } else if (FD_ISSET(clients[i].fd, &readyfds)) { protocol = 1; /* default to synchronous */ do { if ((pdutype = readData(clients[i].fd, &protocol)) < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { char *hostAddr = __pmSockAddrToString(clients[i].addr); __pmNotifyErr(LOG_DEBUG, "client %s [fd=%d]: close connection", hostAddr, clients[i].fd); free(hostAddr); } #endif __pmAccDelClient(clients[i].addr); deleteClient(&clients[i]); } else { clients[i].status.protocol = protocol; if (clients[i].status.connected) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { char *hostAddr = __pmSockAddrToString(clients[i].addr); __pmNotifyErr(LOG_DEBUG, "client %s [fd=%d]: %s ACK (type=%d)", hostAddr, clients[i].fd, protocol ? "sending" : "no", pdutype); free(hostAddr); } #endif if (protocol == 1) { sts = __pmtracesendack(clients[i].fd, pdutype); if (sts < 0) { char *hostAddr = __pmSockAddrToString(clients[i].addr); __pmNotifyErr(LOG_ERR, "client %s [fd=%d]: ACK send failed (type=%d): %s", hostAddr, clients[i].fd, pdutype, pmtraceerrstr(sts)); free(hostAddr); } } } } } while (__pmtracemoreinput(clients[i].fd)); } } __pmAFunblock(); } } void alarming(int sig, void *ptr) { timerUpdate(); } static void hangup(int sig) { showClients(); signal(SIGHUP, hangup); } /* * Create socket for incoming connections and bind to it an address for * clients to use. Only returns if it succeeds (exits on failure). */ static int getcport(void) { int fd; int i=1, one=1, sts; struct sockaddr_in myAddr; struct linger noLinger = {1, 0}; fd = socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) { __pmNotifyErr(LOG_ERR, "getcport: socket: %s", netstrerror()); exit(1); } /* avoid 200 ms delay */ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &i, (__pmSockLen)sizeof(i)) < 0) { __pmNotifyErr(LOG_ERR, "getcport: setsockopt(nodelay): %s", netstrerror()); exit(1); } /* don't linger on close */ if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &noLinger, (__pmSockLen)sizeof(noLinger)) < 0) { __pmNotifyErr(LOG_ERR, "getcport: setsockopt(nolinger): %s", netstrerror()); exit(1); } #ifndef IS_MINGW /* ignore dead client connections */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, (__pmSockLen)sizeof(one)) < 0) { __pmNotifyErr(LOG_ERR, "getcport: setsockopt(reuseaddr): %s", netstrerror()); exit(1); } #else /* see MSDN tech note: "Using SO_REUSEADDR and SO_EXCLUSIVEADDRUSE" */ if (setsockopt(sfd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (char *) &one, (__pmSockLen)sizeof(one)) < 0) { __pmNotifyErr(LOG_ERR, "getcport: setsockopt(excladdruse): %s", netstrerror()); exit(1); } #endif if (ctlport == -1) { /* * check for port info in the environment */ char *env_str; if ((env_str = getenv(TRACE_ENV_PORT)) != NULL) { char *end_ptr; ctlport = (int)strtol(env_str, &end_ptr, 0); if (*end_ptr != '\0' || ctlport < 0) { __pmNotifyErr(LOG_WARNING, "env port is bogus (%s)", env_str); ctlport = TRACE_PORT; } } else ctlport = TRACE_PORT; } /* TODO: IPv6 */ memset(&myAddr, 0, sizeof(myAddr)); myAddr.sin_family = AF_INET; myAddr.sin_addr.s_addr = htonl(INADDR_ANY); myAddr.sin_port = htons(ctlport); sts = bind(fd, &myAddr, sizeof(myAddr)); if (sts < 0) { __pmNotifyErr(LOG_ERR, "bind(%d): %s", ctlport, netstrerror()); exit(1); } sts = listen(fd, 5); /* Max. of 5 pending connection requests */ if (sts == -1) { __pmNotifyErr(LOG_ERR, "listen: %s", netstrerror()); exit(1); } return fd; } pcp-3.8.12ubuntu1/src/pmdas/trace/src/data.h0000664000000000000000000000363112272262501015447 0ustar /* * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef TRACE_DATA_H #define TRACE_DATA_H #include "hash.h" #include "trace.h" #include "trace_dev.h" typedef struct { char *tag; unsigned int type; unsigned int instid; } instdata_t; typedef struct __pmHashTab hashtable_t; int instcmp(void *a, void *b); void instdel(void *a); void instprint(hashtable_t *t, void *e); typedef struct { char *tag; unsigned int id; int fd; unsigned int tracetype : 8; unsigned int taglength : 8; unsigned int padding : 16; __uint64_t realcount; /* real total seen by the PMDA */ double realtime; /* total time for transactions */ __int32_t txcount; /* count this interval or -1 */ double txmin; /* minimum value this interval */ double txmax; /* maximum value this interval */ double txsum; /* summed across the interval */ } hashdata_t; int datacmp(void *a, void *b); void datadel(void *a); void dataprint(hashtable_t *t, void *e); typedef struct { unsigned int numstats : 8; /* number of entries in this table */ unsigned int working : 1; /* this the current working table? */ hashtable_t *stats; } statlist_t; typedef struct { statlist_t *ring; /* points to all statistics */ unsigned int level; /* controls reporting level */ } ringbuf_t; #ifdef PCP_DEBUG void debuglibrary(int); #endif #endif /* TRACE_DATA_H */ pcp-3.8.12ubuntu1/src/pmdas/trace/GNUmakefile0000664000000000000000000000543712272262501015656 0ustar # # Copyright (c) 2000-2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = trace DOMAIN = TRACE PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) DEMODIR = $(PCP_DEMOS_DIR)/$(IAM) SCRIPTS = Install Remove OTHERS = pmns root DFILES = help README DEMOS = app1.c app2.c app3.c fapp1.f japp1.java DEMOFILES = README.demos Makefile.proto GNUmakefile.stub stub.c APPS = app1$(EXECSUFFIX) app2$(EXECSUFFIX) app3$(EXECSUFFIX) LCFLAGS = -I. LLDFLAGS= -L$(TOPDIR)/src/libpcp/src -L$(TOPDIR)/src/libpcp_trace/src LLDLIBS = $(PCP_TRACELIB) LDIRT = *.log *.dir *.pag *.o $(APPS) tmp.c \ pmtrace.c Makefile.demos LSRCFILES= $(SCRIPTS) $(OTHERS) $(DEMOS) $(DEMOFILES) $(DFILES) SUBDIRS = src default: $(SUBDIRS) Makefile.demos build-me $(SUBDIRS_MAKERULE) include $(BUILDRULES) ifneq "$(TARGET_OS)" "mingw" build-me: demos install: $(SUBDIRS) Makefile.demos $(SUBDIRS_MAKERULE) $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(SCRIPTS) $(PMDADIR) $(INSTALL) -m 644 $(OTHERS) $(DFILES) $(PMDADIR) $(INSTALL) -m 755 -d $(DEMODIR) $(INSTALL) -m 644 Makefile.demos $(DEMODIR)/Makefile $(INSTALL) -m 644 README.demos $(DEMODIR)/README $(INSTALL) -m 644 GNUmakefile.stub $(DEMODIR)/Makefile.stub $(INSTALL) -m 644 stub.c pmtrace.c $(DEMOS) $(DEMODIR) else build-me: install: $(SUBDIRS) endif demos: $(APPS) pmtrace.c pmtrace.c: $(TOPDIR)/src/pmtrace/pmtrace.c rm -f $@ && cp $< $@ app1.o: app1.c $(TOPDIR)/src/include/pcp/pmapi.h @rm -f tmp.c sed -e 's;;"\1";' app1.c >tmp.c $(CCF) -c -o $@ tmp.c @rm -f tmp.c app2.o: app2.c $(TOPDIR)/src/include/pcp/pmapi.h @rm -f tmp.c sed -e 's;;"\1";' app2.c >tmp.c $(CCF) -c -o $@ tmp.c @rm -f tmp.c app3.o: app3.c $(TOPDIR)/src/include/pcp/pmapi.h @rm -f tmp.c sed -e 's;;"\1";' app3.c >tmp.c $(CCF) -c -o $@ tmp.c @rm -f tmp.c app1$(EXECSUFFIX): app1.o $(CCF) -o $@ $(LDFLAGS) app1.o $(LDLIBS) app2$(EXECSUFFIX): app2.o $(CCF) -o $@ $(LDFLAGS) app2.o $(LDLIBS) app3$(EXECSUFFIX): app3.o $(CCF) -o $@ $(LDFLAGS) app3.o $(LDLIBS) $(LIB_FOR_PTHREADS) default_pcp: default install_pcp: install .NOTPARALLEL: Makefile.demos: Makefile.proto rm -f $@ sed \ -e 's/PTHREAD_LIB/$(LIB_FOR_PTHREADS)/' \ -e 's/DLOPEN_LIB/$(LIB_FOR_DLOPEN)/' \ -e 's/MATH_LIB/$(LIB_FOR_MATH)/' \ <$^ >$@ pcp-3.8.12ubuntu1/src/pmdas/trace/root0000664000000000000000000000016212272262501014500 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { trace } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/trace/app2.c0000664000000000000000000001000512272262501014575 0ustar /* * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * app2.c * * Sample program to demonstrate use of the PCP trace performance metrics * domain agent (PMDA(3)). This agent needs to be installed before metrics * can be made available via the performance metrics namespace (PMNS(4)), * and the Performance Metrics Collector Daemon (PMCD(1)). * * Once this program is running, the trace PMDA metrics & instances can be * viewed through PCP monitor tools such as pmchart(1), pmgadgets(1), and * pmview(1). To view the help text associated with each of these metrics, * use: * $ pminfo -tT trace */ #include #include #include #include #include #include #define IO_UPPER_LIMIT 1000 /* I/O ops */ #define CPU_UPPER_LIMIT 0xffff /* iterations */ #define TIME_UPPER_LIMIT 10 /* seconds */ static void io_sucker(void); static void cpu_sucker(void); static void time_sucker(void); static char *prog; int main(int argc, char **argv) { int i, sts; prog = argv[0]; srand48(time(0)); /* uncomment this for debugging information */ /* pmtracestate(PMTRACE_STATE_API|PMTRACE_STATE_COMMS|PMTRACE_STATE_PDU); */ /* uncomment this to use the asynchronous protocol */ /* pmtracestate(PMTRACE_STATE_ASYNC); */ for (i = 0;; i++) { if ((sts = pmtracepoint("mainloop")) < 0) { fprintf(stderr, "%s: mainloop point trace failed (%d): %s\n", prog, sts, pmtraceerrstr(sts)); exit(1); } switch(i % 3) { case 0: time_sucker(); break; case 1: io_sucker(); break; case 2: cpu_sucker(); break; } } } static void cpu_sucker(void) { int i, j, sts; double array[100]; long iterations; if ((sts = pmtracebegin("cpu_sucker")) < 0) { fprintf(stderr, "%s: cpu_sucker begin (%d): %s\n", prog, sts, pmtraceerrstr(sts)); return; } iterations = lrand48() % CPU_UPPER_LIMIT; memset((void *)array, 0, 100*sizeof(double)); for (i = 0; i < iterations; i++) for (j = 0; j < 100; j++) array[j] = (double)(j*iterations); if ((sts = pmtraceend("cpu_sucker")) < 0) { fprintf(stderr, "%s: cpu_sucker end (%d): %s\n", prog, sts, pmtraceerrstr(sts)); return; } } static void time_sucker(void) { long seconds; int sts; if ((sts = pmtracebegin("time_sucker")) < 0) { fprintf(stderr, "%s: time_sucker start (%d): %s\n", prog, sts, pmtraceerrstr(sts)); return; } seconds = lrand48() % TIME_UPPER_LIMIT; sleep((unsigned int)seconds); if ((sts = pmtraceend("time_sucker")) < 0) { fprintf(stderr, "%s: time_sucker end (%d): %s\n", prog, sts, pmtraceerrstr(sts)); return; } } static void io_sucker(void) { long characters; FILE *foo; int i, sts; if ((sts = pmtracebegin("io_sucker")) < 0) { fprintf(stderr, "%s: io_sucker start (%d): %s\n", prog, sts, pmtraceerrstr(sts)); return; } if ((foo = fopen("/dev/null", "rw")) == NULL) { fprintf(stderr, "%s: io_sucker can't open /dev/null.\n", prog); return; } characters = lrand48() % IO_UPPER_LIMIT; for (i = 0; i < characters; i++) { fgetc(foo); fputc('!', foo); } fclose(foo); if ((sts = pmtraceend("io_sucker")) < 0) { fprintf(stderr, "%s: io_sucker end (%d): %s\n", prog, sts, pmtraceerrstr(sts)); return; } } pcp-3.8.12ubuntu1/src/pmdas/trace/pmns0000664000000000000000000000261312272262501014475 0ustar /* * Metrics for trace PMDA * * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ trace { transact point observe counter control } trace.transact { count TRACE:0:0 rate TRACE:0:1 ave_time TRACE:0:2 min_time TRACE:0:3 max_time TRACE:0:4 total_time TRACE:0:5 } trace.point { count TRACE:0:6 rate TRACE:0:7 } trace.observe { count TRACE:0:8 rate TRACE:0:9 value TRACE:0:10 } trace.control { period TRACE:0:11 interval TRACE:0:12 buckets TRACE:0:13 port TRACE:0:14 reset TRACE:0:15 debug TRACE:0:16 } trace.counter { count TRACE:0:17 rate TRACE:0:18 value TRACE:0:19 } pcp-3.8.12ubuntu1/src/pmdas/trace/GNUmakefile.stub0000664000000000000000000000443312272262501016625 0ustar # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # include $(PCP_ETC_DIR)/pcp.conf # need to deal with these ... # ELF style # /usr/lib/libpcp_trace.a /usr/lib/libpcp_trace.so /usr/lib/libpcp_trace.so.2 # Mac OS X style # /usr/lib/libpcp_trace.2.dylib # DSO_SUFFIX = $(shell ls $(PCP_LIB_DIR)/libpcp_trace.* | sed -e '/\.a$$/d' -e 's/.*libpcp_trace//' -e 's/\.[0-9][0-9]*//' -e 's/^\.//' | sed -e 1q) ifeq "$(DSO_SUFFIX)" "" $(error cannot set DSO_SUFFIX on this platform) endif # Note: DSO_VERSION includes (starts with or ends with) $(DSO_SUFFIX) # DSO_VERSION = $(shell ls $(PCP_LIB_DIR)/libpcp_trace.* | sed -n -e '/\.a$$/d' -e 's/.*libpcp_trace\.//' -e '/\.$(DSO_SUFFIX)/p' -e '/$(DSO_SUFFIX)\./p' | sed -e 's/^\.//' -e 1q) ifeq "$(DSO_VERSION)" "" $(error cannot set DSO_VERSION on this platform) endif SHELL = /bin/sh CC = cc TARGETS = lib/libpcp_trace.$(DSO_VERSION) ifeq "$(shell [ -f $(PCP_LIB_DIR)/libpcp_trace.$(DSO_SUFFIX) ] && echo 1)" "1" TARGETS += lib/libpcp_trace.$(DSO_SUFFIX) endif CFILES = stub.c CFLAGS += -DPMTRACE_DEBUG CFLAGS += -fPIC -fno-strict-aliasing LDIRT = lib lib32 lib64 default: $(TARGETS) lib/libpcp_trace.$(DSO_VERSION): stub.c -[ ! -d lib ] && mkdir lib rm -f $@ cd lib; $(CC) $(CFLAGS) -shared ../stub.c -o libpcp_trace.$(DSO_VERSION) lib/libpcp_trace.$(DSO_SUFFIX): lib/libpcp_trace.$(DSO_VERSION) rm -f $@ cd lib; ln -s libpcp_trace.$(DSO_VERSION) libpcp_trace.$(DSO_SUFFIX) clean: rm -rf $(LDIRT) clobber: rm -rf $(LDIRT) $(TARGETS) debug: @echo "DSO_SUFFIX=$(DSO_SUFFIX)" @echo "DSO_VERSION=$(DSO_VERSION)" @echo "TARGETS=$(TARGETS)" pcp-3.8.12ubuntu1/src/pmdas/trace/japp1.java0000664000000000000000000000315312272262501015453 0ustar // // Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. // // This program is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your // option) any later version. // // This program is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // public class japp1 { public static void main(String[] args) { int sts; trace pcp = new trace(); pcp.pmtracestate(pcp.PMTRACE_STATE_API); sts = pcp.pmtracebegin("transacting in java"); if (sts < 0) System.out.println("pmtracebegin error: " + pcp.pmtraceerrstr(sts)); sts = pcp.pmtraceend("transacting in java"); if (sts < 0) System.out.println("pmtraceend error: " + pcp.pmtraceerrstr(sts)); sts = pcp.pmtracepoint("java point"); if (sts < 0) System.out.println("pmtracepoint error: " + pcp.pmtraceerrstr(sts)); sts = pcp.pmtraceobs("observing from java", 789.034018); if (sts < 0) System.out.println("pmtraceobs error: " + pcp.pmtraceerrstr(sts)); sts = pcp.pmtracecounter("counter from java", 789.034019); if (sts < 0) System.out.println("pmtracecounter error: " + pcp.pmtraceerrstr(sts)); } } pcp-3.8.12ubuntu1/src/pmdas/trace/help0000664000000000000000000001454712272262501014461 0ustar # # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # trace PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ TRACE.0 Instance domain "trace tag name" for trace PMDA There is one instance for each transaction which has been seen by the trace PMDA during the reporting period. @ trace.transact.count count by transaction Count by transaction tag of transactions serviced since the trace PMDA was started. @ trace.transact.rate transaction completion rate over time period The rate at which each transaction is completed, calculated over the trace PMDAs aggregation period. The exported value is equal to the count of transactions completed during the aggregation interval, divided by the aggregation interval. @ trace.transact.ave_time average transaction time over time period The average time taken to complete each transaction, calculated over the trace PMDAs aggregation period. The exported value is equal to the sum of the transaction completion times seen during the aggregation interval divided by the number of transactions completed during the aggregation interval. @ trace.transact.max_time maximum time per transaction Maximum recorded service time per transaction tag within the current reporting period. @ trace.transact.min_time minimum time per transaction Minimum recorded service time per transaction tag within the current reporting period. @ trace.transact.total_time total time per transaction Cumulative time spent processing each transaction since the trace PMDA was started. @ trace.point.count count of point function executions Count by point tag of marked application points serviced since the trace PMDA was started. @ trace.point.rate point rate over time period The rate at which execution points are completed, calculated over the aggregation period in use by the trace PMDA. The exported value is equal to the count of successful pmtracepoint(3) calls made during the aggregation interval, divided by the aggregation interval. @ trace.counter.count count of counter values received Count, by counter tag, of `counter' values received since the trace PMDA was started. @ trace.counter.rate counter value received rate over time period The rate at which execution counters are received, calculated over the aggregation period in use by the trace PMDA. The exported value is equal to the count of pmtracecounter(3) calls made during the aggregation interval, divided by the aggregation interval. @ trace.counter.value counter value at last observation The numeric counter value associated with the last seen counter tag, since the trace PMDA was started. @ trace.observe.count count of observations Count, by observation tag, of application `observe' points serviced since the trace PMDA was started. @ trace.observe.rate observation rate over time period The rate at which execution observations are completed, calculated over the aggregation period in use by the trace PMDA. The exported value is equal to the count of pmtraceobs(3) calls made during the aggregation interval, divided by the aggregation interval. @ trace.observe.value value at last observation The numeric value associated with the last seen observation, since the trace PMDA was started. @ trace.control.period reporting time period Time (in seconds) over which trace performance data will be gathered. Any transaction or point trace data seen by the trace PMDA during the period will be included in the set of exported values. @ trace.control.interval update interval within time period The update interval (within the overall period) at which the current working set of performance data maintained within the trace PMDA will be switched into the set of historical data buffers, which are then used to calculate the exported performance metric values. This value is directly calculated from the overall time period and the number of buckets of historical data being maintained within the trace PMDA. For example, if the overall period is 60 seconds and the number of historical data buckets being maintained is 12, then the buffers will be rotated once every 5 seconds. @ trace.control.buckets number of historical buffers The number of buffers of historical data maintained by the trace PMDA. Each bucket contains all transaction and event performance data seen over a set time interval within the overall reporting time period. @ trace.control.port port number for client connections The TCP/IP port number which the trace PMDA is waiting for client connections on. This has been set as either the default (4322), via the command line, or via the PMDA_TRACE_PORT environment variable when the trace PMDA was started. @ trace.control.reset clear all tags known to the trace PMDA Storing any value into this metric with pmstore(1) will cause the trace PMDA to clear all tags for all metrics from its historical buffers and begin afresh. This is most useful when the instance domains of the trace metrics have become cluttered with unwanted instances, and the instance domains need to be refreshed without restarting pmcd(1). @ trace.control.debug set the debug level in the trace PMDA Storing values into this metric with pmstore(1) allows the level of diagnostic output from the trace PMDA to be controlled. By default, the diagnostic output will be written to the file $PCP_LOG_DIR/pmcd/trace.log. pcp-3.8.12ubuntu1/src/pmdas/netfilter/0000775000000000000000000000000012272262620014473 5ustar pcp-3.8.12ubuntu1/src/pmdas/netfilter/pmlogconf.config0000664000000000000000000000022612272262501017644 0ustar #pmlogconf-setup 2.0 ident Netfilter configuration probe netfilter.ip_conntrack_max exists ? include : exclude delta once netfilter.ip_conntrack_max pcp-3.8.12ubuntu1/src/pmdas/netfilter/Remove0000775000000000000000000000126512272262501015660 0ustar #!/bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the NetFilter PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=netfilter pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/netfilter/Install0000775000000000000000000000154712272262501016034 0ustar #!/bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the NetFilter PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=netfilter perl_opt=true daemon_opt=false forced_restart=false if ! test -d /proc/sys/net/ipv4/netfilter; then echo "IP connection tracking not enabled in your kernel" exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/netfilter/pmlogconf.summary0000664000000000000000000000022512272262501020073 0ustar #pmlogconf-setup 2.0 ident Netfilter summary information probe netfilter.ip_conntrack_count exists ? include : exclude netfilter.ip_conntrack_count pcp-3.8.12ubuntu1/src/pmdas/netfilter/GNUmakefile0000664000000000000000000000304012272262501016540 0ustar #!gmake # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = netfilter PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl pmlogconf.config pmlogconf.summary LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) ifeq "$(TARGET_OS)" "linux" install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) $(INSTALL) -m 755 -d $(PCP_VAR_DIR)/config/pmlogconf/$(IAM) $(INSTALL) -m 644 pmlogconf.summary $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)/summary $(INSTALL) -m 644 pmlogconf.config $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)/config else install: endif default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/netfilter/pmdanetfilter.pl0000664000000000000000000000513212272262501017665 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; my $pmda = PCP::PMDA->new('netfilter', 97); my $procfs = '/proc/sys/net/ipv4/'; sub netfilter_fetch_callback { my ($cluster, $item, $inst) = @_; my $metric_name = pmda_pmid_name($cluster, $item); my ($path, $name, $value, $fh, @vals); if ($inst != PM_IN_NULL) { return (PM_ERR_INST, 0); } if (!defined($metric_name)) { return (PM_ERR_PMID, 0); } $metric_name =~ s/\./\//; $name = $procfs . $metric_name; open($fh, $name) || return (PM_ERR_APPVERSION, 0); $value = <$fh>; close $fh; chomp $value; return ($value, 1); } $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'netfilter.ip_conntrack_max', '', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'netfilter.ip_conntrack_count', '', ''); $pmda->set_fetch_callback(\&netfilter_fetch_callback); $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdanetfilter - Linux netfilter IP connection tracking performance metrics domain agent (PMDA) =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from IP connection tracking module in the Linux kernel. =head1 INSTALLATION If you want access to the names and values for the netfilter performance metrics, do the following as root: # cd $PCP_PMDAS_DIR/netfilter # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/netfilter # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/netfilter/Install installation script for the B agent =item $PCP_PMDAS_DIR/netfilter/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/netfilter.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1). pcp-3.8.12ubuntu1/src/pmdas/windows/0000775000000000000000000000000012272262620014171 5ustar pcp-3.8.12ubuntu1/src/pmdas/windows/error.c0000664000000000000000000002320712272262501015470 0ustar /* * Error code -> message map comes from * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/perfmon/base/pdh_error_codes.asp * * Copyright (c) 2008 Aconex. All Rights Reserved. * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "hypnotoad.h" static struct { int code; char *msg; } errtab[] = { { PDH_CSTATUS_VALID_DATA, "The returned data is valid." }, { PDH_CSTATUS_NEW_DATA, "The return data value is valid and different from the last sample." }, { PDH_CSTATUS_NO_MACHINE, "Unable to connect to specified machine or machine is off line." }, { PDH_CSTATUS_NO_INSTANCE, "The specified instance is not present." }, { PDH_MORE_DATA, "There is more data to return than would fit in the supplied buffer. Allocate a larger buffer and call the function again." }, { PDH_CSTATUS_ITEM_NOT_VALIDATED, "The data item has been added to the query but has not been validated nor accessed. No other status information on this data item is available." }, { PDH_RETRY, "The selected operation should be retried." }, { PDH_NO_DATA, "No data to return." }, { PDH_CALC_NEGATIVE_DENOMINATOR, "A counter with a negative denominator value was detected." }, { PDH_CALC_NEGATIVE_TIMEBASE, "A counter with a negative time base value was detected." }, { PDH_CALC_NEGATIVE_VALUE, "A counter with a negative value was detected." }, { PDH_DIALOG_CANCELLED, "The user canceled the dialog box." }, { PDH_END_OF_LOG_FILE, "The end of the log file was reached." }, { PDH_ASYNC_QUERY_TIMEOUT, "Time out while waiting for asynchronous counter collection thread to end." }, { PDH_CANNOT_SET_DEFAULT_REALTIME_DATASOURCE, "Cannot change set default real-time data source. There are real-time query sessions collecting counter data." }, { PDH_CSTATUS_NO_OBJECT, "The specified object is not found on the system." }, { PDH_CSTATUS_NO_COUNTER, "The specified counter could not be found." }, { PDH_CSTATUS_INVALID_DATA, "The returned data is not valid." }, { PDH_MEMORY_ALLOCATION_FAILURE, "A PDH function could not allocate enough temporary memory to complete the operation. Close some applications or extend the page file and retry the function." }, { PDH_INVALID_HANDLE, "The handle is not a valid PDH object." }, { PDH_INVALID_ARGUMENT, "A required argument is missing or incorrect." }, { PDH_FUNCTION_NOT_FOUND, "Unable to find the specified function." }, { PDH_CSTATUS_NO_COUNTERNAME, "No counter was specified." }, { PDH_CSTATUS_BAD_COUNTERNAME, "Unable to parse the counter path. Check the format and syntax of the specified path." }, { PDH_INVALID_BUFFER, "The buffer passed by the caller is invalid." }, { PDH_INSUFFICIENT_BUFFER, "The requested data is larger than the buffer supplied. Unable to return the requested data." }, { PDH_CANNOT_CONNECT_MACHINE, "Unable to connect to the requested machine." }, { PDH_INVALID_PATH, "The specified counter path could not be interpreted." }, { PDH_INVALID_INSTANCE, "The instance name could not be read from the specified counter path." }, { PDH_INVALID_DATA, "The data is not valid." }, { PDH_NO_DIALOG_DATA, "The dialog box data block was missing or invalid." }, { PDH_CANNOT_READ_NAME_STRINGS, "Unable to read the counter and/or explain text from the specified machine." }, { PDH_LOG_FILE_CREATE_ERROR, "Unable to create the specified log file." }, { PDH_LOG_FILE_OPEN_ERROR, "Unable to open the specified log file." }, { PDH_LOG_TYPE_NOT_FOUND, "The specified log file type has not been installed on this system." }, { PDH_NO_MORE_DATA, "No more data is available." }, { PDH_ENTRY_NOT_IN_LOG_FILE, "The specified record was not found in the log file." }, { PDH_DATA_SOURCE_IS_LOG_FILE, "The specified data source is a log file." }, { PDH_DATA_SOURCE_IS_REAL_TIME, "The specified data source is the current activity." }, { PDH_UNABLE_READ_LOG_HEADER, "The log file header could not be read." }, { PDH_FILE_NOT_FOUND, "Unable to find the specified file." }, { PDH_FILE_ALREADY_EXISTS, "There is already a file with the specified file name." }, { PDH_NOT_IMPLEMENTED, "The function referenced has not been implemented." }, { PDH_STRING_NOT_FOUND, "Unable to find the specified string in the list of performance name and explain text strings." }, { PDH_UNABLE_MAP_NAME_FILES, "Unable to map to the performance counter name data files. The data will be read from the registry and stored locally." }, { PDH_UNKNOWN_LOG_FORMAT, "The format of the specified log file is not recognized by the PDH DLL." }, { PDH_UNKNOWN_LOGSVC_COMMAND, "The specified Log Service command value is not recognized." }, { PDH_LOGSVC_QUERY_NOT_FOUND, "The specified Query from the Log Service could not be found or could not be opened." }, { PDH_LOGSVC_NOT_OPENED, "The Performance Data Log Service key could not be opened. This may be due to insufficient privilege or because the service has not been installed." }, { PDH_WBEM_ERROR, "An error occurred while accessing the WBEM data store." }, { PDH_ACCESS_DENIED, "Unable to access the desired machine or service. Check the permissions and authentication of the log service or the interactive user session against those on the machine or service being monitored." }, { PDH_LOG_FILE_TOO_SMALL, "The maximum log file size specified is too small to log the selected counters. No data will be recorded in this log file. Specify a smaller set of counters to log or a larger file size and retry this call." }, { PDH_INVALID_DATASOURCE, "Cannot connect to ODBC DataSource Name." }, { PDH_INVALID_SQLDB, "SQL Database does not contain a valid set of tables for Perfmon; use PdhCreateSQLTables." }, { PDH_NO_COUNTERS, "No counters were found for this Perfmon SQL Log Set." }, { PDH_SQL_ALLOC_FAILED, "Call to SQLAllocStmt failed with %1." }, { PDH_SQL_ALLOCCON_FAILED, "Call to SQLAllocConnect failed with %1." }, { PDH_SQL_EXEC_DIRECT_FAILED, "Call to SQLExecDirect failed with %1." }, { PDH_SQL_FETCH_FAILED, "Call to SQLFetch failed with %1." }, { PDH_SQL_ROWCOUNT_FAILED, "Call to SQLRowCount failed with %1." }, { PDH_SQL_MORE_RESULTS_FAILED, "Call to SQLMoreResults failed with %1." }, { PDH_SQL_CONNECT_FAILED, "Call to SQLConnect failed with %1." }, { PDH_SQL_BIND_FAILED, "Call to SQLBindCol failed with %1." }, { PDH_CANNOT_CONNECT_WMI_SERVER, "Unable to connect to the WMI server on requested machine." }, { PDH_PLA_COLLECTION_ALREADY_RUNNING, "Collection %1s is already running." }, { PDH_PLA_ERROR_SCHEDULE_OVERLAP, "The specified start time is after the end time." }, { PDH_PLA_COLLECTION_NOT_FOUND, "Collection %1 does not exist." }, { PDH_PLA_ERROR_SCHEDULE_ELAPSED, "The specified end time has already elapsed." }, { PDH_PLA_ERROR_NOSTART, "Collection %1 did not start check the application event log for any errors." }, { PDH_PLA_ERROR_ALREADY_EXISTS, "Collection %1 already exists." }, { PDH_PLA_ERROR_TYPE_MISMATCH, "There is a mismatch in the settings type." }, { PDH_PLA_ERROR_FILEPATH, "The information specified does not resolve to a valid path name." }, { PDH_PLA_SERVICE_ERROR, "The 'Performance Logs & Alerts' service did not respond." }, { PDH_PLA_VALIDATION_ERROR, "The information passed is not valid." }, { PDH_PLA_VALIDATION_WARNING, "The information passed is not valid." }, { PDH_PLA_ERROR_NAME_TOO_LONG, "The name supplied is too long." }, { PDH_INVALID_SQL_LOG_FORMAT, "SQL log format is incorrect. Correct format is 'SQL:!'." }, { PDH_COUNTER_ALREADY_IN_QUERY, "Performance counter in PdhAddCounter call has already been added in the performance query. This counter is ignored." }, { PDH_BINARY_LOG_CORRUPT, "Unable to read counter information and data from input binary log files." }, { PDH_LOG_SAMPLE_TOO_SMALL, "At least one of the input binary log files contain fewer than two data samples." }, { PDH_OS_LATER_VERSION, "The version of the operating system on the computer named %1 is later than that on the local computer. This operation is not available from the local computer." }, { PDH_OS_EARLIER_VERSION, "supports %2 or later. Check the operating system version on the computer named %3." }, { PDH_INCORRECT_APPEND_TIME, "The output file must contain earlier data than the file to be appended." }, { PDH_UNMATCHED_APPEND_COUNTER, "Both files must have identical counters in order to append." }, { PDH_SQL_ALTER_DETAIL_FAILED, "Cannot alter CounterDetail table layout in SQL database." }, { PDH_QUERY_PERF_DATA_TIMEOUT, "System is busy. Timeout when collecting counter data. Please retry later or increase the CollectTime registry value." } }; static int sz_errtab = sizeof(errtab) / sizeof(errtab[0]); static char *buf = "eh? 0x........"; char *pdherrstr(int code) { int i; for (i = 0; i < sz_errtab; i++) { if (code == errtab[i].code) return errtab[i].msg; } sprintf(buf, "eh? 0x%08x", code); return buf; } pcp-3.8.12ubuntu1/src/pmdas/windows/pmns.network0000664000000000000000000000133112272262501016555 0ustar network { interface tcp } network.interface { in out total bandwidth WINDOWS:0:235 speed WINDOWS:0:236 baudrate WINDOWS:0:237 } network.interface.in { packets WINDOWS:0:38 bytes WINDOWS:0:39 errors WINDOWS:0:40 } network.interface.out { packets WINDOWS:0:41 bytes WINDOWS:0:42 errors WINDOWS:0:43 } network.interface.total { packets WINDOWS:0:44 bytes WINDOWS:0:45 } network.tcp { activeopens WINDOWS:0:123 passiveopens WINDOWS:0:124 attemptfails WINDOWS:0:125 estabresets WINDOWS:0:126 currestab WINDOWS:0:127 insegs WINDOWS:0:128 outsegs WINDOWS:0:129 totalsegs WINDOWS:0:130 retranssegs WINDOWS:0:131 } pcp-3.8.12ubuntu1/src/pmdas/windows/README0000664000000000000000000001225612272262501015055 0ustar Windows PMDA ============ This PMDA collects performance data from a Microsoft Windows kernel. Metrics ======= The help text is exported from the kernel via the PDH (Performance Data Helper) APIs. To view the help text, install the PMDA, then the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT kernel disk mem network filesys sqlserver hinv pmda process Installation ============ + # cd $PCP_PMDAS_DIR/windows + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options -- everything else is automated. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/windows # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/windows.log) should be checked for any warnings or errors. Adding New Metrics ================== The following steps should be followed when adding new metrics ... this assumes the MinGW gcc compiler is being used. a. Make sure you know what you've currently got, so on the target system $ ./pdhlist | ./pdhmatch >status-quo b. Pick the Pdh paths you're interested in (drop the hostname prefix, add the (*/*#*) or * patterns as appropriate. Beware that metrics with multiple instances are reported multiple times ... for example SQLServer:Cache Manager\Cache Hit Ratio SQLServer:Cache Manager(_Total)\Cache Hit Ratio SQLServer:Cache Manager(*/*#*)\Cache Hit Ratio of these, the first pattern must not be used ... use the second one if you want the "over all instances" totals, and the last one gives the per instance metrics. c. Choose a PMID ... use the next unused number in sequence ... check metricdesc[] in pmda.c, you want the PMDA_PMID(0,x) macro from the last entry in the table, and the number you're after is x+1 (x+1 = 81 for my example). d. Choose a name and where to put the new metric in the namespace ... edit the appropriate pmns.* file (let's assume you're adding to one of the existing Pdh groups, rather than creating a new one which is more complicated), adding an appropriate entry using x+1 from above for the last component of the PMID. Something like this in pmns.sqlserver sqlserver { ... cache_mgr // new line } ... // all new lines from here down sqlserver.cache_mgr { all percache } sqlserver.cache_mgr.all { cache_hit_ratio WINDOWS:0:81 } sqlserver.cache_mgr.cache { cache_hit_ratio WINDOWS:0:82 } Write the modified pmns file. Check you've got it right with $ pminfo -m -n root sqlserver.cache_mgr sqlserver.cache_mgr.all.cache_hit_ratio PMID: 79.0.81 sqlserver.cache_mgr.cache.cache_hit_ratio PMID: 79.0.82 e. Metric semantics ... you'll need a complete metricdesc[i] initializer from pmda.c ... pick one that is similar, copy, paste at the end of the table initialization and update PMDA_PMID(0,y) with x+1 from step a. To help with "similar" here are some examples: kernel.all.cpu.user - unsigned 64-bit counter in units of microseconds network.interface.in.bytes - unsigned 32-bit counter in units of bytes with one value per network interface mem.available - unsigned 64-bit instantaneous value in units of Mbytes sqlserver.buf_mgr.cache_hit_ratio - floating point value representing a cache hit ratio, returned in the range 0.0 to 1.0 Be careful with '\' in the Pdh patterns. Replace them with '\\' in the string initializer used here. My new metrics are cache hit ratios /* sqlserver.cache_mgr.all.cache_hit_ratio */ { { PMDA_PMID(0,81), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_OPTIONAL, 0, 0, 0, NULL, "\\SQLServer:Cache Manager(_Total)\\Cache Hit Ratio" }, /* sqlserver.cache_mgr.cache.cache_hit_ratio */ { { PMDA_PMID(0,82), PM_TYPE_FLOAT, SQL_CACHE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_OPTIONAL, 0, 0, 0, NULL, "\\SQLServer:Cache Manager(*/*#*)\\Cache Hit Ratio" }, f. If you've added a new instance domain (SQL_CACHE_INDOM in the case above, this needs to be handled): i. add a new header #define line (use the next ordinal number), e.g. #define SQL_CACHE_INDOM 5 ii. add a new entry to indomtab[] in pmda.c, e.g. { SQL_CACHE_INDOM, 0, NULL }, iii. add a new entry to indomtab[] in instance.c, e.g. SQL_CACHE_INDOM, iv. add new code in the switch of check_instance() in instance.c to parse the Pdh instance name to extract a PCP instance name and assign an instance number ... it is strongly suggested that you study the ones already there, steal and modify the one that is closest to your new instance g. Make and upgrade (assuming you're on the target machine and not interested in packaging) $ make $ su # /etc/pcp stop # make install # cd $PCP_VAR_DIR/pmdas/windows # ./Install pcp-3.8.12ubuntu1/src/pmdas/windows/fetch.c0000664000000000000000000001415412272262501015431 0ustar /* * Copyright (c) 2008-2010 Aconex. All Rights Reserved. * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "hypnotoad.h" MEMORYSTATUSEX windows_memstat; void windows_fetch_memstat(void) { ZeroMemory(&windows_memstat, sizeof(MEMORYSTATUSEX)); windows_memstat.dwLength = sizeof(MEMORYSTATUSEX); GlobalMemoryStatusEx(&windows_memstat); } /* * Instantiate a value for a single metric-instance pair */ int windows_collect_metric(pdh_metric_t *mp, LPSTR pat, pdh_value_t *vp) { PDH_STATUS pdhsts; PDH_HQUERY queryhdl = NULL; PDH_HCOUNTER counthdl = NULL; int sts = -1; if (mp->flags & M_NOVALUES) return sts; pdhsts = PdhOpenQueryA(NULL, 0, &queryhdl); if (pdhsts != ERROR_SUCCESS) { __pmNotifyErr(LOG_ERR, "windows_open: PdhOpenQueryA failed: %s\n", pdherrstr(pdhsts)); return sts; } pdhsts = PdhAddCounterA(queryhdl, pat, vp->inst, &counthdl); if (pdhsts != ERROR_SUCCESS) { __pmNotifyErr(LOG_ERR, "windows_open: Warning: PdhAddCounterA " "@ pmid=%s pat=\"%s\": %s\n", pmIDStr(mp->desc.pmid), pat, pdherrstr(pdhsts)); PdhCloseQuery(queryhdl); return sts; } pdhsts = PdhCollectQueryData(queryhdl); if (pdhsts != ERROR_SUCCESS) { if ((vp->flags & V_ERROR_SEEN) == 0) { __pmNotifyErr(LOG_ERR, "pdh_fetch: Error: PdhCollectQueryData " "failed for metric %s pat %s: %s\n", pmIDStr(mp->desc.pmid), pat, pdherrstr(pdhsts)); vp->flags |= V_ERROR_SEEN; } } else if ((mp->ctype == PERF_ELAPSED_TIME) || mp->ctype == PERF_LARGE_RAW_FRACTION) { PDH_FMT_COUNTERVALUE fmt; DWORD type; if (mp->ctype == PERF_ELAPSED_TIME) type = PDH_FMT_LARGE; else /* PERF_LARGE_RAW_FRACTION */ type = PDH_FMT_DOUBLE; pdhsts = PdhGetFormattedCounterValue(counthdl, type, NULL, &fmt); if (pdhsts != ERROR_SUCCESS) { __pmNotifyErr(LOG_ERR, "Error: PdhGetFormattedCounterValue " "failed for metric %s inst %d: %s\n", pmIDStr(mp->desc.pmid), vp->inst, pdherrstr(pdhsts)); vp->flags = V_NONE; /* no values for you! */ } else if (mp->ctype == PERF_ELAPSED_TIME) { vp->atom.ull = fmt.largeValue; sts = 0; } else { /* PERF_LARGE_RAW_FRACTION */ vp->atom.d = fmt.doubleValue; sts = 0; } } else { PDH_RAW_COUNTER raw; pdhsts = PdhGetRawCounterValue(counthdl, NULL, &raw); if (pdhsts != ERROR_SUCCESS) { __pmNotifyErr(LOG_ERR, "pdh_fetch: Error: PdhGetRawCounterValue " "failed for metric %s inst %d: %s\n", pmIDStr(mp->desc.pmid), vp->inst, pdherrstr(pdhsts)); vp->flags = V_NONE; /* no values for you! */ } else { switch (mp->ctype) { case PERF_COUNTER_COUNTER: case PERF_COUNTER_RAWCOUNT: /* these counters are only 32-bit */ vp->atom.ul = (__uint32_t)raw.FirstValue; break; case PERF_100NSEC_TIMER: case PERF_PRECISION_100NS_TIMER: /* convert 100nsec units to usec */ vp->atom.ull = raw.FirstValue / 10; break; case PERF_RAW_FRACTION: /* v1 / v2 as percentage */ vp->atom.f = (float)raw.FirstValue / raw.SecondValue; break; case PERF_COUNTER_BULK_COUNT: case PERF_COUNTER_LARGE_RAWCOUNT: default: vp->atom.ull = raw.FirstValue; } sts = 0; } } PdhRemoveCounter(counthdl); PdhCloseQuery(queryhdl); return sts; } void windows_collect_callback(pdh_metric_t *pmp, LPTSTR pat, pdh_value_t *pvp) { windows_verify_callback(pmp, pat, pvp); if (!(pvp->flags & V_COLLECTED)) if (windows_collect_metric(pmp, pat, pvp) == 0) pvp->flags |= V_COLLECTED; } /* * Called before each PMDA fetch ... force value refreshes for * requested metrics here; and special case any derived metrics. */ void windows_fetch_refresh(int numpmid, pmID pmidlist[], pmdaExt *pmda) { int i, j, extra_filesys = 0, extra_memstat = 0; int extra_hinv_ncpu = -1, extra_hinv_ndisk = -1; int extra_network = -1; for (i = 0; i < NUMINDOMS; i++) windows_indom_reset[i] = 0; for (i = 0; i < metricdesc_sz; i++) for (j = 0; j < metricdesc[i].num_vals; j++) metricdesc[i].vals[j].flags = V_NONE; for (i = 0; i < numpmid; i++) { __pmID_int *pmidp = (__pmID_int *)&pmidlist[i]; int cluster = pmidp->cluster; int item = pmidp->item; if (cluster == 1) extra_memstat = 1; else if (cluster != 0) continue; else if (item == 106) extra_memstat = 1; else if (item == 107 && extra_hinv_ncpu == -1) extra_hinv_ncpu = 1; else if (item == 108 && extra_hinv_ndisk == -1) extra_hinv_ndisk = 1; else if (item >= 117 && item <= 119) extra_filesys = 1; else if (item >= 236 && item <= 237 && extra_network == -1) extra_network = 1; else { if (item >= 4 && item <= 7) extra_hinv_ncpu = 0; else if ((item >= 21 && item <= 26) || item == 68 || (item >= 217 && item <= 219) || item == 101 || (item >= 226 && item <= 231) || item == 133) extra_hinv_ndisk = 0; else if (item == 235) extra_network = 0; windows_visit_metric(&metricdesc[item], windows_collect_callback); } } if (extra_memstat) windows_fetch_memstat(); if (extra_hinv_ncpu == 1) windows_visit_metric(&metricdesc[4], NULL); if (extra_hinv_ndisk == 1) windows_visit_metric(&metricdesc[21], NULL); if (extra_filesys) { windows_visit_metric(&metricdesc[120], windows_collect_callback); windows_visit_metric(&metricdesc[121], windows_collect_callback); } if (extra_network == 1) windows_visit_metric(&metricdesc[235], windows_collect_callback); for (i = 0; i < NUMINDOMS; i++) { /* Do we want to persist this instance domain to disk? */ if (windows_indom_reset[i] && windows_indom_fixed(i)) pmdaCacheOp(INDOM(pmda->e_domain, i), PMDA_CACHE_SAVE); } } pcp-3.8.12ubuntu1/src/pmdas/windows/pmns.hinv0000664000000000000000000000021512272262501016030 0ustar hinv { physmem WINDOWS:0:106 ncpu WINDOWS:0:107 ndisk WINDOWS:0:108 nfilesys WINDOWS:0:232 pagesize WINDOWS:0:233 } pcp-3.8.12ubuntu1/src/pmdas/windows/pmns.kernel0000664000000000000000000000134112272262501016345 0ustar kernel { all percpu num_processes WINDOWS:0:8 num_threads WINDOWS:0:9 uname } kernel.all { cpu file pswitch WINDOWS:0:10 uptime WINDOWS:0:234 } kernel.all.cpu { user WINDOWS:0:0 idle WINDOWS:0:1 sys WINDOWS:0:2 intr WINDOWS:0:3 } kernel.percpu { cpu } kernel.percpu.cpu { user WINDOWS:0:4 idle WINDOWS:0:5 sys WINDOWS:0:6 intr WINDOWS:0:7 } kernel.all.file { read WINDOWS:0:11 write WINDOWS:0:12 read_bytes WINDOWS:0:13 write_bytes WINDOWS:0:14 } kernel.uname { distro WINDOWS:0:109 release WINDOWS:0:110 version WINDOWS:0:111 sysname WINDOWS:0:112 machine WINDOWS:0:113 nodename WINDOWS:0:114 } pcp-3.8.12ubuntu1/src/pmdas/windows/pmns.sqlserver0000664000000000000000000000630712272262501017122 0ustar sqlserver { access buf_mgr cache_mgr databases latches locks sql connections WINDOWS:0:83 mem_mgr user_settable } sqlserver.buf_mgr { cache_hit_ratio WINDOWS:0:46 page_lookups WINDOWS:0:47 free_list_stalls WINDOWS:0:48 free_pages WINDOWS:0:49 total_pages WINDOWS:0:50 target_pages WINDOWS:0:51 database_pages WINDOWS:0:52 reserved_pages WINDOWS:0:53 stolen_pages WINDOWS:0:54 lazy_writes WINDOWS:0:55 readahead_pages WINDOWS:0:56 procedure_cache_pages WINDOWS:0:57 page_reads WINDOWS:0:58 page_writes WINDOWS:0:59 checkpoint_pages WINDOWS:0:60 awe page_life_expectancy WINDOWS:0:66 } sqlserver.buf_mgr.awe { lookup_maps WINDOWS:0:61 stolen_maps WINDOWS:0:62 write_maps WINDOWS:0:63 unmap_calls WINDOWS:0:64 unmap_pages WINDOWS:0:65 } sqlserver.locks { all region } sqlserver.locks.all { requests WINDOWS:0:69 waits WINDOWS:0:70 deadlocks WINDOWS:0:71 timeouts WINDOWS:0:72 wait_time WINDOWS:0:73 avg_wait_time WINDOWS:0:74 } sqlserver.locks.region { requests WINDOWS:0:75 waits WINDOWS:0:76 deadlocks WINDOWS:0:77 timeouts WINDOWS:0:78 wait_time WINDOWS:0:79 avg_wait_time WINDOWS:0:80 } sqlserver.cache_mgr { all cache } sqlserver.cache_mgr.all { cache_hit_ratio WINDOWS:0:81 cache_pages WINDOWS:0:167 cache_object_count WINDOWS:0:168 cache_use WINDOWS:0:169 } sqlserver.cache_mgr.cache { cache_hit_ratio WINDOWS:0:82 cache_pages WINDOWS:0:170 cache_object_count WINDOWS:0:171 cache_use WINDOWS:0:172 } sqlserver.databases { all db } sqlserver.databases.all { transactions WINDOWS:0:84 log_flushes WINDOWS:0:102 log_bytes_flushed WINDOWS:0:104 data_file_size WINDOWS:0:90 log_file_size WINDOWS:0:91 log_file_used WINDOWS:0:92 active_transactions WINDOWS:0:134 } sqlserver.databases.db { transactions WINDOWS:0:85 log_flushes WINDOWS:0:103 log_bytes_flushed WINDOWS:0:105 data_file_size WINDOWS:0:93 log_file_size WINDOWS:0:94 log_file_used WINDOWS:0:95 active_transactions WINDOWS:0:135 } sqlserver.latches { waits WINDOWS:0:87 wait_time WINDOWS:0:88 avg_wait_time WINDOWS:0:89 } sqlserver.sql { batch_requests WINDOWS:0:86 compilations WINDOWS:0:96 re_compilations WINDOWS:0:97 } sqlserver.access { full_scans WINDOWS:0:98 pages_allocated WINDOWS:0:99 table_lock_escalations WINDOWS:0:100 page_splits WINDOWS:0:122 } sqlserver.mem_mgr { connection_memory WINDOWS:0:153 granted_workspace WINDOWS:0:154 lock_memory WINDOWS:0:155 lock_blocks_allocated WINDOWS:0:156 lock_owner_blocks_allocated WINDOWS:0:157 lock_blocks WINDOWS:0:158 lock_owner_blocks WINDOWS:0:159 maximum_workspace_memory WINDOWS:0:160 memory_grants_outstanding WINDOWS:0:161 memory_grants_pending WINDOWS:0:162 optimizer_memory WINDOWS:0:163 sql_cache_memory WINDOWS:0:164 target_server_memory WINDOWS:0:165 total_server_memory WINDOWS:0:166 } sqlserver.user_settable { query WINDOWS:0:238 } pcp-3.8.12ubuntu1/src/pmdas/windows/pmns.disk0000664000000000000000000000210112272262501016012 0ustar disk { all dev } disk.all { read WINDOWS:0:15 write WINDOWS:0:16 total WINDOWS:0:17 split_io WINDOWS:0:132 read_bytes WINDOWS:0:18 write_bytes WINDOWS:0:19 total_bytes WINDOWS:0:20 read_time WINDOWS:0:214 write_time WINDOWS:0:215 total_time WINDOWS:0:216 average } disk.dev { read WINDOWS:0:21 write WINDOWS:0:22 total WINDOWS:0:23 split_io WINDOWS:0:133 read_bytes WINDOWS:0:24 write_bytes WINDOWS:0:25 total_bytes WINDOWS:0:26 idle WINDOWS:0:68 queue_len WINDOWS:0:101 read_time WINDOWS:0:217 write_time WINDOWS:0:218 total_time WINDOWS:0:219 average } disk.all.average { read_bytes WINDOWS:0:220 write_bytes WINDOWS:0:221 total_bytes WINDOWS:0:222 read_time WINDOWS:0:223 write_time WINDOWS:0:224 total_time WINDOWS:0:225 } disk.dev.average { read_bytes WINDOWS:0:226 write_bytes WINDOWS:0:227 total_bytes WINDOWS:0:228 read_time WINDOWS:0:229 write_time WINDOWS:0:230 total_time WINDOWS:0:231 } pcp-3.8.12ubuntu1/src/pmdas/windows/hypnotoad.h0000664000000000000000000000652612272262501016356 0ustar /* * Copyright (c) 2008-2010 Aconex. All Rights Reserved. * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef HYPNOTOAD_H #define HYPNOTOAD_H #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "pdh.h" #include "pdhmsg.h" #include "domain.h" #define MAX_M_PATH_LEN 80 /* pattern passed to PdhExpandCounterPath */ #define MAX_M_TEXT_LEN 512 /* longest long-text string that we allow */ #define INDOM(x,y) (((x)<<22)|(y)) /* pmdaCache interfaces use indom */ enum { DISK_INDOM, CPU_INDOM, NETIF_INDOM, FILESYS_INDOM, SQL_LOCK_INDOM, SQL_CACHE_INDOM, SQL_DB_INDOM, PROCESS_INDOM, THREAD_INDOM, SQL_USER_INDOM, NUMINDOMS }; typedef enum { V_NONE, V_ERROR_SEEN = 0x1, V_COLLECTED = 0x2, /* if PdhGetRawCounterValue was successful */ } pdh_valueflags_t; typedef struct { int inst; /* PM_IN_NULL or instance identifier */ pdh_valueflags_t flags; pmAtomValue atom; } pdh_value_t; typedef enum { M_NONE, M_EXPANDED = 0x1, /* pattern has been expanded */ M_REDO = 0x2, /* redo pattern expansion on each fetch */ M_NOVALUES = 0x4, /* setup failed, don't bother with the fetch */ M_OPTIONAL = 0x8, /* optional component, no values is expected */ M_VERIFIED = 0x10, /* has this metrics semantics been checked */ M_AUTO64 = 0x20, /* allow auto-modification on 64/32bit type */ } pdh_metricflag_t; typedef struct { pmDesc desc; /* metric descriptor */ pdh_metricflag_t flags; /* state of this metric */ int ctype; /* PDH counter type */ int num_alloc; /* high water allocation mark */ int num_vals; /* one or more metric values */ pdh_value_t *vals; char pat[MAX_M_PATH_LEN]; /* for PdhExpandCounterPath */ } pdh_metric_t; extern pdh_metric_t metricdesc[]; extern int metricdesc_sz; extern char *windows_uname; extern char *windows_build; extern char *windows_machine; extern int windows_indom_setup[]; extern int windows_indom_reset[]; extern unsigned long windows_pagesize; extern MEMORYSTATUSEX windows_memstat; extern void windows_fetch_memstat(void); extern void windows_open(int); extern int windows_indom_fixed(int); extern char *pdherrstr(int); typedef void (*pdh_metric_inform_t)(pdh_metric_t *, PDH_COUNTER_INFO_A *); typedef void (*pdh_metric_visitor_t)(pdh_metric_t *, LPSTR, pdh_value_t *); extern int windows_visit_metric(pdh_metric_t *, pdh_metric_visitor_t); extern int windows_inform_metric(pdh_metric_t *, LPTSTR, pdh_value_t *, BOOLEAN, pdh_metric_inform_t); extern void windows_instance_refresh(pmInDom); extern int windows_lookup_instance(char *, pdh_metric_t *); extern void windows_fetch_refresh(int numpmid, pmID pmidlist[], pmdaExt *); extern void windows_verify_callback(pdh_metric_t *, LPSTR, pdh_value_t *); extern int windows_help(int, int, char **, pmdaExt *); #endif /* HYPNOTOAD_H */ pcp-3.8.12ubuntu1/src/pmdas/windows/GNUmakefile0000664000000000000000000000500112272262501016235 0ustar # # Copyright (c) 2008-2009 Aconex. All Rights Reserved. # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs WINDIR = $(TOPDIR)/src/win32ctl IAM = windows DOMAIN = WINDOWS CFILES = pmda.c error.c open.c instance.c fetch.c helptext.c HFILES = hypnotoad.h LCFLAGS = -DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0500 \ -I$(WINDIR)/include LLDFLAGS = -L$(WINDIR)/lib LLDLIBS = $(PCP_PMDALIB) -lpcp_pdh PMNS = pmns.disk pmns.kernel pmns.mem pmns.network \ pmns.sqlserver pmns.filesys pmns.hinv pmns.pmda \ pmns.process LSRCFILES = $(PMNS) root help README pdhlist.c pdhmatch.sh PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LIBTARGET = pmda_windows.dll EXTRATARGETS = pdhlist.exe help.dir help.pag LDIRT = root_windows domain.h $(IAM).log pmda$(IAM) \ $(EXTRATARGETS) pdhlist.o CONF_LINE = "windows 79 dso windows_init $(PCP_PMDAS_DIR)/windows/pmda_windows.dll" default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "mingw" build-me: root_windows $(LSRCFILES) $(LIBTARGET) $(EXTRATARGETS) @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi install: build-me $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 pdhlist.exe $(LIBTARGET) $(PMDADIR) $(INSTALL) -m 644 README root $(PMNS) $(PMDADIR) $(INSTALL) -m 644 domain.h help.dir help.pag help $(PMDADIR) $(INSTALL) -m 644 root_windows $(PCP_VAR_DIR)/pmns/root_windows else build-me: install: endif help.dir help.pag : help root_windows $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_windows -v 2 -o help < help default_pcp: default install_pcp: install root_windows: ../../pmns/stdpmid $(PMNS) rm -f root_windows sed -e 's;;"../../pmns/stdpmid";' root_windows domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) $(OBJECTS): hypnotoad.h domain.h pdhlist.exe: pdhlist.o error.o $(CCF) -o pdhlist.exe pdhlist.o error.o $(LLDFLAGS) -lpcp_pdh pcp-3.8.12ubuntu1/src/pmdas/windows/open.c0000664000000000000000000005710712272262501015306 0ustar /* * Copyright (c) 2008-2010 Aconex. All Rights Reserved. * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * Parts of this file contributed by Ken McDonell * (kenj At internode DoT on DoT net) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "hypnotoad.h" #include #define roundup(x,y) ((((x) + ((y) - 1)) / (y)) * (y)) char *windows_uname; char *windows_build; char *windows_machine; unsigned long windows_pagesize; int windows_indom_setup[NUMINDOMS]; /* initial setup done on instance */ int windows_indom_reset[NUMINDOMS]; /* instances changed on refresh */ /* * This block of functionality is required to map counter types from * their Windows semantics to equivalent PCP semantics. */ static struct { int type; char *desc; } ctypetab[] = { { PERF_100NSEC_MULTI_TIMER, "PERF_100NSEC_MULTI_TIMER" }, { PERF_100NSEC_MULTI_TIMER_INV, "PERF_100NSEC_MULTI_TIMER_INV" }, { PERF_100NSEC_TIMER, "PERF_100NSEC_TIMER" }, { PERF_100NSEC_TIMER_INV, "PERF_100NSEC_TIMER_INV" }, { PERF_AVERAGE_BASE, "PERF_AVERAGE_BASE" }, { PERF_AVERAGE_BULK, "PERF_AVERAGE_BULK" }, { PERF_AVERAGE_TIMER, "PERF_AVERAGE_TIMER" }, { PERF_COUNTER_100NS_QUEUELEN_TYPE, "PERF_COUNTER_100NS_QUEUELEN_TYPE" }, { PERF_COUNTER_BULK_COUNT, "PERF_COUNTER_BULK_COUNT" }, { PERF_COUNTER_COUNTER, "PERF_COUNTER_COUNTER" }, { PERF_COUNTER_DELTA, "PERF_COUNTER_DELTA" }, { PERF_COUNTER_LARGE_DELTA, "PERF_COUNTER_LARGE_DELTA" }, { PERF_COUNTER_LARGE_QUEUELEN_TYPE, "PERF_COUNTER_LARGE_QUEUELEN_TYPE" }, { PERF_COUNTER_LARGE_RAWCOUNT, "PERF_COUNTER_LARGE_RAWCOUNT" }, { PERF_COUNTER_LARGE_RAWCOUNT_HEX, "PERF_COUNTER_LARGE_RAWCOUNT_HEX" }, { PERF_COUNTER_MULTI_BASE, "PERF_COUNTER_MULTI_BASE" }, { PERF_COUNTER_MULTI_TIMER, "PERF_COUNTER_MULTI_TIMER" }, { PERF_COUNTER_MULTI_TIMER_INV, "PERF_COUNTER_MULTI_TIMER_INV" }, { PERF_COUNTER_NODATA, "PERF_COUNTER_NODATA" }, { PERF_COUNTER_QUEUELEN_TYPE, "PERF_COUNTER_QUEUELEN_TYPE" }, { PERF_COUNTER_RAWCOUNT, "PERF_COUNTER_RAWCOUNT" }, { PERF_COUNTER_RAWCOUNT_HEX, "PERF_COUNTER_RAWCOUNT_HEX" }, { PERF_COUNTER_TEXT, "PERF_COUNTER_TEXT" }, { PERF_COUNTER_TIMER, "PERF_COUNTER_TIMER" }, { PERF_COUNTER_TIMER_INV, "PERF_COUNTER_TIMER_INV" }, { PERF_ELAPSED_TIME, "PERF_ELAPSED_TIME" }, { PERF_LARGE_RAW_BASE, "PERF_LARGE_RAW_BASE" }, { PERF_OBJ_TIME_TIMER, "PERF_OBJ_TIME_TIMER" }, { PERF_PRECISION_100NS_TIMER, "PERF_PRECISION_100NS_TIMER" }, { PERF_PRECISION_OBJECT_TIMER, "PERF_PRECISION_OBJECT_TIMER" }, { PERF_PRECISION_SYSTEM_TIMER, "PERF_PRECISION_SYSTEM_TIMER" }, { PERF_RAW_BASE, "PERF_RAW_BASE" }, { PERF_RAW_FRACTION, "PERF_RAW_FRACTION" }, { PERF_LARGE_RAW_FRACTION, "PERF_LARGE_RAW_FRACTION" }, { PERF_SAMPLE_BASE, "PERF_SAMPLE_BASE" }, { PERF_SAMPLE_COUNTER, "PERF_SAMPLE_COUNTER" }, { PERF_SAMPLE_FRACTION, "PERF_SAMPLE_FRACTION" } }; static int ctypetab_sz = sizeof(ctypetab) / sizeof(ctypetab[0]); static char * decode_ctype(DWORD ctype) { static char unknown[20]; int i; for (i = 0; i < ctypetab_sz; i++) if (ctype == ctypetab[i].type) return ctypetab[i].desc; sprintf(unknown, "0x%08x unknown", (int)ctype); return unknown; } static char * string_append(char *name, char *suff) { if (name == NULL) { name = (char *)strdup(suff); } else { name = (char *)realloc(name, strlen(name)+strlen(suff)+1); strcat(name, suff); } return name; } static char * _semstr(int sem) { static char msg[20]; if (sem == PM_SEM_COUNTER) return "COUNTER"; else if (sem == PM_SEM_INSTANT) return "INSTANT"; else if (sem == PM_SEM_DISCRETE) return "DISCRETE"; else { sprintf(msg, "UNKNOWN! (%d)", sem); return msg; } } static char * _typestr(int type) { static char msg[20]; if (type == PM_TYPE_32) return "PM_TYPE_32"; else if (type == PM_TYPE_U32) return "PM_TYPE_U32"; else if (type == PM_TYPE_64) return "PM_TYPE_64"; else if (type == PM_TYPE_U64) return "PM_TYPE_U64"; else if (type == PM_TYPE_FLOAT) return "PM_TYPE_FLOAT"; else if (type == PM_TYPE_DOUBLE) return "PM_TYPE_DOUBLE"; else { sprintf(msg, "UNKNOWN! (%d)", type); return msg; } } #if 0 // debugging static char * _ctypestr(int ctype) { if (ctype == PERF_COUNTER_COUNTER) return "PERF_COUNTER_COUNTER"; else if (ctype == PERF_RAW_FRACTION) return "PERF_RAW_FRACTION"; else if (ctype == PERF_LARGE_RAW_FRACTION) return "PERF_LARGE_RAW_FRACTION"; else if (ctype == PERF_COUNTER_LARGE_RAWCOUNT_HEX) return "PERF_COUNTER_LARGE_RAWCOUNT_HEX"; else if (ctype == PERF_COUNTER_LARGE_RAWCOUNT) return "PERF_COUNTER_LARGE_RAWCOUNT"; else if (ctype == PERF_PRECISION_100NS_TIMER) return "PERF_PRECISION_100NS_TIMER"; else if (ctype == PERF_100NSEC_TIMER) return "PERF_100NSEC_TIMER"; else if (ctype == PERF_COUNTER_BULK_COUNT) return "PERF_COUNTER_BULK_COUNT"; else if (ctype == PERF_COUNTER_RAWCOUNT_HEX) return "PERF_COUNTER_RAWCOUNT_HEX"; else if (ctype == PERF_COUNTER_RAWCOUNT) return "PERF_COUNTER_RAWCOUNT"; else if (ctype == PERF_COUNTER_COUNTER) return "PERF_COUNTER_COUNTER"; else return "UNKNOWN"; } #endif /* * Based on documentation from ... * http://msdn.microsoft.com/library/default.asp? * url=/library/en-us/sysinfo/base/osversioninfoex_str.asp */ static void windows_format_uname(OSVERSIONINFOEX osv) { char tbuf[80]; char *name = NULL; switch (osv.dwPlatformId) { case VER_PLATFORM_WIN32_NT: if (osv.dwMajorVersion == 6 && osv.dwMinorVersion == 1) { if (osv.wProductType == VER_NT_WORKSTATION) name = string_append(name, "Windows 7"); else name = string_append(name, "Windows Server 2008 R2"); } else if (osv.dwMajorVersion == 6 && osv.dwMinorVersion == 0) { if (osv.wProductType == VER_NT_WORKSTATION) name = string_append(name, "Windows Vista"); else name = string_append(name, "Windows Server 2008"); } else if (osv.dwMajorVersion == 5 && osv.dwMinorVersion == 2) name = string_append(name, "Windows Server 2003"); else if (osv.dwMajorVersion == 5 && osv.dwMinorVersion == 1) name = string_append(name, "Windows XP"); else if (osv.dwMajorVersion == 5 && osv.dwMinorVersion == 0) name = string_append(name, "Windows 2000"); else if (osv.dwMajorVersion <= 4) name = string_append(name, "Windows NT"); else { sprintf(tbuf, "Windows Unknown (%ld.%ld)", osv.dwMajorVersion, osv.dwMinorVersion); name = string_append(name, tbuf); } /* service pack and build number etc */ if (osv.szCSDVersion[0] != '\0') { name = string_append(name, " "); name = string_append(name, osv.szCSDVersion); } sprintf(tbuf, " Build %ld", osv.dwBuildNumber & 0xFFFF); windows_build = name + strlen(name) + 1; windows_uname = string_append(name, tbuf); break; default: windows_uname = "Windows - Platform Unknown"; windows_build = "Unknown Build"; break; } } void windows_setup_globals(void) { SYSTEM_INFO sysinfo; OSVERSIONINFOEX osversion; ZeroMemory(&sysinfo, sizeof(SYSTEM_INFO)); GetSystemInfo(&sysinfo); windows_pagesize = sysinfo.dwPageSize; switch (sysinfo.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_AMD64: windows_machine = "x86_64"; break; case PROCESSOR_ARCHITECTURE_IA64: windows_machine = "ia64"; break; case PROCESSOR_ARCHITECTURE_INTEL: windows_machine = "i686"; break; default: windows_machine = "Unknown"; break; } ZeroMemory(&osversion, sizeof(OSVERSIONINFOEX)); osversion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); GetVersionEx((OSVERSIONINFO *)&osversion); windows_format_uname(osversion); } static void windows_verify_metric(pdh_metric_t *mp, PDH_COUNTER_INFO_A *infop) { char *ctr_type; mp->ctype = infop->dwType; switch (mp->ctype) { /* * Pdh metric sematics ... from WinPerf.h * * SIZE * DWORD 32-bit * LARGE 64-bit * ZERO no support here * VARIABLE_LEN no support here * * TYPE * NUMBER PM_SEM_INSTANT * HEX display in hex (no support here) * DECIMAL display as decimal * DEC_1000 display as value / 1000 * (no support here) * COUNTER PM_SEM_COUNTER * VALUE display value (no support here) * RATE time rate converted * FRACTION divide value by BASE * BASE used for FRACTION * QUEUELEN magic internal queuelen() routines * (you're joking, right?) * HISTOGRAM counter begins or ends a histo (?) * (definitely no support here) * PRECISION divide counter by private clock (?) * (definitely no support here) * TEXT no support here * ZERO no support here */ /* * Known 32-bit counters */ case PERF_COUNTER_COUNTER: /* 32-bit PM_SEM_COUNTER */ if (mp->desc.type != PM_TYPE_32 && mp->desc.type != PM_TYPE_U32) { if (!(mp->flags & M_AUTO64)) __pmNotifyErr(LOG_ERR, "windows_open: PERF_COUNTER_COUNTER: " "metric %s: rewrite type from %s to PM_TYPE_U32\n", pmIDStr(mp->desc.pmid), _typestr(mp->desc.type)); mp->desc.type = PM_TYPE_U32; } if (mp->desc.sem != PM_SEM_COUNTER) { __pmNotifyErr(LOG_ERR, "windows_open: PERF_COUNTER_COUNTER: " "metric %s: semantics %s (expected %s)\n", pmIDStr(mp->desc.pmid), _semstr(mp->desc.sem), _semstr(PM_SEM_COUNTER)); } break; case PERF_COUNTER_RAWCOUNT: case PERF_COUNTER_RAWCOUNT_HEX: if (mp->ctype == PERF_COUNTER_RAWCOUNT) ctr_type = "PERF_COUNTER_RAWCOUNT"; else ctr_type = "PERF_COUNTER_RAWCOUNT_HEX"; /* 32-bit PM_SEM_INSTANT or PM_SEM_DISCRETE */ if (mp->desc.type != PM_TYPE_32 && mp->desc.type != PM_TYPE_U32) { if (!(mp->flags & M_AUTO64)) __pmNotifyErr(LOG_ERR, "windows_open: Warning: %s: metric %s: " "rewrite type from %s to PM_TYPE_U32\n", ctr_type, pmIDStr(mp->desc.pmid), _typestr(mp->desc.type)); mp->desc.type = PM_TYPE_U32; } break; /* * Known 64-bit counters */ case PERF_COUNTER_BULK_COUNT: /* 64-bit PM_SEM_COUNTER */ if (mp->desc.type != PM_TYPE_64 && mp->desc.type != PM_TYPE_U64) { if (!(mp->flags & M_AUTO64)) __pmNotifyErr(LOG_ERR, "windows_open: PERF_COUNTER_BULK_COUNT:" " metric %s: rewrite type from %s to PM_TYPE_U64\n", pmIDStr(mp->desc.pmid), _typestr(mp->desc.type)); mp->desc.type = PM_TYPE_U64; } if (mp->desc.sem != PM_SEM_COUNTER) { __pmNotifyErr(LOG_ERR, "windows_open: PERF_COUNTER_BULK_COUNT:" " metric %s: semantics %s (expected %s)\n", pmIDStr(mp->desc.pmid), _semstr(mp->desc.sem), _semstr(PM_SEM_COUNTER)); mp->desc.sem = PM_SEM_COUNTER; } break; case PERF_100NSEC_TIMER: case PERF_PRECISION_100NS_TIMER: if (mp->ctype == PERF_100NSEC_TIMER) ctr_type = "PERF_100NSEC_TIMER"; else ctr_type = "PERF_PRECISION_100NS_TIMER"; /* * 64-bit PM_SEM_COUNTER, units are 100's of nanosecs, * we shall export 'em as microseconds */ if (mp->desc.type != PM_TYPE_64 && mp->desc.type != PM_TYPE_U64) { if (!(mp->flags & M_AUTO64)) __pmNotifyErr(LOG_ERR, "windows_open: Warning: %s: " "metric %s: rewrite type from %s to PM_TYPE_U64\n", ctr_type, pmIDStr(mp->desc.pmid), _typestr(mp->desc.type)); mp->desc.type = PM_TYPE_U64; } if (mp->desc.sem != PM_SEM_COUNTER) { __pmNotifyErr(LOG_ERR, "windows_open: Warning: %s: " "metric %s: semantics %s (expected %s)\n", ctr_type, pmIDStr(mp->desc.pmid), _semstr(mp->desc.sem), _semstr(PM_SEM_COUNTER)); mp->desc.sem = PM_SEM_COUNTER; } if (mp->desc.units.dimSpace != 0 || mp->desc.units.dimTime != 1 || mp->desc.units.dimCount != 0 || mp->desc.units.scaleTime != PM_TIME_USEC) { pmUnits units = mp->desc.units; mp->desc.units.dimSpace = mp->desc.units.dimCount = 0; mp->desc.units.scaleSpace = mp->desc.units.scaleCount = 0; mp->desc.units.dimTime = 1; mp->desc.units.scaleTime = PM_TIME_USEC; __pmNotifyErr(LOG_ERR, "windows_open: Warning: %s: " "metric %s: rewrite dimension and scale from %s to %s", ctr_type, pmIDStr(mp->desc.pmid), pmUnitsStr(&units), pmUnitsStr(&mp->desc.units)); } break; case PERF_COUNTER_LARGE_RAWCOUNT: case PERF_COUNTER_LARGE_RAWCOUNT_HEX: /* 64-bit PM_SEM_INSTANT or PM_SEM_DISCRETE */ if (mp->desc.type != PM_TYPE_64 && mp->desc.type != PM_TYPE_U64) { if (!(mp->flags & M_AUTO64)) __pmNotifyErr(LOG_ERR, "windows_open: Warning: " "PERF_COUNTER_LARGE_RAWCOUNT: metric %s: " "rewrite type from %s to PM_TYPE_U64\n", pmIDStr(mp->desc.pmid), _typestr(mp->desc.type)); mp->desc.type = PM_TYPE_U64; } break; case PERF_RAW_FRACTION: /* Float PM_SEM_INSTANT or PM_SEM_DISCRETE */ if (mp->desc.type != PM_TYPE_FLOAT) { if (!(mp->flags & M_AUTO64)) __pmNotifyErr(LOG_ERR, "windows_open: Warning: " "PERF_RAW_FRACTION: metric %s: " "rewrite type from %s to PM_TYPE_FLOAT\n", pmIDStr(mp->desc.pmid), _typestr(mp->desc.type)); mp->desc.type = PM_TYPE_FLOAT; } break; case PERF_LARGE_RAW_FRACTION: /* Double PM_SEM_INSTANT or PM_SEM_DISCRETE */ if (mp->desc.type != PM_TYPE_DOUBLE) { if (!(mp->flags & M_AUTO64)) __pmNotifyErr(LOG_ERR, "windows_open: Warning: " "PERF_LARGE_RAW_FRACTION: metric %s: " "rewrite type from %s to PM_TYPE_DOUBLE\n", pmIDStr(mp->desc.pmid), _typestr(mp->desc.type)); mp->desc.type = PM_TYPE_DOUBLE; } break; case PERF_AVERAGE_BULK: case PERF_AVERAGE_TIMER: if (mp->ctype == PERF_AVERAGE_BULK) ctr_type = "PERF_AVERAGE_BULK"; else ctr_type = "PERF_AVERAGE_TIMER"; /* 64-bit PM_SEM_INSTANT or PM_SEM_DISCRETE */ if (mp->desc.sem != PM_SEM_INSTANT && mp->desc.sem != PM_SEM_DISCRETE) { __pmNotifyErr(LOG_ERR, "windows_open: Warning: %s: " "metric %s: semantics %s (expected %s)\n", ctr_type, pmIDStr(mp->desc.pmid), _semstr(mp->desc.sem), _semstr(PM_SEM_INSTANT)); mp->desc.sem = PM_SEM_INSTANT; } if (mp->desc.type != PM_TYPE_64 && mp->desc.type != PM_TYPE_U64) { if (!(mp->flags & M_AUTO64)) __pmNotifyErr(LOG_ERR, "windows_open: Warning: %s " "metric %s: rewrite type from %s to PM_TYPE_U64\n", ctr_type, pmIDStr(mp->desc.pmid), _typestr(mp->desc.type)); mp->desc.type = PM_TYPE_U64; } break; case PERF_SAMPLE_COUNTER: ctr_type = "PERF_SAMPLE_COUNTER"; /* floating point PM_SEM_INSTANT or PM_SEM_DISCRETE */ if (mp->desc.sem != PM_SEM_INSTANT && mp->desc.sem != PM_SEM_DISCRETE) { __pmNotifyErr(LOG_ERR, "windows_open: Warning: %s: " "metric %s: semantics %s (expected %s)\n", ctr_type, pmIDStr(mp->desc.pmid), _semstr(mp->desc.sem), _semstr(PM_SEM_INSTANT)); mp->desc.sem = PM_SEM_INSTANT; } if (mp->desc.type != PM_TYPE_FLOAT && mp->desc.type != PM_TYPE_DOUBLE) { __pmNotifyErr(LOG_ERR, "windows_open: Warning: %s " "metric %s: rewrite type from %s to PM_TYPE_FLOAT\n", ctr_type, pmIDStr(mp->desc.pmid), _typestr(mp->desc.type)); mp->desc.type = PM_TYPE_FLOAT; } break; case PERF_ELAPSED_TIME: ctr_type = "PERF_ELAPSED_TIME"; if (mp->desc.units.dimSpace != 0 || mp->desc.units.dimTime != 1 || mp->desc.units.dimCount != 0) { pmUnits units = mp->desc.units; mp->desc.units.dimSpace = mp->desc.units.dimCount = 0; mp->desc.units.scaleSpace = mp->desc.units.scaleCount = 0; mp->desc.units.dimTime = 1; __pmNotifyErr(LOG_ERR, "windows_open: Warning: %s: " "metric %s: rewrite dimension and scale from %s to %s", ctr_type, pmIDStr(mp->desc.pmid), pmUnitsStr(&units), pmUnitsStr(&mp->desc.units)); } if (mp->desc.type != PM_TYPE_64 && mp->desc.type != PM_TYPE_U64) { if (!(mp->flags & M_AUTO64)) __pmNotifyErr(LOG_ERR, "windows_open: Warning: %s " "metric %s: rewrite type from %s to PM_TYPE_U64\n", ctr_type, pmIDStr(mp->desc.pmid), _typestr(mp->desc.type)); mp->desc.type = PM_TYPE_U64; } break; default: __pmNotifyErr(LOG_ERR, "windows_open: Warning: metric %s: " "unexpected counter type: %s\n", pmIDStr(mp->desc.pmid), decode_ctype(infop->dwType)); } mp->flags |= M_EXPANDED; } int windows_inform_metric(pdh_metric_t *pmp, LPTSTR p, pdh_value_t *pvp, BOOLEAN getExplainText, pdh_metric_inform_t informer) { int sts = -1; PDH_STATUS pdhsts; PDH_HQUERY queryhdl = NULL; PDH_HCOUNTER counterhdl = NULL; DWORD result_sz; static DWORD info_sz = 0; static LPSTR info = NULL; pdhsts = PdhOpenQueryA(NULL, 0, &queryhdl); if (pdhsts != ERROR_SUCCESS) { __pmNotifyErr(LOG_ERR, "windows_open: PdhOpenQueryA failed: %s\n", pdherrstr(pdhsts)); return sts; } pdhsts = PdhAddCounterA(queryhdl, p, pvp->inst, &counterhdl); if (pdhsts != ERROR_SUCCESS) { __pmNotifyErr(LOG_ERR, "windows_open: Warning: PdhAddCounterA " "@ pmid=%s pat=\"%s\": %s\n", pmIDStr(pmp->desc.pmid), p, pdherrstr(pdhsts)); PdhCloseQuery(queryhdl); return sts; } /* * check PCP metric semantics against PDH info */ if (info_sz == 0) { /* * We've observed an initial call to PdhGetCounterInfoA() * hang with a zero sized buffer ... pander to this with * an initial buffer allocation ... (size is a 100% guess). */ info_sz = 256; if ((info = (LPSTR)malloc(info_sz)) == NULL) { __pmNotifyErr(LOG_ERR, "windows_open: PdhGetCounterInfoA " "malloc (%d) failed @ metric %s: ", (int)info_sz, pmIDStr(pmp->desc.pmid)); goto done; } } result_sz = info_sz; pdhsts = PdhGetCounterInfoA(counterhdl, getExplainText, &result_sz, (PDH_COUNTER_INFO_A *)info); if (pdhsts == PDH_MORE_DATA) { info_sz = result_sz; if ((info = (LPSTR)realloc(info, info_sz)) == NULL) { __pmNotifyErr(LOG_ERR, "windows_open: PdhGetCounterInfoA " "realloc (%d) failed @ metric %s: ", (int)info_sz, pmIDStr(pmp->desc.pmid)); goto done; } pdhsts = PdhGetCounterInfoA(counterhdl, getExplainText, &result_sz, (PDH_COUNTER_INFO_A *)info); } if (pdhsts != ERROR_SUCCESS) { __pmNotifyErr(LOG_ERR, "windows_open: PdhGetCounterInfoA " "failed @ metric %s: %s\n", pmIDStr(pmp->desc.pmid), pdherrstr(pdhsts)); goto done; } else { informer(pmp, (PDH_COUNTER_INFO_A *)info); sts = 0; } done: PdhRemoveCounter(counterhdl); PdhCloseQuery(queryhdl); return sts; } void windows_verify_callback(pdh_metric_t *pmp, LPSTR pat, pdh_value_t *pvp) { int v; if (!(pmp->flags & M_VERIFIED)) { v = windows_inform_metric(pmp, pat, pvp, FALSE, windows_verify_metric); if (v == 0) pmp->flags |= M_VERIFIED; } } /* * General purpose metric regex iterator, call out on each instance */ int windows_visit_metric(pdh_metric_t *pmp, pdh_metric_visitor_t visitor) { size_t size; int index = 0; PDH_STATUS pdhsts; DWORD result_sz; static DWORD pattern_sz = 0; static LPSTR pattern = NULL; LPSTR p; if (pmp->desc.indom != PM_INDOM_NULL) { index = pmInDom_serial(pmp->desc.indom); pmdaCacheOp(pmp->desc.indom, PMDA_CACHE_INACTIVE); } pmp->flags &= ~(M_EXPANDED|M_NOVALUES); memset(pmp->vals, 0, pmp->num_alloc * sizeof(pdh_value_t)); pmp->num_vals = 0; result_sz = 0; pdhsts = PdhExpandCounterPathA(pmp->pat, NULL, &result_sz); if (pdhsts == PDH_MORE_DATA) { if (result_sz >= pattern_sz) { pattern_sz = roundup(result_sz, 64); if ((pattern = (LPSTR)realloc(pattern, pattern_sz)) == NULL) { __pmNotifyErr(LOG_ERR, "windows_open: PdhExpandCounterPathA " "realloc (%ld) failed @ metric %s: ", pattern_sz, pmIDStr(pmp->desc.pmid)); return -1; } } result_sz = pattern_sz; pdhsts = PdhExpandCounterPathA(pmp->pat, pattern, &result_sz); } if (pdhsts != PDH_CSTATUS_VALID_DATA) { if (pmp->pat[0] != '\\') { /* * Skip metrics that are derived and do not have an explicit * PDH API retrieval needed ... do nothing here. */ ; } else if (pmp->flags & M_OPTIONAL) { pmp->flags |= M_NOVALUES; return 0; } else { __pmNotifyErr(LOG_ERR, "windows_open: PdhExpandCounterPathA " "failed @ metric pmid=%s pattern=\"%s\": %s\n", pmIDStr(pmp->desc.pmid), pmp->pat, pdherrstr(pdhsts)); } pmp->flags |= M_NOVALUES; return -1; } /* * PdhExpandCounterPathA is apparently busted ... the length * returned includes one byte _after_ the last NULL byte * string terminator, but the final byte is apparently * not being set ... force the issue */ pattern[result_sz-1] = '\0'; for (p = pattern; *p; p += lstrlen(p) + 1) { pdh_value_t *pvp; pmp->num_vals++; if (pmp->num_vals > pmp->num_alloc) { size = pmp->num_vals * sizeof(pdh_value_t); if ((pmp->vals = (pdh_value_t *)realloc(pmp->vals, size)) == NULL) { __pmNotifyErr(LOG_ERR, "windows_open: Error: values realloc " "(%d x %d) failed @ metric %s [%s]: ", pmp->num_vals, sizeof(pdh_value_t), pmIDStr(pmp->desc.pmid), p); pmp->num_alloc = 0; return -1; } pmp->num_alloc = pmp->num_vals; } pvp = &pmp->vals[pmp->num_vals-1]; if (pmp->desc.indom == PM_INDOM_NULL) { /* singular instance */ pvp->inst = PM_IN_NULL; if (pmp->num_vals > 1) { char *q; int k; /* * report only once per pattern */ __pmNotifyErr(LOG_ERR, "windows_open: Warning: singular " "metric %s has more than one instance ...\n", pmIDStr(pmp->desc.pmid)); fprintf(stderr, " pattern: \"%s\"\n", pmp->pat); for (k = 0, q = pattern; *q; q += lstrlen(q) + 1, k++) fprintf(stderr, " match[%d]: \"%s\"\n", k, q); fprintf(stderr, "... skip this counter\n"); /* next realloc() will be a NOP */ pmp->num_vals--; /* no more we can do here, onto next metric-pattern */ break; } } else { /* * if metric has instance domain, parse pattern using * indom type to extract instance name and number, and * add into indom cache data structures as needed. */ if ((pvp->inst = windows_lookup_instance(p, pmp)) < 0) { /* * error reported in windows_check_instance() ... * we cannot return any values for this instance if * we don't recognize the name ... skip this one, * the next realloc() (if any) will be a NOP */ pmp->num_vals--; /* move onto next instance */ continue; } windows_indom_setup[index] = 1; } if (visitor) visitor(pmp, p, pvp); } return 0; } void windows_open(int domain) { int i; windows_setup_globals(); for (i = 0; i < NUMINDOMS; i++) { if (windows_indom_fixed(i)) pmdaCacheOp(INDOM(domain, i), PMDA_CACHE_LOAD); windows_indom_reset[i] = 0; } /* * This initialisation can take a long time - we have many metrics * now for Windows. Better to delay this until we need to do it, * and then only for the metrics needed. However, we cannot delay * for those metrics that may change descriptors depending on the * type of platform (64/32 bit, kernel version, etc), so those we * verify up-front. */ for (i = 0; i < metricdesc_sz; i++) { if ((metricdesc[i].flags & M_AUTO64) || (pmDebug & DBG_TRACE_LIBPMDA)) windows_visit_metric(&metricdesc[i], windows_verify_callback); } for (i = 0; i < NUMINDOMS; i++) { /* Do we want to persist this instance domain to disk? */ if (windows_indom_reset[i] && windows_indom_fixed(i)) pmdaCacheOp(INDOM(domain, i), PMDA_CACHE_SAVE); } } pcp-3.8.12ubuntu1/src/pmdas/windows/root0000664000000000000000000000062112272262501015074 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { hinv kernel disk filesys mem swap network sqlserver pmda process } #include "pmns.hinv" #include "pmns.kernel" #include "pmns.disk" #include "pmns.filesys" #include "pmns.mem" #include "pmns.network" #include "pmns.sqlserver" #include "pmns.pmda" #include "pmns.process" pcp-3.8.12ubuntu1/src/pmdas/windows/pdhmatch.sh0000664000000000000000000001337212272262501016321 0ustar #!/bin/sh # # take the output from pdhlist.exe # - remove hostname # - collapse known instance domains to a symbolic representation # - match up against patterns in data.c # #debug# tmp=/var/tmp/$$ #debug# trap "rm -f $tmp.*; exit 0" 0 1 2 3 15 tmp=`pwd`/tmp # Examples of instance domains to collapse from pdhlist.exe # output # # SQLServer:Buffer Partition(0)\Free pages # Job Object Details(Winlogon Job 0-57c89/logon.scr)\% User Time # Job Object Details(Winlogon Job 0-57c89/_Total)\% User Time # Job Object Details(WmiProviderSubSystemHostJob/wmiprvse)\% User Time # Job Object Details(WmiProviderSubSystemHostJob/_Total)\% User Time # [not] Job Object Details(_Total/_Total)\% User Time # Job Object(WmiProviderSubSystemHostJob)\Current % User Mode Time # [not] Job Object(_Total)\Current % User Mode Time # Thread(Idle/0)\Context Switches/sec # Thread(csrss/0#1)\Context Switches/sec # LogicalDisk(C:)\% Free Space # [not] LogicalDisk(_Total)\% Free Space # Network Interface(Intel[R] PRO_1000 MT Dual Port Network # Connection _2)\Bytes Received/sec # PhysicalDisk(0 C:)\% Disk Read Time # [not] PhysicalDisk(_Total)\% Disk Read Time # Print Queue(Canon LBP-3260 PCL6 on SCRIBE (from LUKE) in session 1)\Add Network Printer Calls # [not] Print Queue(_Total)\Add Network Printer Calls # Process(Idle)\% Privileged Time # [not] Process(_Total)\% Privileged Time # Processor(0)\% Idle Time # [not] Processor(_Total)\% Idle Time # RAS Port(LPT1)\Alignment Errors # SQLServer:Databases(alice)\Active Transactions # [not] SQLServer:Databases(_Total)\Active Transactions # SQLServer:Locks(Database)\Average Wait Time (ms) # [not] SQLServer:Locks(_Total)\Lock Requests/sec # Server Work Queues(3)\Active Threads # SQLServer:Cache Manager(Adhoc Sql Plans)\Cache Hit Ratio # Terminal Services Session(Console)\% Privileged Time # if [ $# -eq 1 ] then cat $1 elif [ $# -eq 0 ] then cat else echo "Usage: $0 [output-file-from-pdhlist]" >&2 exit 1 fi \ | dos2unix \ | sed >$tmp.tmp \ -e 's/^\\\\[^\]*\\//' \ -e '/^SQLServer:Buffer Partition(/s/([0-9]*)\\/()\\/' \ -e '/^Job Object Details(/{ /(_Total\//!s/(.*\/_Total)\\/(\/_Total)\\/ /\/_Total)/!s/(.*\/.*)\\/(\/)\\/ }' \ -e '/^Job Object(/{ /(_Total)/!s/(.*)\\/()\\/ }' \ -e '/^Thread(/{ s/([^/]*\/[0-9]*)\\/(\/)\\/ s/([^/]*\/[0-9]*#[0-9]*)\\/(\/#)\\/ }' \ -e '/^LogicalDisk(/s/([A-Z]:)\\/()\\/' \ -e '/^Network Interface(/s/([^)]*)\\/()\\/' \ -e '/^PhysicalDisk(/s/([0-9][0-9]* [A-Z]:)\\/()\\/' \ -e '/^Print Queue(/{ /(_Total)/!s/(.*)\\/()\\/ }' \ -e '/^Process(/{ /(_Total)/!s/(.*)\\/()\\/ }' \ -e '/^Processor(/{ /(_Total)/!s/(.*)\\/()\\/ }' \ -e '/^RAS Port(/s/(.*)\\/()\\/' \ -e '/^SQLServer:Databases(/{ /(_Total)/!s/(.*)\\/()\\/ }' \ -e '/^SQLServer:Locks(/{ /(_Total)/!s/(.*)\\/()\\/ }' \ -e '/^Server Work Queues(/s/(.*)\\/()\\/' \ -e '/^SQLServer:Cache Manager(/s/(.*)\\/()\\/' \ -e '/^Terminal Services Session(/s/(.*)\\/()\\/' # This step tries to deal with this class of cases ... # pdhlist reports stuff like # SQLServer:Locks\Average Wait Time (ms) # SQLServer:Locks(_Total)\Average Wait Time (ms) # SQLServer:Locks(*/*#*)\Average Wait Time (ms) # but the first one is in fact bogus (only the second 2 forms # can be looked up. # sed <$tmp.tmp \ -e '/^.NET CLR Exceptions\\/d' \ -e '/^.NET CLR Interop\\/d' \ -e '/^.NET CLR Jit\\/d' \ -e '/^.NET CLR Loading\\/d' \ -e '/^.NET CLR LocksAndThreads\\/d' \ -e '/^.NET CLR Memory\\/d' \ -e '/^.NET CLR Remoting\\/d' \ -e '/^.NET CLR Security\\/d' \ -e '/^NBT Connection\\/d' \ -e '/^Paging File\\/d' \ -e '/^SQLServer:User Settable\\/d' \ -e '/^Server Work Queues\\/d' \ -e '/^SQLServer:Buffer Partition\\/d' \ -e '/^Job Object Details\\/d' \ -e '/^Job Object\\/d' \ -e '/^Thread\\/d' \ -e '/^LogicalDisk\\/d' \ -e '/^Network Interface\\/d' \ -e '/^PhysicalDisk\\/d' \ -e '/^Print Queue\\/d' \ -e '/^Process\\/d' \ -e '/^Processor\\/d' \ -e '/^RAS Port\\/d' \ -e '/^SQLServer:Databases\\/d' \ -e '/^SQLServer:Locks\\/d' \ | LC_COLLATE=POSIX sort \ | uniq >$tmp.munged # extract patterns from PMDA source # if [ -f data.c ] then sed -n )\\/' \ -e '/^PhysicalDisk(/s/(\*\/\*#\*)\\/()\\/' \ -e '/^Processor(/s/(\*\/\*#\*)\\/()\\/' \ -e '/^SQLServer:Locks(/s/(\*\/\*#\*)\\/()\\/' \ -e '/^LogicalDisk(/s/(\*\/\*#\*)\\/()\\/' \ | LC_COLLATE=POSIX sort \ | uniq >$tmp.pmda else echo "Warning: no data.c, cannot match metrics up with PMDA patterns" >&2 sed -e 's/^/? /' <$tmp.munged fi # match 'em up # comm -23 $tmp.pmda $tmp.munged >$tmp.tmp if [ -s $tmp.tmp ] then echo "============================================" echo "=== Warning: These current PMDA patterns do NOT match ANY metrics ..." echo "============================================" cat $tmp.tmp echo fi comm -12 $tmp.pmda $tmp.munged >$tmp.tmp if [ -s $tmp.tmp ] then echo "============================================" echo "=== Metrics supported in the current PMDA ..." echo "============================================" cat $tmp.tmp else echo "============================================" echo "=== Warning: The current PMDA patterns match NO metric!" echo "============================================" fi comm -13 $tmp.pmda $tmp.munged >$tmp.tmp if [ -s $tmp.tmp ] then echo echo "============================================" echo "=== Metrics NOT supported in the current PMDA" echo "============================================" cat $tmp.tmp fi pcp-3.8.12ubuntu1/src/pmdas/windows/pmns.process0000664000000000000000000000240712272262501016547 0ustar process { count WINDOWS:0:173 psinfo memory io thread } process.psinfo { pid WINDOWS:0:174 ppid WINDOWS:0:175 cpu_time WINDOWS:0:176 elapsed_time WINDOWS:0:177 utime WINDOWS:0:178 stime WINDOWS:0:179 nthreads WINDOWS:0:180 priority_base WINDOWS:0:181 nhandles WINDOWS:0:182 page_faults WINDOWS:0:183 } process.memory { size WINDOWS:0:184 rss WINDOWS:0:185 rss_peak WINDOWS:0:186 virtual WINDOWS:0:187 virtual_peak WINDOWS:0:188 page_file WINDOWS:0:189 page_file_peak WINDOWS:0:190 private WINDOWS:0:191 pool_paged WINDOWS:0:192 pool_nonpaged WINDOWS:0:193 } process.io { reads WINDOWS:0:194 writes WINDOWS:0:195 data WINDOWS:0:196 other WINDOWS:0:197 read_bytes WINDOWS:0:198 write_bytes WINDOWS:0:199 data_bytes WINDOWS:0:200 other_bytes WINDOWS:0:201 } process.thread { context_switches WINDOWS:0:202 cpu_time WINDOWS:0:203 utime WINDOWS:0:204 stime WINDOWS:0:205 elapsed_time WINDOWS:0:206 priority WINDOWS:0:207 priority_base WINDOWS:0:208 start_address WINDOWS:0:209 state WINDOWS:0:210 wait_reason WINDOWS:0:211 process_id WINDOWS:0:212 thread_id WINDOWS:0:213 } pcp-3.8.12ubuntu1/src/pmdas/windows/pmns.pmda0000664000000000000000000000007512272262501016011 0ustar pmda { uname WINDOWS:0:115 version WINDOWS:0:116 } pcp-3.8.12ubuntu1/src/pmdas/windows/pdhlist.c0000664000000000000000000000404512272262501016005 0ustar /* * List Windows performance counters on the current platform. * * Copyright (c) 2006, Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include static int verbose; extern char *pdherrstr(int); #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) void expand(char *pat) { LPTSTR ptr; LPSTR buf = NULL; DWORD bufsz = 0; int i; PDH_STATUS pdhsts; // Iterate because size grows in first couple of attempts! for (i = 0; i < 5; i++) { if (bufsz && (buf = (LPSTR)malloc(bufsz)) == NULL) { fprintf(stderr, "malloc %ld failed for pattern: %s\n", bufsz, pat); return; } if (verbose) fprintf(stderr, "ExpandCounters pattern: %s\n", pat); if ((pdhsts = PdhExpandCounterPathA(pat, buf, &bufsz)) == PDH_MORE_DATA) { // bufsz has the required length (minus the last NULL) bufsz = roundup(bufsz + 1, 64); free(buf); } else break; } if (pdhsts == PDH_CSTATUS_VALID_DATA) { // success, print all counters ptr = buf; while (*ptr) { printf("%s\n", ptr); ptr += strlen(ptr) + 1; } } else { fprintf(stderr, "PdhExpandCounterPathA failed: %s\n", pdherrstr(pdhsts)); if (pdhsts == PDH_MORE_DATA) fprintf(stderr, "still need to resize buffer to %ld\n", bufsz); } fflush(stderr); fflush(stdin); } int main(int argc, char **argv) { int i; if (argc == 1) { expand("\\*\\*"); expand("\\*(*)\\*"); return 0; } for (i = 1; i < argc; i++) expand(argv[i]); return 0; } pcp-3.8.12ubuntu1/src/pmdas/windows/pmda.c0000664000000000000000000017545212272262501015272 0ustar /* * Windows PMDA * * Copyright (c) 2008-2010 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "hypnotoad.h" #include /* * Array of all metrics - the PMID item field indexes this directly. */ pdh_metric_t metricdesc[] = { /* kernel.all.cpu.user */ { { PMDA_PMID(0,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\Processor(_Total)\\% User Time" }, /* kernel.all.cpu.idle */ { { PMDA_PMID(0,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\Processor(_Total)\\% Idle Time" }, /* kernel.all.cpu.sys */ { { PMDA_PMID(0,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\Processor(_Total)\\% Privileged Time" }, /* kernel.all.cpu.intr */ { { PMDA_PMID(0,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\Processor(_Total)\\% Interrupt Time" }, /* kernel.percpu.cpu.user */ { { PMDA_PMID(0,4), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\Processor(*)\\% User Time" }, /* kernel.percpu.cpu.idle */ { { PMDA_PMID(0,5), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\Processor(*)\\% Idle Time" }, /* kernel.percpu.cpu.sys */ { { PMDA_PMID(0,6), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\Processor(*)\\% Privileged Time" }, /* kernel.percpu.cpu.intr */ { { PMDA_PMID(0,7), PM_TYPE_U64, CPU_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\Processor(*)\\% Interrupt Time" }, /* kernel.num_processes */ { { PMDA_PMID(0,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\System\\Processes" }, /* kernel.num_threads */ { { PMDA_PMID(0,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\System\\Threads" }, /* kernel.all.pswitch */ { { PMDA_PMID(0,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\System\\Context Switches/sec" }, /* kernel.all.file.read */ { { PMDA_PMID(0,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\System\\File Read Operations/sec" }, /* kernel.all.file.write */ { { PMDA_PMID(0,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\System\\File Write Operations/sec" }, /* kernel.all.file.read_bytes */ { { PMDA_PMID(0,13), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\System\\File Read Bytes/sec" }, /* kernel.all.file.write_bytes */ { { PMDA_PMID(0,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\System\\File Write Bytes/sec" }, /* disk.all.read */ { { PMDA_PMID(0,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Disk Reads/sec" }, /* disk.all.write */ { { PMDA_PMID(0,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Disk Writes/sec" }, /* disk.all.total */ { { PMDA_PMID(0,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Disk Transfers/sec" }, /* disk.all.read_bytes */ { { PMDA_PMID(0,18), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Disk Read Bytes/sec" }, /* disk.all.write_bytes */ { { PMDA_PMID(0,19), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Disk Write Bytes/sec" }, /* disk.all.total_bytes */ { { PMDA_PMID(0,20), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Disk Bytes/sec" }, /* disk.dev.read */ { { PMDA_PMID(0,21), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Disk Reads/sec" }, /* disk.dev.write */ { { PMDA_PMID(0,22), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Disk Writes/sec" }, /* disk.dev.total */ { { PMDA_PMID(0,23), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Disk Transfers/sec" }, /* disk.dev.read_bytes */ { { PMDA_PMID(0,24), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Disk Read Bytes/sec" }, /* disk.dev.write_bytes */ { { PMDA_PMID(0,25), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Disk Write Bytes/sec" }, /* disk.dev.total_bytes */ { { PMDA_PMID(0,26), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Disk Bytes/sec" }, /* mem.page_faults */ { { PMDA_PMID(0,27), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Page Faults/sec" }, /* mem.available */ { { PMDA_PMID(0,28), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_MBYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Available MBytes" }, /* mem.committed_bytes */ { { PMDA_PMID(0,29), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Committed Bytes" }, /* mem.pool.paged_bytes */ { { PMDA_PMID(0,30), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Pool Paged Bytes" }, /* mem.pool.non_paged_bytes */ { { PMDA_PMID(0,31), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Pool Nonpaged Bytes" }, /* mem.cache.lazy_writes */ { { PMDA_PMID(0,32), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Cache\\Lazy Write Flushes/sec" }, /* mem.cache.lazy_write_pages */ { { PMDA_PMID(0,33), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Cache\\Lazy Write Pages/sec" }, /* mem.cache.mdl.read */ { { PMDA_PMID(0,34), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Cache\\MDL Reads/sec" }, /* mem.cache.read_ahead */ { { PMDA_PMID(0,35), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Cache\\Read Aheads/sec" }, /* mem.cache.mdl.sync_read */ { { PMDA_PMID(0,36), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Cache\\Sync MDL Reads/sec" }, /* mem.cache.mdl.async_read */ { { PMDA_PMID(0,37), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Cache\\Async MDL Reads/sec" }, /* network.interface.in.packets */ { { PMDA_PMID(0,38), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO | M_AUTO64, 0, 0, 0, NULL, "\\Network Interface(*)\\Packets Received/sec" }, /* network.interface.in.bytes */ { { PMDA_PMID(0,39), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0,0, PM_SPACE_BYTE, 0,0) }, M_REDO | M_AUTO64, 0, 0, 0, NULL, "\\Network Interface(*)\\Bytes Received/sec" }, /* network.interface.in.errors */ { { PMDA_PMID(0,40), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO | M_AUTO64, 0, 0, 0, NULL, "\\Network Interface(*)\\Packets Received Errors" }, /* network.interface.out.packets */ { { PMDA_PMID(0,41), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO | M_AUTO64, 0, 0, 0, NULL, "\\Network Interface(*)\\Packets Sent/sec" }, /* network.interface.out.bytes */ { { PMDA_PMID(0,42), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0,0, PM_SPACE_BYTE, 0,0) }, M_REDO | M_AUTO64, 0, 0, 0, NULL, "\\Network Interface(*)\\Bytes Sent/sec" }, /* network.interface.out.errors */ { { PMDA_PMID(0,43), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO | M_AUTO64, 0, 0, 0, NULL, "\\Network Interface(*)\\Packets Outbound Errors" }, /* network.interface.total.packets */ { { PMDA_PMID(0,44), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE | M_AUTO64, 0, 0, 0, NULL, "\\Network Interface(*)\\Packets/sec" }, /* network.interface.total.bytes */ { { PMDA_PMID(0,45), PM_TYPE_U64, NETIF_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\Network Interface(*)\\Bytes Total/sec" }, /* sqlserver.buf_mgr.cache_hit_ratio */ { { PMDA_PMID(0,46), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Buffer cache hit ratio" }, /* sqlserver.buf_mgr.page_lookups */ { { PMDA_PMID(0,47), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Page lookups/sec" }, /* sqlserver.buf_mgr.free_list_stalls */ { { PMDA_PMID(0,48), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Free list stalls/sec" }, /* sqlserver.buf_mgr.free_pages */ { { PMDA_PMID(0,49), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Free pages" }, /* sqlserver.buf_mgr.total_pages */ { { PMDA_PMID(0,50), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Total pages" }, /* sqlserver.buf_mgr.target_pages */ { { PMDA_PMID(0,51), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Target pages" }, /* sqlserver.buf_mgr.database_pages */ { { PMDA_PMID(0,52), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Database pages" }, /* sqlserver.buf_mgr.reserved_pages */ { { PMDA_PMID(0,53), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Reserved pages" }, /* sqlserver.buf_mgr.stolen_pages */ { { PMDA_PMID(0,54), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Stolen pages" }, /* sqlserver.buf_mgr.lazy_writes */ { { PMDA_PMID(0,55), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Lazy writes/sec" }, /* sqlserver.buf_mgr.readahead_pages */ { { PMDA_PMID(0,56), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Readahead pages/sec" }, /* sqlserver.buf_mgr.procedure_cache_pages */ { { PMDA_PMID(0,57), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Procedure cache pages" }, /* sqlserver.buf_mgr.page_reads */ { { PMDA_PMID(0,58), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Page reads/sec" }, /* sqlserver.buf_mgr.page_writes */ { { PMDA_PMID(0,59), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Page writes/sec" }, /* sqlserver.buf_mgr.checkpoint_pages */ { { PMDA_PMID(0,60), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Checkpoint pages/sec" }, /* sqlserver.buf_mgr.awe.lookup_maps */ { { PMDA_PMID(0,61), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\AWE lookup maps/sec" }, /* sqlserver.buf_mgr.awe.stolen_maps */ { { PMDA_PMID(0,62), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\AWE stolen maps/sec" }, /* sqlserver.buf_mgr.awe.write_maps */ { { PMDA_PMID(0,63), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\AWE write maps/sec" }, /* sqlserver.buf_mgr.awe.unmap_calls */ { { PMDA_PMID(0,64), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\AWE unmap calls/sec" }, /* sqlserver.buf_mgr.awe.unmap_pages */ { { PMDA_PMID(0,65), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\AWE unmap pages/sec" }, /* sqlserver.buf_mgr.page_life_expectancy */ { { PMDA_PMID(0,66), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Buffer Manager\\Page life expectancy" }, /* filesys.full */ { { PMDA_PMID(0,67), PM_TYPE_FLOAT, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\LogicalDisk(*)\\% Free Space" }, /* disk.dev.idle */ { { PMDA_PMID(0,68), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO | M_AUTO64, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\% Idle Time" }, /* sqlserver.locks.all.requests */ { { PMDA_PMID(0,69), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Locks(_Total)\\Lock Requests/sec" }, /* sqlserver.locks.all.waits */ { { PMDA_PMID(0,70), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Locks(_Total)\\Lock Waits/sec" }, /* sqlserver.locks.all.deadlocks */ { { PMDA_PMID(0,71), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Locks(_Total)\\Number of Deadlocks/sec" }, /* sqlserver.locks.all.timeouts */ { { PMDA_PMID(0,72), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Locks(_Total)\\Lock Timeouts/sec" }, /* sqlserver.locks.all.wait_time */ { { PMDA_PMID(0,73), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Locks(_Total)\\Lock Wait Time (ms)" }, /* sqlserver.locks.all.avg_wait_time */ { { PMDA_PMID(0,74), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Locks(_Total)\\Average Wait Time (ms)" }, /* sqlserver.locks.region.requests */ { { PMDA_PMID(0,75), PM_TYPE_U32, SQL_LOCK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Locks(*)\\Lock Requests/sec" }, /* sqlserver.locks.region.waits */ { { PMDA_PMID(0,76), PM_TYPE_U32, SQL_LOCK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Locks(*)\\Lock Waits/sec" }, /* sqlserver.locks.region.deadlocks */ { { PMDA_PMID(0,77), PM_TYPE_U32, SQL_LOCK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Locks(*)\\Number of Deadlocks/sec" }, /* sqlserver.locks.region.timeouts */ { { PMDA_PMID(0,78), PM_TYPE_U32, SQL_LOCK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Locks(*)\\Lock Timeouts/sec" }, /* sqlserver.locks.region.wait_time */ { { PMDA_PMID(0,79), PM_TYPE_U32, SQL_LOCK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Locks(*)\\Lock Wait Time (ms)" }, /* sqlserver.locks.region.avg_wait */ { { PMDA_PMID(0,80), PM_TYPE_FLOAT, SQL_LOCK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Locks(*)\\Average Wait Time (ms)" }, /* sqlserver.cache_mgr.all.cache_hit_ratio */ { { PMDA_PMID(0,81), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_OPTIONAL, 0, 0, 0, NULL, "\\SQLServer:Cache Manager(_Total)\\Cache Hit Ratio" }, /* sqlserver.cache_mgr.cache.cache_hit_ratio */ { { PMDA_PMID(0,82), PM_TYPE_FLOAT, SQL_CACHE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_OPTIONAL, 0, 0, 0, NULL, "\\SQLServer:Cache Manager(*)\\Cache Hit Ratio" }, /* sqlserver.connections */ { { PMDA_PMID(0,83), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:General Statistics\\User Connections" }, /* sqlserver.databases.all.transactions */ { { PMDA_PMID(0,84), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(_Total)\\Transactions/sec" }, /* sqlserver.databases.db.transactions */ { { PMDA_PMID(0,85), PM_TYPE_U32, SQL_DB_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(*)\\Transactions/sec" }, /* sqlserver.sql.batch_requests */ { { PMDA_PMID(0,86), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:SQL Statistics\\Batch Requests/sec" }, /* sqlserver.latches.waits */ { { PMDA_PMID(0,87), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Latches\\Latch Waits/sec" }, /* sqlserver.latches.wait_time */ { { PMDA_PMID(0,88), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Latches\\Total Latch Wait Time (ms)" }, /* sqlserver.latches.avg_wait_time */ { { PMDA_PMID(0,89), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_MSEC, 0) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Latches\\Average Latch Wait Time (ms)" }, /* sqlserver.databases.all.data_file_size */ { { PMDA_PMID(0,90), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(_Total)\\Data File(s) Size (KB)" }, /* sqlserver.databases.all.log_file_size */ { { PMDA_PMID(0,91), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(_Total)\\Log File(s) Size (KB)" }, /* sqlserver.databases.all.log_file_used */ { { PMDA_PMID(0,92), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(_Total)\\Log File(s) Used Size (KB)" }, /* sqlserver.databases.db.data_file_size */ { { PMDA_PMID(0,93), PM_TYPE_U32, SQL_DB_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(*)\\Data File(s) Size (KB)" }, /* sqlserver.databases.db.log_file_size */ { { PMDA_PMID(0,94), PM_TYPE_U32, SQL_DB_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(*)\\Log File(s) Size (KB)" }, /* sqlserver.databases.db.log_file_used */ { { PMDA_PMID(0,95), PM_TYPE_U32, SQL_DB_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(*)\\Log File(s) Used Size (KB)" }, /* sqlserver.sql.compilations */ { { PMDA_PMID(0,96), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:SQL Statistics\\SQL Compilations/sec" }, /* sqlserver.sql.re_compilations */ { { PMDA_PMID(0,97), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:SQL Statistics\\SQL Re-Compilations/sec" }, /* sqlserver.access.full_scans */ { { PMDA_PMID(0,98), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Access Methods\\Full Scans/sec" }, /* sqlserver.access.pages_allocated */ { { PMDA_PMID(0,99), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Access Methods\\Pages Allocated/sec" }, /* sqlserver.access.table_lock_escalations */ { { PMDA_PMID(0,100), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Access Methods\\Table Lock Escalations/sec" }, /* disk.dev.queuelen */ { { PMDA_PMID(0,101), PM_TYPE_U32, DISK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Current Disk Queue Length" }, /* sqlserver.databases.all.log_flushes */ { { PMDA_PMID(0,102), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(_Total)\\Log Flushes/sec" }, /* sqlserver.databases.db.log_flushes */ { { PMDA_PMID(0,103), PM_TYPE_U32, SQL_DB_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(*)\\Log Flushes/sec" }, /* sqlserver.databases.all.log_bytes_flushed */ { { PMDA_PMID(0,104), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(_Total)\\Log Bytes Flushed/sec" }, /* sqlserver.databases.db.log_bytes_flushed */ { { PMDA_PMID(0,105), PM_TYPE_U32, SQL_DB_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(*)\\Log Bytes Flushed/sec" }, /* hinv.physmem */ { { PMDA_PMID(0,106), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_MBYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "" }, /* hinv.ncpu */ { { PMDA_PMID(0,107), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "" }, /* hinv.ndisk */ { { PMDA_PMID(0,108), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "" }, /* kernel.uname.distro */ { { PMDA_PMID(0,109), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_NONE, 0, 0, 0, NULL, "" }, /* kernel.uname.release */ { { PMDA_PMID(0,110), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_NONE, 0, 0, 0, NULL, "" }, /* kernel.uname.version */ { { PMDA_PMID(0,111), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, M_NONE, 0, 0, 0, NULL, "" }, /* kernel.uname.sysname */ { { PMDA_PMID(0,112), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, M_NONE, 0, 0, 0, NULL, "" }, /* kernel.uname.machine */ { { PMDA_PMID(0,113), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, M_NONE, 0, 0, 0, NULL, "" }, /* kernel.uname.nodename */ { { PMDA_PMID(0,114), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, M_NONE, 0, 0, 0, NULL, "" }, /* pmda.uname */ { { PMDA_PMID(0,115), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, M_NONE, 0, 0, 0, NULL, "" }, /* pmda.version */ { { PMDA_PMID(0,116), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, M_NONE, 0, 0, 0, NULL, "" }, /* filesys.capacity */ { { PMDA_PMID(0,117), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "" }, /* filesys.used */ { { PMDA_PMID(0,118), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "" }, /* filesys.free */ { { PMDA_PMID(0,119), PM_TYPE_U64, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "" }, /* dummy - filesys.free_space */ { { PMDA_PMID(0,120), PM_TYPE_U32, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_MBYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "\\LogicalDisk(*)\\Free Megabytes" }, /* dummy - filesys.free_percent */ { { PMDA_PMID(0,121), PM_TYPE_FLOAT, FILESYS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, M_REDO, 0, 0, 0, NULL, "\\LogicalDisk(*)\\% Free Space" }, /* sqlserver.access.page_splits */ { { PMDA_PMID(0,122), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Access Methods\\Page Splits/sec" }, /* network.tcp.activeopens */ { { PMDA_PMID(0,123), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\TCPv4\\Connections Active" }, /* network.tcp.passiveopens */ { { PMDA_PMID(0,124), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\TCPv4\\Connections Passive" }, /* network.tcp.attemptfails */ { { PMDA_PMID(0,125), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\TCPv4\\Connection Failures" }, /* network.tcp.estabresets */ { { PMDA_PMID(0,126), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\TCPv4\\Connections Reset" }, /* network.tcp.currestab */ { { PMDA_PMID(0,127), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\TCPv4\\Connections Established" }, /* network.tcp.insegs */ { { PMDA_PMID(0,128), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\TCPv4\\Segments Received/sec" }, /* network.tcp.outsegs */ { { PMDA_PMID(0,129), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\TCPv4\\Segments Sent/sec" }, /* network.tcp.totalsegs */ { { PMDA_PMID(0,130), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\TCPv4\\Segments/sec" }, /* network.tcp.retranssegs */ { { PMDA_PMID(0,131), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\TCPv4\\Segments Retransmitted/sec" }, /* disk.all.split_io */ { { PMDA_PMID(0,132), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Split IO/Sec" }, /* disk.dev.split_io */ { { PMDA_PMID(0,133), PM_TYPE_U32, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Split IO/Sec" }, /* sqlserver.databases.all.active_transactions */ { { PMDA_PMID(0,134), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(_Total)\\Active Transactions" }, /* sqlserver.databases.db.active_transactions */ { { PMDA_PMID(0,135), PM_TYPE_U32, SQL_DB_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO | M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Databases(*)\\Active Transactions" }, /* mem.commit_limit */ { { PMDA_PMID(0,136), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Commit Limit" }, /* mem.write_copies */ { { PMDA_PMID(0,137), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Write Copies/sec" }, /* mem.transition_faults */ { { PMDA_PMID(0,138), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Transition Faults/sec" }, /* mem.cache.faults */ { { PMDA_PMID(0,139), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Cache Faults/sec" }, /* mem.demand_zero_faults */ { { PMDA_PMID(0,140), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Demand Zero Faults/sec" }, /* mem.pages_total */ { { PMDA_PMID(0,141), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Pages/sec" }, /* mem.page_reads */ { { PMDA_PMID(0,142), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Page Reads/sec" }, /* mem.pages_output */ { { PMDA_PMID(0,143), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Pages Output/sec" }, /* mem.page_writes */ { { PMDA_PMID(0,144), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Page Writes/sec" }, /* mem.pool.paged_allocs */ { { PMDA_PMID(0,145), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Pool Paged Allocs" }, /* mem.pool.nonpaged_allocs */ { { PMDA_PMID(0,146), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Pool Nonpaged Allocs" }, /* mem.system.free_ptes */ { { PMDA_PMID(0,147), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Free System Page Table Entries" }, /* mem.cache.bytes */ { { PMDA_PMID(0,148), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Page Faults/sec" }, /* mem.cache.bytes_peak */ { { PMDA_PMID(0,149), PM_TYPE_64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Cache Bytes Peak" }, /* mem.pool.paged_resident_bytes */ { { PMDA_PMID(0,150), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\Pool Paged Resident Bytes" }, /* mem.system.total_code_bytes */ { { PMDA_PMID(0,151), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\System Code Total Bytes" }, /* mem.system.resident_code_bytes */ { { PMDA_PMID(0,152), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_NONE, 0, 0, 0, NULL, "\\Memory\\System Code Resident Bytes" }, /* sqlserver.mem_mgr.connection_memory */ { { PMDA_PMID(0,153), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,PM_SPACE_KBYTE,0,0,0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Connection Memory (KB)" }, /* sqlserver.mem_mgr.granted_workspace */ { { PMDA_PMID(0,154), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,PM_SPACE_KBYTE,0,0,0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Granted Workspace Memory (KB)" }, /* sqlserver.mem_mgr.lock_memory */ { { PMDA_PMID(0,155), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,PM_SPACE_KBYTE,0,0,0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Lock Memory (KB)" }, /* sqlserver.mem_mgr.lock_blocks_allocated */ { { PMDA_PMID(0,156), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Lock Blocks Allocated" }, /* sqlserver.mem_mgr.lock_owner_blocks_allocated */ { { PMDA_PMID(0,157), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Lock Owner Blocks Allocated" }, /* sqlserver.mem_mgr.lock_blocks */ { { PMDA_PMID(0,158), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Lock Blocks" }, /* sqlserver.mem_mgr.lock_owner_blocks */ { { PMDA_PMID(0,159), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Lock Owner Blocks" }, /* sqlserver.mem_mgr.maximum_workspace_memory */ { { PMDA_PMID(0,160), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,PM_SPACE_KBYTE,0,0,0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Maximum Workspace Memory (KB)" }, /* sqlserver.mem_mgr.memory_grants_outstanding */ { { PMDA_PMID(0,161), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Memory Grants Outstanding" }, /* sqlserver.mem_mgr.memory_grants_pending */ { { PMDA_PMID(0,162), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Memory Grants Pending" }, /* sqlserver.mem_mgr.optimizer_memory */ { { PMDA_PMID(0,163), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,PM_SPACE_KBYTE,0,0,0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Optimizer Memory (KB)" }, /* sqlserver.mem_mgr.sql_cache_memory */ { { PMDA_PMID(0,164), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,PM_SPACE_KBYTE,0,0,0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\SQL Cache Memory (KB)" }, /* sqlserver.mem_mgr.target_server_memory */ { { PMDA_PMID(0,165), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,PM_SPACE_KBYTE,0,0,0) }, M_OPTIONAL, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Target Server Memory(KB)" }, /* sqlserver.mem_mgr.total_server_memory */ { { PMDA_PMID(0,166), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,PM_SPACE_KBYTE,0,0,0) }, M_OPTIONAL | M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:Memory Manager\\Total Server Memory (KB)" }, /* sqlserver.cache_mgr.all.cache_pages */ { { PMDA_PMID(0,167), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_OPTIONAL, 0, 0, 0, NULL, "\\SQLServer:Cache Manager(_Total)\\Cache Pages" }, /* sqlserver.cache_mgr.all.cache_object_count */ { { PMDA_PMID(0,168), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_OPTIONAL, 0, 0, 0, NULL, "\\SQLServer:Cache Manager(_Total)\\Cache Object Counts" }, /* sqlserver.cache_mgr.all.cache_use */ { { PMDA_PMID(0,169), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_OPTIONAL, 0, 0, 0, NULL, "\\SQLServer:Cache Manager(_Total)\\Cache Use Counts/sec" }, /* sqlserver.cache_mgr.cache.cache_pages */ { { PMDA_PMID(0,170), PM_TYPE_U32, SQL_CACHE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_OPTIONAL, 0, 0, 0, NULL, "\\SQLServer:Cache Manager(*)\\Cache Pages" }, /* sqlserver.cache_mgr.cache.cache_object_count */ { { PMDA_PMID(0,171), PM_TYPE_32, SQL_CACHE_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_OPTIONAL, 0, 0, 0, NULL, "\\SQLServer:Cache Manager(*)\\Cache Object Counts" }, /* sqlserver.cache_mgr.cache.cache_use */ { { PMDA_PMID(0,172), PM_TYPE_U32, SQL_CACHE_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, M_OPTIONAL, 0, 0, 0, NULL, "\\SQLServer:Cache Manager(*)\\Cache Use Counts/sec" }, /* process.count */ { { PMDA_PMID(0,173), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\Objects\\Processes" }, /* process.psinfo.pid */ { { PMDA_PMID(0,174), PM_TYPE_U32, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\ID Process" }, /* process.psinfo.ppid */ { { PMDA_PMID(0,175), PM_TYPE_U32, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Creating Process ID" }, /* process.psinfo.cpu_time */ { { PMDA_PMID(0,176), PM_TYPE_U32, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO | M_AUTO64, 0, 0, 0, NULL, "\\Process(*)\\% Processor Time" }, /* process.psinfo.elapsed_time */ { { PMDA_PMID(0,177), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Elapsed Time" }, /* process.psinfo.utime */ { { PMDA_PMID(0,178), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\% User Time" }, /* process.psinfo.stime */ { { PMDA_PMID(0,179), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\% Privileged Time" }, /* process.psinfo.nthreads */ { { PMDA_PMID(0,180), PM_TYPE_U32, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Thread Count" }, /* process.psinfo.priority_base */ { { PMDA_PMID(0,181), PM_TYPE_U32, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Priority Base" }, /* process.psinfo.nhandles */ { { PMDA_PMID(0,182), PM_TYPE_U32, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Handle Count" }, /* process.psinfo.page_faults */ { { PMDA_PMID(0,183), PM_TYPE_U32, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Page Faults/sec" }, /* process.memory.size */ { { PMDA_PMID(0,184), PM_TYPE_U32, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Pool Paged Bytes" }, /* process.memory.rss */ { { PMDA_PMID(0,185), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Working Set" }, /* process.memory.rss_peak */ { { PMDA_PMID(0,186), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Working Set Peak" }, /* process.memory.virtual */ { { PMDA_PMID(0,187), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Virtual Bytes" }, /* process.memory.virtual_peak */ { { PMDA_PMID(0,188), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Virtual Bytes Peak" }, /* process.memory.page_file */ { { PMDA_PMID(0,189), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Page File Bytes" }, /* process.memory.page_file_peak */ { { PMDA_PMID(0,190), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Page File Bytes Peak" }, /* process.memory.private */ { { PMDA_PMID(0,191), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Private Bytes" }, /* process.memory.pool_paged */ { { PMDA_PMID(0,192), PM_TYPE_U32, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Pool Paged Bytes" }, /* process.memory.pool_nonpaged */ { { PMDA_PMID(0,193), PM_TYPE_U32, PROCESS_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\Pool Nonpaged Bytes" }, /* process.io.reads */ { { PMDA_PMID(0,194), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\IO Read Operations/sec" }, /* process.io.writes */ { { PMDA_PMID(0,195), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\IO Write Operations/sec" }, /* process.io.data */ { { PMDA_PMID(0,196), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\IO Data Operations/sec" }, /* process.io.other */ { { PMDA_PMID(0,197), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\IO Other Operations/sec" }, /* process.io.read_bytes */ { { PMDA_PMID(0,198), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\IO Read Bytes/sec" }, /* process.io.write_bytes */ { { PMDA_PMID(0,199), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\IO Write Bytes/sec" }, /* process.io.data_bytes */ { { PMDA_PMID(0,200), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\IO Data Bytes/sec" }, /* process.io.other_bytes */ { { PMDA_PMID(0,201), PM_TYPE_U64, PROCESS_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Process(*)\\IO Other Bytes/sec" }, /* process.thread.context_switches */ { { PMDA_PMID(0,202), PM_TYPE_U32, THREAD_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_REDO, 0, 0, 0, NULL, "\\Thread(*)\\Context Switches/sec" }, /* process.thread.cpu_time */ { { PMDA_PMID(0,203), PM_TYPE_U64, THREAD_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\Thread(*)\\% Processor Time" }, /* process.thread.utime */ { { PMDA_PMID(0,204), PM_TYPE_U64, THREAD_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\Thread(*)\\% User Time" }, /* process.thread.stime */ { { PMDA_PMID(0,205), PM_TYPE_U64, THREAD_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\Thread(*)\\% Privileged Time" }, /* process.thread.elapsed_time */ { { PMDA_PMID(0,206), PM_TYPE_U64, THREAD_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\Thread(*)\\Elapsed Time" }, /* process.thread.priority */ { { PMDA_PMID(0,207), PM_TYPE_U32, THREAD_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Thread(*)\\Priority Current" }, /* process.thread.priority_base */ { { PMDA_PMID(0,208), PM_TYPE_U32, THREAD_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Thread(*)\\Priority Base" }, /* process.thread.start_address */ { { PMDA_PMID(0,209), PM_TYPE_U32, THREAD_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Thread(*)\\Start Address" }, /* process.thread.state */ { { PMDA_PMID(0,210), PM_TYPE_U32, THREAD_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Thread(*)\\Thread State" }, /* process.thread.wait_reason */ { { PMDA_PMID(0,211), PM_TYPE_U32, THREAD_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Thread(*)\\Thread Wait Reason" }, /* process.thread.process_id */ { { PMDA_PMID(0,212), PM_TYPE_U32, THREAD_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Thread(*)\\ID Process" }, /* process.thread.thread_id */ { { PMDA_PMID(0,213), PM_TYPE_U32, THREAD_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\Thread(*)\\ID Thread" }, /* disk.all.read_time */ { { PMDA_PMID(0,214), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\% Disk Read Time" }, /* disk.all.write_time */ { { PMDA_PMID(0,215), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\% Disk Write Time" }, /* disk.all.total_time */ { { PMDA_PMID(0,216), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\% Disk Time" }, /* disk.dev.read_time */ { { PMDA_PMID(0,217), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\% Disk Read Time" }, /* disk.dev.write_time */ { { PMDA_PMID(0,218), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\% Disk Write Time" }, /* disk.dev.total_time */ { { PMDA_PMID(0,219), PM_TYPE_U64, DISK_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\% Disk Time" }, /* disk.all.average.read_bytes */ { { PMDA_PMID(0,220), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Avg. Disk Bytes/Read" }, /* disk.all.average.write_bytes */ { { PMDA_PMID(0,221), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Avg. Disk Bytes/Write" }, /* disk.all.average.total_bytes */ { { PMDA_PMID(0,222), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Avg. Disk Bytes/Transfer" }, /* disk.all.average.read_time */ { { PMDA_PMID(0,223), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Avg. Disk sec/Read" }, /* disk.all.average.write_time */ { { PMDA_PMID(0,224), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Avg. Disk sec/Write" }, /* disk.all.average.total_time */ { { PMDA_PMID(0,225), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_NONE, 0, 0, 0, NULL, "\\PhysicalDisk(_Total)\\Avg. Disk sec/Transfer" }, /* disk.dev.average.read_bytes */ { { PMDA_PMID(0,226), PM_TYPE_U64, DISK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Avg. Disk Bytes/Read" }, /* disk.dev.write_bytes */ { { PMDA_PMID(0,227), PM_TYPE_U64, DISK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Avg. Disk Bytes/Write" }, /* disk.dev.total_bytes */ { { PMDA_PMID(0,228), PM_TYPE_U64, DISK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1, 0, 0, PM_SPACE_BYTE, 0, 0) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Avg. Disk Bytes/Transfer" }, /* disk.dev.average.read_time */ { { PMDA_PMID(0,229), PM_TYPE_U64, DISK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Avg. Disk sec/Read" }, /* disk.dev.average.write_time */ { { PMDA_PMID(0,230), PM_TYPE_U64, DISK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Avg. Disk sec/Write" }, /* disk.dev.average.total_time */ { { PMDA_PMID(0,231), PM_TYPE_U64, DISK_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_USEC, 0) }, M_REDO, 0, 0, 0, NULL, "\\PhysicalDisk(*)\\Avg. Disk sec/Transfer" }, /* hinv.nfilesys */ { { PMDA_PMID(0,232), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 1, 0, 0, PM_COUNT_ONE) }, M_NONE, 0, 0, 0, NULL, "" }, /* hinv.pagesize */ { { PMDA_PMID(0,233), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_NONE, 0, 0, 0, NULL, "" }, /* kernel.all.uptime */ { { PMDA_PMID(0,234), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) }, M_REDO, 0, 0, 0, NULL, "\\System\\System Up Time" }, /* network.interface.bandwidth */ { { PMDA_PMID(0,235), PM_TYPE_U32, NETIF_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(0, -1, 0, 0, PM_TIME_SEC, 0) }, M_REDO | M_AUTO64, 0, 0, 0, NULL, "\\Network Interface(*)\\Current Bandwidth" }, /* network.interface.speed */ { { PMDA_PMID(0,236), PM_TYPE_FLOAT, NETIF_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, -1, 0, PM_SPACE_MBYTE, PM_TIME_SEC, 0) }, M_REDO, 0, 0, 0, NULL, "" }, /* network.interface.baudrate */ { { PMDA_PMID(0,237), PM_TYPE_U32, NETIF_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1, -1, 0, PM_SPACE_BYTE, PM_TIME_SEC, 0) }, M_REDO, 0, 0, 0, NULL, "" }, /* sqlserver.user_settable.query */ { { PMDA_PMID(0,238), PM_TYPE_U32, SQL_USER_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, M_AUTO64, 0, 0, 0, NULL, "\\SQLServer:User Settable(*)\\Query" }, /* mem.physmem */ { { PMDA_PMID(1,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "The amount of actual physical memory" }, /* mem.freemem */ { { PMDA_PMID(1,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "The amount of physical memory currently available" }, /* mem.util.load */ { { PMDA_PMID(1,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, M_NONE, 0, 0, 0, NULL, "Approximate percentage of physical memory in use" }, /* mem.util.used */ { { PMDA_PMID(1,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "Amount of physical memory in use" }, /* mem.util.free */ { { PMDA_PMID(1,4), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "Amount of physical memory currently available" }, /* swap.length */ { { PMDA_PMID(1,5), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "The current committed memory limit for the system" }, /* swap.used */ { { PMDA_PMID(1,6), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "The current committed memory for the system" }, /* swap.free */ { { PMDA_PMID(1,7), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(1, 0, 0, PM_SPACE_KBYTE, 0, 0) }, M_NONE, 0, 0, 0, NULL, "The maximum amount of memory the system can commit" }, }; int metricdesc_sz = sizeof(metricdesc) / sizeof(metricdesc[0]); static int windows_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) { windows_instance_refresh(indom); return pmdaInstance(indom, inst, name, result, pmda); } static int windows_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { windows_fetch_refresh(numpmid, pmidlist, pmda); return pmdaFetch(numpmid, pmidlist, resp, pmda); } static pdh_value_t * find_instance_value(unsigned int item, unsigned int inst) { pdh_metric_t *mp = &metricdesc[item]; int i; /* fast check for direct mapped instance ID */ if (inst < mp->num_vals && mp->vals[inst].inst == inst) return (mp->vals[inst].flags & V_COLLECTED) ? &mp->vals[inst] : NULL; /* scan iteratively through instance IDs looking for this one */ for (i = 0; i < mp->num_vals; i++) { if (mp->vals[i].inst != inst) continue; if (!(mp->vals[i].flags & V_COLLECTED)) break; return &mp->vals[i]; } return NULL; } static int filesys_fetch_callback(unsigned int item, unsigned int inst, pmAtomValue *atom) { pdh_value_t *vp; unsigned long long used, avail, capacity; float used_space, free_space, free_percent; /* * Special case handling for the derived filesystem metrics * which map the PDH services semantics for some metrics to * the usual metrics from other platforms. * 67 filesys.full * 117 filesys.capacity * 118 filesys.used * 119 filesys.free * 120 dummy metric, metricdesc holds FreeMB * 121 dummy metric, metricdesc holds %Free */ if (item == 67) { /* filesys.full, metricdesc holds %Free */ vp = find_instance_value(item, inst); if (!vp) return 0; atom->f = (1.0 - vp->atom.f) * 100.0; return 1; } vp = find_instance_value(120,inst); /* dummy, metricdesc holds FreeMB */ if (!vp) return 0; free_space = ((float)vp->atom.ul); vp = find_instance_value(121,inst); /* dummy, metricdesc holds %Free */ if (!vp) return 0; free_percent = vp->atom.f; used_space = (free_space / free_percent) - free_space; used = 1024 * (unsigned long long)used_space; /* MB to KB */ avail = 1024 * (unsigned long long)free_space; /* MB to KB */ capacity = used + avail; if (item == 117) /* filesys.capacity */ atom->ull = capacity; else if (item == 118) /* filesys.used */ atom->ull = used; else if (item == 119) /* filesys.free */ atom->ull = avail; return 1; } static int network_fetch_callback(unsigned int item, unsigned int inst, pmAtomValue *atom) { pdh_value_t *vp; /* * Special case handling for the derived network bandwidth metrics * 235 network.interface.bandwidth (base, no derived) * 236 network.interface.speed (mbytes, float) * 237 network.interface.baudrate (in bytes) */ vp = find_instance_value(235,inst); if (!vp) return 0; if (item == 236) atom->f = ((float)vp->atom.ull / 8 / 1024 / 1024); else if (item == 237) atom->ul = (vp->atom.ull / 8); return 1; } static int memstat_fetch_callback(unsigned int item, unsigned int inst, pmAtomValue *atom) { if (inst == PM_INDOM_NULL) { switch (item) { case 0: /* mem.physmem */ atom->ull = windows_memstat.ullTotalPhys / 1024; return 1; case 1: /* mem.freemem */ case 4: /* mem.util.free */ atom->ull = windows_memstat.ullAvailPhys / 1024; return 1; case 2: /* mem.util.load */ atom->ul = windows_memstat.dwMemoryLoad; return 1; case 3: /* mem.util.used */ atom->ull = windows_memstat.ullTotalPhys; atom->ull =- windows_memstat.ullAvailPhys; atom->ull /= 1024; return 1; case 5: /* swap.length */ atom->ull = windows_memstat.ullTotalPageFile / 1024; return 1; case 6: /* swap.used */ atom->ull = windows_memstat.ullTotalPageFile; atom->ull -= windows_memstat.ullAvailPageFile; atom->ull /= 1024; return 1; case 7: /* swap.free */ atom->ull = windows_memstat.ullAvailPageFile / 1024; return 1; } } return 0; } static int windows_fetch_callback(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *pmidp = (__pmID_int *)&mdesc->m_desc.pmid; pdh_value_t *vp; if (pmidp->cluster == 1) return memstat_fetch_callback(pmidp->item, inst, atom); if (pmidp->cluster != 0 || pmidp->item > metricdesc_sz || (pmidp->item == 120 || pmidp->item == 121)) /* dummies */ return PM_ERR_PMID; /* * Check if its one of the derived metrics, or one that doesn't use PDH */ switch (pmidp->item) { case 106: /* hinv.physmem */ atom->ul = (windows_memstat.ullTotalPhys / (1024 * 1024)); return 1; case 107: /* hinv.ncpu */ atom->ul = pmdaCacheOp(INDOM(pmidp->domain, CPU_INDOM), PMDA_CACHE_SIZE_ACTIVE); return 1; case 108: /* hinv.ndisk */ atom->ul = pmdaCacheOp(INDOM(pmidp->domain, DISK_INDOM), PMDA_CACHE_SIZE_ACTIVE); return 1; case 109: /* kernel.uname.distro */ atom->cp = windows_uname; return 1; case 110: /* kernel.uname.release */ atom->cp = windows_build; return 1; case 111: /* kernel.uname.version */ atom->cp = windows_build; return 1; case 112: /* kernel.uname.sysname */ atom->cp = "Windows"; return 1; case 113: /* kernel.uname.machine */ atom->cp = windows_machine; return 1; case 114: /* kernel.uname.nodename */ atom->cp = "?"; return 1; case 115: /* pmda.uname */ atom->cp = windows_uname; return 1; case 116: /* pmda.version */ atom->cp = pmGetConfig("PCP_VERSION"); return 1; case 67: case 117: case 118: case 119: return filesys_fetch_callback(pmidp->item, inst, atom); case 232: /* hinv.nfilesys */ atom->ul = pmdaCacheOp(INDOM(pmidp->domain, FILESYS_INDOM), PMDA_CACHE_SIZE_ACTIVE); return 1; case 233: /* hinv.pagesize */ atom->ul = windows_pagesize; return 1; case 236: case 237: return network_fetch_callback(pmidp->item, inst, atom); } /* * All other (most) metrics will go through this path */ vp = find_instance_value(pmidp->item, inst); if (!vp) return 0; *atom = vp->atom; return 1; } /* * Initialise the agent. */ void windows_init(pmdaInterface *dp) { static pmdaMetric *metrictab; char helppath[MAXPATHLEN]; int metrictab_sz = metricdesc_sz; int i, sep = __pmPathSeparator(); snprintf(helppath, sizeof(helppath), "%s%c" "windows" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_3, "windows DSO", helppath); if (dp->status != 0) return; /* Create the PMDA's metrictab[] version of the per-metric table */ metrictab = (pmdaMetric *)malloc(metrictab_sz * sizeof(pmdaMetric)); if (metrictab == NULL) { fprintf(stderr, "Error: malloc metrictab [%d] failed: %s\n", metrictab_sz * sizeof(pmdaMetric), osstrerror()); return; } /* rewrite pmid & indom, now that we know what the domain number is */ for (i = 0; i < metrictab_sz; i++) { pdh_metric_t *mp = &metricdesc[i]; pmID pmid = mp->desc.pmid; mp->desc.pmid = pmid_build(dp->domain, pmid_cluster(pmid), pmid_item(pmid)); if (mp->desc.indom != PM_INDOM_NULL) mp->desc.indom = INDOM(dp->domain, mp->desc.indom); } windows_open(dp->domain); /* write the metrictab entry for this metric, descriptor now setup */ for (i = 0; i < metrictab_sz; i++) { metrictab[i].m_desc = metricdesc[i].desc; metrictab[i].m_user = NULL; } dp->version.two.fetch = windows_fetch; dp->version.two.instance = windows_instance; dp->version.two.text = windows_help; pmdaSetFetchCallBack(dp, windows_fetch_callback); pmdaInit(dp, NULL, 0, metrictab, metrictab_sz); } pcp-3.8.12ubuntu1/src/pmdas/windows/helptext.c0000664000000000000000000000452112272262501016172 0ustar /* * Copyright (c) 2008-2009 Aconex. All Rights Reserved. * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "hypnotoad.h" static char *text; /* filled in by iterator callback routine */ static char texts[MAX_M_TEXT_LEN]; /* static callback buffer */ /* * Replace backslashes in the help string returned from Pdh APIs. * Everything done "in-place" so no change to size of the string. */ static char * windows_fmt(char *text) { char *p; int n; for (p = text, n = 0; p && *p != '\0'; p++, n++) { if (!isprint((int)*p)) /* toss any dodgey characters */ *p = '?'; else if (*p == '\r') /* remove Windows line ending */ *p = '\n'; if (n < 70 || !isspace((int)*p)) /* very simple line wrapping */ continue; *p = '\n'; n = 0; } return text; } static void windows_helptext_metric(pdh_metric_t *mp, PDH_COUNTER_INFO_A *infop) { text = infop->szExplainText; } static void windows_helptext_callback(pdh_metric_t *pmp, LPSTR pat, pdh_value_t *pvp) { windows_inform_metric(pmp, pat, pvp, TRUE, windows_helptext_metric); } int windows_help(int ident, int type, char **buf, pmdaExt *pmda) { pmID pmid = (pmID)ident; int i; if ((type & PM_TEXT_PMID) != PM_TEXT_PMID) return pmdaText(ident, type, buf, pmda); for (i = 0; i < metricdesc_sz; i++) if (pmid == metricdesc[i].desc.pmid) break; if (i == metricdesc_sz) return PM_ERR_PMID; if (type & PM_TEXT_ONELINE) { if (metricdesc[i].pat[0] == '\0') return pmdaText(ident, type, buf, pmda); *buf = windows_fmt(strncpy(texts, &metricdesc[i].pat[0], sizeof(texts))); } else { text = NULL; windows_visit_metric(&metricdesc[i], windows_helptext_callback); if (!text) return pmdaText(ident, type, buf, pmda); *buf = windows_fmt(strncpy(texts, text, sizeof(texts))); } return 0; } pcp-3.8.12ubuntu1/src/pmdas/windows/pmns.filesys0000664000000000000000000000015712272262501016547 0ustar filesys { full WINDOWS:0:67 capacity WINDOWS:0:117 used WINDOWS:0:118 free WINDOWS:0:119 } pcp-3.8.12ubuntu1/src/pmdas/windows/instance.c0000664000000000000000000002314512272262501016144 0ustar /* * Copyright (c) 2008-2010 Aconex. All Rights Reserved. * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. * Parts of this file contributed by Ken McDonell * (kenj At internode DoT on DoT net) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "hypnotoad.h" #include int windows_indom_fixed(int serial) { return (serial != PROCESS_INDOM && serial != THREAD_INDOM); } void windows_instance_refresh(pmInDom indom) { int i, index, setup; index = pmInDom_serial(indom); windows_indom_reset[index] = 0; setup = windows_indom_setup[index]; for (i = 0; i < metricdesc_sz; i++) { pdh_metric_t *mp = &metricdesc[i]; if (indom != mp->desc.indom || mp->pat[0] != '\\') continue; if (!setup || (mp->flags & M_REDO)) windows_visit_metric(mp, NULL); break; } /* Do we want to persist this instance domain to disk? */ if (windows_indom_reset[index] && windows_indom_fixed(index)) pmdaCacheOp(indom, PMDA_CACHE_SAVE); } int windows_lookup_instance(char *path, pdh_metric_t *mp) { __pmInDom_int *ip; static void *seen = (void *)0xfeedbabe; void *sp; char *p, *q, *name = NULL; int sts, ok = 0; if (mp->desc.indom == PM_INDOM_NULL) return PM_IN_NULL; ip = (__pmInDom_int *)&mp->desc.indom; switch (ip->serial) { /* * Examples: * \\WINBUILD\PhysicalDisk(0 C:)\Disk Reads/sec * \\SOMEHOST\PhysicalDisk(0 C: D: E:)\Disk Transfers/sec * \\WINBUILD\PhysicalDisk(_Total)\Disk Write Bytes/sec */ case DISK_INDOM: p = strchr(path, '('); // skip hostname and metric name if (p != NULL) { p++; if (strncmp(p, "_Total)", 7) == 0) { /* * The totals get enumerated in the per disk path * expansion, just skip 'em here */ return -1; } while (isascii((int)*p) && isdigit((int)*p)) p++; if (*p == ' ') { p++; q = strchr(p, ')'); if (q != NULL) { name = (char *)malloc(q - p + 1); if (name != NULL) { strncpy(name, p, q - p); name[q - p] = '\0'; ok = 1; } else { __pmNotifyErr(LOG_ERR, "windows_check_instance: " "Error: DISK_INDOM malloc[%d] failed " "path=%s\n", q - p + 1, path); return -1; } /* * If more than one drive letter maps to the same * logical disk (e.g. mirrored root),, the name * contains spaces, e.g. * "C: D:" ... replace ' ' by '_' to play by the * PCP rules for instance names */ for (p = name; *p; p++) { if (*p == ' ') *p = '_'; } } } } /* * expecting something like ...\PhysicalDisk(N name)... * we will just have to ignore this one! (might be due * to: http://support.microsoft.com/kb/974878 - fail as * entries like "17" and "17#1" are not useable anyway) */ if (!ok) { if (pmDebug & DBG_TRACE_LIBPMDA) __pmNotifyErr(LOG_ERR, "windows_check_instance: Error: " "unrecognized disk instance: %s\n", path); free(name); return -1; } break; /* * Examples: * \\WINBUILD\Processor(0)\% User Time * \\WINBUILD\Processor(_Total)\Interrupts/sec */ case CPU_INDOM: p = strchr(path, '('); // skip hostname and metric name if (p != NULL) { p++; if (strncmp(p, "_Total)", 7) == 0) { /* * The totals get enumerated in the per cpu path * expansion, just skip 'em here */ return -1; } int inst = atoi(p); name = (char *)malloc(8); // "cpuNNNN" if (name != NULL) sprintf(name, "cpu%d", inst); ok = 1; } /* * expecting something like ...\Processor(N)... * don't know what to do with this one! */ if (!ok) { __pmNotifyErr(LOG_ERR, "windows_check_instance: Error: " "unrecognized cpu instance: %s\n", path); free(name); return -1; } break; /* * Examples: * \\WINNT\Network Interface(MS TCP Loopback interface)\Bytes Total/sec */ case NETIF_INDOM: p = strchr(path, '('); // skip hostname and metric name if (p != NULL) { p++; q = strchr(p, ')'); if (q != NULL) { name = (char *)malloc(q - p + 1); if (name != NULL) { strncpy(name, p, q - p); name[q - p] = '\0'; ok = 1; } else { __pmNotifyErr(LOG_ERR, "windows_check_instance: Error: " "malloc[%d] failed for NETIF_INDOM " "path=%s\n", q - p + 1, path); return -1; } /* * The network interface names have many spaces and are * not unique up to the first space by any means. So, * replace ' 's to play by the PCP instance name rules. */ for (p = name; *p; p++) { if (*p == ' ') *p = '_'; } } } /* * expecting something like ...\Network Interface(...)... * don't know what to do with this one! */ if (!ok) { __pmNotifyErr(LOG_ERR, "windows_check_instance: Error: " "unrecognized network interface instance: %s\n", path); free(name); return -1; } break; /* * Examples: * \\TOWER\LogicalDisk(C:)\% Free Space */ case FILESYS_INDOM: p = strchr(path, '('); // skip hostname and metric name if (p != NULL) { p++; if (strncmp(p, "_Total)", 7) == 0) { /* * The totals value makes no semantic sense, * just skip it here */ return -1; } while (isascii((int)*p) && isdigit((int)*p)) p++; if (*p == ' ') p++; q = strchr(p, ')'); if (q != NULL) { name = (char *)malloc(q - p + 1); if (name != NULL) { strncpy(name, p, q - p); name[q - p] = '\0'; ok = 1; } else { __pmNotifyErr(LOG_ERR, "windows_check_instance: Error: " "malloc[%d] failed for LDISK_INDOM path=%s\n", q - p + 1, path); return -1; } } } /* * expecting something like ...\LogicalDisk(C:)... * don't know what to do with this one! */ if (!ok) { __pmNotifyErr(LOG_ERR, "windows_check_instance: Error: " "unrecognized logical disk instance: %s\n", path); free(name); return -1; } break; /* * SQLServer instance domains all have similar syntax * * Examples: * \\TOWER\SQLServer:Locks(Table)\Average Wait Time (ms) * \\TOWER\SQLServer:Cache Manager(Cursors)\Cache Hit Ratio * \\TOWER\SQLServer:Databases(ACONEX_SYS)\Transactions/sec */ case SQL_LOCK_INDOM: case SQL_CACHE_INDOM: case SQL_DB_INDOM: case SQL_USER_INDOM: p = strchr(path, '('); // skip hostname and metric name if (p != NULL) { p++; if (strncmp(p, "_Total)", 7) == 0) { /* * The totals are done as independent metrics, * just skip them here */ return -1; } q = strchr(p, ')'); if (q != NULL) { name = (char *)malloc(q - p + 1); if (name != NULL) { strncpy(name, p, q - p); name[q - p] = '\0'; ok = 1; } else { __pmNotifyErr(LOG_ERR, "windows_check_instance: Error: " "malloc[%d] failed, SQL_INDOM path=%s\n", q - p + 1, path); return -1; } /* * The user counter names have many spaces and are * not unique up to the first space by any means. So, * replace ' 's to play by the PCP instance name rules. */ if (ip->serial == SQL_USER_INDOM) { for (p = name; *p; p++) if (*p == ' ') *p = '_'; } } } /* * expecting something like ... \SQLServer:...(...)\... * don't know what to do with this one! */ if (!ok) { __pmNotifyErr(LOG_ERR, "windows_check_instance: Error: " "unrecognized SQLServer instance: %s\n", path); free(name); return -1; } break; /* * Per-process and per-thread instance domain * * Examples: * \\TOWER\Process(svchost#6)\% Processor Time * \\TOWER\Thread(svchost/1#1)\% Processor Time * \\TOWER\Thread(Idle/0)\ID Process * \\TOWER\Thread(Idle/0)\ID Thread */ case PROCESS_INDOM: case THREAD_INDOM: p = strchr(path, '('); // skip hostname and Process/Thread if (p != NULL) { p++; if ((strncmp(p, "_Total)", 7) == 0) || (strncmp(p, "_Total/", 7) == 0)) { /* * The totals are done as independent metrics, * just skip them here */ return -1; } q = strchr(p, ')'); if (q != NULL) { name = (char *)malloc(q - p + 1); if (name != NULL) { strncpy(name, p, q - p); name[q - p] = '\0'; ok = 1; } else { __pmNotifyErr(LOG_ERR, "windows_check_instance: Error: " "malloc[%d] failed, process/thread path=%s\n", q - p + 1, path); return -1; } } } /* * expecting something like ... \Process(...)\... * don't know what to do with this one! */ if (!ok) { __pmNotifyErr(LOG_ERR, "windows_check_instance: Error: " "unrecognized process/thread name: %s\n", path); free(name); return -1; } break; default: __pmNotifyErr(LOG_ERR, "windows_check_instance: Error: " "pmInDom %s is unknown for metric %s\n", pmInDomStr(mp->desc.indom), pmIDStr(mp->desc.pmid)); return -1; } sts = pmdaCacheLookupName(mp->desc.indom, name, &ok, &sp); if (sts != PMDA_CACHE_ACTIVE) { if (sp != seen) /* new instance, never seen before, mark it */ windows_indom_reset[pmInDom_serial(mp->desc.indom)] = 1; ok = pmdaCacheStore(mp->desc.indom, PMDA_CACHE_ADD, name, seen); } free(name); return ok; } pcp-3.8.12ubuntu1/src/pmdas/windows/help0000664000000000000000000000546012272262501015047 0ustar # # Copyright (c) 2010 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Windows PMDA help file in the ASCII format. Only metrics which are # not using PDH regular expressions for extraction should be contained # here - the rest have their help text auto-generated by Windows PDH. # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ kernel.uname.release release level of the running kernel @ kernel.uname.version version level (build number) and build date of the running kernel @ kernel.uname.sysname name of the implementation of the operating system @ kernel.uname.machine name of the hardware type the system is running on @ kernel.uname.nodename host name of this node on the network @ kernel.uname.distro Windows distribution name The Windows distribution name, from the GetVersionEx Win32 API. @ network.interface.speed interface speed in megabytes per second The linespeed on the network interface, as reported by the kernel, scaled from Megabits/second to Megabytes/second. See also network.interface.baudrate for the bytes/second value. @ network.interface.baudrate interface speed in bytes per second The linespeed on the network interface, as reported by the kernel, scaled from bits/second and divided by 8 to convert to bytes/second. See also network.interface.speed for the Megabytes/second value. @ pmda.uname identity and type of current system Identity and type of current system. See also the kernel.uname.* metrics @ pmda.version build version of Windows PMDA @ hinv.physmem total system memory metric @ hinv.pagesize Memory page size The memory page size of the running kernel in bytes. @ hinv.ncpu number of CPUs in the system @ hinv.ndisk number of disks in the syste (excluding floppy drives) @ hinv.nfilesys number of (local) file systems currently mounted @ filesys.capacity Total capacity of mounted filesystem (Kbytes) @ filesys.used Total space used on mounted filesystem (Kbytes) @ filesys.free Total space free on mounted filesystem (Kbytes) pcp-3.8.12ubuntu1/src/pmdas/windows/pmns.mem0000664000000000000000000000225712272262501015652 0ustar mem { page_faults WINDOWS:0:27 available WINDOWS:0:28 committed_bytes WINDOWS:0:29 pool cache commit_limit WINDOWS:0:136 write_copies WINDOWS:0:137 transition_faults WINDOWS:0:138 demand_zero_faults WINDOWS:0:140 pages_total WINDOWS:0:141 page_reads WINDOWS:0:142 pages_output WINDOWS:0:143 page_writes WINDOWS:0:144 system physmem WINDOWS:1:0 freemem WINDOWS:1:1 util } mem.util { load WINDOWS:1:2 used WINDOWS:1:3 free WINDOWS:1:4 } swap { length WINDOWS:1:5 used WINDOWS:1:6 free WINDOWS:1:7 } mem.pool { paged_bytes WINDOWS:0:30 non_paged_bytes WINDOWS:0:31 paged_allocs WINDOWS:0:145 nonpaged_allocs WINDOWS:0:146 paged_resident_bytes WINDOWS:0:150 } mem.cache { read_ahead WINDOWS:0:35 lazy_writes WINDOWS:0:32 lazy_write_pages WINDOWS:0:33 mdl faults WINDOWS:0:139 bytes WINDOWS:0:148 bytes_peak WINDOWS:0:149 } mem.cache.mdl { read WINDOWS:0:34 sync_read WINDOWS:0:36 async_read WINDOWS:0:37 } mem.system { free_ptes WINDOWS:0:147 total_code_bytes WINDOWS:0:151 resident_code_bytes WINDOWS:0:152 } pcp-3.8.12ubuntu1/src/pmdas/pmcd/0000775000000000000000000000000012272262620013422 5ustar pcp-3.8.12ubuntu1/src/pmdas/pmcd/src/0000775000000000000000000000000012272262620014211 5ustar pcp-3.8.12ubuntu1/src/pmdas/pmcd/src/GNUmakefile0000664000000000000000000000320412272262501016260 0ustar # # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../../.. include $(TOPDIR)/src/include/builddefs LIBTARGET = pmda_pmcd.$(DSOSUFFIX) PMDAINIT = pmcd_init CFILES = pmcd.c LSRCFILES = objstyle VERSION_SCRIPT = exports LDIRT = $(VERSION_SCRIPT) # Add to CFLAGS to find files in pmcd/src... LCFLAGS = -I$(TOPDIR)/src LCFLAGS += -I$(TOPDIR)/src/pmie/src ifneq (, $(filter linux kfreebsd, $(TARGET_OS))) ABI = $(shell ./objstyle) LCFLAGS += -DSIM_ABI=\""$(ABI)"\" endif ifeq "$(TARGET_OS)" "darwin" ABI = $(shell ./objstyle) LCFLAGS += -DSIM_ABI=\"$(ABI)\" endif ifdef PACKAGE_BUILD BUILD = $(PACKAGE_BUILD) else BUILD = unknown endif LCFLAGS += -DBUILD=\"$(BUILD)\" LCFLAGS += $(INVISIBILITY) LLDLIBS = $(PCP_PMDALIB) ifeq "$(TARGET_OS)" "mingw" LLDLIBS += -lpcp_pmcd PCPLIB_LDFLAGS += -L$(TOPDIR)/src/libpcp_pmcd/src endif default: $(LIBTARGET) install: default $(INSTALL) -m 755 -d $(PCP_PMDAS_DIR)/pmcd $(INSTALL) -m 755 $(LIBTARGET) $(PCP_PMDAS_DIR)/pmcd/$(LIBTARGET) include $(BUILDRULES) default_pcp : default install_pcp : install $(LIBTARGET): $(VERSION_SCRIPT) $(VERSION_SCRIPT): $(VERSION_SCRIPT_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/pmcd/src/pmcd.c0000664000000000000000000014447512272262501015315 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1995-2001,2003,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "stats.h" #include "pmcd/src/pmcd.h" #include "pmcd/src/client.h" #include #if defined(IS_SOLARIS) #include #endif /* * Note: strange numbering for pmcd.pdu_{in,out}.total for * compatibility with earlier PCP versions ... this is the "item" * field of the PMID */ #define _TOTAL 16 /* * all metrics supported in this PMD - one table entry for each */ static pmDesc desctab[] = { /* control.debug */ { PMDA_PMID(0,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* datasize */ { PMDA_PMID(0,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) }, /* numagents */ { PMDA_PMID(0,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* numclients */ { PMDA_PMID(0,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* control.timeout */ { PMDA_PMID(0,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* timezone -- local $TZ -- for pmlogger */ { PMDA_PMID(0,5), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* simabi -- Subprogram Interface Model, ABI version of this pmcd (normally PM_TYPE_STRING) */ { PMDA_PMID(0,6), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* version -- pcp version */ { PMDA_PMID(0,7), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* control.register -- bulletin board */ { PMDA_PMID(0,8), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* control.traceconn -- trace connections */ { PMDA_PMID(0,9), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* control.tracepdu -- trace PDU traffic */ { PMDA_PMID(0,10), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* control.tracebufs -- number of trace buffers */ { PMDA_PMID(0,11), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* control.dumptrace -- push-button, pmStore to dump trace */ { PMDA_PMID(0,12), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* control.dumpconn -- push-button, pmStore to dump connections */ { PMDA_PMID(0,13), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* control.tracenobuf -- unbuffered tracing */ { PMDA_PMID(0,14), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* control.sighup -- push-button, pmStore to SIGHUP pmcd */ { PMDA_PMID(0,15), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* license -- bit-vector of license capabilities -- removed PMDA_PMID(0,16) */ /* openfds -- number of open file descriptors */ { PMDA_PMID(0,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* buf.alloc */ { PMDA_PMID(0,18), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* buf.free */ { PMDA_PMID(0,19), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* build -- pcp build number */ { PMDA_PMID(0,20), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* hostname -- local hostname -- for pmlogger */ { PMDA_PMID(0,21), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pdu_in.error */ { PMDA_PMID(1,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.result */ { PMDA_PMID(1,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.profile */ { PMDA_PMID(1,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.fetch */ { PMDA_PMID(1,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.desc_req */ { PMDA_PMID(1,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.desc */ { PMDA_PMID(1,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.instance_req */ { PMDA_PMID(1,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.instance */ { PMDA_PMID(1,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.text_req */ { PMDA_PMID(1,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.text */ { PMDA_PMID(1,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.control_req */ { PMDA_PMID(1,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.creds */ { PMDA_PMID(1,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.pmns_ids */ { PMDA_PMID(1,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.pmns_names */ { PMDA_PMID(1,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.pmns_child */ { PMDA_PMID(1,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.total */ { PMDA_PMID(1,_TOTAL), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.pmns_traverse */ { PMDA_PMID(1,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_in.auth */ { PMDA_PMID(1,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.error */ { PMDA_PMID(2,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.result */ { PMDA_PMID(2,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.profile */ { PMDA_PMID(2,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.fetch */ { PMDA_PMID(2,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.desc_req */ { PMDA_PMID(2,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.desc */ { PMDA_PMID(2,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.instance_req */ { PMDA_PMID(2,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.instance */ { PMDA_PMID(2,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.text_req */ { PMDA_PMID(2,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.text */ { PMDA_PMID(2,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.control_req */ { PMDA_PMID(2,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.creds */ { PMDA_PMID(2,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.pmns_ids */ { PMDA_PMID(2,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.pmns_names */ { PMDA_PMID(2,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.pmns_child */ { PMDA_PMID(2,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.total */ { PMDA_PMID(2,_TOTAL), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.pmns_traverse */ { PMDA_PMID(2,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pdu_out.auth */ { PMDA_PMID(2,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pmlogger.port */ { PMDA_PMID(3,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmlogger.pmcd_host */ { PMDA_PMID(3,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmlogger.archive */ { PMDA_PMID(3,2), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmlogger.host */ { PMDA_PMID(3,3), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* agent.type */ { PMDA_PMID(4,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* agent.status */ { PMDA_PMID(4,1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmie.configfile */ { PMDA_PMID(5,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmie.logfile */ { PMDA_PMID(5,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmie.pmcd_host */ { PMDA_PMID(5,2), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmie.numrules */ { PMDA_PMID(5,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmie.actions */ { PMDA_PMID(5,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pmie.eval.true */ { PMDA_PMID(5,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pmie.eval.false */ { PMDA_PMID(5,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pmie.eval.unknown */ { PMDA_PMID(5,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* pmie.eval.expected */ { PMDA_PMID(5,8), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE) }, /* pmie.eval.actual */ { PMDA_PMID(5,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, /* client.whoami */ { PMDA_PMID(6,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* client.start_date */ { PMDA_PMID(6,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmcd.cputime.total */ { PMDA_PMID(7,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0) }, /* pmcd.cputime.per_pdu_in */ { PMDA_PMID(7,1), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,-1,0,PM_TIME_USEC,PM_COUNT_ONE) }, /* pmcd.feature.secure */ { PMDA_PMID(8,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmcd.feature.compress */ { PMDA_PMID(8,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmcd.feature.ipv6 */ { PMDA_PMID(8,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmcd.feature.authentication */ { PMDA_PMID(8,3), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmcd.feature.creds_required */ { PMDA_PMID(8,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmcd.feature.unix_domain_sockets */ { PMDA_PMID(8,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* pmcd.feature.service_discovery */ { PMDA_PMID(8,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, /* End-of-List */ { PM_ID_NULL, 0, 0, 0, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) } }; static int ndesc = sizeof(desctab)/sizeof(desctab[0]); static __pmProfile *_profile; /* last received profile */ /* there are four instance domains: pmlogger, register, PMDA, and pmie */ #define INDOM_PMLOGGERS 1 static pmInDom logindom; #define INDOM_REGISTER 2 static pmInDom regindom; #define INDOM_PMDAS 3 static pmInDom pmdaindom; #define INDOM_PMIES 4 static pmInDom pmieindom; #define INDOM_POOL 5 static pmInDom bufindom; #define INDOM_CLIENT 6 static pmInDom clientindom; #define NUMREG 16 static int reg[NUMREG]; typedef struct { pid_t pid; int size; char *name; void *mmap; } pmie_t; static pmie_t *pmies; static unsigned int npmies; static struct { int inst; char *iname; } bufinst[] = { { 12, "0012" }, { 20, "0020" }, { 1024, "1024" }, { 2048, "2048" }, { 4196, "4196" }, { 8192, "8192" }, { 8193, "8192+" }, }; static int nbufsz = sizeof(bufinst) / sizeof(bufinst[0]); typedef struct { int id; /* index into client[] */ int seq; char *value; } whoami_t; static whoami_t *whoamis; static unsigned int nwhoamis; typedef struct { int state; double last_cputime; __uint64_t last_pdu_in; } perctx_t; /* values for per context state */ #define CTX_INACTIVE 0 #define CTX_ACTIVE 1 static perctx_t *ctxtab = NULL; static int num_ctx = 0; /* * expand and initialize the per client context table */ static void grow_ctxtab(int ctx) { ctxtab = (perctx_t *)realloc(ctxtab, (ctx+1)*sizeof(ctxtab[0])); if (ctxtab == NULL) { __pmNoMem("grow_ctxtab", (ctx+1)*sizeof(ctxtab[0]), PM_FATAL_ERR); /*NOTREACHED*/ } while (num_ctx <= ctx) { ctxtab[num_ctx].state = CTX_INACTIVE; num_ctx++; } ctxtab[ctx].state = CTX_INACTIVE; } /* * this routine is called at initialization to patch up any parts of the * desctab that cannot be statically initialized, and to optionally * modify our Performance Metrics Domain Id (dom) */ static void init_tables(int dom) { int i; __pmID_int *pmidp; __pmInDom_int *indomp; /* set domain in instance domain correctly */ indomp = (__pmInDom_int *)&logindom; indomp->flag = 0; indomp->domain = dom; indomp->serial = INDOM_PMLOGGERS; indomp = (__pmInDom_int *)®indom; indomp->flag = 0; indomp->domain = dom; indomp->serial = INDOM_REGISTER; indomp = (__pmInDom_int *)&pmdaindom; indomp->flag = 0; indomp->domain = dom; indomp->serial = INDOM_PMDAS; indomp = (__pmInDom_int *)&pmieindom; indomp->flag = 0; indomp->domain = dom; indomp->serial = INDOM_PMIES; indomp = (__pmInDom_int *)&bufindom; indomp->flag = 0; indomp->domain = dom; indomp->serial = INDOM_POOL; indomp = (__pmInDom_int *)&clientindom; indomp->flag = 0; indomp->domain = dom; indomp->serial = INDOM_CLIENT; /* merge performance domain id part into PMIDs in pmDesc table */ for (i = 0; desctab[i].pmid != PM_ID_NULL; i++) { pmidp = (__pmID_int *)&desctab[i].pmid; pmidp->domain = dom; if (pmidp->cluster == 0 && pmidp->item == 8) desctab[i].indom = regindom; else if (pmidp->cluster == 0 && (pmidp->item == 18 || pmidp->item == 19)) desctab[i].indom = bufindom; else if (pmidp->cluster == 3) desctab[i].indom = logindom; else if (pmidp->cluster == 4) desctab[i].indom = pmdaindom; else if (pmidp->cluster == 5) desctab[i].indom = pmieindom; else if (pmidp->cluster == 6) desctab[i].indom = clientindom; } ndesc--; } static int pmcd_profile(__pmProfile *prof, pmdaExt *pmda) { _profile = prof; return 0; } static void remove_pmie_indom(void) { int n; for (n = 0; n < npmies; n++) { free(pmies[n].name); __pmMemoryUnmap(pmies[n].mmap, pmies[n].size); } free(pmies); pmies = NULL; npmies = 0; } /* use a static timestamp, stat PMIE_SUBDIR, if changed update "pmies" */ static unsigned int refresh_pmie_indom(void) { static struct stat lastsbuf; pid_t pmiepid; struct dirent *dp; struct stat statbuf; size_t size; char *endp; char fullpath[MAXPATHLEN]; void *ptr; DIR *pmiedir; int fd; int sep = __pmPathSeparator(); snprintf(fullpath, sizeof(fullpath), "%s%c%s", pmGetConfig("PCP_TMP_DIR"), sep, PMIE_SUBDIR); if (stat(fullpath, &statbuf) == 0) { #if defined(HAVE_ST_MTIME_WITH_E) && defined(HAVE_STAT_TIME_T) if (statbuf.st_mtime != lastsbuf.st_mtime) #elif defined(HAVE_ST_MTIME_WITH_SPEC) if ((statbuf.st_mtimespec.tv_sec != lastsbuf.st_mtimespec.tv_sec) || (statbuf.st_mtimespec.tv_nsec != lastsbuf.st_mtimespec.tv_nsec)) #elif defined(HAVE_STAT_TIMESTRUC) || defined(HAVE_STAT_TIMESPEC) || defined(HAVE_STAT_TIMESPEC_T) if ((statbuf.st_mtim.tv_sec != lastsbuf.st_mtim.tv_sec) || (statbuf.st_mtim.tv_nsec != lastsbuf.st_mtim.tv_nsec)) #else !bozo! #endif { lastsbuf = statbuf; /* tear down the old instance domain */ if (pmies) remove_pmie_indom(); /* open the directory iterate through mmaping as we go */ if ((pmiedir = opendir(fullpath)) == NULL) { __pmNotifyErr(LOG_ERR, "pmcd pmda cannot open %s: %s", fullpath, osstrerror()); return 0; } /* NOTE: all valid files are already mmapped by pmie */ while ((dp = readdir(pmiedir)) != NULL) { size = (npmies+1) * sizeof(pmie_t); pmiepid = (pid_t)strtoul(dp->d_name, &endp, 10); if (*endp != '\0') /* skips over "." and ".." here */ continue; if (!__pmProcessExists(pmiepid)) continue; snprintf(fullpath, sizeof(fullpath), "%s%c%s%c%s", pmGetConfig("PCP_TMP_DIR"), sep, PMIE_SUBDIR, sep, dp->d_name); if (stat(fullpath, &statbuf) < 0) { __pmNotifyErr(LOG_WARNING, "pmcd pmda cannot stat %s: %s", fullpath, osstrerror()); continue; } if (statbuf.st_size != sizeof(pmiestats_t)) continue; if ((endp = strdup(dp->d_name)) == NULL) { __pmNoMem("pmie iname", strlen(dp->d_name), PM_RECOV_ERR); continue; } if ((pmies = (pmie_t *)realloc(pmies, size)) == NULL) { __pmNoMem("pmie instlist", size, PM_RECOV_ERR); free(endp); continue; } if ((fd = open(fullpath, O_RDONLY)) < 0) { __pmNotifyErr(LOG_WARNING, "pmcd pmda cannot open %s: %s", fullpath, osstrerror()); free(endp); continue; } ptr = __pmMemoryMap(fd, statbuf.st_size, 0); close(fd); if (ptr == NULL) { __pmNotifyErr(LOG_ERR, "pmcd pmda memmap of %s failed: %s", fullpath, osstrerror()); free(endp); continue; } else if (((pmiestats_t *)ptr)->version != 1) { __pmNotifyErr(LOG_WARNING, "incompatible pmie version: %s", fullpath); __pmMemoryUnmap(ptr, statbuf.st_size); free(endp); continue; } pmies[npmies].pid = pmiepid; pmies[npmies].name = endp; pmies[npmies].size = statbuf.st_size; pmies[npmies].mmap = ptr; npmies++; } closedir(pmiedir); } } else { remove_pmie_indom(); } setoserror(0); return npmies; } static int pmcd_instance_reg(int inst, char *name, __pmInResult **result) { __pmInResult *res; int i; char idx[3]; /* ok for NUMREG <= 99 */ res = (__pmInResult *)malloc(sizeof(__pmInResult)); if (res == NULL) return -oserror(); if (name == NULL && inst == PM_IN_NULL) res->numinst = NUMREG; else res->numinst = 1; if (inst == PM_IN_NULL) { if ((res->instlist = (int *)malloc(res->numinst * sizeof(res->instlist[0]))) == NULL) { free(res); return -oserror(); } } else res->instlist = NULL; if (name == NULL) { if ((res->namelist = (char **)malloc(res->numinst * sizeof(res->namelist[0]))) == NULL) { __pmFreeInResult(res); return -oserror(); } for (i = 0; i < res->numinst; i++) res->namelist[0] = NULL; } else res->namelist = NULL; if (name == NULL && inst == PM_IN_NULL) { /* return inst and name for everything */ for (i = 0; i < res->numinst; i++) { res->instlist[i] = i; snprintf(idx, sizeof(idx), "%d", i); if ((res->namelist[i] = strdup(idx)) == NULL) { __pmFreeInResult(res); return -oserror(); } } } else if (name == NULL) { /* given an inst, return the name */ if (0 <= inst && inst < NUMREG) { snprintf(idx, sizeof(idx), "%d", inst); if ((res->namelist[0] = strdup(idx)) == NULL) { __pmFreeInResult(res); return -oserror(); } } else { __pmFreeInResult(res); return PM_ERR_INST; } } else if (inst == PM_IN_NULL) { /* given a name, return an inst */ char *endp; i = (int)strtol(name, &endp, 10); if (*endp == '\0' && 0 <= i && i < NUMREG) res->instlist[0] = i; else { __pmFreeInResult(res); return PM_ERR_INST; } } *result = res; return 0; } static int pmcd_instance_pool(int inst, char *name, __pmInResult **result) { __pmInResult *res; int i; res = (__pmInResult *)malloc(sizeof(__pmInResult)); if (res == NULL) return -oserror(); if (name == NULL && inst == PM_IN_NULL) res->numinst = nbufsz; else res->numinst = 1; if (inst == PM_IN_NULL) { if ((res->instlist = (int *)malloc(res->numinst * sizeof(res->instlist[0]))) == NULL) { free(res); return -oserror(); } } else res->instlist = NULL; if (name == NULL) { if ((res->namelist = (char **)malloc(res->numinst * sizeof(res->namelist[0]))) == NULL) { __pmFreeInResult(res); return -oserror(); } for (i = 0; i < res->numinst; i++) res->namelist[0] = NULL; } else res->namelist = NULL; if (name == NULL && inst == PM_IN_NULL) { /* return inst and name for everything */ for (i = 0; i < nbufsz; i++) { res->instlist[i] = bufinst[i].inst; if ((res->namelist[i] = strdup(bufinst[i].iname)) == NULL) { __pmFreeInResult(res); return -oserror(); } } } else if (name == NULL) { /* given an inst, return the name */ for (i = 0; i < nbufsz; i++) { if (inst == bufinst[i].inst) { if ((res->namelist[0] = strdup(bufinst[i].iname)) == NULL) { __pmFreeInResult(res); return -oserror(); } break; } } if (i == nbufsz) { __pmFreeInResult(res); return PM_ERR_INST; } } else if (inst == PM_IN_NULL) { /* given a name, return an inst */ for (i = 0; i < nbufsz; i++) { if (strcmp(name, bufinst[i].iname) == 0) { res->instlist[0] = bufinst[i].inst; break; } } if (i == nbufsz) { __pmFreeInResult(res); return PM_ERR_INST; } } *result = res; return 0; } static int pmcd_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) { int sts = 0; __pmInResult *res; int getall = 0; int getname = 0; /* initialize to pander to gcc */ int nports = 0; /* initialize to pander to gcc */ __pmLogPort *ports; unsigned int pmiecount = 0; /* initialize to pander to gcc */ int i; if (indom == regindom) return pmcd_instance_reg(inst, name, result); else if (indom == bufindom) return pmcd_instance_pool(inst, name, result); else if (indom == logindom || indom == pmdaindom || indom == pmieindom || indom == clientindom) { res = (__pmInResult *)malloc(sizeof(__pmInResult)); if (res == NULL) return -oserror(); res->instlist = NULL; res->namelist = NULL; if (indom == logindom) { /* use the wildcard behaviour of __pmLogFindPort to find * all pmlogger ports on localhost. Note that * __pmLogFindPort will not attempt to contact pmcd if * localhost is specified---this means we don't get a * recursive call to pmcd which would hang! */ if ((nports = __pmLogFindPort("localhost", PM_LOG_ALL_PIDS, &ports)) < 0) { free(res); return nports; } } else if (indom == pmieindom) pmiecount = refresh_pmie_indom(); if (name == NULL && inst == PM_IN_NULL) { getall = 1; if (indom == logindom) res->numinst = nports; else if (indom == pmdaindom) res->numinst = nAgents; else if (indom == pmieindom) res->numinst = pmiecount; else if (indom == clientindom) { res->numinst = 0; for (i = 0; i < nClients; i++) { if (client[i].status.connected) res->numinst++; } } } else { getname = name == NULL; res->numinst = 1; } if (getall || !getname) { if ((res->instlist = (int *)malloc(res->numinst * sizeof(int))) == NULL) { sts = -oserror(); __pmNoMem("pmcd_instance instlist", res->numinst * sizeof(int), PM_RECOV_ERR); __pmFreeInResult(res); return sts; } } if (getall || getname) { if ((res->namelist = (char **)malloc(res->numinst * sizeof(char *))) == NULL) { sts = -oserror(); __pmNoMem("pmcd_instance namelist", res->numinst * sizeof(char *), PM_RECOV_ERR); free(res->instlist); __pmFreeInResult(res); return sts; } } } else return PM_ERR_INDOM; if (indom == logindom) { res->indom = logindom; if (getall) { /* get instance ids and names */ for (i = 0; i < nports; i++) { res->instlist[i] = ports[i].pid; res->namelist[i] = strdup(ports[i].name); if (res->namelist[i] == NULL) { sts = -oserror(); __pmNoMem("pmcd_instance pmGetInDom", strlen(ports[i].name), PM_RECOV_ERR); /* ensure pmFreeInResult only gets valid pointers */ res->numinst = i; break; } } } else if (getname) { /* given id, get name */ for (i = 0; i < nports; i++) { if (inst == ports[i].pid) break; } if (i == nports) { sts = PM_ERR_INST; res->namelist[0] = NULL; } else { res->namelist[0] = strdup(ports[i].name); if (res->namelist[0] == NULL) { __pmNoMem("pmcd_instance pmNameInDom", strlen(ports[i].name), PM_RECOV_ERR); sts = -oserror(); } } } else { /* given name, get id */ for (i = 0; i < nports; i++) { if (strcmp(name, ports[i].name) == 0) break; } if (i == nports) sts = PM_ERR_INST; else res->instlist[0] = ports[i].pid; } } else if (indom == pmieindom) { res->indom = pmieindom; if (getall) { /* get instance ids and names */ for (i = 0; i < pmiecount; i++) { res->instlist[i] = pmies[i].pid; res->namelist[i] = strdup(pmies[i].name); if (res->namelist[i] == NULL) { sts = -oserror(); __pmNoMem("pmie_instance pmGetInDom", strlen(pmies[i].name), PM_RECOV_ERR); /* ensure pmFreeInResult only gets valid pointers */ res->numinst = i; break; } } } else if (getname) { /* given id, get name */ for (i = 0; i < pmiecount; i++) { if (inst == pmies[i].pid) break; } if (i == pmiecount) { sts = PM_ERR_INST; res->namelist[0] = NULL; } else { res->namelist[0] = strdup(pmies[i].name); if (res->namelist[0] == NULL) { sts = -oserror(); __pmNoMem("pmcd_instance pmNameInDom", strlen(pmies[i].name), PM_RECOV_ERR); } } } else { /* given name, get id */ for (i = 0; i < pmiecount; i++) { if (strcmp(name, pmies[i].name) == 0) break; } if (i == pmiecount) sts = PM_ERR_INST; else res->instlist[0] = pmies[i].pid; } } else if (indom == pmdaindom) { res->indom = pmdaindom; if (getall) { /* get instance ids and names */ for (i = 0; i < nAgents; i++) { res->instlist[i] = agent[i].pmDomainId; res->namelist[i] = strdup(agent[i].pmDomainLabel); if (res->namelist[i] == NULL) { sts = -oserror(); __pmNoMem("pmcd_instance pmGetInDom", strlen(agent[i].pmDomainLabel), PM_RECOV_ERR); /* ensure pmFreeInResult only gets valid pointers */ res->numinst = i; break; } } } else if (getname) { /* given id, get name */ for (i = 0; i < nAgents; i++) { if (inst == agent[i].pmDomainId) break; } if (i == nAgents) { sts = PM_ERR_INST; res->namelist[0] = NULL; } else { res->namelist[0] = strdup(agent[i].pmDomainLabel); if (res->namelist[0] == NULL) { sts = -oserror(); __pmNoMem("pmcd_instance pmNameInDom", strlen(agent[i].pmDomainLabel), PM_RECOV_ERR); } } } else { /* given name, get id */ for (i = 0; i < nAgents; i++) { if (strcmp(name, agent[i].pmDomainLabel) == 0) break; } if (i == nAgents) sts = PM_ERR_INST; else res->instlist[0] = agent[i].pmDomainId; } } else if (indom == clientindom) { res->indom = clientindom; if (getall) { /* get instance ids and names */ int k = 0; for (i = 0; i < nClients; i++) { char buf[11]; /* enough for 32-bit client seq number */ if (!client[i].status.connected) continue; res->instlist[k] = client[i].seq; snprintf(buf, sizeof(buf), "%u", client[i].seq); res->namelist[k] = strdup(buf); if (res->namelist[k] == NULL) { sts = -oserror(); __pmNoMem("pmcd_instance pmGetInDom", strlen(buf), PM_RECOV_ERR); /* ensure pmFreeInResult only gets valid pointers */ res->numinst = i; break; } k++; } } else if (getname) { /* given id, get name */ for (i = 0; i < nClients; i++) { if (client[i].status.connected && inst == client[i].seq) break; } if (i == nClients) { sts = PM_ERR_INST; res->namelist[0] = NULL; } else { char buf[11]; /* enough for 32-bit client seq number */ snprintf(buf, sizeof(buf), "%u", (unsigned int)inst); res->namelist[0] = strdup(buf); if (res->namelist[0] == NULL) { sts = -oserror(); __pmNoMem("pmcd_instance pmNameInDom", strlen(buf), PM_RECOV_ERR); } } } else { /* given name, get id */ char buf[11]; /* enough for 32-bit client seq number */ for (i = 0; i < nClients; i++) { if (!client[i].status.connected) continue; snprintf(buf, sizeof(buf), "%u", client[i].seq); if (strcmp(name, buf) == 0) break; } if (i == nClients) sts = PM_ERR_INST; else res->instlist[0] = client[i].seq; } } if (sts < 0) { __pmFreeInResult(res); return sts; } *result = res; return 0; } /* * numval != 1, so re-do vset[i] allocation */ static int vset_resize(pmResult *rp, int i, int onumval, int numval) { int expect = numval; if (rp->vset[i] != NULL) { free(rp->vset[i]); } if (numval < 0) expect = 0; rp->vset[i] = (pmValueSet *)malloc(sizeof(pmValueSet) + (expect-1)*sizeof(pmValue)); if (rp->vset[i] == NULL) { if (i) { /* we're doomed ... reclaim pmValues 0, 1, ... i-1 */ rp->numpmid = i; __pmFreeResultValues(rp); } return -1; } rp->vset[i]->numval = numval; return 0; } static char * simabi() { #if defined(__linux__) # if defined(__i386__) return "ia32"; # elif defined(__ia64__) || defined(__ia64) return "ia64"; # else return SIM_ABI; /* SIM_ABI is defined in the linux Makefile */ # endif /* __linux__ */ #elif defined(IS_SOLARIS) static char abi[32]; if (sysinfo(SI_ARCHITECTURE_NATIVE, abi, sizeof(abi)) < 0) { return "unknown"; } else { return abi; } #elif defined(IS_FREEBSD) || defined(IS_NETBSD) return "elf"; #elif defined(IS_DARWIN) return "Mach-O " SIM_ABI; #elif defined(IS_MINGW) return "i386"; // TODO: need to handle x86_64 too #elif defined(IS_AIX) return "powerpc"; #else !!! bozo : dont know which executable format pmcd should be!!! #endif } static char * tzinfo(void) { /* * __pmTimezone() caches its result in $TZ - pmcd is long running, * however, and we *really* want to see changes in the timezone or * daylight savings state via pmcd.timezone, so we clear TZ first. */ #ifdef HAVE_UNSETENV unsetenv("TZ"); #else /* MINGW */ putenv("TZ="); #endif return __pmTimezone(); } static char * hostnameinfo(void) { static char host[MAXHOSTNAMELEN]; char *name; (void)gethostname(host, MAXHOSTNAMELEN); name = host; return name; } static int fetch_feature(int item, pmAtomValue *avp) { if (item < 0 || item >= PM_SERVER_FEATURES) return PM_ERR_PMID; avp->ul = __pmServerHasFeature((__pmServerFeature)item); return 0; } static int fetch_cputime(int item, int ctx, pmAtomValue *avp) { double usr, sys; double cputime; if (item < 0 || item > 1) { return PM_ERR_PMID; } if (ctx < 0) { /* should not happen */ return PM_ERR_NOTCONN; } __pmProcessRunTimes(&usr, &sys); cputime = (usr+sys)*1000; if (ctx >= num_ctx) grow_ctxtab(ctx); if (item == 0) { /* pmcd.cputime.total */ avp->ull = (__uint64_t)cputime; } else if (item == 1) { /* pmcd.cputime.per_pdu_in */ int j; int pdu_in; for (pdu_in = j = 0; j <= PDU_MAX; j++) pdu_in += __pmPDUCntIn[j]; if (ctxtab[ctx].state == CTX_INACTIVE) { /* first call for this context */ ctxtab[ctx].state = CTX_ACTIVE; avp->d = cputime*1000/pdu_in; } else { if (pdu_in > ctxtab[ctx].last_pdu_in) avp->d = 1000*(cputime-ctxtab[ctx].last_cputime)/(pdu_in-ctxtab[ctx].last_pdu_in); else { /* should not happen, as you need another pdu to get here */ avp->d = 0; } } ctxtab[ctx].last_cputime = cputime; ctxtab[ctx].last_pdu_in = pdu_in; } return 0; } static void end_context(int ctx) { if (ctx >= 0 && ctx < num_ctx && ctxtab[ctx].state == CTX_ACTIVE) { ctxtab[ctx].state = CTX_INACTIVE; } } static int pmcd_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i; /* over pmidlist[] */ int j; int sts, nports; int need; int numval; int valfmt; unsigned long datasize; static pmResult *res = NULL; static int maxnpmids = 0; char *host = NULL; /* refresh max once per fetch */ pmiestats_t *pmie; pmValueSet *vset; pmDesc *dp = NULL; /* initialize to pander to gcc */ __pmID_int *pmidp; pmAtomValue atom; __pmLogPort *lpp; if (numpmid > maxnpmids) { if (res != NULL) free(res); /* (numpmid - 1) because there's room for one valueSet in a pmResult */ need = (int)sizeof(pmResult) + (numpmid - 1) * (int)sizeof(pmValueSet *); if ((res = (pmResult *) malloc(need)) == NULL) return -ENOMEM; maxnpmids = numpmid; } res->timestamp.tv_sec = 0; res->timestamp.tv_usec = 0; res->numpmid = numpmid; for (i = 0; i < numpmid; i++) { /* Allocate a pmValueSet with room for just one value. Even for the * pmlogger port metric which has an instance domain, most of the time * there will only be one logger running (i.e. one instance). For the * infrequent cases resize the value set later. */ res->vset[i] = NULL; if (vset_resize(res, i, 0, 1) == -1) return -ENOMEM; vset = res->vset[i]; vset->pmid = pmidlist[i]; vset->vlist[0].inst = PM_IN_NULL; for (j = 0; j < ndesc; j++) { if (desctab[j].pmid == pmidlist[i]) { dp = &desctab[j]; break; } } if (j == ndesc) { /* Error, need a smaller vset */ if (vset_resize(res, i, 1, PM_ERR_PMID) == -1) return -ENOMEM; res->vset[i]->pmid = pmidlist[i]; continue; } valfmt = -1; sts = 0; pmidp = (__pmID_int *)&pmidlist[i]; switch (pmidp->cluster) { case 0: /* global metrics */ switch (pmidp->item) { case 0: /* control.debug */ atom.l = pmDebug; break; case 1: /* datasize */ __pmProcessDataSize(&datasize); atom.ul = datasize; break; case 2: /* numagents */ atom.ul = 0; for (j = 0; j < nAgents; j++) if (agent[j].status.connected) atom.ul++; break; case 3: /* numclients */ atom.ul = 0; for (j = 0; j < nClients; j++) if (client[j].status.connected) atom.ul++; break; case 4: /* control.timeout */ atom.ul = _pmcd_timeout; break; case 5: /* timezone $TZ */ atom.cp = tzinfo(); break; case 6: /* simabi (pmcd calling convention) */ atom.cp = simabi(); break; case 7: /* version */ atom.cp = PCP_VERSION; break; case 8: /* register */ for (j = numval = 0; j < NUMREG; j++) { if (__pmInProfile(regindom, _profile, j)) numval++; } if (numval != 1) { /* need a different vset size */ if (vset_resize(res, i, 1, numval) == -1) return -ENOMEM; vset = res->vset[i]; vset->pmid = pmidlist[i]; } for (j = numval = 0; j < NUMREG; j++) { if (!__pmInProfile(regindom, _profile, j)) continue; vset->vlist[numval].inst = j; atom.l = reg[j]; sts = __pmStuffValue(&atom, &vset->vlist[numval], dp->type); if (sts < 0) break; valfmt = sts; numval++; } break; case 9: /* traceconn */ atom.l = (_pmcd_trace_mask & TR_MASK_CONN) ? 1 : 0; break; case 10: /* tracepdu */ atom.l = (_pmcd_trace_mask & TR_MASK_PDU) ? 1 : 0; break; case 11: /* tracebufs */ atom.l = _pmcd_trace_nbufs; break; case 12: /* dumptrace ... always 0 */ atom.l = 0; break; case 13: /* dumpconn ... always 0 */ atom.l = 0; break; case 14: /* tracenobuf */ atom.l = (_pmcd_trace_mask & TR_MASK_NOBUF) ? 1 : 0; break; case 15: /* sighup ... always 0 */ atom.l = 0; break; case 17: /* openfds */ atom.ul = (unsigned int)pmcd_hi_openfds; break; case 18: /* buf.alloc */ case 19: /* buf.free */ for (j = numval = 0; j < nbufsz; j++) { if (__pmInProfile(bufindom, _profile, bufinst[j].inst)) numval++; } if (numval != 1) { /* need a different vset size */ if (vset_resize(res, i, 1, numval) == -1) return -ENOMEM; vset = res->vset[i]; vset->pmid = pmidlist[i]; } for (j = numval = 0; j < nbufsz; j++) { int alloced; int free; int xtra_alloced; int xtra_free; if (!__pmInProfile(bufindom, _profile, bufinst[j].inst)) continue; vset->vlist[numval].inst = bufinst[j].inst; /* PDUBuf pool */ __pmCountPDUBuf(bufinst[j].inst, &alloced, &free); /* * the 2K buffer count also includes * the 3K, 4K, ... buffers, so sub * these ... which are reported as * the 3K buffer count */ __pmCountPDUBuf(bufinst[j].inst + 1024, &xtra_alloced, &xtra_free); alloced -= xtra_alloced; free -= xtra_free; if (pmidp->item == 18) atom.l = alloced; else atom.l = free; sts = __pmStuffValue(&atom, &vset->vlist[numval], dp->type); if (sts < 0) break; valfmt = sts; numval++; } break; case 20: /* build */ atom.cp = BUILD; break; case 21: /* hostname */ if (_pmcd_hostname) { atom.cp = _pmcd_hostname; } else { if (!host) host = hostnameinfo(); atom.cp = host; } break; default: sts = atom.l = PM_ERR_PMID; break; } break; case 1: /* PDUs received */ if (pmidp->item == _TOTAL) { /* total */ atom.ul = 0; for (j = 0; j <= PDU_MAX; j++) atom.ul += __pmPDUCntIn[j]; } else if (pmidp->item > PDU_MAX+1) sts = atom.l = PM_ERR_PMID; else if (pmidp->item < _TOTAL) atom.ul = __pmPDUCntIn[pmidp->item]; else atom.ul = __pmPDUCntIn[pmidp->item-1]; break; case 2: /* PDUs sent */ if (pmidp->item == _TOTAL) { /* total */ atom.ul = 0; for (j = 0; j <= PDU_MAX; j++) atom.ul += __pmPDUCntOut[j]; } else if (pmidp->item > PDU_MAX+1) sts = atom.l = PM_ERR_PMID; else if (pmidp->item < _TOTAL) atom.ul = __pmPDUCntOut[pmidp->item]; else atom.ul = __pmPDUCntOut[pmidp->item-1]; break; case 3: /* pmlogger control port, pmcd_host, archive and host */ /* find all ports. localhost => no recursive pmcd access */ nports = __pmLogFindPort("localhost", PM_LOG_ALL_PIDS, &lpp); if (nports < 0) { sts = nports; break; } for (j = numval = 0; j < nports; j++) { if (__pmInProfile(logindom, _profile, lpp[j].pid)) numval++; } if (numval != 1) { /* need a different vset size */ if (vset_resize(res, i, 1, numval) == -1) return -ENOMEM; vset = res->vset[i]; vset->pmid = pmidlist[i]; } for (j = numval = 0; j < nports; j++) { if (!__pmInProfile(logindom, _profile, lpp[j].pid)) continue; vset->vlist[numval].inst = lpp[j].pid; switch (pmidp->item) { case 0: /* pmlogger.port */ atom.ul = lpp[j].port; break; case 1: /* pmlogger.pmcd_host */ atom.cp = lpp[j].pmcd_host ? lpp[j].pmcd_host : ""; break; case 2: /* pmlogger.archive */ atom.cp = lpp[j].archive ? lpp[j].archive : ""; break; case 3: /* pmlogger.host */ if (!host) host = hostnameinfo(); atom.cp = host; break; default: sts = atom.l = PM_ERR_PMID; break; } if (sts >= 0) sts = __pmStuffValue(&atom, &vset->vlist[numval], dp->type); if (sts < 0) break; valfmt = sts; numval++; } break; case 4: /* PMDA metrics */ for (j = numval = 0; j < nAgents; j++) { if (__pmInProfile(pmdaindom, _profile, agent[j].pmDomainId)) numval++; } if (numval != 1) { /* need a different vset size */ if (vset_resize(res, i, 1, numval) == -1) return -ENOMEM; vset = res->vset[i]; vset->pmid = pmidlist[i]; } for (j = numval = 0; j < nAgents; j++) { if (!__pmInProfile(pmdaindom, _profile, agent[j].pmDomainId)) continue; vset->vlist[numval].inst = agent[j].pmDomainId; switch (pmidp->item) { case 0: /* agent.type */ atom.ul = agent[j].ipcType << 1; break; case 1: /* agent.status */ if (agent[j].status.notReady) atom.l = 1; else if (agent[j].status.connected) atom.l = 0; else atom.l = agent[j].reason; break; default: sts = atom.l = PM_ERR_PMID; break; } if (sts >= 0) sts = __pmStuffValue(&atom, &vset->vlist[numval], dp->type); if (sts < 0) break; valfmt = sts; numval++; } if (numval > 0) { pmResult sortme; sortme.numpmid = 1; sortme.vset[0] = vset; pmSortInstances(&sortme); } break; case 5: /* pmie metrics */ refresh_pmie_indom(); for (j = numval = 0; j < npmies; j++) { if (__pmInProfile(pmieindom, _profile, pmies[j].pid)) numval++; } if (numval != 1) { /* need a different vset size */ if (vset_resize(res, i, 1, numval) == -1) return -ENOMEM; vset = res->vset[i]; vset->pmid = pmidlist[i]; } for (j = numval = 0; j < npmies; ++j) { if (!__pmInProfile(pmieindom, _profile, pmies[j].pid)) continue; vset->vlist[numval].inst = pmies[j].pid; pmie = (pmiestats_t *)pmies[j].mmap; switch (pmidp->item) { case 0: /* pmie.configfile */ atom.cp = pmie->config; break; case 1: /* pmie.logfile */ atom.cp = pmie->logfile; break; case 2: /* pmie.pmcd_host */ atom.cp = pmie->defaultfqdn; break; case 3: /* pmie.numrules */ atom.ul = pmie->numrules; break; case 4: /* pmie.actions */ atom.ul = pmie->actions; break; case 5: /* pmie.eval.true */ atom.ul = pmie->eval_true; break; case 6: /* pmie.eval.false */ atom.ul = pmie->eval_false; break; case 7: /* pmie.eval.unknown */ atom.ul = pmie->eval_unknown; break; case 8: /* pmie.eval.expected */ atom.f = pmie->eval_expected; break; case 9: /* pmie.eval.actual */ atom.ul = pmie->eval_actual; break; default: sts = atom.l = PM_ERR_PMID; break; } if (sts >= 0) sts = __pmStuffValue(&atom, &vset->vlist[numval], dp->type); if (sts < 0) break; valfmt = sts; numval++; } if (numval > 0) { pmResult sortme; sortme.numpmid = 1; sortme.vset[0] = vset; pmSortInstances(&sortme); } break; case 6: /* client metrics */ for (j = numval = 0; j < nClients; j++) { if (!client[j].status.connected) continue; if (__pmInProfile(clientindom, _profile, client[j].seq)) numval++; } if (numval != 1) { /* need a different vset size */ if (vset_resize(res, i, 1, numval) == -1) return -ENOMEM; vset = res->vset[i]; vset->pmid = pmidlist[i]; } for (j = numval = 0; j < nClients; ++j) { int k; char ctim[sizeof("Thu Nov 24 18:22:48 1986\n")]; if (!client[j].status.connected) continue; if (!__pmInProfile(clientindom, _profile, client[j].seq)) continue; vset->vlist[numval].inst = client[j].seq; switch (pmidp->item) { case 0: /* client.whoami */ for (k = 0; k < nwhoamis; k++) { if (whoamis[k].seq == client[j].seq) { atom.cp = whoamis[k].value; break; } } if (k == nwhoamis) /* no id registered, so no value */ atom.cp = ""; break; case 1: /* client.start_date */ atom.cp = strcpy(ctim, ctime(&client[j].start)); /* trim trailing \n */ k = strlen(atom.cp); atom.cp[k-1] = '\0'; break; default: sts = atom.l = PM_ERR_PMID; break; } if (sts >= 0) sts = __pmStuffValue(&atom, &vset->vlist[numval], dp->type); if (sts < 0) break; valfmt = sts; numval++; } if (numval > 0) { pmResult sortme; sortme.numpmid = 1; sortme.vset[0] = vset; pmSortInstances(&sortme); } break; case 7: /* cputime metrics */ sts = fetch_cputime(pmidp->item, pmda->e_context, &atom); break; case 8: /* feature metrics */ sts = fetch_feature(pmidp->item, &atom); break; } if (sts == 0 && valfmt == -1 && vset->numval == 1) sts = valfmt = __pmStuffValue(&atom, &vset->vlist[0], dp->type); if (sts < 0) { /* failure, encode status in numval, need a different vset size */ if (vset_resize(res, i, vset->numval, sts) == -1) return -ENOMEM; } else vset->valfmt = valfmt; } *resp = res; return 0; } static int pmcd_desc(pmID pmid, pmDesc *desc, pmdaExt *pmda) { int i; for (i = 0; i < ndesc; i++) { if (desctab[i].pmid == pmid) { *desc = desctab[i]; return 0; } } return PM_ERR_PMID; } static int pmcd_store(pmResult *result, pmdaExt *pmda) { int i; pmValueSet *vsp; int sts = 0; __pmID_int *pmidp; for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; pmidp = (__pmID_int *)&vsp->pmid; if (pmidp->cluster == 0) { if (pmidp->item == 0) { /* pmcd.control.debug */ pmDebug = vsp->vlist[0].value.lval; } else if (pmidp->item == 4) { /* pmcd.control.timeout */ int val = vsp->vlist[0].value.lval; if (val < 0) { sts = PM_ERR_SIGN; break; } if (val != _pmcd_timeout) { _pmcd_timeout = val; } } else if (pmidp->item == 8) { /* pmcd.control.register */ int j; for (j = 0; j < vsp->numval; j++) { if (0 <= vsp->vlist[j].inst && vsp->vlist[j].inst < NUMREG) reg[vsp->vlist[j].inst] = vsp->vlist[j].value.lval; else { sts = PM_ERR_INST; break; } } } else if (pmidp->item == 9) { /* pmcd.control.traceconn */ int val = vsp->vlist[0].value.lval; if (val == 0) _pmcd_trace_mask &= (~TR_MASK_CONN); else if (val == 1) _pmcd_trace_mask |= TR_MASK_CONN; else { sts = PM_ERR_CONV; break; } } else if (pmidp->item == 10) { /* pmcd.control.tracepdu */ int val = vsp->vlist[0].value.lval; if (val == 0) _pmcd_trace_mask &= (~TR_MASK_PDU); else if (val == 1) _pmcd_trace_mask |= TR_MASK_PDU; else { sts = PM_ERR_CONV; break; } } else if (pmidp->item == 11) { /* pmcd.control.tracebufs */ int val = vsp->vlist[0].value.lval; if (val < 0) { sts = PM_ERR_SIGN; break; } pmcd_init_trace(val); } else if (pmidp->item == 12) { /* pmcd.control.dumptrace */ pmcd_dump_trace(stderr); } else if (pmidp->item == 13) { /* pmcd.control.dumpconn */ time_t now; time(&now); fprintf(stderr, "\n->Current PMCD clients at %s", ctime(&now)); ShowClients(stderr); } else if (pmidp->item == 14) { /* pmcd.control.tracenobuf */ int val = vsp->vlist[0].value.lval; if (val == 0) _pmcd_trace_mask &= (~TR_MASK_NOBUF); else if (val == 1) _pmcd_trace_mask |= TR_MASK_NOBUF; else { sts = PM_ERR_CONV; break; } } else if (pmidp->item == 15) { /* pmcd.control.sighup */ #ifdef HAVE_SIGHUP /* * send myself SIGHUP */ __pmNotifyErr(LOG_INFO, "pmcd reset via pmcd.control.sighup"); raise(SIGHUP); #endif } else { sts = PM_ERR_PMID; break; } } else if (pmidp->cluster == 6) { if (pmidp->item == 0) { /* pmcd.client.whoami */ /* * Expect one value for one instance (PM_IN_NULL) * * Use the value from the pmResult to change the value * for the client[] that matches the current pmcd client. */ char *cp = vsp->vlist[0].value.pval->vbuf; int j; int last_free = -1; if (vsp->numval != 1 || vsp->vlist[0].inst != PM_IN_NULL) { return PM_ERR_INST; } for (j = 0; j < nwhoamis; j++) { if (whoamis[j].id == -1) { /* slot in whoamis[] not in use */ last_free = j; continue; } if (whoamis[j].id == this_client_id && whoamis[j].seq == client[this_client_id].seq) { /* found the one to replace */ free(whoamis[j].value); break; } if (!client[whoamis[j].id].status.connected || client[whoamis[j].id].seq != whoamis[j].seq) { /* old whoamis[] entry, mark as available for reuse */ free(whoamis[j].value); whoamis[j].id = -1; last_free = j; } } if (j == nwhoamis) { if (last_free != -1) { j = last_free; } else { nwhoamis++; if ((whoamis = (whoami_t *)realloc(whoamis, nwhoamis*sizeof(whoamis[0]))) == NULL) { __pmNoMem("pmstore whoami", nwhoamis*sizeof(whoamis[0]), PM_RECOV_ERR); nwhoamis = 0; return -ENOMEM; } } whoamis[j].id = this_client_id; whoamis[j].seq = client[this_client_id].seq; } whoamis[j].value = strdup(cp); } else { sts = PM_ERR_PMID; break; } } else { /* not one of the metrics we are willing to change */ sts = PM_ERR_PMID; break; } } return sts; } void __PMDA_INIT_CALL pmcd_init(pmdaInterface *dp) { char helppath[MAXPATHLEN]; int sep = __pmPathSeparator(); snprintf(helppath, sizeof(helppath), "%s%c" "pmcd" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_5, "pmcd", helppath); dp->version.four.profile = pmcd_profile; dp->version.four.fetch = pmcd_fetch; dp->version.four.desc = pmcd_desc; dp->version.four.instance = pmcd_instance; dp->version.four.store = pmcd_store; dp->version.four.ext->e_endCallBack = end_context; init_tables(dp->domain); pmdaInit(dp, NULL, 0, NULL, 0); } pcp-3.8.12ubuntu1/src/pmdas/pmcd/src/objstyle0000775000000000000000000000430712272262501015774 0ustar #! /bin/sh # # Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # identify the objstyle of linux platforms other than ia32 and ia64. echo 'int main(){return 0;}' >dummy.c cc -c dummy.c # we've had bad experience with file(1) and compiled "magic" files # on assorted Linux versions ... try to use the uncompiled magic # file if possible # # if you need to modify this, make consistent changes in # src/pmdas/pmcd/src/objstyle # qa/605 # magic='' for file in /usr/share/misc/magic /usr/share/file/magic /usr/share/magic \ /etc/magic do if [ -f "$file" ] then # found a file, check it contains some definitions ... nl=`sed -e '/^#/d' -e '/^[ ]*$/d' <"$file" | wc -l | sed -e 's/ //g'` if [ "$nl" -gt 0 ] then magic=$file break fi fi done # sample file output # # ia32 laptop # dummy.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped # # Mac OS X # pmcd.o: Mach-O universal binary with 2 architectures # pmcd.o (for architecture i386): Mach-O object i386 # pmcd.o (for architecture x86_64): Mach-O 64-bit object x86_64 # # dummy.o: Mach-O 64-bit object x86_64 # # SLES10 # dummy.o: ELF 64-bit LSB relocatable, IA-64 (Intel 64 bit architecture), version 1 (SYSV), not stripped # if [ -n "$magic" ] then file -m $magic dummy.o else file dummy.o fi \ | ( sed -n \ -e '/ ELF /{ s/^[^,]*, // s/, .*// s/ *([^)]*)// s/ // s/x86-64/x86_64/ p }' \ -e '/object/{ s/[ ]*$// s/.*[ ]// p }' \ | tr '[\012]' '[+]' \ ; echo ) \ | sed -e 's/+$//' rm -f dummy.[co] pcp-3.8.12ubuntu1/src/pmdas/pmcd/GNUmakefile0000664000000000000000000000323712272262501015477 0ustar #!gmake # # Copyright (c) 2000-2001,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # pmcd PMDA # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs DFILES = help LTARGETS = help.dir LDIRT = *.log *.dir *.pag domain.h so_locations TARGETS = help.dir LSRCFILES = help root_pmcd SUBDIRS = src PMDADIR = $(PCP_PMDAS_DIR)/pmcd CONF_LINE = "pmcd 2 dso pmcd_init $(PCP_PMDAS_DIR)/pmcd/pmda_pmcd.$(DSOSUFFIX)" default_pcp default :: $(TARGETS) default_pcp default :: $(SUBDIRS) $(SUBDIRS_MAKERULE) @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi install_pcp install :: $(SUBDIRS) $(SUBDIRS_MAKERULE) install_pcp install :: $(SUBDIRS) $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 644 help.dir help.pag $(PMDADIR) $(INSTALL) -m 644 root_pmcd $(PCP_VAR_DIR)/pmns/root_pmcd help.dir: help root_pmcd $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -v 2 -n root_pmcd -o help < help include $(BUILDRULES) pcp-3.8.12ubuntu1/src/pmdas/pmcd/root_pmcd0000664000000000000000000000465212272262501015340 0ustar /* * PMCD metrics name space */ root { pmcd } /* * the domain for the pmcd PMDA ... */ #ifndef PMCD #define PMCD 2 #endif pmcd { control pdu_in pdu_out datasize PMCD:0:1 numagents PMCD:0:2 agent numclients PMCD:0:3 pmlogger timezone PMCD:0:5 simabi PMCD:0:6 version PMCD:0:7 build PMCD:0:20 openfds PMCD:0:17 hostname PMCD:0:21 pmie buf client cputime feature } pmcd.control { debug PMCD:0:0 timeout PMCD:0:4 register PMCD:0:8 traceconn PMCD:0:9 tracepdu PMCD:0:10 tracenobuf PMCD:0:14 tracebufs PMCD:0:11 dumptrace PMCD:0:12 dumpconn PMCD:0:13 sighup PMCD:0:15 } /* * Note: strange numbering for pmcd.pdu_{in,out}.total for * compatibility with earlier PCP versions */ pmcd.pdu_in { error PMCD:1:0 result PMCD:1:1 profile PMCD:1:2 fetch PMCD:1:3 desc_req PMCD:1:4 desc PMCD:1:5 instance_req PMCD:1:6 instance PMCD:1:7 text_req PMCD:1:8 text PMCD:1:9 control_req PMCD:1:10 creds PMCD:1:12 pmns_ids PMCD:1:13 pmns_names PMCD:1:14 pmns_child PMCD:1:15 total PMCD:1:16 pmns_traverse PMCD:1:17 auth PMCD:1:18 } pmcd.pdu_out { error PMCD:2:0 result PMCD:2:1 profile PMCD:2:2 fetch PMCD:2:3 desc_req PMCD:2:4 desc PMCD:2:5 instance_req PMCD:2:6 instance PMCD:2:7 text_req PMCD:2:8 text PMCD:2:9 control_req PMCD:2:10 creds PMCD:2:12 pmns_ids PMCD:2:13 pmns_names PMCD:2:14 pmns_child PMCD:2:15 total PMCD:2:16 pmns_traverse PMCD:2:17 auth PMCD:2:18 } pmcd.pmlogger { host PMCD:3:3 port PMCD:3:0 archive PMCD:3:2 pmcd_host PMCD:3:1 } pmcd.agent { type PMCD:4:0 status PMCD:4:1 } pmcd.pmie { configfile PMCD:5:0 logfile PMCD:5:1 pmcd_host PMCD:5:2 numrules PMCD:5:3 actions PMCD:5:4 eval } pmcd.pmie.eval { true PMCD:5:5 false PMCD:5:6 unknown PMCD:5:7 expected PMCD:5:8 actual PMCD:5:9 } pmcd.buf { alloc PMCD:0:18 free PMCD:0:19 } pmcd.client { whoami PMCD:6:0 start_date PMCD:6:1 } pmcd.cputime { total PMCD:7:0 per_pdu_in PMCD:7:1 } pmcd.feature { secure PMCD:8:0 compress PMCD:8:1 ipv6 PMCD:8:2 authentication PMCD:8:3 creds_required PMCD:8:4 unix_domain_sockets PMCD:8:5 service_discovery PMCD:8:6 } #undef PMCD pcp-3.8.12ubuntu1/src/pmdas/pmcd/help0000664000000000000000000005237112272262501014303 0ustar # # Copyright (c) 2013 Red Hat. # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # pmcd PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help text goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ 2.1 Instance domain "pmloggers" from PMCD PMDA This is the list of currently active pmlogger instances on the same machine as this PMCD. The instance names are the process ids of the pmlogger instances. The primary pmlogger has an extra instance with the instance name "primary" and an instance id of zero (in addition to its normal process id instance). @ 2.2 pmcd control register Instance Domain One instance per pmcd control register. The internal instance identifiers are the numbers 0 to 15. The external instance names are he ASCII equivalent of the internal instance identifiers. @ 2.3 PMDA Instance Domain One instance per PMDA managed by PMCD. The external and internal instance identifiers are taken from the first two fields of the PMDA specification in $PCP_PMCDCONF_PATH. @ 2.4 pmie Instance Domain One instance per running pmie process. The internal and external instance identifiers are the process ids of the pmie instances. @ 2.5 buffer pool Instance Domain The instances are as follows: 1024 1024-byte PDU buffers managed by __pmFindPDUBuf, __pmPinPDUBuf and __pmUnpinPDUBuf 2048 2-Kbyte PDU buffers managed by __pmFindPDUBuf, __pmPinPDUBuf and __pmUnpinPDUBuf 4096 3-Kbyte or 4-Kbyte PDU buffers managed by __pmFindPDUBuf, __pmPinPDUBuf and __pmUnpinPDUBuf 8192 5-Kbyte, 6-Kbyte, 7-Kbyte or 8-Kbyte PDU buffers managed by __pmFindPDUBuf, __pmPinPDUBuf and __pmUnpinPDUBuf 8192+ PDU buffers larger that 8-Kbyte managed by __pmFindPDUBuf, __pmPinPDUBuf and __pmUnpinPDUBuf @ pmcd.numagents Number of agents (PMDAs) currently connected to PMCD The number of agents (PMDAs) currently connected to PMCD. This may differ from the number of agents configured in $PCP_PMCDCONF_PATH if agents have terminated and/or been timed-out by PMCD. @ pmcd.numclients Number of clients currently connected to PMCD The number of connections open to client programs retrieving information from PMCD. @ pmcd.datasize Space allocated for PMCD and DSO agents' data segment (K) This metric returns the amount of memory in kilobytes allocated for the data segment of PMCD and any DSO agents (PMDAs) that it has loaded. This is handy for tracing memory utilization (and leaks) in DSOs during development. @ pmcd.buf.alloc Allocated buffers in internal memory pools This metric returns the number of allocated buffers for the various buffer pools used by pmcd. This is handy for tracing memory utilization (and leaks) in DSOs during development. @ pmcd.buf.free Free buffers in internal memory pools This metric returns the number of free buffers for the various buffer pools used by pmcd. This is handy for tracing memory utilization (and leaks) in DSOs during development. @ pmcd.control.timeout Timeout interval for slow/hung agents (PMDAs) PDU exchanges with agents (PMDAs) managed by PMCD are subject to timeouts which detect and clean up slow or disfunctional agents. This metric returns the current timeout period in seconds being used for the agents. If the value is zero, timeouts are not being used. This corresponds to the -t option described in the man page, pmcd(1). It is possible to store a new timeout value into this metric. Storing zero will turn off timeouts. Subsequent storing of a non-zero value will turn on the timeouts again. @ pmcd.control.debug Current value of PMCD debug flags The current value of the PMCD debug flags. This is a bit-wise OR of the flags described in the output of pmdbg -l. The PMCD-specific flags are: DBG_TRACE_APPL0 2048 Trace agent & client I/O and termination DBG_TRACE_APPL1 4096 Trace host access control DBG_TRACE_APPL2 8192 Trace config file scanner and parser It is possible to store values into this metric. Diagnostic output is written to the PMCD log file (usually $PCP_LOG_DIR/pmcd/pmcd.log). Setting this metric to -1 terminates PMCD. @ pmcd.pdu_in.total Total PDUs received by PMCD Running total of all BINARY mode PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.error ERROR PDUs received by PMCD Running total of BINARY mode ERROR PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.result RESULT PDUs received by PMCD Running total of BINARY mode RESULT PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.profile PROFILE PDUs received by PMCD Running total of BINARY mode PROFILE PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.fetch FETCH PDUs received by PMCD Running total of BINARY mode FETCH PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.desc_req DESC_REQ PDUs received by PMCD Running total of BINARY mode DESC_REQ PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.desc DESC PDUs received by PMCD Running total of BINARY mode DESC PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.instance_req INSTANCE_REQ PDUs received by PMCD Running total of BINARY mode INSTANCE_REQ PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.instance INSTANCE PDUs received by PMCD Running total of BINARY mode INSTANCE PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.text_req TEXT_REQ PDUs received by PMCD Running total of BINARY mode TEXT_REQ PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.text TEXT PDUs received by PMCD Running total of BINARY mode TEXT PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.control_req CONTROL_REQ PDUs received by PMCD Running total of BINARY mode CONTROL_REQ PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.creds CREDS PDUs received by PMCD Running total of BINARY mode CREDS PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.pmns_ids PMNS_IDS PDUs received by PMCD Running total of BINARY mode PMNS_IDS PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.pmns_names PMNS_NAMES PDUs received by PMCD Running total of BINARY mode PMNS_NAMES PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.pmns_child PMNS_CHILD PDUs received by PMCD Running total of BINARY mode PMNS_CHILD PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.pmns_traverse PMNS_TRAVERSE PDUs received by PMCD Running total of BINARY mode PMNS_TRAVERSE PDUs received by the PMCD from clients and agents. @ pmcd.pdu_in.auth AUTH PDUs received by PMCD Running total of BINARY mode AUTH PDUs received by the PMCD from clients and agents. These PDUs are used for authentication. @ pmcd.pdu_out.total Total PDUs sent by PMCD Running total of all BINARY mode PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.error ERROR PDUs sent by PMCD Running total of BINARY mode ERROR PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.result RESULT PDUs sent by PMCD Running total of BINARY mode RESULT PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.profile PROFILE PDUs sent by PMCD Running total of BINARY mode PROFILE PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.fetch FETCH PDUs sent by PMCD Running total of BINARY mode FETCH PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.desc_req DESC_REQ PDUs sent by PMCD Running total of BINARY mode DESC_REQ PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.desc DESC PDUs sent by PMCD Running total of BINARY mode DESC PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.instance_req INSTANCE_REQ PDUs sent by PMCD Running total of BINARY mode INSTANCE_REQ PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.instance INSTANCE PDUs sent by PMCD Running total of BINARY mode INSTANCE PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.text_req TEXT_REQ PDUs sent by PMCD Running total of BINARY mode TEXT_REQ PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.text TEXT PDUs sent by PMCD Running total of BINARY mode TEXT PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.control_req CONTROL_REQ PDUs sent by PMCD Running total of BINARY mode CONTROL_REQ PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.creds CREDS PDUs sent by PMCD Running total of BINARY mode CREDS PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.pmns_ids PMNS_IDS PDUs sent by PMCD Running total of BINARY mode PMNS_IDS PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.pmns_names PMNS_NAMES PDUs sent by PMCD Running total of BINARY mode PMNS_NAMES PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.pmns_child PMNS_CHILD PDUs sent by PMCD Running total of BINARY mode PMNS_CHILD PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.pmns_traverse PMNS_TRAVERSE PDUs sent by PMCD Running total of BINARY mode PMNS_TRAVERSE PDUs sent by the PMCD to clients and agents. @ pmcd.pdu_out.auth AUTH PDUs sent by PMCD Running total of BINARY mode AUTH PDUs sent by the PMCD to clients and agents. These PDUs are used for authentication. @ pmcd.pmlogger.host host where active pmlogger is running The fully qualified domain name of the host on which a pmlogger instance is running. The instance names are process ids of the active pmloggers. The primary pmlogger has an extra instance with the instance name "primary" and an instance id of zero (in addition to its normal process id instance). @ pmcd.pmlogger.port control port for active pmlogger Each pmlogger instance has a port for receiving log control information. This metric is a list of the active pmlogger control ports on the same machine as this PMCD (i.e. the host identified in the corresponding pmcd.pmlogger.host metric). The instance names are process ids of the active pmloggers. The primary pmlogger has an extra instance with the instance name "primary" and an instance id of zero (in addition to its normal process id instance). @ pmcd.pmlogger.archive full pathname to archive basename for active pmlogger The full pathname through the filesystem on the corresponding host (pmcd.pmlogger.host) that is the base name for the archive log files. The instance names are process ids of the active pmloggers. The primary pmlogger has an extra instance with the instance name "primary" and an instance id of zero (in addition to its normal process id instance). @ pmcd.pmlogger.pmcd_host host from which active pmlogger is fetching metrics The fully qualified domain name of the host from which a pmlogger instance is fetching metrics to be archived. The instance names are process ids of the active pmloggers. The primary pmlogger has an extra instance with the instance name "primary" and an instance id of zero (in addition to its normal process id instance). @ pmcd.timezone local $TZ Value for the $TZ environment variable where the PMCD is running. Enables determination of "local" time for timestamps returned via PMCD from a remote host. @ pmcd.hostname local hostname A reasonably unique identifier of the PMCD installation, for use by pmlogger or other tools to identify the source principal of the data (as distinct from identifying the connection/protocol used to reach it). @ pmcd.simabi Procedure call model and ABI version of this PMCD SIM is the subprogram interface model (originally from the MIPS object code formats), and ABI is the application binary interface. Both relate to the way the PMCD binary was compiled and linked. Usually DSO PMDAs must be compiled and linked in the same way before they can be used with PMCD. On some platforms this metric is not available. @ pmcd.version PMCD version @ pmcd.control.register a vector of registers that may be set by users A vector of 16 32-bit registers that are identified by the instance identifiers 0 through 15. The register contents are initially zero, but may be subsequently modified to be an arbitrary value using pmStore(3) or pmstore(1). The values are not used internally, but rather act as a repository into which operational information might be stored, and then exported to modify the behavior of client programs, e.g. inhibit pmie(1) rule firing, or trigger a status indicator. In this way, pmcd.control.register acts like a primitive bulletin board. Example use might be as follows register[0] telephone no. of person assigned to current system problem register[1] telephone no. of person assigned to current network problem register[2] ORACLE database is down register[3] backup in progress register[4] shopping days to Christmas @ pmcd.control.traceconn control PMCD connection event tracing Set to 1 to enable PMCD event tracing for all connection-related events for clients and PMDAs. Set to 0 to disable PMCD connection event tracing. @ pmcd.control.tracepdu control PMCD PDU event tracing Set to 1 to enable PMCD event tracing for all PDUs sent and received by PMCD. Set to 0 to disable PMCD PDU event tracing. @ pmcd.control.tracenobuf control buffering of PMCD event tracing Set to 1 to enable unbuffered PMCD event tracing, where each event is reported as it happens. Set to 0 to enable buffering of PMCD event traces (this is the default), and event traces will only be dumped or reported when an error occurs or a value is stored into the PCP metric pmcd.control.dumptrace. @ pmcd.control.tracebufs number of buffers for PMCD event tracing Defaults to 20. May be changed dynamically. @ pmcd.control.dumptrace force dump of PMCD event tracing buffers Storing any value into this metric causes the PMCD event trace buffers to be dumped to PMCD's log file. @ pmcd.control.sighup force PMCD reset via SIGHUP Storing any value into this metric causes PMCD to be reset by sending itself a SIGHUP signal. On reset (either by storing into pmcd.control.sighup or by sending PMCD a SIGHUP directly), PMCD will restart any failed PMDAs and reload the PMNS if it has been changed. @ pmcd.control.dumpconn force dump of PMCD client connections Storing any value into this metric causes the details of the current PMCD client connections to be dumped to PMCD's log file. @ pmcd.agent.type PMDA type From $PCP_PMCDCONF_PATH, this metric encodes the PMDA type as follows: (x << 1) | y where "x" is the IPC type between PMCD and the PMDA, i.e. 0 for DSO, 1 for socket or 2 for pipe, and "y" is the message passing style, i.e. 0 for binary or 1 for ASCII. @ pmcd.agent.status PMDA status This metric encodes the current status of each PMDA. The default value is 0 if the PMDA is active. Other values encode various degrees of PMDA difficulty in three bit fields (bit 0 is the low-order bit) as follows: bits 7..0 1 the PMDA is connected, but not yet "ready" to accept requests from the PMDA 2 the PMDA has exited of its own accord 4 some error prevented the PMDA being started 8 PMCD stopped communication with the PMDA due to a protocol or timeout error bits 15..8 the exit() status from the PMDA bits 23..16 the number of the signal that terminated the PMDA @ pmcd.openfds highest PMCD file descriptor The highest file descriptor index used by PMCD for a Client or PMDA connection. @ pmcd.pmie.numrules number of rules being evaluated The total number of rules being evaluated by each pmie process. @ pmcd.pmie.eval.true count of pmie predicates evaluated to true The predicate part of a pmie rule can be said to evaluate to either true, false, or not known. This metric is a cumulative count of the number of rules which have evaluated to true for each pmie instance. @ pmcd.pmie.eval.false count of pmie predicates evaluated to false The predicate part of a pmie rule can be said to evaluate to either true, false, or not known. This metric is a cumulative count of the number of rules which have evaluated to false for each pmie instance. @ pmcd.pmie.eval.unknown count of pmie predicates not evaluated The predicate part of a pmie rule can be said to evaluate to either true, false, or not known. This metric is a cumulative count of the number of rules which have not been successfully evaluated. This could be due to not yet having sufficient values to evaluate the rule, or a metric fetch may have been unsuccessful in retrieving current values for metrics required for evaluation of the rule. @ pmcd.pmie.eval.expected expected rate of rule evaluations This is the expected rate of evaluation of pmie rules. The value is calculated once when pmie starts, and is the number of pmie rules divided by the average time interval over which they are to be evaluated. @ pmcd.pmie.eval.actual count of actual rule evaluations A cumulative count of the pmie rules which have been evaluated. This value is incremented once for each evaluation of each rule. @ pmcd.pmie.actions count of rules evaluating to true A cumulative count of the evaluated pmie rules which have evaluated to true. This value is incremented once each time an action is executed. This value will always be less than or equal to pmcd.pmie.eval.true because predicates which have evaluated to true may be suppressed in the action part of the pmie rule, in which case this counter will not be incremented. @ pmcd.pmie.configfile configuration file name The full path in the filesystem to the configuration file containing the rules being evaluated by each pmie instance. If the configuration file was supplied on the standard input, then this metric will have the value "". If multiple configuration files were given to pmie, then the value of this metric will be the first configuration file specified. @ pmcd.pmie.pmcd_host default hostname for pmie instance The default host from which pmie is fetching metrics. This is either the hostname given to pmie on the command line or the local host. Note that this does not consider host names specified in the pmie configuration file (these are considered non-default and can be more than one per pmie instance). All daemon pmie instances started through pmie_check(1) will have their default host passed in on their command line. @ pmcd.pmie.logfile filename of pmie instance event log The file to which each instance of pmie is writting events. No two pmie instances can share the same log file. If no logfile was specified when pmie was started, this metrics has the value "". All daemon pmie instances started through pmie_check(1) must have an associated log file. @ pmcd.build build version for installed PCP package Minor part of the PCP build version numbering. For example on Linux with RPM packaging, if the PCP RPM version is pcp-2.5.99-20070323 then pmcd.build returns the string "20070323". @ pmcd.client.whoami optional identification information for clients of pmcd This metric is defined over an instance domain containing one entry per active client of pmcd. The instance number is a sequence number for each client (restarts at 0 each time pmcd is restarted). The value of the metric by default is the IP address of the client. Clients can optionally use pmStore to modify their own "whoami" string to provide more useful information about the client. @ pmcd.client.start_date date and time client connected to pmcd The date and time in ctime(2) format on which the client connected to pmcd. @ pmcd.cputime.total CPU time used by pmcd and DSO PMDAs Sum of user and system time since pmcd started. @ pmcd.cputime.per_pdu_in average CPU time per PDU received by pmcd When first requested it is the average since pmcd started, so pmcd.cputime.total divided by pmcd.pdu_in.total. Subsequent fetches by a PMAPI client will return the average CPU time per PDU received by pmcd (for all clients) since the last time the PMAPI client fetched this metric. @ pmcd.feature.secure status of secure_sockets protocol feature in pmcd A value of zero indicates no support, one indicates actively available (including configuration and validity of the server side certificates). @ pmcd.feature.compress status of protocol compression feature in pmcd A value of zero indicates no support, one indicates actively available. @ pmcd.feature.ipv6 status of Internet Protocol Version 6 support in pmcd A value of zero indicates no support, one indicates actively available. @ pmcd.feature.authentication status of per-user authentication support A value of zero indicates no support, one indicates actively available. @ pmcd.feature.creds_required status of required credentials support A value of zero indicates no support, one indicates actively available. @ pmcd.feature.unix_domain_sockets status of unix domain socket support A value of zero indicates no support, one indicates actively available. @ pmcd.feature.service_discovery status of service advertising and discovery A value of zero indicates no support, one indicates actively available. pcp-3.8.12ubuntu1/src/pmdas/lmsensors/0000775000000000000000000000000012272262620014524 5ustar pcp-3.8.12ubuntu1/src/pmdas/lmsensors/README0000664000000000000000000000366112272262501015410 0ustar # # Original implementation by Troy Dawson (dawson@fnal.gov) # # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # lmsensors PMDA ============== This PMDA exports information about the lm sensors on compatible motherboards. This source code was contributed by Troy Dawson (dawson@fnal.gov) to the PCP open source project. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT lmsensors Installation ============ + # cd $PCP_PMDAS_DIR/lmsensors + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use ($PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options -- everything else is automated. + Alternatively, to install just the Performance Metrics Name Space for the lmsensors metrics on the local system, but not the lmsensors PMDA (presumably because the local system is running PCP 1.x and you wish to connect to a remote system where PCP 2.0 and the lmsensors PMDA is running), make sure the Performance Metrics Domain defined in ./domain.h matches the domain chosen for the lmsensors PMDA on the remote system (check the second field in the corresponding line of the $PCP_PMCDCONF_PATH file on the remote system), then # ./Install -N De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/lmsensors # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/lmsensors.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/lmsensors/Remove0000775000000000000000000000211612272262501015705 0ustar #! /bin/sh # # Original implementation by Troy Dawson (dawson@fnal.gov) # # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # source the PCP configuration environment variables . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=lmsensors # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/lmsensors/lmsensors.h0000664000000000000000000000425012272262501016721 0ustar /* * Original implementation by Troy Dawson (dawson@fnal.gov) * * Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ typedef struct { int total; int n_lm75; int n_lm79; int n_lm87; int n_w83781d; int n_mtp008; char s_lm75[2][1024] ; char s_lm79[2][1024] ; char s_lm87[2][1024] ; char s_w83781d[2][1024] ; char s_mtp008[2][1024] ; } chips; typedef struct { float temp; } lm75; typedef struct { int fan1; int fan2; int fan3; int fan_div; float temp; int alarms; float VCore1; float VCore2; float p33V; float p5V; float p12V; float n12V; float n5V; float vid; } lm79; typedef struct { int fan1; int fan2; float temp1; float CPUtemp; float Vccp1; float Vccp2; float p25V; float p33V; float p5V; float p12V; float vid; } lm87; typedef struct { int fan1; int fan2; int fan3; int fan_div; float temp1; float temp2; float temp3; int alarms; int beep; float VCore1; float VCore2; float p33V; float p5V; float p12V; float n12V; float n5V; float vid; } w83781d; typedef struct { int fan1; int fan2; int fan3; float temp1; float temp2; float VCore1; float VCore2; float p33V; float p12V; float n12V; float vid; float vtt; } mtp008; extern void get_chips(); extern lm75 get_lm75(); extern lm79 get_lm79(); extern lm87 get_lm87(); extern w83781d get_w83781d(); extern mtp008 get_mtp008(); extern int get_file(char *, char *); extern int get_int(char * , int); extern float get_float(char * , int); pcp-3.8.12ubuntu1/src/pmdas/lmsensors/Install0000775000000000000000000000151612272262501016061 0ustar #! /bin/sh # # Original implementation by Troy Dawson (dawson@fnal.gov) # # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=lmsensors pmda_interface=2 forced_restart=true # Do it # pmdaSetup dso_opt=true socket_opt=true socket_inet_def=2079 pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/lmsensors/GNUmakefile0000664000000000000000000000272012272262501016575 0ustar # # Original implementation by Troy Dawson (dawson@fnal.gov) # # Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = lmsensors DOMAIN = LMSENSORS TARGETS = $(IAM) CFILES = lmsensors.c HFILES = lmsensors.h SCRIPTS = Install Remove DFILES = README LSRCFILES = $(SCRIPTS) pmns help root $(DFILES) PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LDIRT = domain.h $(IAM).log pmda$(IAM) pmda_$(IAM).so $(TARGETS) \ help.pag help.dir LLDLIBS = $(PCP_PMDALIB) default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "linux" build-me: $(TARGETS) install : default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) $(INSTALL) -m 755 $(SCRIPTS) $(PMDADIR) $(INSTALL) -m 644 $(DFILES) pmns help root domain.h $(PMDADIR) else build-me: install: endif $(IAM): $(OBJECTS) lmsensors.o: domain.h default_pcp: default install_pcp: install domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/lmsensors/root0000664000000000000000000000026612272262501015434 0ustar /* * fake "root" for validating the local PMNS subtree * * Original implementation by Troy Dawson (dawson@fnal.gov) */ #include root { lmsensors } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/lmsensors/pmns0000664000000000000000000000525612272262501015432 0ustar /* * Metrics for lmsensors PMDA * * Original implementation by Troy Dawson (dawson@fnal.gov) * * Copyright (c) 2001 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ lmsensors { n_total LMSENSORS:0:0 n_lm75 LMSENSORS:0:1 n_lm79 LMSENSORS:0:2 n_lm87 LMSENSORS:0:3 n_w83781d LMSENSORS:0:4 n_mtp008 LMSENSORS:0:5 lm75 lm79 lm87 w83781d mtp008 } lmsensors.lm75 { temp LMSENSORS:1:0 } lmsensors.lm79 { fan1 LMSENSORS:2:0 fan2 LMSENSORS:2:1 fan3 LMSENSORS:2:2 fan_div LMSENSORS:2:3 temp LMSENSORS:2:4 alarms LMSENSORS:2:5 VCore1 LMSENSORS:2:6 VCore2 LMSENSORS:2:7 p33V LMSENSORS:2:8 p5V LMSENSORS:2:9 p12V LMSENSORS:2:10 n12V LMSENSORS:2:11 n5V LMSENSORS:2:12 vid LMSENSORS:2:13 } lmsensors.lm87 { fan1 LMSENSORS:3:0 fan2 LMSENSORS:3:1 temp1 LMSENSORS:3:2 CPUtemp LMSENSORS:3:3 Vccp1 LMSENSORS:3:4 Vccp2 LMSENSORS:3:5 p25V LMSENSORS:3:6 p33V LMSENSORS:3:7 p5V LMSENSORS:3:8 p12V LMSENSORS:3:9 vid LMSENSORS:3:10 } lmsensors.w83781d { fan1 LMSENSORS:4:0 fan2 LMSENSORS:4:1 fan3 LMSENSORS:4:2 fan_div LMSENSORS:4:3 temp1 LMSENSORS:4:4 temp2 LMSENSORS:4:5 temp3 LMSENSORS:4:6 alarms LMSENSORS:4:7 beep LMSENSORS:4:8 VCore1 LMSENSORS:4:9 VCore2 LMSENSORS:4:10 p33V LMSENSORS:4:11 p5V LMSENSORS:4:12 p12V LMSENSORS:4:13 n12V LMSENSORS:4:14 n5V LMSENSORS:4:15 vid LMSENSORS:4:16 } lmsensors.mtp008 { fan1 LMSENSORS:5:0 fan2 LMSENSORS:5:1 fan3 LMSENSORS:5:2 temp1 LMSENSORS:5:3 temp2 LMSENSORS:5:4 VCore1 LMSENSORS:5:5 VCore2 LMSENSORS:5:6 p33V LMSENSORS:5:7 p12V LMSENSORS:5:8 n12V LMSENSORS:5:9 vid LMSENSORS:5:10 vtt LMSENSORS:5:11 } pcp-3.8.12ubuntu1/src/pmdas/lmsensors/lmsensors.c0000664000000000000000000005704612272262501016727 0ustar /* * lmsensors, configurable PMDA * * Original implementation by Troy Dawson (dawson@fnal.gov) * * Copyright (c) 2012 Red Hat. * Copyright (c) 2001,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include "lmsensors.h" static char *username; static char buf[4096]; static chips schips; /* * lmsensors PMDA * */ /* * all metrics supported in this PMDA - one table entry for each */ static pmdaMetric metrictab[] = { /* n_total */ { NULL, { PMDA_PMID(0,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* n_lm75 */ { NULL, { PMDA_PMID(0,1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* n_lm79 */ { NULL, { PMDA_PMID(0,2), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* n_lm87 */ { NULL, { PMDA_PMID(0,3), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* n_w83781d */ { NULL, { PMDA_PMID(0,4), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* n_mtp008 */ { NULL, { PMDA_PMID(0,5), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm75 temp */ { NULL, { PMDA_PMID(1,0), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 fan1 */ { NULL, { PMDA_PMID(2,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 fan2 */ { NULL, { PMDA_PMID(2,1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 fan3 */ { NULL, { PMDA_PMID(2,2), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 fan_div */ { NULL, { PMDA_PMID(2,3), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 temp */ { NULL, { PMDA_PMID(2,4), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 alarms */ { NULL, { PMDA_PMID(2,5), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 VCore1 */ { NULL, { PMDA_PMID(2,6), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 VCore2 */ { NULL, { PMDA_PMID(2,7), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 p33V */ { NULL, { PMDA_PMID(2,8), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 p5V */ { NULL, { PMDA_PMID(2,9), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 p12V */ { NULL, { PMDA_PMID(2,10), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 n12V */ { NULL, { PMDA_PMID(2,11), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 n5V */ { NULL, { PMDA_PMID(2,12), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm79 vid */ { NULL, { PMDA_PMID(2,13), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm87 fan1 */ { NULL, { PMDA_PMID(3,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm87 fan2 */ { NULL, { PMDA_PMID(3,1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm87 temp1 */ { NULL, { PMDA_PMID(3,2), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm87 CPUtemp */ { NULL, { PMDA_PMID(3,3), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm87 Vccp1 */ { NULL, { PMDA_PMID(3,4), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm87 Vccp2 */ { NULL, { PMDA_PMID(3,5), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm87 p25V */ { NULL, { PMDA_PMID(3,6), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm87 p33V */ { NULL, { PMDA_PMID(3,7), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm87 p5V */ { NULL, { PMDA_PMID(3,8), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm87 p12V */ { NULL, { PMDA_PMID(3,9), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* lm87 vid */ { NULL, { PMDA_PMID(3,10), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d fan1 */ { NULL, { PMDA_PMID(4,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d fan2 */ { NULL, { PMDA_PMID(4,1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d fan3 */ { NULL, { PMDA_PMID(4,2), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d fan_div */ { NULL, { PMDA_PMID(4,3), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d temp1 */ { NULL, { PMDA_PMID(4,4), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d temp2 */ { NULL, { PMDA_PMID(4,5), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d temp3 */ { NULL, { PMDA_PMID(4,6), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d alarms */ { NULL, { PMDA_PMID(4,7), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d beep */ { NULL, { PMDA_PMID(4,8), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d VCore1 */ { NULL, { PMDA_PMID(4,9), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d VCore2 */ { NULL, { PMDA_PMID(4,10), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d p33V */ { NULL, { PMDA_PMID(4,11), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d p5V */ { NULL, { PMDA_PMID(4,12), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d p12V */ { NULL, { PMDA_PMID(4,13), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d n12V */ { NULL, { PMDA_PMID(4,14), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d n5V */ { NULL, { PMDA_PMID(4,15), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* w83781d vid */ { NULL, { PMDA_PMID(4,16), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* mtp008 fan1 */ { NULL, { PMDA_PMID(5,0), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* mtp008 fan2 */ { NULL, { PMDA_PMID(5,1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* mtp008 fan3 */ { NULL, { PMDA_PMID(5,2), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* mtp008 temp1 */ { NULL, { PMDA_PMID(5,3), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* mtp008 temp2 */ { NULL, { PMDA_PMID(5,4), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* mtp008 VCore1 */ { NULL, { PMDA_PMID(5,5), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* mtp008 VCore2 */ { NULL, { PMDA_PMID(5,6), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* mtp008 p33V */ { NULL, { PMDA_PMID(5,7), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* mtp008 p12V */ { NULL, { PMDA_PMID(5,8), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* mtp008 n12V */ { NULL, { PMDA_PMID(5,9), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* mtp008 vid */ { NULL, { PMDA_PMID(5,10), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, /* mtp008 vtt */ { NULL, { PMDA_PMID(5,11), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0, 0, 0, 0, 0, 0) }, }, }; w83781d get_w83781d() { float f; w83781d sensor= {0,0,0,0,00.01,00.01,00.01,0,0,00.01,00.01,00.01,00.01,00.01,00.01,00.01,00.01}; if (schips.n_w83781d > 0) { /* fan1 */ get_file(schips.s_w83781d[0],"/fan1"); sensor.fan1 = get_int(buf,2); /* fan2 */ get_file(schips.s_w83781d[0],"/fan2"); sensor.fan2 = get_int(buf,2); /* fan3 */ get_file(schips.s_w83781d[0],"/fan3"); sensor.fan3 = get_int(buf,2); /* fan_div */ get_file(schips.s_w83781d[0],"/fan_div"); sensor.fan_div = get_int(buf,1); /* temp1 */ get_file(schips.s_w83781d[0],"/temp1"); sensor.temp1 = get_float(buf,3); /* temp2 */ get_file(schips.s_w83781d[0],"/temp2"); sensor.temp2 = get_float(buf,3); /* temp3 */ get_file(schips.s_w83781d[0],"/temp3"); sensor.temp3 = get_float(buf,3); /* alarms */ get_file(schips.s_w83781d[0],"/alarms"); sensor.alarms = get_int(buf,1); /* beep */ get_file(schips.s_w83781d[0],"/beep"); sensor.beep = get_int(buf,1); /* VCore1 */ get_file(schips.s_w83781d[0],"/in0"); sensor.VCore1 = get_float(buf,3); /* VCore2 */ get_file(schips.s_w83781d[0],"/in1"); sensor.VCore2 = get_float(buf,3); /* p33V */ get_file(schips.s_w83781d[0],"/in2"); sensor.p33V = get_float(buf,3); /* p5V */ get_file(schips.s_w83781d[0],"/in3"); f = get_float(buf,3); sensor.p5V = f * ((6.80/10)+1); /* p12V */ get_file(schips.s_w83781d[0],"/in4"); f = get_float(buf,3); sensor.p12V = f * ((28.00/10)+1); /* n12V */ get_file(schips.s_w83781d[0],"/in5"); f = get_float(buf,3); sensor.n12V = -1 * f * (210/60.40); /* n5V */ get_file(schips.s_w83781d[0],"/in6"); f = get_float(buf,3); sensor.n5V = -1 * f * (90.9/60.40); /* vid */ get_file(schips.s_w83781d[0],"/vid"); sensor.vid = get_float(buf,1); } return sensor; } mtp008 get_mtp008() { float f; mtp008 sensor= {0,0,0,00.01,00.01,00.01,00.01,00.01,00.01,00.01,00.01,00.01}; if (schips.n_mtp008 > 0) { /* fan1 */ get_file(schips.s_mtp008[0],"/fan1"); sensor.fan1 = get_int(buf,2); /* fan2 */ get_file(schips.s_mtp008[0],"/fan2"); sensor.fan2 = get_int(buf,2); /* fan3 */ get_file(schips.s_mtp008[0],"/fan3"); sensor.fan3 = get_int(buf,2); /* temp1 */ get_file(schips.s_mtp008[0],"/temp1"); sensor.temp1 = get_float(buf,3); /* temp2 */ get_file(schips.s_mtp008[0],"/temp2"); sensor.temp2 = get_float(buf,3); /* VCore1 */ get_file(schips.s_mtp008[0],"/in0"); sensor.VCore1 = get_float(buf,3); /* VCore2 */ get_file(schips.s_mtp008[0],"/in3"); sensor.VCore2 = get_float(buf,3); /* p33V */ get_file(schips.s_mtp008[0],"/in1"); sensor.p33V = get_float(buf,3); /* p12V */ get_file(schips.s_mtp008[0],"/in2"); f = get_float(buf,3); sensor.p12V = f * ((38.00/10)+1); /* n12V */ get_file(schips.s_mtp008[0],"/in5"); f = get_float(buf,3); sensor.n12V = ( f * 36 - 118.61 ) / 7; /* vid */ get_file(schips.s_mtp008[0],"/vid"); sensor.vid = get_float(buf,1); /* vtt */ get_file(schips.s_mtp008[0],"/in6"); sensor.vid = get_float(buf,3); } return sensor; } lm79 get_lm79() { float f; lm79 sensor= {0,0,0,00.01,0,00.01,00.01,00.01,00.01,00.01,00.01,00.01,00.01,00.01}; if (schips.n_lm79 > 0) { /* fan1 */ get_file(schips.s_lm79[0],"/fan1"); sensor.fan1 = get_int(buf,2); /* fan2 */ get_file(schips.s_lm79[0],"/fan2"); sensor.fan2 = get_int(buf,2); /* fan3 */ get_file(schips.s_lm79[0],"/fan3"); sensor.fan3 = get_int(buf,2); /* fan_div */ get_file(schips.s_lm79[0],"/fan_div"); sensor.fan_div = get_int(buf,1); /* temp */ get_file(schips.s_lm79[0],"/temp"); sensor.temp = get_float(buf,3); /* alarms */ get_file(schips.s_lm79[0],"/alarms"); sensor.alarms = get_int(buf,1); /* VCore1 */ get_file(schips.s_lm79[0],"/in0"); sensor.VCore1 = get_float(buf,3); /* VCore2 */ get_file(schips.s_lm79[0],"/in1"); sensor.VCore2 = get_float(buf,3); /* p33V */ get_file(schips.s_lm79[0],"/in2"); sensor.p33V = get_float(buf,3); /* p5V */ get_file(schips.s_lm79[0],"/in3"); f = get_float(buf,3); sensor.p5V = f * ((6.80/10)+1); /* p12V */ get_file(schips.s_lm79[0],"/in4"); f = get_float(buf,3); sensor.p12V = f * ((28.00/10)+1); /* n12V */ get_file(schips.s_lm79[0],"/in5"); f = get_float(buf,3); sensor.n12V = -1 * f * (210/60.40); /* n5V */ get_file(schips.s_lm79[0],"/in6"); f = get_float(buf,3); sensor.n5V = -1 * f * (90.9/60.40); /* vid */ get_file(schips.s_lm79[0],"/vid"); sensor.vid = get_float(buf,1); } return sensor; } lm87 get_lm87() { lm87 sensor= {0,0,00.01,00.01,00.01,00.01,00.01,00.01,00.01,00.01,00.01}; if (schips.n_lm87 > 0) { /* fan1 */ get_file(schips.s_lm87[0],"/fan"); sensor.fan1 = get_int(buf,2); /* fan2 */ get_file(schips.s_lm87[0],"/fan2"); sensor.fan2 = get_int(buf,2); /* temp1 */ get_file(schips.s_lm87[0],"/temp1"); sensor.temp1 = get_float(buf,3); /* CPUtemp */ get_file(schips.s_lm87[0],"/temp2"); sensor.CPUtemp = get_float(buf,3); /* Vccp1 */ get_file(schips.s_lm87[0],"/in1"); sensor.Vccp1 = get_float(buf,3); /* Vccp2 */ get_file(schips.s_lm87[0],"/in5"); sensor.Vccp2 = get_float(buf,3); /* p25V */ get_file(schips.s_lm87[0],"/in0"); sensor.p25V = get_float(buf,3); /* p33V */ get_file(schips.s_lm87[0],"/in2"); sensor.p33V = get_float(buf,3); /* p5V */ get_file(schips.s_lm87[0],"/in3"); sensor.p5V = get_float(buf,3); /* p12V */ get_file(schips.s_lm87[0],"/in4"); sensor.p12V = get_float(buf,3); /* vid */ get_file(schips.s_lm87[0],"/vid"); sensor.vid = get_float(buf,1); } return sensor; } lm75 get_lm75() { lm75 sensor= {00.01}; if (schips.n_lm75 > 0) { get_file(schips.s_lm75[0],"/temp"); sensor.temp = get_float(buf,3); } return sensor; } void get_chips() { int i; int n; int nbufindex; char *bufindex[64]; char *temp; n = get_file("chips", ""); buf[sizeof(buf)-1] = '\0'; nbufindex = 0; bufindex[nbufindex++] = &buf[0]; for (i=0; i < n; i++) { if (buf[i] == '\n') { buf[i] = '\0'; bufindex[nbufindex++] = buf + i + 1; } } for ( i=0; i < nbufindex ; i++ ) { temp=""; if (strncmp("lm75", bufindex[i]+4, 4) == 0 ) { temp = strtok(bufindex[i]+4," "); strcat(schips.s_lm75[schips.n_lm75], temp); schips.total++; schips.n_lm75++; } else if (strncmp("lm79", bufindex[i]+4, 4) == 0 ) { temp = strtok(bufindex[i]+4," "); strcat(schips.s_lm79[schips.n_lm79], temp); schips.total++; schips.n_lm79++; } else if (strncmp("lm87", bufindex[i]+4, 4) == 0 ) { temp = strtok(bufindex[i]+4," "); strcat(schips.s_lm87[schips.n_lm87], temp); schips.total++; schips.n_lm87++; } else if (strncmp("w83781d", bufindex[i]+4, 7) == 0 ) { temp = strtok(bufindex[i]+4," "); strcat(schips.s_w83781d[schips.n_w83781d], temp); schips.total++; schips.n_w83781d++; } else if (strncmp("mtp008", bufindex[i]+4, 6) == 0 ) { temp = strtok(bufindex[i]+4," "); strcat(schips.s_mtp008[schips.n_mtp008], temp); schips.total++; schips.n_mtp008++; } } } /* * Get the contents of a file and return them */ int get_file(char *middle, char *end){ int fd; int n; char s[1024]="/proc/sys/dev/sensors/"; /* * create the new string, the end result being the actual file name */ strcat(s,middle); strcat(s,end); /* * read in the file into the buffer buf */ if ((fd = open(s, O_RDONLY)) < 0) { return -1; } n = read(fd, buf, sizeof(buf)); close(fd); return n; } /* * Pull a certain float value out of a string of floats */ float get_float(char *s, int i){ char *temp; float f; int j; temp = strtok(s," "); for (j=1;jm_desc.pmid); if (idp->cluster > 5) return PM_ERR_PMID; else if (inst != PM_IN_NULL) return PM_ERR_INST; if (idp->cluster == 0) { /*lmsensors*/ switch (idp->item) { case 0: atom->l = schips.total; break ; case 1: atom->l = schips.n_lm75; break ; case 2: atom->l = schips.n_lm79; break ; case 3: atom->l = schips.n_lm87; break ; case 4: atom->l = schips.n_w83781d; break ; case 5: atom->l = schips.n_mtp008; break ; default: return PM_ERR_PMID; } } if (idp->cluster == 1) { /*lmsensors.lm75*/ if (schips.n_lm75 > 0) { sensor75=get_lm75(); switch (idp->item) { case 0: atom->f = sensor75.temp; break ; default: return PM_ERR_PMID; } } else atom->f=9999; } if (idp->cluster == 2) { /*lmsensors.lm79*/ if (schips.n_lm79 > 0) { sensor79=get_lm79(); switch (idp->item) { case 0: atom->l = sensor79.fan1; break ; case 1: atom->l = sensor79.fan2; break ; case 2: atom->l = sensor79.fan3; break ; case 3: atom->l = sensor79.fan_div; break ; case 4: atom->f = sensor79.temp; break ; case 5: atom->l = sensor79.alarms; break ; case 6: atom->f = sensor79.VCore1; break ; case 7: atom->f = sensor79.VCore2; break ; case 8: atom->f = sensor79.p33V; break ; case 9: atom->f = sensor79.p5V; break ; case 10: atom->f = sensor79.p12V; break ; case 11: atom->f = sensor79.n12V; break ; case 12: atom->f = sensor79.n5V; break ; case 13: atom->f = sensor79.vid; break ; default: return PM_ERR_PMID; } } else atom->f=9999; } if (idp->cluster == 3) { /*lmsensors.lm87*/ if (schips.n_lm87 > 0) { sensor87=get_lm87(); switch (idp->item) { case 0: atom->l = sensor87.fan1; break ; case 1: atom->l = sensor87.fan2; break ; case 2: atom->f = sensor87.temp1; break ; case 3: atom->f = sensor87.CPUtemp; break ; case 4: atom->f = sensor87.Vccp1; break ; case 5: atom->f = sensor87.Vccp2; break ; case 6: atom->f = sensor87.p25V; break ; case 7: atom->f = sensor87.p33V; break ; case 8: atom->f = sensor87.p5V; break ; case 9: atom->f = sensor87.p12V; break ; case 10: atom->f = sensor87.vid; break ; default: return PM_ERR_PMID; } } else atom->f=9999; } if (idp->cluster == 4) { /*lmsensors.w83781d*/ if (schips.n_w83781d > 0) { sensorw83781d=get_w83781d(); switch (idp->item) { case 0: atom->l = sensorw83781d.fan1; break ; case 1: atom->l = sensorw83781d.fan2; break ; case 2: atom->l = sensorw83781d.fan3; break ; case 3: atom->l = sensorw83781d.fan_div; break ; case 4: atom->f = sensorw83781d.temp1; break ; case 5: atom->f = sensorw83781d.temp2; break ; case 6: atom->f = sensorw83781d.temp3; break ; case 7: atom->l = sensorw83781d.alarms; break ; case 8: atom->l = sensorw83781d.beep; break ; case 9: atom->f = sensorw83781d.VCore1; break ; case 10: atom->f = sensorw83781d.VCore2; break ; case 11: atom->f = sensorw83781d.p33V; break ; case 12: atom->f = sensorw83781d.p5V; break ; case 13: atom->f = sensorw83781d.p12V; break ; case 14: atom->f = sensorw83781d.n12V; break ; case 15: atom->f = sensorw83781d.n5V; break ; case 16: atom->f = sensorw83781d.vid; break ; default: return PM_ERR_PMID; } } else atom->f=9999; } if (idp->cluster == 5) { /*lmsensors.mtp008*/ if (schips.n_mtp008 > 0) { sensormtp008=get_mtp008(); switch (idp->item) { case 0: atom->l = sensormtp008.fan1; break ; case 1: atom->l = sensormtp008.fan2; break ; case 2: atom->l = sensormtp008.fan3; break ; case 3: atom->f = sensormtp008.temp1; break ; case 4: atom->f = sensormtp008.temp2; break ; case 5: atom->f = sensormtp008.VCore1; break ; case 6: atom->f = sensormtp008.VCore2; break ; case 7: atom->f = sensormtp008.p33V; break ; case 8: atom->f = sensormtp008.p12V; break ; case 9: atom->f = sensormtp008.n12V; break ; case 10: atom->f = sensormtp008.vid; break ; case 11: atom->f = sensormtp008.vtt; break ; default: return PM_ERR_PMID; } } else atom->f=9999; } return 0; } /* * Initialise the agent (both daemon and DSO). */ void lmsensors_init(pmdaInterface *dp) { get_chips(); __pmSetProcessIdentity(username); pmdaSetFetchCallBack(dp, lmsensors_fetchCallBack); pmdaInit(dp, NULL, 0, metrictab, sizeof(metrictab)/sizeof(metrictab[0])); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int c, sep = __pmPathSeparator(); int err = 0; pmdaInterface desc; char mypath[MAXPATHLEN]; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(mypath, sizeof(mypath), "%s%c" "lmsensors" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&desc, PMDA_INTERFACE_2, pmProgname, LMSENSORS, "lmsensors.log", mypath); while ((c = pmdaGetOpt(argc, argv, "D:d:l:U:?", &desc, &err)) != EOF) { switch(c) { case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&desc); lmsensors_init(&desc); pmdaConnect(&desc); pmdaMain(&desc); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/lmsensors/help0000664000000000000000000000000212272262501015365 0ustar # pcp-3.8.12ubuntu1/src/pmdas/shping/0000775000000000000000000000000012272262620013767 5ustar pcp-3.8.12ubuntu1/src/pmdas/shping/shping.RealTime.pmchart0000664000000000000000000000036512272262501020342 0ustar #pmchart Version 2.0 host dynamic Chart Title "Elapsed Time for shping Commands" Style plot Plot Color #-cycle Host * Metric shping.time.real Matching .* # # Elapsed time (or real time, or response time) for commands run by the # shping PMDA pcp-3.8.12ubuntu1/src/pmdas/shping/sample.conf0000664000000000000000000000305612272262501016121 0ustar # sample configuration file for shping PMDA # # Warning: these commands will be run as "root" using sh(1) with the # current directory set to $PCP_LOG_DIR/pmcd and the # following set in the environment: # IFS=" \t\n" # PATH=... as per $PCP_DIR/etc/pcp.env ... # # Specification format, one per line ("Tags" must be unique) # Tag Shell command # minimal effort here, no stress for the shell ... just start and quit null exit 0 # not too much work, date(1) is pretty light-weight date date # compile and run the generic simple program ... requires a C compiler # to be installed cc cd /tmp; rm -f $$.[oc] $$; echo "main(){printf(\"g'day world\\\\n\");}" >/tmp/$$.c; cc -o $$ $$.c; ./$$; rm -f $$.[oc] $$ # Is the default DNS server responding? # CONFIGURE-ME-PLEASE - local customization required # CONFIGURE-ME-PLEASE - DEFAULT-DNS-SERVER will be changed by Install to # CONFIGURE-ME-PLEASE - be the hostname for the default DNS server # CONFIGURE-ME-PLEASE - and NSLOOKUP is the path of the nslookup(1) command dns NSLOOKUP - DEFAULT-DNS-SERVER /dev/null then # nslookup(1) may be hiding, like for OpenIndiana # export PATH=$PATH:/usr/sbin nslookup=`which nslookup 2>/dev/null` if [ -z "$nslookup" ] then echo "Warning: cannot find nslookup" nslookup=nslookup fi # sample configuration file needs a little customization # if [ -f /etc/resolv.conf ] then my_dns_server=`$PCP_AWK_PROG $tmp/tmp \ -e '/CONFIGURE-ME-PLEASE/d' \ -e "s@DEFAULT-DNS-SERVER@$my_dns_server@" \ -e "s@NSLOOKUP@$nslookup@" cp $tmp/tmp $default_configfile fi # go figure out which configuration file to use ... # pmdaChooseConfigFile if [ ! -f "$configfile" ] then $PCP_ECHO_PROG $PCP_ECHO_N "Do you wish to enter commands to create a new configuration file? [y] ""$PCP_ECHO_C" read ans if [ "X$ans" = "Xy" -o "X$ans" = "XY" -o -z "$ans" ] then configfile="$configdir/$iam.conf" if [ -f $configfile ] then echo "Removing old configuration file \"$configfile\"" rm -f $configfile if [ -f $configfile ] then echo "Cannot remove \"$configfile\"" _quit 1 fi fi echo echo \ 'Enter one ping specification per line, in the format tag command line details where the "tag" is a single unique word (no spaces) and the "command line details" are the corresponding sh(1) command. For example dns-self nslookup `hostname` An empty line terminates the specification process and there must be at least one specification. ' args="" touch $configfile if [ ! -f $configfile ] then echo "Installation aborted." _quit 1 fi while [ ! -s "$configfile" ] do while true do $PCP_ECHO_PROG $PCP_ECHO_N "Tag Command: ""$PCP_ECHO_C" read tag cmd [ -z "$tag" ] && break if grep "^$tag " $configfile >/dev/null then echo "Sorry, tag \"$tag\" already in use. Please try again." continue fi echo "$tag $cmd" >>$configfile done done else echo "" echo "Error: Abandoning installation as no configuration file was specified." _quit 1 fi fi echo echo "All commands are run one after another as a group and the group is run" $PCP_ECHO_PROG $PCP_ECHO_N "once per \"cycle\" time. Enter the cycle time in seconds [$cycle] ""$PCP_ECHO_C" read ans if [ ! -z "$ans" ] then cycle=$ans fi echo echo "Each command must complete within a timeout period, or it will be aborted" $PCP_ECHO_PROG $PCP_ECHO_N "by the \"$iam\" PMDA. Enter the timeout period (in seconds) [$timeout] ""$PCP_ECHO_C" read ans if [ ! -z "$ans" ] then timeout=$ans fi if [ "$do_debug" = true ] then echo $PCP_ECHO_PROG $PCP_ECHO_N "Enter the debugging flag (see pmdbg(1)) [$debug] ""$PCP_ECHO_C" read ans if [ ! -z "$ans" ] then debug=$ans fi fi args="-I $cycle -t $timeout -D $debug $configfile" fi pmdaInstall _quit 0 pcp-3.8.12ubuntu1/src/pmdas/shping/pmlogconf.summary0000664000000000000000000000022412272262501017366 0ustar #pmlogconf-setup 2.0 ident shping PMDA summary information probe shping.status exists ? include : exclude shping.status shping.time shping.error pcp-3.8.12ubuntu1/src/pmdas/shping/GNUmakefile0000664000000000000000000000407712272262501016047 0ustar # # Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = shping DOMAIN = SHPING CMDTARGETS = $(IAM)$(EXECSUFFIX) HFILES = shping.h CFILES = shping.c pmda.c OTHERS = README root help pmns sample.conf CHARTS = shping.CPUTime.pmchart shping.RealTime.pmchart PMIECS = shping.status.pmie shping.response.pmie LSRCFILES = $(OTHERS) $(CHARTS) $(PMIECS) Install Remove pmlogconf.summary LLDLIBS = $(PCP_PMDALIB) $(LIB_FOR_PTHREADS) PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) PMCHART = $(PCP_VAR_DIR)/config/pmchart PMIE = $(PCP_VAR_DIR)/config/pmieconf/$(IAM) LDIRT = *.log *.dir *.pag so_locations a.out domain.h $(CMDTARGETS) default: build-me include $(TOPDIR)/src/include/buildrules ifneq "$(TARGET_OS)" "mingw" build-me: $(CMDTARGETS) install: build-me $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 $(OTHERS) domain.h $(PMDADIR) $(INSTALL) -m 644 shping.CPUTime.pmchart $(PMCHART)/shping.CPUTime $(INSTALL) -m 644 shping.RealTime.pmchart $(PMCHART)/shping.RealTime $(INSTALL) -m 755 -d $(PMIE) $(INSTALL) -m 644 shping.status.pmie $(PMIE)/status $(INSTALL) -m 644 shping.response.pmie $(PMIE)/response $(INSTALL) -m 755 -d $(PCP_VAR_DIR)/config/pmlogconf/$(IAM) $(INSTALL) -m 644 pmlogconf.summary $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)/summary else build-me: install: endif $(IAM)$(EXECSUFFIX): $(OBJECTS) shping.o pmda.o: domain.h domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmdas/shping/root0000664000000000000000000000016212272262501014672 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { shping } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/shping/pmns0000664000000000000000000000217012272262501014665 0ustar /* * Metrics for shping PMDA * * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ shping { status SHPING:0:6 error SHPING:0:10 time cmd SHPING:0:7 control } shping.time { real SHPING:0:0 cpu_usr SHPING:0:1 cpu_sys SHPING:0:2 } shping.control { numcmd SHPING:0:3 cycles SHPING:0:9 cycletime SHPING:0:4 timeout SHPING:0:5 debug SHPING:0:8 } pcp-3.8.12ubuntu1/src/pmdas/shping/shping.c0000664000000000000000000004003112272262501015417 0ustar /* * Copyright (c) 2012 Red Hat. * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "shping.h" #include "domain.h" #include #if defined(HAVE_SYS_WAIT_H) #include #endif #if defined(HAVE_SYS_RESOURCE_H) #include #endif #if defined(HAVE_SYS_PRCTL_H) #include #endif #if defined(HAVE_SCHED_H) #include #endif #if defined(HAVE_PTHREAD_H) #include #endif #define LOG_PRI(p) ((p) & LOG_PRIMASK) static int cycles; /* completed cycles */ static int numskip; /* skipped cycles */ static int numcmd; /* number of commands */ static int timedout; /* command timed out */ static pid_t shpid; /* for /sbin/sh running command */ #if defined(HAVE_PTHREAD_H) static pthread_t sprocpid; #elif defined(HAVE_SCHED_H) pid_t sprocpid; /* for refresh() */ #else #error "Need pthreads or sproc" #endif /* * only one instance domain here ... */ #define SHPING_INDOM 0 pmdaIndom indomtab = { 0, 0, NULL }; /* * all metrics supported in this PMDA - one table entry for each */ static pmdaMetric metrics[] = { /* time.real */ { NULL, { PMDA_PMID(0,0), PM_TYPE_FLOAT, SHPING_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0), }, }, /* time.cpu_usr */ { NULL, { PMDA_PMID(0,1), PM_TYPE_FLOAT, SHPING_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0), }, }, /* time.cpu_sys */ { NULL, { PMDA_PMID(0,2), PM_TYPE_FLOAT, SHPING_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_MSEC,0), }, }, /* control.numcmd */ { NULL, { PMDA_PMID(0,3),PM_TYPE_U32,PM_INDOM_NULL,PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0), }, }, /* control.cycletime */ { NULL, { PMDA_PMID(0,4),PM_TYPE_U32,PM_INDOM_NULL,PM_SEM_DISCRETE, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0), }, }, /* control.timeout */ { NULL, { PMDA_PMID(0,5),PM_TYPE_U32,PM_INDOM_NULL,PM_SEM_DISCRETE, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0), }, }, /* status */ { NULL, { PMDA_PMID(0,6),PM_TYPE_32,SHPING_INDOM,PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0), }, }, /* cmd */ { NULL, { PMDA_PMID(0,7),PM_TYPE_STRING,SHPING_INDOM,PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0), }, }, /* control.debug */ { NULL, { PMDA_PMID(0,8),PM_TYPE_32,PM_INDOM_NULL,PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0), }, }, /* control.cycles */ { NULL, { PMDA_PMID(0,9),PM_TYPE_U32,PM_INDOM_NULL,PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE), }, }, /* error */ { NULL, { PMDA_PMID(0,10),PM_TYPE_32,SHPING_INDOM,PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0), }, }, }; static int nummetric = (sizeof(metrics)/sizeof(metrics[0])); void logmessage(int priority, const char *format, ...) { va_list arglist; char buffer[2048]; char *level; char *p; time_t now; buffer[0] = '\0'; time(&now); priority = LOG_PRI(priority); switch (priority) { case LOG_EMERG : level = "Emergency"; break; case LOG_ALERT : level = "Alert"; break; case LOG_CRIT : level = "Critical"; break; case LOG_ERR : level = "Error"; break; case LOG_WARNING : level = "Warning"; break; case LOG_NOTICE : level = "Notice"; break; case LOG_INFO : level = "Info"; break; case LOG_DEBUG : level = "Debug"; break; default: level = "???"; break; } va_start (arglist, format); vsnprintf (buffer, sizeof(buffer), format, arglist); /* strip unwanted '\n' at end of text so's not to double up */ for (p = buffer; *p; p++); if (*(--p) == '\n') *p = '\0'; fprintf (stderr, "[%.19s] %s(%" FMT_PID ") %s: %s\n", ctime(&now), pmProgname, getpid(), level, buffer) ; va_end (arglist) ; } static void onhup(int dummy) { _exit(0); } static void onalarm(int dummy) { timedout = 1; if (shpid > 1) { /* something other than error, self or init */ kill(-shpid, SIGTERM); /* nuke process group */ sleep(1); kill(-shpid, SIGKILL); } signal(SIGALRM, onalarm); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) fprintf(stderr, "Timeout!\n"); #endif } /* * the sproc starts here to refresh the metric values periodically */ static void refresh(void *dummy) { int i; int sts; int waittime; struct timeval startcycle; struct timeval now; struct timeval then; struct rusage cpu_now; struct rusage cpu_then; char *argv[4]; signal(SIGHUP, onhup); #if defined (PR_TERMCHILD) prctl(PR_TERMCHILD); /* SIGHUP when the parent dies */ #elif defined (PR_SET_PDEATHSIG) prctl(PR_SET_PDEATHSIG, SIGTERM); #elif defined(IS_SOLARIS) || defined(IS_DARWIN) || defined(IS_MINGW) || defined(IS_AIX) || defined(IS_FREEBSD) || defined(IS_NETBSD) /* no signals here for child exit */ #else !bozo: cant decide between PR_TERMCHILD and PR_SET_PDEATHSIG #endif signal(SIGALRM, onalarm); putenv("IFS= \t\n"); putenv("PATH=/usr/sbin:/usr/bsd:/sbin:/usr/bin:/bin"); argv[0] = "sh"; argv[1] = "-c"; argv[2] = ""; argv[3] = NULL; for ( ; ; ) { cycles++; __pmtimevalNow(&startcycle); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) fprintf(stderr, "\nStart cycle @ %s", ctime(&startcycle.tv_sec)); #endif for (i = 0; i < numcmd; i++) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) fprintf(stderr, "[%s] %s ->\n", cmdlist[i].tag, cmdlist[i].cmd); #endif getrusage(RUSAGE_CHILDREN, &cpu_then); __pmtimevalNow(&then); fflush(stderr); fflush(stdout); shpid = fork(); if (shpid == 0) { int j; setsid(); /* make new process group */ for (j = 0; j < NOFILE; j++) close(j); open("/dev/null", O_RDONLY, 0); sts = -1; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { FILE *f; if ((f = fopen("shping.out", "a")) != NULL) { fprintf(f, "\n[%s] %s\n", cmdlist[i].tag, cmdlist[i].cmd); fclose(f); } sts = open("shping.out", O_WRONLY|O_APPEND|O_CREAT, 0644); } #endif if (sts == -1) open("/dev/null", O_WRONLY, 0); if (dup(1) == -1) { fprintf(stderr, "Warning: dup() failed: %s\n", pmErrStr(-oserror())); } argv[2] = cmdlist[i].cmd; sts = execv("/bin/sh", argv); exit(-1); } else if (shpid < 0) { logmessage(LOG_CRIT, "refresh: fork() failed: %s", osstrerror()); cmdlist[i].status = STATUS_SYS; cmdlist[i].error = oserror(); cmdlist[i].real = cmdlist[i].usr = cmdlist[i].sys = -1; continue; } timedout = 0; alarm(timeout); waitpid(shpid, &sts, 0); __pmtimevalNow(&now); getrusage(RUSAGE_CHILDREN, &cpu_now); alarm(0); if (timedout) { cmdlist[i].error = PM_ERR_TIMEOUT; cmdlist[i].status = STATUS_TIMEOUT; cmdlist[i].real = cmdlist[i].usr = cmdlist[i].sys = -1; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) logmessage(LOG_INFO, "[%s] timeout\n", cmdlist[i].tag); #endif } else { if (WIFEXITED(sts)) { cmdlist[i].error = WEXITSTATUS(sts); if (cmdlist[i].error == 0) cmdlist[i].status = STATUS_OK; else { cmdlist[i].status = STATUS_EXIT; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) logmessage(LOG_INFO, "[%s] exit status: %d\n", cmdlist[i].tag, cmdlist[i].error); #endif } } else if (WIFSIGNALED(sts)) { cmdlist[i].error = WTERMSIG(sts); cmdlist[i].status = STATUS_SIG; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) logmessage(LOG_INFO, "[%s] killed signal: %d\n", cmdlist[i].tag, cmdlist[i].error); #endif } else { /* assume WIFSTOPPED(sts) */ cmdlist[i].error = WSTOPSIG(sts); cmdlist[i].status = STATUS_SIG; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) logmessage(LOG_INFO, "[%s] stopped signal: %d\n", cmdlist[i].tag, cmdlist[i].error); #endif } cmdlist[i].real = 1000 * (float)(now.tv_sec - then.tv_sec) + (float)(now.tv_usec - then.tv_usec) / 1000; cmdlist[i].usr = 1000 * (float)(cpu_now.ru_utime.tv_sec - cpu_then.ru_utime.tv_sec) + (float)(cpu_now.ru_utime.tv_usec - cpu_then.ru_utime.tv_usec) / 1000; cmdlist[i].sys = 1000 * (float)(cpu_now.ru_stime.tv_sec - cpu_then.ru_stime.tv_sec) + (float)(cpu_now.ru_stime.tv_usec - cpu_then.ru_stime.tv_usec) / 1000; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) fprintf(stderr, "status: %d error: %d real: %.3f usr: %.3f sys: %.3f\n\n", cmdlist[i].status, cmdlist[i].error, cmdlist[i].real, cmdlist[i].usr, cmdlist[i].sys); #endif } /* * harvest delinquent children ... includes those who were fork()'d * above, and timed out. */ for ( ; ; ) { sts = waitpid(-1, NULL, WNOHANG); if (sts <= 0) break; } __pmtimevalNow(&now); if (cycletime) { waittime = (int)cycletime - now.tv_sec + startcycle.tv_sec; if (waittime < 0) { /* can't keep up */ while (waittime < 0) { numskip++; waittime += cycletime; } } sleep(waittime); } } } static int shping_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *ext) { int i; /* over pmidlist[] */ int j; /* over vset->vlist[] */ int sts; int need; int inst; int numval; static pmResult *res = NULL; static int maxnpmids = 0; pmValueSet *vset; __pmID_int *pmidp; pmAtomValue atom; pmDesc *dp = NULL; int type; #ifndef HAVE_SPROC /* In the pthread world we don't have asyncronous notification that * a thread has died, so we use pthread_kill to check is refresh * is still running. */ int err; if ( (err = pthread_kill (sprocpid, 0)) != 0 ) { logmessage (LOG_CRIT, "'refresh' thread is not responding: %s\n", strerror (err)); exit (1); } #endif if (numpmid > maxnpmids) { if (res != NULL) free(res); /* (numpmid - 1) because there's room for one valueSet in a pmResult */ need = sizeof(pmResult) + (numpmid - 1) * sizeof(pmValueSet *); if ((res = (pmResult *) malloc(need)) == NULL) return -oserror(); maxnpmids = numpmid; } res->timestamp.tv_sec = 0; res->timestamp.tv_usec = 0; res->numpmid = numpmid; for (i = 0; i < numpmid; i++) { pmidp = (__pmID_int*)&pmidlist[i]; dp = NULL; if (ext->e_direct) { if (pmidp->cluster == 0 && pmidp->item < nummetric) dp = &metrics[pmidp->item].m_desc; } else { for (j = 1; jcluster == 0 && metrics[j].m_desc.pmid == pmidlist[i]) { dp = &metrics[j].m_desc; break; } } } if (dp == NULL) numval = PM_ERR_PMID; else { if (dp->indom != PM_INDOM_NULL) { numval = 0; __pmdaStartInst(dp->indom, ext); while(__pmdaNextInst(&inst, ext)) { numval++; } } else { numval = 1; } } if (numval >= 1) res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue)); else res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) - sizeof(pmValue)); if (vset == NULL) { if (i) { res->numpmid = i; __pmFreeResultValues(res); } return -oserror(); } vset->pmid = pmidlist[i]; vset->numval = numval; vset->valfmt = PM_VAL_INSITU; if (vset->numval <= 0) continue; if (dp->indom == PM_INDOM_NULL) inst = PM_IN_NULL; else { __pmdaStartInst(dp->indom, ext); __pmdaNextInst(&inst, ext); } type = dp->type; pmidp = (__pmID_int *)&pmidlist[i]; j = 0; do { if (j == numval) { /* more instances than expected! */ numval++; res->vset[i] = vset = (pmValueSet *)realloc(vset, sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue)); if (vset == NULL) { if (i) { res->numpmid = i; __pmFreeResultValues(res); } return -oserror(); } } vset->vlist[j].inst = inst; if (pmidp->cluster == 0) { switch (pmidp->item) { case 0: /* shping.time.real PMID: ...0.0 */ atom.f = cmdlist[inst].real; break; case 1: /* shping.time.cpu_usr PMID: ...0.1 */ atom.f = cmdlist[inst].usr; break; case 2: /* shping.time.cpu_sys PMID: ...0.2 */ atom.f = cmdlist[inst].sys; break; case 3: /* shping.control.numcmd PMID: ...0.3 */ atom.ul = numcmd; break; case 4: /* shping.control.cycletime PMID: ...0.4 */ atom.ul = cycletime; break; case 5: /* shping.control.timeout PMID: ...0.5 */ atom.ul = timeout; break; case 6: /* shping.status PMID: ...0.6 */ atom.l = cmdlist[inst].status; break; case 7: /* shping.cmd PMID: ...0.7 */ atom.cp = cmdlist[inst].cmd; break; case 8: /* shping.control.debug PMID: ...0.8 */ atom.l = pmDebug; break; case 9: /* shping.control.cycles PMID: ...0.9 */ atom.ul = cycles; break; case 10: /* shping.error PMID: ...0.10 */ atom.ul = cmdlist[inst].error; break; default: j = PM_ERR_PMID; break; } } if (j < 0) break; sts = __pmStuffValue(&atom, &vset->vlist[j], type); if (sts < 0) { __pmFreeResultValues(res); return sts; } vset->valfmt = sts; j++; /* next element in vlist[] for next instance */ } while (dp->indom != PM_INDOM_NULL && __pmdaNextInst(&inst, ext)); vset->numval = j; } *resp = res; return 0; } static int shping_store(pmResult *result, pmdaExt *ext) { int i; pmValueSet *vsp; int sts = 0; int ival; __pmID_int *pmidp; for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; pmidp = (__pmID_int *)&vsp->pmid; if (pmidp->cluster == 0) { switch (pmidp->item) { case 4: /* shping.control.cycletime PMID: ...0.4 */ ival = vsp->vlist[0].value.lval; if (ival < 0) { sts = PM_ERR_SIGN; break; } cycletime = ival; break; case 5: /* shping.control.timeout PMID: ...0.5 */ ival = vsp->vlist[0].value.lval; if (ival < 0) { sts = PM_ERR_SIGN; break; } timeout = ival; break; case 8: /* shping.control.debug PMID: ...0.8 */ ival = vsp->vlist[0].value.lval; if (ival < 0) { sts = PM_ERR_SIGN; break; } pmDebug = ival; break; default: sts = PM_ERR_PMID; break; } } else { /* not one of the metrics we are willing to change */ sts = PM_ERR_PMID; break; } } return sts; } void shping_init(pmdaInterface *dp) { if (dp->status != 0) return; unlink("shping.out"); /* just in case */ dp->version.two.fetch = shping_fetch; dp->version.two.store = shping_store; pmdaInit(dp, &indomtab, 1, metrics, nummetric); if (dp->version.two.ext->e_direct == 0) { logmessage(LOG_CRIT, "Metric tables require direct mapping.\n"); dp->status = -1; return; } numcmd = indomtab.it_numinst; /* start the sproc for async fetches */ #ifdef HAVE_SPROC if ( (sprocpid = sproc(refresh, PR_SADDR, NULL)) < 0 ) { logmessage(LOG_CRIT, "sproc failed: %s\n", osstrerror()); dp->status = sprocpid; } else { dp->status = 0; logmessage(LOG_INFO, "Started sproc (spid=%" FMT_PID ")\n", sprocpid); } /* we're talking to pmcd ... no timeout's for us thanks */ signal(SIGALRM, SIG_IGN); #elif defined (HAVE_PTHREAD_H) { int err = pthread_create(&sprocpid, NULL, (void (*))refresh, NULL); if ( err != 0 ) { logmessage (LOG_CRIT, "Cannot spawn a new thread: %s\n", strerror (err)); dp->status = err; } else { dp->status = 0; logmessage (LOG_INFO, "Started refresh thread\n"); } } #else #error "Need pthreads or sproc" #endif } pcp-3.8.12ubuntu1/src/pmdas/shping/pmda.c0000664000000000000000000001405012272262501015052 0ustar /* * sh(1) ping PMDA * * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "shping.h" #include "domain.h" __uint32_t cycletime = 120; /* default cycle time, 2 minutes */ __uint32_t timeout = 20; /* response timeout in seconds */ static char *username; /* user account to run under */ cmd_t *cmdlist; #ifdef HAVE_SPROC /* Signals are only used with sproc, threads will never generate SIGGHLD */ void onchld(int s) { int done; int waitStatus; int die = 0; while ((done = waitpid(-1, &waitStatus, WNOHANG)) > 0) { if (done != sprocpid) continue; die = 1; if (WIFEXITED(waitStatus)) { if (WEXITSTATUS(waitStatus) == 0) logmessage(LOG_INFO, "Sproc (pid=%d) exited normally\n", done); else logmessage(LOG_CRIT, "Sproc (pid=%d) exited with status = %d\n", done, WEXITSTATUS(waitStatus)); } else if (WIFSIGNALED(waitStatus)) { if (WCOREDUMP(waitStatus)) logmessage(LOG_CRIT, "Sproc (pid=%d) received signal = %d and dumped core\n", done, WTERMSIG(waitStatus)); else logmessage(LOG_CRIT, "Sproc (pid=%d) received signal = %d\n", done, WTERMSIG(waitStatus)); } else { logmessage(LOG_CRIT, "Sproc (pid=%d) died, reason unknown\n", done); } } if (die) { logmessage(LOG_INFO, "Main process exiting\n"); exit(0); } } #endif void usage(void) { fprintf(stderr, "Usage: %s [options] configfile\n\n\ Options:\n\ -C parse configuration file and exit\n\ -d domain use domain (numeric) for metrics domain of PMDA\n\ -I interval cycle time in seconds between subsequent executions of each\n\ command [default 120 seconds]\n\ -l logfile write log into logfile rather than using the default log\n\ -t timeout time in seconds before aborting the wait for individual\n\ commands to complete [default 20 seconds]\n\ -U username run the agent and commands as alternate user [default \"pcp\"]\n", pmProgname); exit(1); } int main(int argc, char **argv) { pmdaInterface dispatch; int n = 0; int i; int err = 0; int sep = __pmPathSeparator(); int line; int numcmd = 0; int parseonly = 0; char *configfile; FILE *conf; char *endnum; char *p; char *tag; char lbuf[256]; char mypath[MAXPATHLEN]; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(mypath, sizeof(mypath), "%s%c" "shping" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_2, pmProgname, SHPING, "shping.log", mypath); while ((n = pmdaGetOpt(argc, argv,"CD:d:I:l:t:U:?", &dispatch, &err)) != EOF) { switch (n) { case 'C': parseonly = 1; break; case 'I': cycletime = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0') { fprintf(stderr, "%s: -I requires number of seconds as argument\n", pmProgname); err++; } break; case 't': timeout = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0') { fprintf(stderr, "%s: -t requires number of seconds as argument\n", pmProgname); err++; } break; case 'U': username = optarg; break; case '?': err++; } } if (err || optind != argc -1) { usage(); } configfile = argv[optind]; if ((conf = fopen(configfile, "r")) == NULL) { fprintf(stderr, "%s: Unable to open config file \"%s\": %s\n", pmProgname, configfile, osstrerror()); exit(1); } line = 0; for ( ; ; ) { if (fgets(lbuf, sizeof(lbuf), conf) == NULL) break; line++; p = lbuf; while (*p && isspace((int)*p)) p++; if (*p == '\0' || *p == '\n' || *p == '#') continue; tag = p++; while (*p && !isspace((int)*p)) p++; if (*p) *p++ = '\0'; while (*p && isspace((int)*p)) p++; if (*p == '\0' || *p == '\n') { fprintf(stderr, "[%s:%d] missing command after tag \"%s\"\n", configfile, line, tag); exit(1); } numcmd++; if (parseonly) continue; if ((cmdlist = (cmd_t *)realloc(cmdlist, numcmd * sizeof(cmd_t))) == NULL) { __pmNoMem("main:cmdlist", numcmd * sizeof(cmd_t), PM_FATAL_ERR); } cmdlist[numcmd-1].tag = strdup(tag); cmdlist[numcmd-1].cmd = strdup(p); cmdlist[numcmd-1].status = STATUS_NOTYET; cmdlist[numcmd-1].error = 0; cmdlist[numcmd-1].real = cmdlist[numcmd-1].usr = cmdlist[numcmd-1].sys = -1; /* trim trailing newline */ p = cmdlist[numcmd-1].cmd; while (*p && *p != '\n') p++; *p = '\0'; } fclose(conf); if (numcmd == 0) { fprintf(stderr, "%s: No commands in config file \"%s\"?\n", pmProgname, configfile); exit(1); } else if (parseonly) exit(0); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "Parsed %d commands\n", numcmd); fprintf(stderr, "Tag\tCommand\n"); for (i = 0; i < numcmd; i++) { fprintf(stderr, "[%s]\t%s\n", cmdlist[i].tag, cmdlist[i].cmd); } } #endif /* set up indom description */ indomtab.it_numinst = numcmd; if ((indomtab.it_set = (pmdaInstid *)malloc(numcmd*sizeof(pmdaInstid))) == NULL) { __pmNoMem("main.indomtab", numcmd * sizeof(pmdaInstid), PM_FATAL_ERR); } for (i = 0; i < numcmd; i++) { indomtab.it_set[i].i_inst = i; indomtab.it_set[i].i_name = cmdlist[i].tag; } #ifdef HAVE_SPROC signal(SIGCHLD, onchld); #endif pmdaOpenLog(&dispatch); __pmSetProcessIdentity(username); shping_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/shping/shping.response.pmie0000664000000000000000000000274312272262501017774 0ustar #pmieconf-rules 1 # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) rule shping.response summary = "$rule$" enumerate = hosts predicate = "some_inst ( shping.time.real $hosts$ > $threshold$ && shping.status $hosts$ == 0 )" enabled = no version = 1 help = "A monitored application or service probe from the shping PMDA has taken more than threshold milliseconds to complete. If this rule is enabled, the shping PMDA should be installed; see $PCP_PMDAS_DIR/shping/README and pmdashping(1). If some application or service is not available then the corresponding line should be commented out of the shping configuration file ($PCP_PMDAS_DIR/shping/shping.conf by default) and the shping PMDA restarted."; string rule default = "Shell-ping PMDA slow application or service response" modify = no display = no; unsigned threshold default = 3000 help = "Threshold time, in milliseconds, for command to run to completion."; string action_expand default = %vmsec[%i] display = no modify = no; string email_expand default = "service: %i response time: %vmsec" display = no modify = no; # Configuration info specific to non-PCP tools follows... # # for SGI Embedded Support Partner integration: string esp_type default = "0x200095" display = no modify = no; # for EnlightenDSM integration: string enln_test default = shping.response display = no modify = no; string enln_units default = msec[%i] display = no modify = no; # # --- DO NOT MODIFY THIS FILE --- see pmieconf(4) pcp-3.8.12ubuntu1/src/pmdas/shping/help0000664000000000000000000001271212272262501014643 0ustar # # Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # shping PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ 19.0 shping command instance domain There is one instance for each command run by the shping PMDA. The external instance name comes from the "tag" in the shping PMDA configuration file. The internal instance number is the ordinal command number in the configuration file. @ shping.error command execution error code for shping PMDA As each command is executed, if there is a problem, the error code or cause is stored in shping.error. The interpretation of the value for shping.error depends on shping.status as follows: If shping.status is 1 (the command was run but returned a non-zero exit status) then shping.error is the exit status. If shping.status is 2 (the command was run but was terminated by a signal) then shping.error is the signal number. If shping.status is 3 (the command did not complete) then shping.error is a PCP error codes: see pmerr(1). Of particular relevance is -1008 (PM_ERR_TIMEOUT) when the command failed to complete in the time specified by shping.control.timeout. If shping.status is 4 (the commands was not run) then shping.error is the value of the system error code. Otherwise shping.error will be zero. @ shping.status command execution status for shping PMDA As each command is executed, the success or failure is encoded in shping.status, using the following values: -1 PMDA is initializing and command has not been run yet 0 command completed and exit status was 0 1 command completed and exit status was non-zero 2 command was run but terminated by a signal 3 command was run but did not complete (usually a timeout) 4 command was not run due to some system error or resource availability @ shping.time.real elapsed time for a command This metric records the elapsed time in milliseconds for the most recent execution of each command to be run by the shping PMDA. Care should be used when interpreting the value if the corresponding value for shping.status is non-zero, as the command may not have run to completion. If the command timed out, shping.time.real will be -1. @ shping.time.cpu_usr user mode CPU time for a command This metric records the user mode CPU time in milliseconds for the most recent execution of each command to be run by the shping PMDA. Care should be used when interpreting the value if the corresponding value for shping.status is non-zero, as the command may not have run to completion. If the command timed out, shping.time.cpu_usr will be -1. @ shping.time.cpu_sys system mode CPU time for a command This metric records the system mode CPU time in milliseconds for the most recent execution of each command to be run by the shping PMDA. Care should be used when interpreting the value if the corresponding value for shping.status is non-zero, as the command may not have run to completion. If the command timed out, shping.time.cpu_sys will be -1. @ shping.cmd commands run by shping PMDA The text of each sh(1) command run by the shping PMDA. @ shping.control.numcmd number of commands in the group to be run by the shping PMDA @ shping.control.cycles number of times the command group has been run by the shping PMDA @ shping.control.cycletime shping PMDA cycle time All commands are run by the shping PMDA are executed one after another in a group, and the group is run once per "cycle" time. This metric reports the cycle time in seconds. The cycle time may be changed dynamically by modifying this metric with pmstore(1). @ shping.control.timeout shping PMDA timeout period The number of seconds the shping PMDA is willing to wait before considering a single command to have timed out and killing it off. The time out interval may be changed dynamically by modifying this metric with pmstore(1). @ shping.control.debug shping PMDA debug flag The debug flag for the shping PMDA (see pmdbg(1)). All trace and diagnostic files are created in $PCP_LOG_DIR/pmcd. The debug flags DBG_TRACE_APPL0 (2048) and DBG_TRACE_APPL1 (4096) may be used as follows: DBG_TRACE_APPL0 - additional trace messages associated with the running of each command appear in shping.log DBG_TRACE_APPL1 - the standard output and standard error of each command is appended to shping.out (instead of the default /dev/null) The debug flags may be changed dynamically by modifying this metric with pmstore(1), e.g. $ pmstore shping.control.debug 6144 would enable both of the diagnostic traces associated with DBG_TRACE_APPL0 and DBG_TRACE_APPL1. pcp-3.8.12ubuntu1/src/pmdas/hotproc/0000775000000000000000000000000012272262620014155 5ustar pcp-3.8.12ubuntu1/src/pmdas/hotproc/help.hotproc0000664000000000000000000001477712272262501016523 0ustar @ hotproc.cpuburn CPU utilization per "interesting" process CPU utilization, or the fraction of time that each "interesting" process was executing (user and system time) over the last refresh interval. Also known as the "cpuburn" time. @ hotproc.control.refresh time in secs between refreshes Controls how long it takes before the "interesting" process list is refreshed and new cpuburn times (see hotproc.cpuburn) calculated. This value can be changed at any time by using pmstore(1) if the permission is given during installation of the hotproc PMDA. Once the value is changed, the instances will not be available until after the new refresh period has elapsed. @ hotproc.control.config configuration predicate The configuration predicate that is used to characterize "interesting" processes. This will initially be the predicate as specified in the configuration file. This value can be changed at any time by using pmstore(1) if the permission is given during installation of the hotproc PMDA. Once the value is changed, the instances will not be available until after the refresh period has elapsed. @ hotproc.control.config_gen configuration generation number Each time the configuration predicate is updated (see hotproc.control.config) the configuration generation number is incremented. @ hotproc.total.cpuburn total amount of cpuburn over all "interesting" processes The sum of the CPU utilization ("cpuburn" or the fraction of time that each process was executing in user or system mode over the last refresh interval) for all the "interesting" processes. Values are in the range 0 to the number of CPUs. @ hotproc.total.cpuidle fraction of CPU idle time The fraction of all CPU time classified as idle over the last refresh interval. @ hotproc.total.cpuother.not_cpuburn total amount of cpuburn over all uninteresting processes The sum of the CPU utilization ("cpuburn" or the fraction of time that each process was executing in user or system mode over the last refresh interval) for all the "uninteresting" processes. If this value is high in comparison to hotproc.total.cpuburn, then configuration predicate of the hotproc PMDA is classifying a significant fraction of the CPU utilization to processes that are not "interesting". Values are in the range 0 to the number of CPUs. @ hotproc.total.cpuother.transient fraction of time utilized by "transient" processes The total CPU utilization (fraction of time that each process was executing in user or system mode) for processes which are not present throughout the most recent refreshes interval. The hotproc PMDA is limited to selecting processes which are present throughout each refresh intervals. If processes come and/or go during a refresh interval then they will never be considered. This metric gives an indication of the level of activity of these "transient" processes. If the value is large in comparison to the sum of hotproc.total.cpuburn and hotproc.total.cpuother.not_cpuburn then the "transient" processes are consuming lots of CPU time. Under these circumstances, the hotproc PMDA may be less useful, or consideration should be given to decreasing the value of the refresh interval (hotproc.control.refresh) so fewer "transient" processes escape consideration. Values are in the range 0 to the number of CPUs. @ hotproc.total.cpuother.total total amount of cpuburn other than the "interesting" processes Non-idle CPU utilization not accounted for by processes other than those deemed "interesting". It is equivalent to hotproc.total.cpuother.not_cpuburn + hotproc.total.cpuother.transient. Values are in the range 0 to the number of CPUs. @ hotproc.total.cpuother.percent how much of the cpu for "transients" and uninterestings Gives an indication of how much of the CPU time the "transient" processes and the "uninteresting" processes are accounting for. Computed as: 100 * hotproc.total.cpuother.total / number of CPUs @ hotproc.predicate.syscalls number of system calls per second over refresh interval The number of system calls per second over the last refresh interval for each "interesting" process. If the refresh interval spans times from t1 to t2, then this is calculated by: m = hotproc.psusage.pu_sysc (m@t2 - m@t1) / (t2 - t1) @ hotproc.predicate.ctxswitch number of context switches per second over refresh interval The number of context switches per second over the last refresh interval for each "interesting" process. If the refresh interval spans times from t1 to t2, then this is calculated by: m = hotproc.psusage.pu_vctx + hotproc.psusage.pu_ictx (m@t2 - m@t1) / (t2 - t1) @ hotproc.predicate.virtualsize virtual size of process in kilobytes at last refresh The virtual size of each "interesting" process in kilobytes at the last refresh time, calculated by: hotproc.psinfo.size @ hotproc.predicate.residentsize resident size of process in kilobytes at last refresh The resident size of each "interesting" process in kilobytes at the last refresh, calculated by: hotproc.psinfo.rssize @ hotproc.predicate.iodemand total kilobytes read and written per second over refresh interval The total kilobytes read and written per second over the last refresh interval for each "interesting" process. If the refresh interval spans times from t1 to t2, then this is calculated by: // bytes read() br = hotproc.psusage.bread@t2 - hotproc.psusage.bread@t1 // Gigabytes read() gbr = hotproc.psusage.gbread@t2 - hotproc.psusage.gbread@t1 // bytes write() bw = hotproc.psusage.bwrit@t2 - hotproc.psusage.bwrit@t1 // Gigabytes write() gbw = hotproc.psusage.gbwrit@t2 - hotproc.psusage.gbwrit@t1 ((gbr + gbw) * 1024 * 1024 + (br + bw) / 1024 ) / (t2 - t1) @ hotproc.predicate.iowait time in secs waiting for I/O per second over refresh interval The fraction of time waiting for I/O for each "interesting" process over refresh interval. If the refresh interval spans times from t1 to t2, then this is calculated by: bw = (hotproc.accounting.timers.bwtime@t2 - hotproc.accounting.timers.bwtime@t1) / 1000000000 rw = (hotproc.accounting.timers.rwtime@t2 - hotproc.accounting.timers.rwtime@t1) / 1000000000 (bw + rw) / (t2 - t1) @ hotproc.predicate.schedwait time in secs waiting on run queue per second over refresh interval The fraction of time waiting on the run queue for each "interesting" process over the last refresh interval. If the refresh interval spans times from t1 to t2, then this is calculated by: qw = (hotproc.accounting.timers.qwtime@t2 - hotproc.accounting.timers.qwtime@t1) / 1000000000 qw / (t2 - t1) pcp-3.8.12ubuntu1/src/pmdas/hotproc/sample.conf0000664000000000000000000000060412272262501016303 0ustar #pmdahotproc Version 1.0 # Sample configuration file for hotproc PMDA # # It selects processes who are using more than 85% of the cpu # over the refresh interval. cpuburn > 0.85 # Another example: # Reporting processes which are either # using greater than 85% cpu or # are root processes using greater than 1% cpu # ((cpuburn > 0.01) && (uname == "root")) || (cpuburn > 0.85) pcp-3.8.12ubuntu1/src/pmdas/hotproc/README0000664000000000000000000001222412272262501015034 0ustar Performance Co-Pilot hotproc PMDA for Active Process Monitoring =============================================================== This PMDA is designed to be configurable to monitor processes which the administrator deems "hot" or "interesting." The PMDA is similar to the proc PMDA except in two main aspects: (i) it extends the proc metric set by: hotproc.cpuburn, hotproc.control.*, hotproc.predicate.*, hotproc.total.* . (ii) it allows one to retrieve all the instances. It is allowed to retrieve all the instances because the set of instances is restricted by a predicate specified in a configuration file. The predicate specifies what processes are "interesting", for example, (cpuburn > 0.1 && uname == "root") and it applies this predicate every seconds. Therefore, hotproc.nprocs now refers to the number of "interesting" processes instead of the list of all the processes. To monitor how successful (according to activity) that the configuration predicate and refresh interval are, the hotproc.total.* metrics can be used. For example, hotproc.total.cpuother.transient shows how much of the cpu that transient processes (ones which do not live for the refresh interval) get. If one is interested in some of these processes then reducing the refresh interval may catch them. Hotproc.total.cpuother.not_cpuburn indicates how much of the cpu that the "uninteresting" processes are getting. On the basis of this value, one may decide to change what is "interesting" by modifying the configuration predicate. If one wants to get a simple indication of how much of the cpu that all of the transient and "uninteresting" processes are getting, then hotproc.total.cpuother.percent is the answer. In order to see why the instances (processes) of the hotproc agent were chosen, one can check the hotproc.predicate.* metrics. These metrics show the values used by the predicate evaluation at the last refresh of the instance domain. For example, if one used a predicate of (syscalls > 100), then doing: $ pminfo -f hotproc.predicate.syscalls will show the values of the system call rates of the processes which satisfy the predicate (i.e. are greater than 100 per second over the last refresh interval). Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT hotproc Installation of the hotproc PMDA ================================ + # cd $PCP_PMDAS_DIR/hotproc + Check that there is no clash with the Performance Metrics Domain number defined in domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit domain.h and choose another domain number. + Inspect the ./sample.conf file and either modify it or create a new configuration file that suits your need for "interesting". See pmdahotproc(1) for configuration specification. + Then run the Install script (as root) # ./Install and choose both the "collector" and "monitor" installation configuration options. Answer the questions, which include the option to specify the configuration file that you created. You will also need to specify a refresh interval which determines how often the "hot" predicate is used over the current set of processes. A smaller number will mean that the predicate will be able to choose processes which have short lives or sporadic activity but will consume more CPU because it is run more often. + At the end of installation a check is made to verify that the metrics of the agent can be retrieved. The reported number from this check will be low because most of the hotproc metrics will not be available until after the first refresh interval. Special TRIX Installation Considerations ======================================== For SGI Trix systems, the hotproc PMDA needs the CAP_MAC_READ capability in addition to the default capability (CAP_SCHED_MGT), before it can interrogate the resource utilization of all processes. To achieve this, run the ./Install script as described above, then 1. edit /etc/pmcd.conf and for the pmdahotproc line, replace the pmda invocation arguments $PCP_PMDAS_DIR/hotproc/pmdahotproc ... by /sbin/suattr -C CAP_SCHED_MGT,CAP_MAC_READ+ipe -c "$PCP_PMDAS_DIR/hotproc/pmdahotproc ..." 2. restart pmcd # /etc/init.d/pcp start Thanks to Roald Lygre for this recipe. De-installation =============== Simply use # cd $PCP_PMDAS_DIR/hotproc # ./Remove Changing the settings ===================== The refresh period can be dynamically modified using pmstore(1) for the metric hotproc.control.refresh. To make permanent changes, re-run the Install script. Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/hotproc.log) should be checked for any warnings or errors. + If the Install script reports some warnings when checking the metrics, the problem should be listed in one of the log files. pcp-3.8.12ubuntu1/src/pmdas/hotproc/Remove0000664000000000000000000000205012272262501015330 0ustar #!/bin/sh # # Copyright (c) 1997-2001 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the sample PMDA # # source the PCP configuration environment variables . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=hotproc # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/hotproc/fixpmns.awk0000664000000000000000000000163612272262501016351 0ustar # states # 0 nothing interesting is happening, looking for proc { ... } # 1 inside proc { ... }; want to copy all lines except # "nprocs" metric that does not come from here for the # hotproc PMDA # 2 looking for proc.foo { ... } # 3 inside proc.foo { ... }; want to copy all lines # BEGIN { print "/*" print " * Hotproc Performance Metric Domain (PMD) Identifiers" print " * (generated from pmns for hotproc and proc metrics)" print " */" print "" print "hotproc {" print " nprocs HOTPROC:100:0" print " cpuburn HOTPROC:102:0" print " total" print " predicate" print " control" state = 0 } state == 0 && /^proc / { state = 1; next } state == 1 && /nprocs/ { next } state == 1 && /^}/ { print; print ""; state = 2; next } state == 1 { print } state == 2 && /^proc\./ { state = 3 } state == 3 && /^}/ { print; print ""; state = 2; next } state == 3 { print } pcp-3.8.12ubuntu1/src/pmdas/hotproc/Makefile0000664000000000000000000000417112272262501015616 0ustar #!make LTARGETS = help.dir LLDIRT = domain.h *.log *.dir *.pag pmns help PCP_SRC_DEPTH = ../.. include $(PCP_SRC_DEPTH)/include/commondefs include $(PCP_SRC_DEPTH)/include/isacommondefs PROC_DIR = ../proc IAM = hotproc DOMAIN = HOTPROC IDBTAG = PMDA_$(DOMAIN) PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) install: default $(INSTALL) -F /usr/pcp/lib -idb "$(IDBTAG)" -lns ../../..$(PMDADIR)/pmda$(IAM) pmda$(IAM) $(INSTALL) -idb '$(IDBTAG) removeop("rm -f $$rbase$(PMDADIR)/help.*")' -m 755 -dir $(PMDADIR) $(INSTALL) -F /usr/pcp/pmdas -idb "$(IDBTAG)" -lns ../../..$(PMDADIR) $(IAM) #if $(BEFORE_IRIX6_5) $(I_32) $(INSTALL) -f $(PMDADIR) -idb "$(IDBTAG) $(MODE32) $(STRIPBIN)" -m 555 -src 32/pmda$(IAM) pmda$(IAM) $(I_64) $(INSTALL) -f $(PMDADIR) -idb "$(IDBTAG) $(MODE64) $(STRIPBIN)" -m 555 -src 64/pmda$(IAM) pmda$(IAM) #else $(I_N32) $(INSTALL) -f $(PMDADIR) -idb "$(IDBTAG) $(MODE32) $(STRIPBIN)" -m 555 -src N32/pmda$(IAM) pmda$(IAM) $(I_64) $(INSTALL) -f $(PMDADIR) -idb "$(IDBTAG) $(MODE64) $(STRIPBIN)" -m 555 -src 64/pmda$(IAM) pmda$(IAM) #endif $(INSTALL) -f $(PMDADIR) -idb "$(IDBTAG)" -m 555 Install Remove $(INSTALL) -f $(PMDADIR) -idb "$(IDBTAG)" -m 444 README root help pmns domain.h sample.conf general.conf general.pmie $(INSTALL) -f $(PMDADIR) -idb "$(IDBTAG)" -m 444 -src Makefile.install Makefile help: $(PROC_DIR)/help help.hotproc pmns sed < $(PROC_DIR)/help -e 's/proc\./hotproc./g' \ -e 's/number of processes/number of "interesting" processes/g' \ | cat - help.hotproc | ./help.fmt > $@ help.dir: domain.h help root pmns ../../buildtools/newhelp PCP_SRC_DEPTH=$(PCP_SRC_DEPTH) $(PCP_SRC_DEPTH)/buildtools/check_help_src help root pmns: $(PROC_DIR)/root_proc pmns.hotproc fixpmns.awk nawk < $(PROC_DIR)/root_proc -f fixpmns.awk \ | sed -e '/[ ]PROC:/s/PROC:/HOTPROC:/g' -e 's/^proc/hotproc/g' \ | cat - pmns.hotproc >$@ .NOTPARALLEL: .ORDER: domain.h $(OBJECTS) domain.h: ../../pmns/stdpmid rm -f domain.h echo "/*" >domain.h echo " * built from $(PCP_VAR_DIR)/pmns/stdpmid" >>domain.h echo " */" >>domain.h nawk <../../pmns/stdpmid >>domain.h '/#define[ ][ ]*$(DOMAIN)[ ]/ { print "#define $(DOMAIN) " $$3 }' pcp-3.8.12ubuntu1/src/pmdas/hotproc/Install0000664000000000000000000000652212272262501015511 0ustar #!/bin/sh # # Copyright (c) 1997-2001 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the hotproc PMDA and/or PMNS # # XXX these values are overwritten by pmdaproc.sh! tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 status=1 # failure is the default! trap "cd /; rm -rf $tmp; exit \$status" 0 1 2 3 15 . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=hotproc pmda_interface=2 forced_restart=false pmdaSetup daemon_opt=true # can install as daemon dso_opt=false pipe_opt=true # supports pipe IPC socket_opt=false # no socket IPC # be careful that mortals cannot write any configuration files, as # these would present a security problem # umask 022 # PMDA variables # configfile="" refresh=60 debug=0 storable="n" do_debug=false _parsedefaults() { echo "Extracting options from current installation ..." while getopts D:d:h:i:l:p:st:u: c do case $c in \?) echo "Warning: Unrecognized option in $PCP_PMCDCONF_PATH" echo " Remove line for the $iam PMDA in $PCP_PMCDCONF_PATH and re-run ./Install" exit 2;; D ) debug=$OPTARG;; t ) refresh=$OPTARG;; s ) storable="n";; * ) ;; esac done eval configfile='$'$OPTIND } if $do_pmda then # set options from $PCP_PMCDCONF_PATH, if possible # ans=`$PCP_AWK_PROG <$PCP_PMCDCONF_PATH ' $1 == "'$iam'" { printf "%s",$6 for (i=7;i<=NF;i++) printf " %s",$i print "" }'` if [ ! -z "$ans" ] then _parsedefaults $ans fi # go figure out which configuration file to use ... # default_configfile=./sample.conf pmdaChooseConfigFile if [ -z "$configfile" ] then echo "" echo "Error: Abandoning installation as no configuration file was specified." exit 1 fi # make sure that the chosen configuration file parses ok # $pmda_dir/$pmda_name -C $configfile >$tmp/err 2>&1 if [ $? -eq 1 ] then echo "" echo "Error: Abandoning installation due to errors in configuration file:" cat $tmp/err exit 1 fi echo echo "Enter the refresh interval (in seconds) [$refresh] \c" read ans if [ ! -z "$ans" ] then refresh=$ans fi echo echo "Do you want to modify the configuration predicate or refresh interval" echo "at run time [$storable]? \c" read ans if [ ! -z "$ans" ] then case $ans in N|n|NO|No|no) storable=n;; Y|y|YES|Yes|yes) storable=y;; esac fi if [ $storable = y ] then store_opt="" else store_opt="-s" fi if [ "$do_debug" = true ] then echo echo "Enter the debugging flag (see pmdbg(1)) [$debug] \c" read ans if [ ! -z "$ans" ] then debug=$ans fi fi args="$store_opt -t $refresh -D $debug $configfile" fi pmdaInstall echo "Please note that instance related metrics will not be available" echo "until after the initial refresh of $refresh seconds." status=0 exit 0 pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/0000775000000000000000000000000012272262620014744 5ustar pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/error.c0000664000000000000000000000223312272262501016237 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include void yywarn(s) char *s; { extern int yylineno; (void)fprintf(stderr, "Warning [line %d]\n%s\n", yylineno, s); } void yyerror(s) char *s; { extern int yylineno; extern char yytext[]; (void)fprintf(stderr, "Specification error in configuration\n"); (void)fprintf(stderr, "[line %d] %s: %s\n", yylineno, s, yytext); } pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/config.h0000664000000000000000000000376612272262501016374 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef CONFIG_H #define CONFIG_H #include typedef struct { double syscalls; double ctxswitch; double virtualsize; double residentsize; double iodemand; double iowait; double schedwait; } derived_pred_t; typedef struct { uid_t uid; /* real user id */ gid_t gid; /* real group id */ char *uname; char *gname; char fname[PRCOMSIZ]; /* basename of exec()'d pathname */ char psargs[PRARGSZ]; /* initial chars of arg list */ double cpuburn; derived_pred_t preds; /* --- ioctl buffer fields for testing purposes only --- */ /* prpsinfo_t fields */ ulong_t pr_size; ulong_t pr_rssize; /* prusage_t fields */ ulong_t pu_sysc; ulong_t pu_ictx; ulong_t pu_vctx; ulong_t pu_gbread; ulong_t pu_bread; ulong_t pu_gbwrit; ulong_t pu_bwrit; /* accounting fields */ accum_t ac_bwtime; accum_t ac_rwtime; accum_t ac_qwtime; } config_vars; #include "gram_node.h" FILE *open_config(void); void read_config(FILE *); int parse_config(bool_node **tree); void new_tree(bool_node *tree); int eval_tree(config_vars *); void dump_tree(FILE *); void do_pred_testing(void); int read_test_values(FILE *, config_vars *); #endif pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/gram_node.h0000664000000000000000000000347212272262501017054 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef GRAM_NODE_H #define GRAM_NODE_H /* --- types --- */ typedef enum { N_and, N_or, N_not, N_lt, N_le, N_gt, N_ge, N_eq, N_neq, N_seq, N_sneq, N_match, N_nmatch, N_str, N_pat, N_number, N_uid, N_gid, N_uname, N_gname, N_fname, N_psargs, N_cpuburn, N_true, N_false, N_syscalls, N_ctxswitch, N_virtualsize, N_residentsize, N_iodemand, N_iowait, N_schedwait } N_tag; typedef struct { struct bool_node *left; struct bool_node *right; } bool_children; typedef struct bool_node { N_tag tag; struct bool_node *next; union { bool_children children; char *str_val; double num_val; } data; } bool_node; /* --- functions --- */ void free_tree(bool_node *); void start_tree(void); bool_node *create_tnode(N_tag, bool_node *, bool_node *); bool_node *create_tag_node(N_tag); bool_node *create_number_node(double); bool_node *create_str_node(char *); bool_node *create_pat_node(char *); void dump_bool_tree(FILE *, bool_node *); void dump_predicate(FILE *, bool_node *); #endif pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/hotproc.h0000664000000000000000000000251512272262501016574 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PHOTPROC_H #define PHOTPROC_H #include "config.h" /* main process node type */ typedef struct process_t { pid_t pid; /* refreshed data */ ulong_t r_vctx; ulong_t r_ictx; ulong_t r_syscalls; ulong_t r_bread; ulong_t r_gbread; ulong_t r_bwrit; ulong_t r_gbwrit; float r_cpuburn; double r_cputimestamp; double r_cputime; accum_t r_bwtime; accum_t r_rwtime; accum_t r_qwtime; /* predicate values */ derived_pred_t preds; } process_t; process_t * lookup_curr_node(pid_t); #endif pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/ppred_values.c0000664000000000000000000001012112272262501017572 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "proc.h" #include "proc_aux.h" #include "cluster.h" #include "ppred_values.h" #include "hotproc.h" static pmDesc desctab[] = { /* hotproc.predicate.syscalls */ { PMID(CLUSTER_PRED,ITEM_SYSCALLS), PM_TYPE_FLOAT, PM_INDOM_PROC, PM_SEM_INSTANT, {0,-1,1, 0,PM_TIME_SEC,0} }, /* hotproc.predicate.ctxswitch */ { PMID(CLUSTER_PRED,ITEM_CTXSWITCH), PM_TYPE_FLOAT, PM_INDOM_PROC, PM_SEM_INSTANT, {0,-1,1, 0,PM_TIME_SEC,0} }, /* hotproc.predicate.virtualsize */ { PMID(CLUSTER_PRED,ITEM_VIRTUALSIZE), PM_TYPE_FLOAT, PM_INDOM_PROC, PM_SEM_INSTANT, {1,0,0, PM_SPACE_KBYTE,0,0} }, /* hotproc.predicate.residentsize */ { PMID(CLUSTER_PRED,ITEM_RESIDENTSIZE), PM_TYPE_FLOAT, PM_INDOM_PROC, PM_SEM_INSTANT, {1,0,0, PM_SPACE_KBYTE,0,0} }, /* hotproc.predicate.iodemand */ { PMID(CLUSTER_PRED,ITEM_IODEMAND), PM_TYPE_FLOAT, PM_INDOM_PROC, PM_SEM_INSTANT, {1,-1,0, PM_SPACE_KBYTE,PM_TIME_SEC,0} }, /* * NOTE * iowait and schedwait really have units of sec/sec, i.e. utilization */ /* hotproc.predicate.iowait */ { PMID(CLUSTER_PRED,ITEM_IOWAIT), PM_TYPE_FLOAT, PM_INDOM_PROC, PM_SEM_INSTANT, {0,0,0, 0,0,0} }, /* hotproc.predicate.schedwait */ { PMID(CLUSTER_PRED,ITEM_SCHEDWAIT), PM_TYPE_FLOAT, PM_INDOM_PROC, PM_SEM_INSTANT, {0,0,0, 0,0,0} }, }; static int ndesc = (sizeof(desctab)/sizeof(desctab[0])); static derived_pred_t *pred_buf = NULL; void ppred_init(int dom) { init_table(ndesc, desctab, dom); } int ppred_getdesc(pmID pmid, pmDesc *desc) { return getdesc(ndesc, desctab, pmid, desc); } int ppred_available(int item) { extern int need_psusage; /* is psusage buffer needed or not */ extern int need_accounting; /* is pracinfo buffer needed or not */ switch (item) { case ITEM_SYSCALLS: case ITEM_CTXSWITCH: case ITEM_IODEMAND: return need_psusage; case ITEM_IOWAIT: case ITEM_SCHEDWAIT: return need_accounting; case ITEM_VIRTUALSIZE: case ITEM_RESIDENTSIZE: /* need_psinfo - always have it */ return 1; } return 1; } int ppred_setatom(int item, pmAtomValue *atom, int j) { switch (item) { case ITEM_SYSCALLS: atom->f = pred_buf[j].syscalls; break; case ITEM_CTXSWITCH: atom->f = pred_buf[j].ctxswitch; break; case ITEM_VIRTUALSIZE: atom->f = pred_buf[j].virtualsize; break; case ITEM_RESIDENTSIZE: atom->f = pred_buf[j].residentsize; break; case ITEM_IODEMAND: atom->f = pred_buf[j].iodemand; break; case ITEM_IOWAIT: atom->f = pred_buf[j].iowait; break; case ITEM_SCHEDWAIT: atom->f = pred_buf[j].schedwait; break; } return 0; } int ppred_getinfo(pid_t pid, int j) { process_t *node; char *path; node = lookup_curr_node(pid); if (node == NULL) { /* node should be there if it's in active list ! */ (void)fprintf(stderr, "%s: Internal error for lookup_node()", pmProgname); exit(1); } proc_pid_to_path(pid, NULL, &path, PINFO_PATH); if (access(path, R_OK) < 0) return -oserror(); pred_buf[j] = node->preds; return 0; } int ppred_allocbuf(int size) { static int max_size = 0; derived_pred_t *predb; if (size > max_size) { predb = realloc(pred_buf, size * sizeof(derived_pred_t)); if (predb == NULL) return -oserror(); pred_buf = predb; max_size = size; } return 0; } pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/pcpu.c0000664000000000000000000000411512272262501016056 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "proc.h" #include "proc_aux.h" #include "cluster.h" #include "pcpu.h" #include "hotproc.h" static pmDesc desctab[] = { /* hotproc.cpuburn */ { PMID(CLUSTER_CPU,ITEM_CPUBURN), PM_TYPE_FLOAT, PM_INDOM_PROC, PM_SEM_INSTANT, {0,0,0,0,0,0} }, }; static int ndesc = (sizeof(desctab)/sizeof(desctab[0])); static float *cpuburn_buf = NULL; void pcpu_init(int dom) { init_table(ndesc, desctab, dom); } int pcpu_getdesc(pmID pmid, pmDesc *desc) { return getdesc(ndesc, desctab, pmid, desc); } int pcpu_setatom(int item, pmAtomValue *atom, int j) { switch (item) { case ITEM_CPUBURN: atom->f = cpuburn_buf[j]; break; } return 0; } int pcpu_getinfo(pid_t pid, int j) { process_t *node; char *path; node = lookup_curr_node(pid); if (node == NULL) { /* node should be there if it's in active list ! */ (void)fprintf(stderr, "%s: Internal error for lookup_node()", pmProgname); exit(1); } proc_pid_to_path(pid, NULL, &path, PINFO_PATH); if (access(path, R_OK) < 0) return -oserror(); cpuburn_buf[j] = node->r_cpuburn; return 0; } int pcpu_allocbuf(int size) { static int max_size = 0; float *cpub; if (size > max_size) { cpub = realloc(cpuburn_buf, size * sizeof(float)); if (cpub == NULL) return -oserror(); cpuburn_buf = cpub; max_size = size; } return 0; } pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/ppred_values.h0000664000000000000000000000241112272262501017602 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PPRED_H #define PPRED_H #define CLUSTER_PRED 101 #define ITEM_SYSCALLS 0 #define ITEM_CTXSWITCH 1 #define ITEM_VIRTUALSIZE 2 #define ITEM_RESIDENTSIZE 3 #define ITEM_IODEMAND 4 #define ITEM_IOWAIT 5 #define ITEM_SCHEDWAIT 6 void ppred_init(int dom); int ppred_getdesc(pmID pmid, pmDesc *desc); int ppred_setatom(int item, pmAtomValue *atom, int j); int ppred_getinfo(pid_t pid, int j); int ppred_allocbuf(int size); int ppred_available(int item); #endif pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/Makefile0000664000000000000000000000462312272262501016407 0ustar #!make PCP_SRC_DEPTH = ../../.. include versiondefs include $(ROOT)/usr/include/make/commondefs include $(PCP_SRC_DEPTH)/include/commondefs TARGETS = $(FROM_PROC) pmda$(IAM) PROC_DIR = ../../proc PROC_SRCDIR = $(PROC_DIR)/src FROM_PROC_H = cluster.h pracinfo.h proc_aux.h pscred.h \ pstatus.h pmemory.h proc.h procmem.h psinfo.h \ psusage.h ctltab.h nameinfo.h FROM_PROC_C = pmemory.c pracinfo.c proc_aux.c \ pscred.c psinfo.c pstatus.c psusage.c \ ttyname.c procmem.c nameinfo.c FROM_PROC = $(FROM_PROC_C) $(FROM_PROC_H) CFILES = $(FROM_PROC_C) \ pglobal.c ctltab.c hotproc.c pcpu.c \ config.c gram_node.c error.c ppred_values.c OBJECTS = gram.o lex.o $(CFILES:S/.c/.o/g) LCOPTS = -fullwarn LCINCS = $(PCP_INC_PATH) LCDEFS = $(DEBUG) LLDOPTS = $(PCP_LIBS_PATH) LLDLIBS = -lpcp_dev -lpcp_pmda -lpcp -lc -ll IAM = hotproc DOMAIN = HOTPROC LDIRT = ../domain.h gram.h yy.lex.c y.tab.? default: ../domain.h $(TARGETS) include $(COMMONRULES) install: default pmda$(IAM): $(OBJECTS) rm -f $@ $(CCF) -o $@ $(OBJECTS) $(LDOPTS) $(LDLIBS) $(TAG) 0x00010D01 $@ # # PROC_SRCDIR dependencies # cluster.h: $(PROC_SRCDIR)/cluster.h ln -s $? $@ pracinfo.h: $(PROC_SRCDIR)/pracinfo.h ln -s $? $@ pracinfo.c: $(PROC_SRCDIR)/pracinfo.c ln -s $? $@ proc_aux.h: $(PROC_SRCDIR)/proc_aux.h ln -s $? $@ proc_aux.c: $(PROC_SRCDIR)/proc_aux.c ln -s $? $@ pscred.h: $(PROC_SRCDIR)/pscred.h ln -s $? $@ pscred.c: $(PROC_SRCDIR)/pscred.c ln -s $? $@ pstatus.h: $(PROC_SRCDIR)/pstatus.h ln -s $? $@ pstatus.c: $(PROC_SRCDIR)/pstatus.c ln -s $? $@ pmemory.h: $(PROC_SRCDIR)/pmemory.h ln -s $? $@ pmemory.c: $(PROC_SRCDIR)/pmemory.c ln -s $? $@ proc.h: $(PROC_SRCDIR)/proc.h ln -s $? $@ procmem.h: $(PROC_SRCDIR)/procmem.h ln -s $? $@ procmem.c: $(PROC_SRCDIR)/procmem.c ln -s $? $@ psinfo.h: $(PROC_SRCDIR)/psinfo.h ln -s $? $@ psinfo.c: $(PROC_SRCDIR)/psinfo.c ln -s $? $@ psusage.h: $(PROC_SRCDIR)/psusage.h ln -s $? $@ psusage.c: $(PROC_SRCDIR)/psusage.c ln -s $? $@ ttyname.c: $(PROC_SRCDIR)/ttyname.c ln -s $? $@ ctltab.h: $(PROC_SRCDIR)/ctltab.h ln -s $? $@ nameinfo.h: $(PROC_SRCDIR)/nameinfo.h ln -s $? $@ nameinfo.c: $(PROC_SRCDIR)/nameinfo.c ln -s $? $@ # grammar stuff lex.o gram.o config.o: gram.h gram.h: gram.y $(YACC) -d gram.y -if cmp -s y.tab.h $@; then rm y.tab.h; touch gram.h; else mv y.tab.h $@; fi .NOTPARALLEL: .ORDER: ../domain.h $(OBJECTS) ../domain.h: cd ..; make domain.h pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/hotproc.c0000664000000000000000000011674012272262501016575 0ustar /* * Copyright (c) 1995,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" /* local stuff */ #include "./cluster.h" #include "../domain.h" #include "./proc.h" #include "./proc_aux.h" #include "./psinfo.h" #include "./psusage.h" #include "./pglobal.h" #include "./pcpu.h" #include "./ctltab.h" #include "./config.h" #include "./hotproc.h" #include "./pracinfo.h" #include "./ppred_values.h" #define MIN_REFRESH 1 #define INIT_PROC_MAX 200 #if (_MIPS_SZLONG == 32) #define IO_PMTYPE PM_TYPE_U32 /* ulong_t from procfs.h/prusage */ #define CTX_PMTYPE PM_TYPE_U32 /* ulong_t from procfs.h/prusage */ #define SYSCALLS_PMTYPE PM_TYPE_U32 /* ulong_t from procfs.h/prusage */ #define SYSIDLE_PMTYPE PM_TYPE_32 /* long=time_t from sysinfo.h/sysinfo */ #define TIME_PMTYPE PM_TYPE_32 /* long from time.h or types.h */ #define ACCUM_PMTYPE PM_TYPE_U64 /* accum_t from types.h */ #endif /* _MIPS_SZLONG == 32 */ #if (_MIPS_SZLONG == 64) #define IO_PMTYPE PM_TYPE_U64 /* ulong_t from procfs.h/prusage */ #define CTX_PMTYPE PM_TYPE_U64 /* ulong_t from procfs.h/prusage */ #define SYSCALLS_PMTYPE PM_TYPE_U64 /* ulong_t from procfs.h/prusage */ #define SYSIDLE_PMTYPE PM_TYPE_64 /* long=time_t from sysinfo.h/sysinfo */ #define TIME_PMTYPE PM_TYPE_64 /* long from time.h or types.h */ #define ACCUM_PMTYPE PM_TYPE_U64 /* accum_t from types.h */ #endif /* _MIPS_SZLONG == 64 */ extern char *conf_buffer; extern char *conf_buffer_ptr; extern char *pred_buffer; char *configfile = NULL; static int conf_gen = 1; /* configuration file generation number */ static int allow_stores = 1; /* allow stores or not */ static int hotproc_domain = 7; /* set in hotproc_init */ static int pred_testing; /* just do predicate testing or not */ static int parse_only; /* just parse config file and exit */ static char* testing_fname; /* filename root for testing */ static char *username; /* user account for pmda */ /* handle on /proc */ static DIR *procdir; /* active list */ static pid_t *active_list = NULL; /* generated per refresh */ static int numactive = 0; static int maxactive = INIT_PROC_MAX; /* process lists for current and previous */ static process_t *proc_list[2] = {NULL, NULL}; /* array size allocated */ static int maxprocs[2] = {INIT_PROC_MAX, INIT_PROC_MAX}; /* number of procs used in list (<= maxprocs) */ static int numprocs[2] = {0, 0}; /* index into proc_list etc.. */ static int current = 0; static int previous = 1; /* refresh time interval in seconds - cmd arg */ static struct timeval refresh_delta; /* event id for refreshing */ static int refresh_afid; /* various cpu time totals */ static int num_cpus = 0; static int have_totals = 0; static double transient; static double cpuidle; static double total_active; static double total_inactive; /* number of refreshes */ /* will wrap back to 2 */ static unsigned long refresh_count = 0; /* format of an entry in /proc */ char proc_fmt[8]; /* export for procfs fname conversions */ int proc_entry_len; char *log = NULL; #ifndef USEC_PER_SEC #define USEC_PER_SEC 1000000 /* number of usecs for 1 second */ #endif #ifndef NSEC_PER_SEC #define NSEC_PER_SEC 1000000000 /* number of nsecs for 1 second */ #endif #define ntime2double(x) \ (((double)(x).tv_sec) + ((double)((ulong_t)((x).tv_nsec)))/NSEC_PER_SEC) #define utime2double(x) \ (((double)(x).tv_sec) + ((double)((ulong_t)((x).tv_usec)))/USEC_PER_SEC) #define TWOe32 (double) 4.295e9 /* * Make initial allocation for proc list. */ static int init_proc_list(void) { active_list = (pid_t*)malloc(INIT_PROC_MAX * sizeof(pid_t)); proc_list[0] = (process_t*)malloc(INIT_PROC_MAX * sizeof(process_t)); proc_list[1] = (process_t*)malloc(INIT_PROC_MAX * sizeof(process_t)); if (proc_list[0] == NULL || proc_list[1] == NULL || active_list == NULL) return -oserror(); return 0; } /* * Work out the active list from the constraints. */ static void init_active_list(void) { numactive = 0; } /* * add_active_list: * If unsuccessful in add - due to memory then return neg status. * If member of active list return 1 * If non-member of active list return 0 */ static int add_active_list(process_t *node, config_vars *vars) { if (eval_tree(vars) == 0) { return 0; } if (numactive == maxactive) { pid_t *res; maxactive = numactive*2; res = (pid_t *)realloc(active_list, maxactive * sizeof(pid_t)); if (res == NULL) return -osoerror(); active_list = res; } active_list[numactive++] = node->pid; return 1; } #ifdef PCP_DEBUG static void dump_active_list(void) { int i = 0; (void)fprintf(stderr, "--- active list ---\n"); for(i = 0; i < numactive; i++) { (void)fprintf(stderr, "[%d] = %" FMT_PID "\n", i, active_list[i]); }/*for*/ (void)fprintf(stderr, "--- end active list ---\n"); } static void dump_proc_list(void) { int i; process_t *node; (void)fprintf(stderr, "--- proc list ---\n"); for (i = 0; i < numprocs[current]; i++) { node = &proc_list[current][i]; (void)fprintf(stderr, "[%d] = %" FMT_PID " ", i, node->pid); (void)fprintf(stderr, "(syscalls = %ld) ", node->r_syscalls); (void)fputc('\n', stderr); }/*for*/ (void)fprintf(stderr, "--- end proc list ---\n"); } static void dump_cputime(double pre_usr, double pre_sys, double post_usr, double post_sys) { fprintf(stderr, "CPU Time: user = %f, sys = %f\n", post_usr - pre_usr, post_sys - pre_sys); } static void dump_pred(derived_pred_t *pred) { (void)fprintf(stderr, "--- pred vars ---\n"); (void)fprintf(stderr, "syscalls = %f\n", pred->syscalls); (void)fprintf(stderr, "ctxswitch = %f\n", pred->ctxswitch); (void)fprintf(stderr, "virtualsize = %f\n", pred->virtualsize); (void)fprintf(stderr, "residentsize = %f\n", pred->residentsize); (void)fprintf(stderr, "iodemand = %f\n", pred->iodemand); (void)fprintf(stderr, "iowait = %f\n", pred->iowait); (void)fprintf(stderr, "schedwait = %f\n", pred->schedwait); (void)fprintf(stderr, "--- end pred vars ---\n"); } #endif /* * Return 1 if pid is in active list. * Return 0 if pid is NOT in active list. */ static int in_active_list(pid_t pid) { int i; for(i = 0; i < numactive; i++) { if (pid == active_list[i]) return 1; } return 0; } static int compar_pids(const void *n1, const void *n2) { return ((process_t*)n2)->pid - ((process_t*)n1)->pid; } static void set_proc_fmt(void) { struct dirent *directp; /* go thru /proc directory */ for (rewinddir(procdir); directp=readdir(procdir);) { if (!isdigit((int)directp->d_name[0])) continue; proc_entry_len = (int)strlen(directp->d_name); (void)sprintf(proc_fmt, "%%0%dd", proc_entry_len); break; } } /* * look up node in proc list */ static process_t * lookup_node(int curr_prev, pid_t pid) { process_t key; process_t *node; key.pid = pid; if ( (numprocs[curr_prev] > 0) && ((node = bsearch(&key, proc_list[curr_prev], numprocs[curr_prev], sizeof(process_t), compar_pids)) != NULL) ) { return node; } return NULL; } /* * look up current node */ process_t * lookup_curr_node(pid_t pid) { return lookup_node(current, pid); } /* * Calculate difference allowing for single wrapping of counters */ static double DiffCounter(double current, double previous, int pmtype) { double outval = current-previous; if (outval < 0.0) { switch (pmtype) { case PM_TYPE_32: case PM_TYPE_U32: outval += (double)UINT_MAX+1; break; case PM_TYPE_64: case PM_TYPE_U64: outval += (double)ULONGLONG_MAX+1; break; } } return outval; } static void set_psinfo(prpsinfo_t *psinfo, config_vars *vars) { psinfo->pr_size = (long)vars->pr_size; psinfo->pr_rssize = (long)vars->pr_rssize; } static void set_psusage(prusage_t *psusage, config_vars *vars) { psusage->pu_sysc = vars->pu_sysc; psusage->pu_vctx = vars->pu_vctx; psusage->pu_ictx = vars->pu_ictx; psusage->pu_gbread = vars->pu_gbread; psusage->pu_bread = vars->pu_bread; psusage->pu_gbwrit = vars->pu_gbwrit; psusage->pu_bwrit = vars->pu_bwrit; } /* If have a test file then read in values * and overwrite some variables in the proc buffer. * Only read from file for each refresh => * make each process have same line from file as values * If read fails, then return -1 * else if read something then return 0 * else if not time to read then return 1 */ static int read_buf_file(int *rcount, char *suffix, FILE **testing_file, config_vars *vars) { if (*testing_file == NULL) { char fname[80]; strcpy(fname, testing_fname); strcat(fname, suffix); *testing_file = fopen(fname, "r"); if (*testing_file == NULL) { fprintf(stderr, "%s: Unable to open test file \"%s\": %s\n", pmProgname, fname, osstrerror()); return -1; } } /* only read new values for each refresh */ if (refresh_count != *rcount) { *rcount = (int)refresh_count; if (read_test_values(*testing_file, vars) != 1) return -1; return 0; } return 1; /* no values actually read */ } static int psusage_getbuf_file(pid_t pid, prusage_t *psusage) { static config_vars vars; /* configuration variable values */ static FILE *testing_file = NULL; static int rcount = -1; /* last refresh_count */ static int dont_read = 0; int sts; if ((sts = psusage_getbuf(pid, psusage)) != 0) return sts; if (testing_fname != NULL && !dont_read) { sts = read_buf_file(&rcount, ".psusage", &testing_file, &vars); if (sts >= 0) set_psusage(psusage, &vars); else dont_read = 1; } return 0; } static int psinfo_getbuf_file(pid_t pid, prpsinfo_t *psinfo) { static config_vars vars; /* configuration variable values */ static FILE *testing_file = NULL; static int rcount = -1; /* last refresh_count */ static int dont_read = 0; int sts; if ((sts = psinfo_getbuf(pid, psinfo)) != 0) return sts; if (testing_fname != NULL && !dont_read) { sts = read_buf_file(&rcount, ".psinfo", &testing_file, &vars); if (sts >= 0) set_psinfo(psinfo, &vars); else dont_read = 1; } return 0; } static void set_pracinfo(pracinfo_t *acct, config_vars *vars) { acct->pr_timers.ac_bwtime = vars->ac_bwtime; acct->pr_timers.ac_rwtime = vars->ac_rwtime; acct->pr_timers.ac_qwtime = vars->ac_qwtime; } static int pracinfo_getbuf_file(pid_t pid, pracinfo_t *acct) { static config_vars vars; /* configuration variable values */ static FILE *testing_file = NULL; static int rcount = -1; /* last refresh_count */ static int dont_read = 0; int sts; if ((sts = pracinfo_getbuf(pid, acct)) != 0) return sts; if (testing_fname != NULL && !dont_read) { sts = read_buf_file(&rcount, ".pracinfo", &testing_file, &vars); if (sts >= 0) set_pracinfo(acct, &vars); else dont_read = 1; } return 0; } /* * Refresh the process list for /proc entries. */ static int refresh_proc_list(void) { extern int need_psusage; /* is psusage buffer needed or not */ extern int need_accounting; /* is pracinfo buffer needed or not */ int sts; int sysmp_sts; pid_t pid; struct dirent *directp; /* go thru /proc directory */ prpsinfo_t psinfo; /* read in proc info */ prusage_t psusage; /* read in proc usage */ pracinfo_t acct; /* read in acct info */ struct sysinfo sinfo; /* sysinfo from sysmp */ process_t *oldnode = NULL; /* node from previous proc list */ process_t *newnode = NULL; /* new node in current proc list */ int np = 0; /* number of procs index */ struct timeval p_timestamp; /* timestamp pre getting proc info */ config_vars vars; /* configuration variable values */ struct timeval ts; static double refresh_time[2]; /* timestamp after refresh */ static time_t sysidle[2]; /* sys idle from sysmp */ double sysidle_delta; /* system idle delta time since last refresh */ double actual_delta; /* actual delta time since last refresh */ double transient_delta; /* calculated delta time of transient procs */ double cputime_delta; /* delta cpu time for a process */ double syscalls_delta; /* delta num of syscalls for a process */ double vctx_delta; /* delta num of valid ctx switches for a process */ double ictx_delta; /* delta num of invalid ctx switches for a process */ double bread_delta; /* delta num of bytes read */ double gbread_delta; /* delta num of gigabytes read */ double bwrit_delta; /* delta num of bytes written */ double gbwrit_delta; /* delta num of gigabytes written */ double bwtime_delta; /* delta num of nanosesc for waiting for blocked io */ double rwtime_delta; /* delta num of nanosesc for waiting for raw io */ double qwtime_delta; /* delta num of nanosesc waiting on run queue */ double timestamp_delta; /* real time delta b/w refreshes for process */ double total_cputime = 0; /* total of cputime_deltas for each process */ double total_activetime = 0; /* total of cputime_deltas for active processes */ double total_inactivetime = 0; /* total of cputime_deltas for inactive processes */ #ifdef PCP_DEBUG double curr_time; /* for current time */ double pre_usr, pre_sys; double post_usr, post_sys; #endif /* switch current and previous */ if (current == 0) { current = 1; previous = 0; } else { current = 0; previous = 1; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { __pmtimevalNow(&ts); curr_time = utime2double(ts); fprintf(stderr, "refresh_proc_list():\n"); __pmProcessRunTimes(&pre_usr, &pre_sys); } #endif #ifdef PCP_DEBUG /* used to verify externally (approx.) the values */ /* note: doing this is _slow_ */ if (pmDebug & DBG_TRACE_APPL2) { static char cmd[80]; sprintf(cmd, "(date ; ps -le )>> %s.refresh", log); fprintf(stderr, "refresh: cmd = %s\n", cmd); system(cmd); } #endif init_active_list(); (void)memset(&vars, 0, sizeof(config_vars)); for (np = 0, rewinddir(procdir); directp=readdir(procdir);) { if (!isdigit((int)directp->d_name[0])) continue; (void)sscanf(directp->d_name, proc_fmt, &pid); __pmtimevalNow(&p_timestamp); if (psinfo_getbuf_file(pid, &psinfo) != 0) continue; /* reallocate if run out of room */ if (np == maxprocs[current]) { process_t *res; maxprocs[current] = np*2; res = (process_t *)realloc(proc_list[current], maxprocs[current] * sizeof(process_t)); if (res == NULL) return -oserror(); proc_list[current] = res; } newnode = &proc_list[current][np++]; newnode->pid = pid; newnode->r_cputime = ntime2double(psinfo.pr_time); newnode->r_cputimestamp = utime2double(p_timestamp); if (need_psusage) { if (psusage_getbuf_file(pid, &psusage) != 0) continue; newnode->r_syscalls = psusage.pu_sysc; newnode->r_vctx = psusage.pu_vctx; newnode->r_ictx = psusage.pu_ictx; newnode->r_bread = psusage.pu_bread; newnode->r_gbread = psusage.pu_gbread; newnode->r_bwrit = psusage.pu_bwrit; newnode->r_gbwrit = psusage.pu_gbwrit; } if (need_accounting) { if (pracinfo_getbuf_file(pid, &acct) != 0) continue; newnode->r_bwtime = acct.pr_timers.ac_bwtime; newnode->r_rwtime = acct.pr_timers.ac_rwtime; newnode->r_qwtime = acct.pr_timers.ac_qwtime; } /* if we have a previous i.e. not the first time */ if ((oldnode = lookup_node(previous, pid)) != NULL) { cputime_delta = DiffCounter(newnode->r_cputime, oldnode->r_cputime, TIME_PMTYPE); timestamp_delta = DiffCounter(newnode->r_cputimestamp, oldnode->r_cputimestamp, TIME_PMTYPE); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { (void)fprintf(stderr, "refresh_proc_list: " "fname = \"%s\"; cputime = %f; elapsed = %f\n", psinfo.pr_fname, cputime_delta, timestamp_delta); } #endif #ifdef PCP_DEBUG /* used to verify externally (approx.) the values */ /* note: doing this is _slow_ */ if (pmDebug & DBG_TRACE_APPL2) { static char cmd[80]; if (cputime_delta > timestamp_delta) { sprintf(cmd, "(date ; ps -lp %" FMT_PID " )>> %s.refresh", pid, log); fprintf(stderr, "refresh: cmd = %s\n", cmd); system(cmd); } } #endif newnode->r_cpuburn = cputime_delta / timestamp_delta; vars.cpuburn = newnode->r_cpuburn; if (need_psusage) { /* rate convert syscalls */ syscalls_delta = DiffCounter((double)newnode->r_syscalls, (double)oldnode->r_syscalls, SYSCALLS_PMTYPE); vars.preds.syscalls = syscalls_delta / timestamp_delta; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { (void)fprintf(stderr, "refresh_proc_list: " "syscalls = %f\n", vars.preds.syscalls); } #endif /* rate convert ctxswitch */ vctx_delta = DiffCounter((double)newnode->r_vctx, (double)oldnode->r_vctx, CTX_PMTYPE); ictx_delta = DiffCounter((double)newnode->r_ictx, (double)oldnode->r_ictx, CTX_PMTYPE); vars.preds.ctxswitch = (vctx_delta + ictx_delta) / timestamp_delta; /* rate convert reading/writing (iodemand) */ bread_delta = DiffCounter((double)newnode->r_bread, (double)oldnode->r_bread, IO_PMTYPE); gbread_delta = DiffCounter((double)newnode->r_gbread, (double)oldnode->r_gbread, IO_PMTYPE); bwrit_delta = DiffCounter((double)newnode->r_bwrit, (double)oldnode->r_bwrit, IO_PMTYPE); gbwrit_delta = DiffCounter((double)newnode->r_gbwrit, (double)oldnode->r_gbwrit, IO_PMTYPE); vars.preds.iodemand = (gbread_delta * 1024 * 1024 + (double)bread_delta / 1024 + gbwrit_delta * 1024 * 1024 + (double)bwrit_delta / 1024) / timestamp_delta; } if (need_accounting) { /* rate convert iowait */ bwtime_delta = DiffCounter((double)newnode->r_bwtime, (double)oldnode->r_bwtime, ACCUM_PMTYPE); bwtime_delta /= 1000000000.0; /* nanosecs -> secs */ rwtime_delta = DiffCounter((double)newnode->r_rwtime, (double)oldnode->r_rwtime, ACCUM_PMTYPE); rwtime_delta /= 1000000000.0; /* nanosecs -> secs */ vars.preds.iowait = (bwtime_delta + rwtime_delta) / timestamp_delta; /* rate convert schedwait */ qwtime_delta = DiffCounter((double)newnode->r_qwtime, (double)oldnode->r_qwtime, ACCUM_PMTYPE); qwtime_delta /= 1000000000.0; /* nanosecs -> secs */ vars.preds.schedwait = qwtime_delta / timestamp_delta; } newnode->preds = vars.preds; /* struct copy */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { dump_pred(&newnode->preds); } #endif } else { newnode->r_cpuburn = 0; bzero(&newnode->preds, sizeof(newnode->preds)); vars.cpuburn = 0; vars.preds.syscalls = 0; vars.preds.ctxswitch = 0; vars.preds.iowait = 0; vars.preds.schedwait = 0; vars.preds.iodemand = 0; cputime_delta = 0; } total_cputime += cputime_delta; /* fix up vars record from psinfo */ (void)strcpy(vars.fname, psinfo.pr_fname); (void)strcpy(vars.psargs, psinfo.pr_psargs); vars.uid = psinfo.pr_uid; vars.gid = psinfo.pr_gid; vars.uname = NULL; vars.gname = NULL; vars.preds.virtualsize = (double)psinfo.pr_size * (_pagesize / 1024); vars.preds.residentsize = (double)psinfo.pr_rssize * (_pagesize / 1024); if ((sts = add_active_list(newnode, &vars)) < 0) { return sts; } if (sts == 0) total_inactivetime += cputime_delta; else total_activetime += cputime_delta; }/*for each pid*/ numprocs[current] = np; __pmtimevalNow(&ts); refresh_time[current] = utime2double(ts); refresh_count++; /* If we wrap then say that we atleast have 2, * inorder to indicate we have seen two successive refreshes. */ if (refresh_count == 0) refresh_count = 2; bzero(&sinfo, sizeof(sinfo)); /* for purify */ if ((sysmp_sts = (int)sysmp(MP_SAGET, MPSA_SINFO, &sinfo, sizeof(struct sysinfo))) < 0) { __pmNotifyErr(LOG_ERR, "sysmp failed in refresh: %s\n", osstrerror()); sysidle[current] = -1; } else { sysidle[current] = sinfo.cpu[CPU_IDLE]; } have_totals = 0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { (void)fprintf(stderr, "refresh_proc_list: refresh_count = %lu\n", refresh_count); } #endif if (refresh_count > 1 && sysmp_sts != -1 && sysidle[previous] != -1) { sysidle_delta = DiffCounter(sysidle[current], sysidle[previous], SYSIDLE_PMTYPE) / (double)HZ; actual_delta = DiffCounter(refresh_time[current], refresh_time[previous], TIME_PMTYPE); transient_delta = num_cpus * actual_delta - (total_cputime + sysidle_delta); if (transient_delta < 0) /* sysidle is only accurate to 0.01 second */ transient_delta = 0; have_totals = 1; transient = transient_delta / actual_delta; cpuidle = sysidle_delta / actual_delta; total_active = total_activetime / actual_delta; total_inactive = total_inactivetime / actual_delta; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { (void)fprintf(stderr, "refresh_proc_list: " "total_cputime = %f\n", total_cputime); (void)fprintf(stderr, "refresh_proc_list: " "total_activetime = %f, total_inactivetime = %f\n", total_activetime, total_inactivetime); (void)fprintf(stderr, "refresh_proc_list: " "sysidle_delta = %f, actual_delta = %f\n", sysidle_delta, actual_delta); (void)fprintf(stderr, "refresh_proc_list: " "transient_delta = %f, transient = %f\n", transient_delta, transient); } #endif } /* sort it for bsearching later */ qsort(proc_list[current], numprocs[current], sizeof(process_t), compar_pids); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { __pmProcessRunTimes(&post_usr, &post_sys); dump_proc_list(); fprintf(stderr, "refresh_proc_list: duration = %f secs; ", refresh_time[current] - curr_time); dump_cputime(pre_usr, pre_sys, post_usr, post_sys); dump_active_list(); } #endif return 0; }/*refresh_proc_list*/ static int restart_proc_list(void) { int sts; refresh_count = 0; numprocs[current] = 0; /* clear the current list */ sts = refresh_proc_list(); return sts; } static void timer_callback(int afid, void *data) { int sts = refresh_proc_list(); if (sts < 0) { __pmNotifyErr(LOG_ERR, "timer_callback: refresh list failed: %s\n", pmErrStr(sts)); } } static int hotproc_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) { __pmInResult *res; int j; int sts; if (indom != proc_indom) return PM_ERR_INDOM; if ((res = (__pmInResult *)malloc(sizeof(*res))) == NULL) return -oserror(); res->indom = indom; res->instlist = NULL; res->namelist = NULL; sts = 0; if (name == NULL && inst == PM_IN_NULL) res->numinst = numactive; else res->numinst = 1; if (inst == PM_IN_NULL) { if ((res->instlist = (int *)malloc(res->numinst * sizeof(res->instlist[0]))) == NULL) { __pmFreeInResult(res); return -oserror(); } } if (name == NULL) { if ((res->namelist = (char **)malloc(res->numinst * sizeof(res->namelist[0]))) == NULL) { __pmFreeInResult(res); return -oserror(); } for (j = 0; j < res->numinst; j++) res->namelist[j] = NULL; } /* --> names and ids (the whole instance map) */ if (name == NULL && inst == PM_IN_NULL) { /* find all instance ids and names for the PROC indom */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { (void)fprintf(stderr, "hotproc_instance: Getting whole instance map...\n"); } #endif /* go thru active list */ for(j = 0; j < numactive; j++) { res->instlist[j] = active_list[j]; if ((sts = proc_id_to_mapname(active_list[j], &res->namelist[j])) < 0) break; } } /* id --> name */ else if (name == NULL) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { (void)fprintf(stderr, "hotproc_instance: id --> name\n"); } #endif if (!in_active_list(inst)) { __pmNotifyErr(LOG_ERR, "proc_instance: pid not in active list %d\n", inst); sts = PM_ERR_INST; } else { sts = proc_id_to_name(inst, &res->namelist[0]); } } /* name --> id */ else { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { (void)fprintf(stderr, "hotproc_instance: name --> id\n"); } #endif /* find the instance for the given indom/name */ sts = proc_name_to_id(name, &res->instlist[0]); if (!in_active_list(res->instlist[0])) { __pmNotifyErr(LOG_ERR, "proc_instance: pid not in active list %d\n", res->instlist[0]); sts = PM_ERR_INST; } } if (sts == 0) *result = res; else __pmFreeInResult(res); return sts; } static int hotproc_desc(pmID pmid, pmDesc *desc, pmdaExt *pmda) { int pmidErr; int ctl_i; __pmID_int *pmidp = (__pmID_int *)&pmid; pmidErr = PM_ERR_PMID; if (pmidp->domain == hotproc_domain) { ctl_i = lookup_ctltab(pmidp->cluster); if (ctl_i < 0) pmidErr = ctl_i; else pmidErr = ctltab[ctl_i].getdesc(pmid, desc); } return pmidErr; } static int hotproc_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i; /* over pmidlist[] */ int ctl_i; /* over ctltab[] and fetched[] */ int j; int n; int numvals; int sts; size_t need; static pmResult *res = NULL; static int maxnpmids = 0; pmValueSet *vset; pmDesc dp; __pmID_int *pmidp; pmAtomValue atom; int aggregate_len; static int max_numactive = 0; static int **fetched = NULL; if (fetched == NULL) { fetched = (int **)malloc(nctltab * sizeof(fetched[0])); if (fetched == NULL) return -oserror(); memset(fetched, 0, nctltab * sizeof(fetched[0])); } /* allocate for result structure */ if (numpmid > maxnpmids) { if (res != NULL) free(res); /* (numpmid - 1) because there's room for one valueSet in a pmResult */ need = sizeof(pmResult) + (numpmid - 1) * sizeof(pmValueSet *); if ((res = (pmResult *) malloc(need)) == NULL) return -oserror(); maxnpmids = numpmid; } res->timestamp.tv_sec = 0; res->timestamp.tv_usec = 0; res->numpmid = numpmid; /* fix up allocations for fetched array */ for (ctl_i=1; ctl_i < nctltab; ctl_i++) { if (numactive > max_numactive) { int *f = (int*)realloc(fetched[ctl_i], numactive * sizeof(int)); int ctl_j; /* over ctltab[] and fetched[] */ if (f == NULL) { max_numactive = 0; for (ctl_j=1; ctl_j < nctltab; ctl_j++) { if (fetched[ctl_j]) free(fetched[ctl_j]); fetched[ctl_j] = NULL; } return -oserror(); } fetched[ctl_i] = f; } (void)memset(fetched[ctl_i], 0, numactive * sizeof(int)); if ((sts = ctltab[ctl_i].allocbuf(numactive)) < 0) return sts; }/*for*/ if (numactive > max_numactive) { max_numactive = numactive; } sts = 0; for (i = 0; i < numpmid; i++) { int pmidErr = 0; pmidp = (__pmID_int *)&pmidlist[i]; pmidErr = hotproc_desc(pmidlist[i], &dp, pmda); /* create a vset with the error code in it */ if (pmidErr < 0) { res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet)); if (vset == NULL) { if (i) { res->numpmid = i; __pmFreeResultValues(res); } return -oserror(); } vset->pmid = pmidlist[i]; vset->numval = pmidErr; continue; } if (pmidp->cluster == CLUSTER_GLOBAL) { /* global metrics, singular instance domain */ res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet)); if (vset == NULL) { if (i > 0) { res->numpmid = i; __pmFreeResultValues(res); } return -oserror(); } vset->pmid = pmidlist[i]; vset->numval = 1; switch (pmidp->item) { case ITEM_NPROCS: { char *path; /* pv#589180 * Reduce the active list if processes have exitted. */ for (j=0; j < numactive; j++) { pid_t pid = active_list[j]; proc_pid_to_path(pid, NULL, &path, PINFO_PATH); /* if process not found then remove from active list */ if (access(path, R_OK) < 0) { int ctl_k; /* remove from active list */ /* replace with end one */ active_list[j] = active_list[numactive-1]; /* also do same thing to fetched array */ for(ctl_k = 1; ctl_k < nctltab; ctl_k++) { fetched[ctl_k][j] = fetched[ctl_k][numactive-1]; } numactive--; j--; /* test this slot again */ } } atom.l = numactive; break; } case ITEM_REFRESH: atom.l = (__int32_t)refresh_delta.tv_sec; break; case ITEM_CONFIG: atom.cp = pred_buffer; break; case ITEM_CONFIG_GEN: atom.l = conf_gen; break; case ITEM_TRANSIENT: if (!have_totals) vset->numval = 0; else atom.f = transient; break; case ITEM_CPUIDLE: if (!have_totals) vset->numval = 0; else atom.f = cpuidle; break; case ITEM_TOTAL_CPUBURN: if (!have_totals) vset->numval = 0; else atom.f = total_active; break; case ITEM_TOTAL_NOTCPUBURN: if (!have_totals) vset->numval = 0; else atom.f = total_inactive; break; case ITEM_OTHER_TOTAL: if (!have_totals) vset->numval = 0; else atom.f = transient + total_inactive; break; case ITEM_OTHER_PERCENT: { double other = transient + total_inactive; double non_idle = other + total_active; /* if non_idle = 0, very unlikely, * then the value here is meaningless */ if (!have_totals || non_idle == 0) vset->numval = 0; else atom.f = other / non_idle * 100; } break; } if (vset->numval == 1 ) { sts = __pmStuffValue(&atom, 0, &vset->vlist[0], dp.type); vset->valfmt = sts; vset->vlist[0].inst = PM_IN_NULL; } } else { /* * Multiple instance domain metrics. */ if ((ctl_i = lookup_ctltab(pmidp->cluster)) < 0) return ctl_i; if (!ctltab[ctl_i].supported) { numvals = 0; } else if (pmidp->cluster == CLUSTER_PRED && !ppred_available(pmidp->item)) { numvals = 0; } else { pid_t pid; numvals = 0; for (j = 0; j < numactive; j++) { pid = active_list[j]; if (!__pmInProfile(proc_indom, pmda->e_prof, pid)) continue; if (fetched[ctl_i][j] == 0) { int sts; if ((sts = ctltab[ctl_i].getinfo(pid, j)) == 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "hotproc_fetch: getinfo succeeded: " "pid=%" FMT_PID ", j=%d\n", pid, j); } #endif fetched[ctl_i][j] = 1; numvals++; } else if (sts == -ENOENT) { int ctl_k; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "hotproc_fetch: " "getinfo failed: pid=%" FMT_PID ", j=%d\n", pid, j); } #endif /* remove from active list */ /* replace with end one */ active_list[j] = active_list[numactive-1]; /* also do same thing to fetched array */ for(ctl_k = 1; ctl_k < nctltab; ctl_k++) { fetched[ctl_k][j] = fetched[ctl_k][numactive-1]; } numactive--; j--; /* test this slot again */ } } else { numvals++; } } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "hotproc_fetch: numvals = %d\n", numvals); } #endif res->vset[i] = vset = (pmValueSet *)malloc( sizeof(pmValueSet) + (numvals-1) * sizeof(pmValue)); if (vset == NULL) { if (i > 0) { /* not the first malloc failing */ res->numpmid = i; __pmFreeResultValues(res); } return -oserror(); } vset->pmid = pmidlist[i]; vset->numval = numvals; vset->valfmt = PM_VAL_INSITU; if (!ctltab[ctl_i].supported) { vset->numval = PM_ERR_APPVERSION; } else { if (numvals != 0) { pid_t pid; for (n=j=0; j < numactive; j++) { pid = active_list[j]; if (fetched[ctl_i][j] == 0) continue; aggregate_len = ctltab[ctl_i].setatom(pmidp->item, &atom, j); sts = __pmStuffValue(&atom, aggregate_len, &vset->vlist[n], dp.type); vset->valfmt = sts; vset->vlist[n].inst = pid; n++; }/*for*/ }/*if*/ }/*if*/ }/*if*/ }/*for*/ *resp = res; return 0; }/*hotproc_fetch*/ static int restart_refresh(void) { int sts; /* * Reschedule as if starting from init. */ sts = restart_proc_list(); if (sts >= 0) { /* Get rid of current event from queue, register new one */ __pmAFunregister(refresh_afid); refresh_afid = __pmAFregister(&refresh_delta, NULL, timer_callback); } return sts; } static int hotproc_store(pmResult *result, pmdaExt *pmda) { int i; pmValueSet *vsp; pmDesc desc; __pmID_int *pmidp; int sts = 0; pmAtomValue av; if (!allow_stores) { return PM_ERR_PERMISSION; } for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; pmidp = (__pmID_int *)&vsp->pmid; sts = hotproc_desc(vsp->pmid, &desc, pmda); if (sts < 0) break; if (pmidp->cluster == CLUSTER_GLOBAL) { switch (pmidp->item) { case ITEM_REFRESH: if (vsp->numval != 1 || vsp->valfmt != PM_VAL_INSITU) { sts = PM_ERR_CONV; } break; case ITEM_CONFIG: if (vsp->numval != 1 || vsp->valfmt == PM_VAL_INSITU) { sts = PM_ERR_CONV; } break; default: sts = PM_ERR_PERMISSION; break; } } else { sts = PM_ERR_PERMISSION; } if (sts < 0) break; if ((sts = pmExtractValue(vsp->valfmt, &vsp->vlist[0], desc.type, &av, desc.type)) < 0) break; switch (pmidp->item) { case ITEM_REFRESH: if (av.l < MIN_REFRESH) { sts = PM_ERR_CONV; } else { refresh_delta.tv_sec = av.l; if ((sts = restart_refresh()) < 0) __pmNotifyErr(LOG_ERR, "hotproc_store: refresh list failed: %s\n", pmErrStr(sts)); } break; case ITEM_CONFIG: { bool_node *tree; conf_buffer_ptr = av.cp; /* Only accept the new config if its predicate is parsed ok */ if (parse_config(&tree) != 0) { conf_buffer_ptr = conf_buffer; free(av.cp); sts = PM_ERR_CONV; } else { conf_gen++; new_tree(tree); free(conf_buffer); /* free old one */ conf_buffer = av.cp; /* use the new one */ if ((sts = restart_refresh()) < 0) __pmNotifyErr(LOG_ERR, "hotproc_store: refresh list failed: %s\n", pmErrStr(sts)); } } break; }/*switch*/ }/*for*/ return sts; } /* * Initialise the agent (only daemon and NOT DSO). */ static void hotproc_init(pmdaInterface *dp) { int sts; __pmSetProcessIdentity(username); dp->version.two.fetch = hotproc_fetch; dp->version.two.store = hotproc_store; dp->version.two.desc = hotproc_desc; dp->version.two.instance = hotproc_instance; /* * Maintaining my own desc and indom table/info. * This is why the passed in tables are NULL. */ pmdaInit(dp, NULL, 0, NULL, 0); init_tables(dp->domain); hotproc_domain = dp->domain; if ((procdir = opendir(PROCFS)) == NULL) { dp->status = -oserror(); __pmNotifyErr(LOG_ERR, "opendir(%s) failed: %s\n", PROCFS, osstrerror()); return; } set_proc_fmt(); if ((num_cpus = (int)sysmp(MP_NPROCS)) < 0) { dp->status = -oserror(); __pmNotifyErr(LOG_ERR, "sysmp failed to get NPROCS: %s\n", osstrerror()); return; } if ((sts = init_proc_list()) < 0) { dp->status = sts; return; } if ((sts = restart_proc_list()) < 0) { dp->status = sts; return; } } static void usage(void) { (void)fprintf(stderr, "Usage: %s [options] configfile\n\n", pmProgname); (void)fputs("Options:\n" " -C parse configfile and exit\n" " -U username user account to run under (default \"pcp\")\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -s do NOT allow dynamic changes to the selection predicate\n" " -t refresh set the refresh time interval in seconds\n", stderr); exit(1); } static void get_options(int argc, char *argv[], pmdaInterface *dispatch) { int n; int err = 0; char *err_msg; while ((n = pmdaGetOpt(argc, argv, "CD:d:l:t:U:xX:?s", dispatch, &err)) != EOF) { switch (n) { case 'C': parse_only = 1; break; case 's': allow_stores = 0; break; case 't': if (pmParseInterval(optarg, &refresh_delta, &err_msg) < 0) { (void)fprintf(stderr, "%s: -t requires a time interval: %s\n", err_msg, pmProgname); free(err_msg); err++; } break; case 'U': username = optarg; break; case 'x': /* hidden option for predicate testing */ pred_testing = 1; break; case 'X': /* hidden option for predicate testing with iocntl buffers */ testing_fname = optarg; break; case '?': err++; } } if (err || optind != argc -1) { usage(); } configfile = argv[optind]; } /* * Set up the agent for running as a daemon. */ int main(int argc, char **argv) { pmdaInterface dispatch; char *p; int sep = __pmPathSeparator(); int infd; fd_set fds; fd_set readyfds; int nready; int numfds; FILE *conf; char mypath[MAXPATHLEN]; __pmSetProgname(argv[0]); __pmGetUsername(&username); refresh_delta.tv_sec = 10; refresh_delta.tv_usec = 0; snprintf(mypath, sizeof(mypath), "%s%c" "hotproc" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_2, pmProgname, HOTPROC, "hotproc.log", mypath); get_options(argc, argv, &dispatch); if (pred_testing) { do_pred_testing(); exit(0); } if (!parse_only) { pmdaOpenLog(&dispatch); log = dispatch.version.two.ext->e_logfile; } conf = open_config(); read_config(conf); (void)fclose(conf); if (parse_only) exit(0); hotproc_init(&dispatch); pmdaConnect(&dispatch); if ((infd = __pmdaInFd(&dispatch)) < 0) exit(1); FD_ZERO(&fds); FD_SET(infd, &fds); numfds = infd+1; refresh_afid = __pmAFregister(&refresh_delta, NULL, timer_callback); /* custom pmda main loop */ for (;;) { (void)memcpy(&readyfds, &fds, sizeof(readyfds)); nready = select(numfds, &readyfds, NULL, NULL, NULL); if (nready > 0) { __pmAFblock(); if (__pmdaMainPDU(&dispatch) < 0) break; __pmAFunblock(); } else if (nready < 0 && neterror() != EINTR) { __pmNotifyErr(LOG_ERR, "select failed: %s\n", netstrerror()); } } exit(0); } pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/GNUmakefile0000664000000000000000000000243712272262501017022 0ustar #!gmake # # Copyright (c) 2007 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../../../.. include $(TOPDIR)/src/include/builddefs # This is just to get the source exported to the community. # 'Makefile' in particular is included only for clues it might offer, # and should almost certainly be removed from SRCFILES once # the pmda is working. LSRCFILES = Makefile config.c config.h ctltab.c error.c gram.y \ gram_node.c gram_node.h hotproc.c hotproc.h lex.l pcpu.c pcpu.h \ pglobal.c pglobal.h ppred_values.c ppred_values.h default default_pcp: install install_pcp: include $(BUILDRULES) pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/config.c0000664000000000000000000003212512272262501016356 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include "gram_node.h" #include "gram.h" #include "nameinfo.h" #include "config.h" char *conf_buffer = NULL; /* contains config text */ char *conf_buffer_ptr = NULL; char *pred_buffer = NULL; /* contains parsed predicate */ static bool_node *the_tree = NULL; static config_vars *the_vars = NULL; /* internal functions */ static int eval_predicate(bool_node *); static int eval_comparison(bool_node *); static int eval_num_comp(N_tag, bool_node *, bool_node *); static int eval_str_comp(N_tag, bool_node *, bool_node *); static int eval_match_comp(N_tag, bool_node *, bool_node *); static char* get_strvalue(bool_node *); static double get_numvalue(bool_node *); static void eval_error(char *); extern int parse_predicate(bool_node **); extern char *pmProgname; extern char *configfile; extern FILE *yyin; FILE * open_config(void) { FILE *conf; if ((conf = fopen(configfile, "r")) == NULL) { (void)fprintf(stderr, "%s: Unable to open configuration file \"%s\": %s\n", pmProgname, configfile, osstrerror()); exit(1); } return conf; } int parse_config(bool_node **tree) { int sts; FILE *file = NULL; char *fname; struct stat stat_buf; long size; char *ptr; if ((sts = parse_predicate(tree)) != 0) { (void)fprintf(stderr, "%s: Failed to parse configuration file\n", pmProgname); return sts; } /* --- dump to tmp file & read to buffer --- */ if ((fname = tmpnam(NULL)) == NULL || (file = fopen(fname, "w+")) == NULL) { sts = -oserror(); fprintf(stderr, "%s: parse_config: failed to create \"%s\": %s\n", pmProgname, fname, strerror(-sts)); goto error; } if (unlink(fname) == -1) { sts = -oserror(); fprintf(stderr, "%s: parse_config: failed to unlink \"%s\": %s\n", pmProgname, fname, strerror(-sts)); goto error; } dump_predicate(file, *tree); fflush(file); if (fstat(fileno(file), &stat_buf) < 0) { sts = -oserror(); fprintf(stderr, "%s: parse_config: failed to stat \"%s\": %s\n", pmProgname, fname, strerror(-sts)); goto error; } size = (long)stat_buf.st_size; ptr = malloc(size+1); if (ptr == NULL) { sts = -oserror(); fprintf(stderr, "%s: parse_config: failed to malloc: %s\n", pmProgname, strerror(-sts)); goto error; } rewind(file); if (fread(ptr, size, 1, file) != 1) { clearerr(file); fprintf(stderr, "%s: parse_config: failed to fread \"%s\"\n", pmProgname, fname); sts = -1; goto error; } (void)fclose(file); if (pred_buffer != NULL) free(pred_buffer); pred_buffer = ptr; pred_buffer[size] = '\0'; return 0; error: if (file != NULL) (void)fclose(file); return sts; } void new_tree(bool_node *tree) { free_tree(the_tree); the_tree = tree; } void read_config(FILE *conf) { struct stat stat_buf; long size; int sts; size_t nread; /* get length of file */ sts = fstat(fileno(conf), &stat_buf); if (sts < 0) { (void)fprintf(stderr, "%s: Failure to stat configuration file \"%s\": %s\n", pmProgname, configfile, osstrerror()); exit(1); } size = (long)stat_buf.st_size; /* create buffer */ conf_buffer = (char*)malloc(size+1*sizeof(char)); if (conf_buffer == NULL) { (void)fprintf(stderr, "%s: Failure to create buffer for configuration file \"%s\"\n", pmProgname, configfile); exit(1); } conf_buffer_ptr = conf_buffer; /* read whole file into buffer */ nread = fread(conf_buffer, sizeof(char), size, conf); if (nread != size) { (void)fprintf(stderr, "%s: Failure to read configuration file \"%s\" into buffer\n", pmProgname, configfile); exit(1); } conf_buffer[size] = '\0'; /* terminate the buffer */ if (parse_config(&the_tree) != 0) exit(1); } void dump_tree(FILE *f) { dump_bool_tree(f, the_tree); } int eval_tree(config_vars *vars) { the_vars = vars; return eval_predicate(the_tree); } /* * do predicate testing for qa */ #define QA_LINE 512 /* * Return convention * EOF = finished line or file * 0 = error in input * 1 = successful and continue */ /* * Read test vars of form: "var=value|var=value|var=value" */ static int read_test_var(char *line, config_vars *vars) { const char EQUALS = '='; const char DIVIDER = '|'; char var[QA_LINE]; char value[QA_LINE]; static char *c; int i = 0; /* if line is NULL then continue where left off */ if (line != NULL) c = line; if (*c == '\n') return EOF; /* --- get variable name --- */ i = 0; while(*c != EQUALS && *c != '\n') { var[i++] = *c++; } var[i] = '\0'; if (*c == '\n') { fprintf(stderr, "%s: Error reading test variable, " "looking for \"%c\"\n", pmProgname, EQUALS); return 0; } c++; /* skip over EQUALS */ /* --- get value --- */ i = 0; while(*c != DIVIDER && *c != '\n') { value[i++] = *c++; } value[i] = '\0'; if (*c == DIVIDER) /* skip over DIVIDER */ c++; /* --- var = value --- */ if (strcmp(var, "uid") == 0) { vars->uid = atoi(value); } else if (strcmp(var, "uname") == 0) { if ((vars->uname = strdup(value)) == NULL) goto failure; } else if (strcmp(var, "gid") == 0) { vars->gid = atoi(value); } else if (strcmp(var, "gname") == 0) { if ((vars->gname = strdup(value)) == NULL) goto failure; } else if (strcmp(var, "fname") == 0) { (void)strcpy(vars->fname, value); } else if (strcmp(var, "psargs") == 0) { (void)strcpy(vars->psargs, value); } else if (strcmp(var, "cpuburn") == 0) { vars->cpuburn = atof(value); } else if (strcmp(var, "syscalls") == 0) { vars->preds.syscalls = atof(value); } else if (strcmp(var, "pu_sysc") == 0) { vars->pu_sysc = atol(value); } else if (strcmp(var, "ctxswitch") == 0) { vars->preds.ctxswitch = atof(value); } else if (strcmp(var, "pu_vctx") == 0) { vars->pu_vctx = atol(value); } else if (strcmp(var, "pu_ictx") == 0) { vars->pu_ictx = atol(value); } else if (strcmp(var, "virtualsize") == 0) { vars->preds.virtualsize = atof(value); } else if (strcmp(var, "pr_size") == 0) { vars->pr_size = atol(value); } else if (strcmp(var, "residentsize") == 0) { vars->preds.residentsize = atof(value); } else if (strcmp(var, "pr_rssize") == 0) { vars->pr_rssize = atol(value); } else if (strcmp(var, "iodemand") == 0) { vars->preds.iodemand = atof(value); } else if (strcmp(var, "pu_gbread") == 0) { vars->pu_gbread = atol(value); } else if (strcmp(var, "pu_bread") == 0) { vars->pu_bread = atol(value); } else if (strcmp(var, "pu_gbwrit") == 0) { vars->pu_gbwrit = atol(value); } else if (strcmp(var, "pu_bwrit") == 0) { vars->pu_bwrit = atol(value); } else if (strcmp(var, "iowait") == 0) { vars->preds.iowait = atof(value); } else if (strcmp(var, "ac_bwtime") == 0) { vars->ac_bwtime = atoll(value); } else if (strcmp(var, "ac_rwtime") == 0) { vars->ac_rwtime = atoll(value); } else if (strcmp(var, "schedwait") == 0) { vars->preds.schedwait = atof(value); } else if (strcmp(var, "ac_qwtime") == 0) { vars->ac_qwtime = atoll(value); } else { fprintf(stderr, "%s: Error unrecognised test variable: \"%s\"\n", pmProgname, var); return 0; } return 1; failure: (void)fprintf(stderr, "%s: malloc failed for read_test_var()\n", pmProgname); exit(1); } int read_test_values(FILE *file, config_vars *vars) { static char line[QA_LINE]; int sts; int i; if (fgets(line, QA_LINE-1, file) == NULL) return EOF; if (strlen(line) == QA_LINE-1) { fprintf(stderr, "%s: line limit exceeded\n", pmProgname); return 0; } /* note that line must end in '\n' */ /* reset all values */ (void)memset(vars, 0, sizeof(*vars)); /* read each var=value pair for a line */ for(i=0;/*forever*/;i++) { sts = read_test_var((i==0?line:NULL), vars); if (sts == EOF) return 1; if (sts == 0) return 0; } } void do_pred_testing(void) { int sts; config_vars vars; FILE *conf = NULL; conf = open_config(); read_config(conf); (void)fclose(conf); dump_tree(stdout); for (;;) { sts = read_test_values(stdin, &vars); if (sts == EOF) break; if (sts == 0) { (void)fprintf(stderr, "Bad input line\n"); continue; } if (eval_tree(&vars)) { (void)fprintf(stdout, "true\n"); } else { (void)fprintf(stdout, "false\n"); } } } static void eval_error(char *msg) { (void)fprintf(stderr, "%s: Internal error : %s\n", pmProgname, msg?msg:""); exit(1); } static int eval_predicate(bool_node *pred) { bool_node *lhs, *rhs; switch(pred->tag) { case N_and: lhs = pred->data.children.left; rhs = pred->data.children.right; return eval_predicate(lhs) && eval_predicate(rhs); case N_or: lhs = pred->data.children.left; rhs = pred->data.children.right; return eval_predicate(lhs) || eval_predicate(rhs); case N_not: lhs = pred->data.children.left; return !eval_predicate(lhs); case N_true: return 1; case N_false: return 0; default: return eval_comparison(pred); }/*switch*/ } static int eval_comparison(bool_node *comp) { bool_node *lhs = comp->data.children.left; bool_node *rhs = comp->data.children.right; switch(comp->tag) { case N_lt: case N_gt: case N_ge: case N_le: case N_eq: case N_neq: return eval_num_comp(comp->tag, lhs, rhs); case N_seq: case N_sneq: return eval_str_comp(comp->tag, lhs, rhs); case N_match: case N_nmatch: return eval_match_comp(comp->tag, lhs, rhs); default: eval_error("comparison"); }/*switch*/ } static int eval_num_comp(N_tag tag, bool_node *lhs, bool_node *rhs) { double x = get_numvalue(lhs); double y = get_numvalue(rhs); switch(tag) { case N_lt: return (x < y); case N_gt: return (x > y); case N_le: return (x <= y); case N_ge: return (x >= y); case N_eq: return (x == y); case N_neq: return (x != y); default: eval_error("number comparison"); }/*switch*/ } static double get_numvalue(bool_node *n) { switch(n->tag) { case N_number: return n->data.num_val; case N_cpuburn: return the_vars->cpuburn; case N_syscalls: return the_vars->preds.syscalls; case N_ctxswitch: return the_vars->preds.ctxswitch; case N_virtualsize: return the_vars->preds.virtualsize; case N_residentsize: return the_vars->preds.residentsize; case N_iodemand: return the_vars->preds.iodemand; case N_iowait: return the_vars->preds.iowait; case N_schedwait: return the_vars->preds.schedwait; case N_gid: return the_vars->gid; case N_uid: return the_vars->uid; default: eval_error("number value"); } } static int eval_str_comp(N_tag tag, bool_node *lhs, bool_node *rhs) { char *x = get_strvalue(lhs); char *y = get_strvalue(rhs); switch(tag) { case N_seq: return (strcmp(x,y)==0?1:0); case N_sneq: return (strcmp(x,y)==0?0:1); default: eval_error("string comparison"); }/*switch*/ } static int eval_match_comp(N_tag tag, bool_node *lhs, bool_node *rhs) { int sts; char *res; char *str= get_strvalue(lhs); char *pat = get_strvalue(rhs); if (rhs->tag != N_pat) { eval_error("match"); } res = re_comp(pat); if (res != NULL) { /* should have been checked at lex stage */ /* => internal error */ eval_error(res); } sts = re_exec(str); if (sts < 0) { eval_error("re_exec"); } switch(tag) { case N_match: return sts; case N_nmatch: return !sts; default: eval_error("match comparison"); }/*switch*/ } static char * get_strvalue(bool_node *n) { switch(n->tag) { case N_str: case N_pat: return n->data.str_val; case N_gname: if (the_vars->gname != NULL) return the_vars->gname; else return get_gname_info(the_vars->gid); case N_uname: if (the_vars->uname != NULL) return the_vars->uname; else return get_uname_info(the_vars->uid); case N_fname: return the_vars->fname; case N_psargs: return the_vars->psargs; default: eval_error("string value"); }/*switch*/ } pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/lex.l0000664000000000000000000000520612272262501015712 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ %{ #include "./gram_node.h" #include "./gram.h" void yyerror(char *s); static char emsg[256]; /* error message */ static char yy_ichar; /* input char from conf_buffer */ extern char *conf_buffer_ptr; #undef input #undef unput #define input() ( (yy_ichar = *conf_buffer_ptr++) == '\n' ? (yylineno++, yy_ichar) : yy_ichar) #define unput(c) { if ((*--conf_buffer_ptr = c) == '\n') yylineno--; } %} %option noinput %option nounput %% Version { return VERSION; } schedwait { return SCHEDWAIT; } iowait { return IOWAIT; } iodemand { return IODEMAND; } residentsize { return RESIDENTSIZE; } virtualsize { return VIRTUALSIZE; } ctxswitch { return CTXSWITCH; } syscalls { return SYSCALLS; } gid { return GID; } uid { return UID; } uname { return UNAME; } gname { return GNAME; } fname { return FNAME; } psargs { return PSARGS; } cpuburn { return CPUBURN; } "&&" { return AND; } "||" { return OR; } "!" { return NOT; } "(" { return LPAREN; } ")" { return RPAREN; } true { return TRUE; } false { return FALSE; } "==" { return EQUAL; } "!=" { return NEQUAL; } "<" { return LTHAN; } "<=" { return LEQUAL; } ">" { return GTHAN; } ">=" { return GEQUAL; } "~" { return MATCH; } "!~" { return NMATCH; } \/[^/\n]*[/\n] { char *str; yylval.y_str = (char *)malloc(yyleng-1); if (yylval.y_str == 0) { (void)sprintf(emsg, "malloc failed: %s", osstrerror()); yyerror(emsg); } strncpy(yylval.y_str, &yytext[1], yyleng-2); yylval.y_str[yyleng-2] = '\0'; if ((str = re_comp(yylval.y_str)) != 0) { yyerror(str); } return PATTERN; } \"[^"\n]*["\n] { yylval.y_str = (char *)malloc(yyleng-1); if (yylval.y_str == 0) { (void)sprintf(emsg, "malloc failed: %s", osstrerror()); yyerror(emsg); } strncpy(yylval.y_str, &yytext[1], yyleng-2); yylval.y_str[yyleng-2] = '\0'; return STRING; } [0-9]+ | [0-9]*"."[0-9]+ | [0-9]+"."[0-9]* { yylval.y_number = atof(yytext); return NUMBER; } \#.*\n { } [\t \r\n]+ { } [a-zA-Z]+ { yyerror("Illegal word"); } . { yyerror("Illegal character"); } %% pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/ctltab.c0000664000000000000000000000435612272262501016367 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include "pmapi.h" #include "ctltab.h" #include "pglobal.h" #include "pmemory.h" #include "pracinfo.h" #include "pscred.h" #include "psinfo.h" #include "pstatus.h" #include "psusage.h" #include "pcpu.h" #include "ppred_values.h" ctltab_entry ctltab[] = { { CLUSTER_GLOBAL, 1, pglobal_init, pglobal_getdesc, pglobal_setatom, pglobal_getinfo, pglobal_allocbuf }, { 1, 1, psinfo_init, psinfo_getdesc, psinfo_setatom, psinfo_getinfo, psinfo_allocbuf }, { 2, 1, pstatus_init, pstatus_getdesc, pstatus_setatom, pstatus_getinfo, pstatus_allocbuf }, { 3, 1, pscred_init, pscred_getdesc, pscred_setatom, pscred_getinfo, pscred_allocbuf }, { 4, 1, psusage_init, psusage_getdesc, psusage_setatom, psusage_getinfo, psusage_allocbuf }, { 5, 1, pmem_init, pmem_getdesc, pmem_setatom, pmem_getinfo, pmem_allocbuf }, { 6, 1, pracinfo_init, pracinfo_getdesc, pracinfo_setatom, pracinfo_getinfo, pracinfo_allocbuf }, { CLUSTER_CPU, 1, pcpu_init, pcpu_getdesc, pcpu_setatom, pcpu_getinfo, pcpu_allocbuf }, { CLUSTER_PRED, 1, ppred_init, ppred_getdesc, ppred_setatom, ppred_getinfo, ppred_allocbuf }, }; int nctltab = sizeof(ctltab) / sizeof (ctltab[0]); int lookup_ctltab(int cluster) { int i; for (i = 0; i < nctltab; i++) { if (ctltab[i].cluster == cluster) return i; } return PM_ERR_PMID; } pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/gram.y0000664000000000000000000001007212272262501016062 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ %{ #include #include "./gram_node.h" void yyerror(char *s); int yylex(void); int yyparse(void); int need_psusage = 0; int need_accounting = 0; static bool_node *pred_tree = NULL; %} %union { char *y_str; double y_number; bool_node *y_node; } %token NUMBER %token STRING PATTERN %term AND OR NOT LPAREN RPAREN TRUE FALSE EQUAL NEQUAL LTHAN LEQUAL GTHAN GEQUAL MATCH NMATCH GID UID CPUBURN GNAME UNAME FNAME PSARGS SYSCALLS CTXSWITCH VIRTUALSIZE RESIDENTSIZE IODEMAND IOWAIT SCHEDWAIT VERSION %type predicate comparison num_compar numvar str_compar strvar pattern_compar %type version %left OR %left AND %left NOT %% pred_tree: predicate { pred_tree = $1;} | version predicate { pred_tree = $2;} ; version: VERSION NUMBER { float version_num = $2; if (version_num != 1.0) { (void)fprintf(stderr, "Wrong version number in configuration predicate\n"); (void)fprintf(stderr, "Expected version %.2f, but was given version %.2f .\n", 1.0, version_num); YYABORT; } } predicate: predicate AND predicate { $$ = create_tnode(N_and, $1, $3); } | predicate OR predicate { $$ = create_tnode(N_or, $1, $3); } | NOT predicate { $$ = create_tnode(N_not, $2, NULL); } | LPAREN predicate RPAREN { $$ = $2; } | comparison | TRUE { $$ = create_tag_node(N_true); } | FALSE { $$ = create_tag_node(N_false); } ; comparison: num_compar | str_compar | pattern_compar ; num_compar: numvar LTHAN numvar { $$ = create_tnode(N_lt, $1, $3); } | numvar LEQUAL numvar { $$ = create_tnode(N_le, $1, $3); } | numvar GTHAN numvar { $$ = create_tnode(N_gt, $1, $3); } | numvar GEQUAL numvar { $$ = create_tnode(N_ge, $1, $3); } | numvar EQUAL numvar { $$ = create_tnode(N_eq, $1, $3); } | numvar NEQUAL numvar { $$ = create_tnode(N_neq, $1, $3); } ; numvar: NUMBER { $$ = create_number_node($1); } | GID { $$ = create_tag_node(N_gid); } | UID { $$ = create_tag_node(N_uid); } | CPUBURN { $$ = create_tag_node(N_cpuburn); } | SYSCALLS { need_psusage = 1; $$ = create_tag_node(N_syscalls); } | CTXSWITCH { need_psusage = 1; $$ = create_tag_node(N_ctxswitch); } | VIRTUALSIZE { $$ = create_tag_node(N_virtualsize); } | RESIDENTSIZE { $$ = create_tag_node(N_residentsize); } | IODEMAND { need_psusage = 1; $$ = create_tag_node(N_iodemand); } | IOWAIT { need_accounting = 1; $$ = create_tag_node(N_iowait); } | SCHEDWAIT { need_accounting = 1; $$ = create_tag_node(N_schedwait); } ; str_compar: strvar EQUAL strvar { $$ = create_tnode(N_seq, $1, $3); } | strvar NEQUAL strvar { $$ = create_tnode(N_sneq, $1, $3); } ; strvar: STRING { $$ = create_str_node($1); } | GNAME { $$ = create_tag_node(N_gname); } | UNAME { $$ = create_tag_node(N_uname); } | FNAME { $$ = create_tag_node(N_fname); } | PSARGS { $$ = create_tag_node(N_psargs); } ; pattern_compar: strvar MATCH PATTERN { $$ = create_tnode(N_match, $1, create_pat_node($3)); } | strvar NMATCH PATTERN { $$ = create_tnode(N_nmatch, $1, create_pat_node($3)); } ; %% int parse_predicate(bool_node **tree) { int sts; extern int yylineno; /* defined by lex */ yylineno=1; start_tree(); sts = yyparse(); /* free any partial trees */ if (sts != 0) { free_tree(NULL); return sts; } *tree = pred_tree; return 0; } pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/gram_node.c0000664000000000000000000001205512272262501017044 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include "./gram_node.h" /* functions */ static void dump_comparison(FILE *, bool_node *); static void dump_var(FILE *, bool_node *); static bool_node *node_list = NULL; void start_tree(void) { node_list = NULL; } void free_tree(bool_node *root) { bool_node *n, *next; if (root == NULL) root = node_list; /* use last tree */ /* free all nodes in list */ for (n = root; n != NULL; ) { next = n->next; if (n->tag == N_pat || n->tag == N_str) free(n->data.str_val); free(n); n = next; } if (root == node_list) node_list = NULL; } bool_node * create_tag_node(N_tag tag) { bool_node *new_node; new_node = (bool_node*)malloc(sizeof(bool_node)); if (new_node == NULL) { fprintf(stderr, "hotproc: malloc failed in config: %s", osstrerror()); exit(1); } new_node->tag = tag; /* add to front of node-list */ new_node->next = node_list; node_list = new_node; return new_node; } bool_node * create_tnode(N_tag tag, bool_node *lnode, bool_node *rnode) { bool_node *n = create_tag_node(tag); n->data.children.left = lnode; n->data.children.right = rnode; return n; } bool_node * create_number_node(double x) { bool_node *n = create_tag_node(N_number); n->data.num_val = x; return n; } bool_node *create_str_node(char *str) { bool_node *n = create_tag_node(N_str); n->data.str_val = str; return n; } bool_node *create_pat_node(char *str) { bool_node *n = create_tag_node(N_pat); n->data.str_val = str; return n; } void dump_bool_tree(FILE *f, bool_node *tree) { (void)fprintf(f, "--- bool tree ---\n"); dump_predicate(f, tree); (void)fprintf(f, "\n--- end bool tree ---\n"); } void dump_predicate(FILE *f, bool_node *pred) { bool_node *lhs, *rhs; switch(pred->tag) { case N_and: lhs = pred->data.children.left; rhs = pred->data.children.right; (void)fprintf(f, "("); dump_predicate(f, lhs); (void)fprintf(f, " && "); dump_predicate(f, rhs); (void)fprintf(f, ")"); break; case N_or: lhs = pred->data.children.left; rhs = pred->data.children.right; (void)fprintf(f, "("); dump_predicate(f, lhs); (void)fprintf(f, " || "); dump_predicate(f, rhs); (void)fprintf(f, ")"); break; case N_not: lhs = pred->data.children.left; (void)fprintf(f, "(! "); dump_predicate(f, lhs); (void)fprintf(f, ")"); break; case N_true: (void)fprintf(f, "(true)"); break; case N_false: (void)fprintf(f, "(false)"); break; default: dump_comparison(f, pred); }/*switch*/ } static void dump_comparison(FILE *f, bool_node *comp) { bool_node *lhs = comp->data.children.left; bool_node *rhs = comp->data.children.right; (void)fprintf(f, "("); dump_var(f, lhs); switch(comp->tag) { case N_lt: (void)fprintf(f, " < "); break; case N_gt: (void)fprintf(f, " > "); break; case N_le: (void)fprintf(f, " <= "); break; case N_ge: (void)fprintf(f, " >= "); break; case N_eq: (void)fprintf(f, " == "); break; case N_seq: (void)fprintf(f, " == "); break; case N_sneq: (void)fprintf(f, " != "); break; case N_neq: (void)fprintf(f, " != "); break; case N_match: (void)fprintf(f, " ~ "); break; case N_nmatch: (void)fprintf(f, " !~ "); break; default: (void)fprintf(f, ""); break; }/*switch*/ dump_var(f, rhs); (void)fprintf(f, ")"); } static void dump_var(FILE *f, bool_node *var) { switch(var->tag) { case N_str: (void)fprintf(f, "\"%s\"", var->data.str_val); break; case N_pat: (void)fprintf(f, "\"%s\"", var->data.str_val); break; case N_number: (void)fprintf(f, "%f", var->data.num_val); break; case N_uid: (void)fprintf(f, "uid"); break; case N_gid: (void)fprintf(f, "gid"); break; case N_uname: (void)fprintf(f, "uname"); break; case N_gname: (void)fprintf(f, "gname"); break; case N_fname: (void)fprintf(f, "fname"); break; case N_psargs: (void)fprintf(f, "psargs"); break; case N_cpuburn: (void)fprintf(f, "cpuburn"); break; case N_syscalls: (void)fprintf(f, "syscalls"); break; case N_ctxswitch: (void)fprintf(f, "ctxswitch"); break; case N_virtualsize: (void)fprintf(f, "virtualsize"); break; case N_residentsize: (void)fprintf(f, "residentsize"); break; case N_iodemand: (void)fprintf(f, "iodemand"); break; case N_iowait: (void)fprintf(f, "iowait"); break; case N_schedwait: (void)fprintf(f, "schedwait"); break; default: (void)fprintf(f, ""); break; }/*switch*/ } pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/pcpu.h0000664000000000000000000000205712272262501016066 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PCPU_H #define PCPU_H #define CLUSTER_CPU 102 #define ITEM_CPUBURN 0 void pcpu_init(int dom); int pcpu_getdesc(pmID pmid, pmDesc *desc); int pcpu_setatom(int item, pmAtomValue *atom, int j); int pcpu_getinfo(pid_t pid, int j); int pcpu_allocbuf(int size); #endif pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/pglobal.h0000664000000000000000000000256112272262501016537 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PGLOBAL_H #define PGLOBAL_H #define CLUSTER_GLOBAL 100 #define ITEM_NPROCS 0 #define ITEM_REFRESH 1 #define ITEM_CPUIDLE 2 #define ITEM_TOTAL_CPUBURN 3 #define ITEM_TRANSIENT 4 #define ITEM_TOTAL_NOTCPUBURN 5 #define ITEM_OTHER_TOTAL 6 #define ITEM_OTHER_PERCENT 7 #define ITEM_CONFIG 8 #define ITEM_CONFIG_GEN 9 void pglobal_init(int dom); int pglobal_getdesc(pmID pmid, pmDesc *desc); int pglobal_setatom(int item, pmAtomValue *atom, int j); int pglobal_getinfo(pid_t pid, int j); int pglobal_allocbuf(int size); #endif pcp-3.8.12ubuntu1/src/pmdas/hotproc/src/pglobal.c0000664000000000000000000000475112272262501016535 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "pmapi.h" #include "./proc.h" #include "./proc_aux.h" #include "./pglobal.h" static pmDesc desctab[] = { { PMID(CLUSTER_GLOBAL,ITEM_NPROCS), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} }, { PMID(CLUSTER_GLOBAL,ITEM_REFRESH), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} }, { PMID(CLUSTER_GLOBAL,ITEM_CONFIG), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} }, { PMID(CLUSTER_GLOBAL,ITEM_CONFIG_GEN), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} }, { PMID(CLUSTER_GLOBAL,ITEM_CPUIDLE), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} }, { PMID(CLUSTER_GLOBAL,ITEM_TOTAL_CPUBURN), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} }, { PMID(CLUSTER_GLOBAL,ITEM_TRANSIENT), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} }, { PMID(CLUSTER_GLOBAL,ITEM_TOTAL_NOTCPUBURN), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} }, { PMID(CLUSTER_GLOBAL,ITEM_OTHER_TOTAL), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} }, { PMID(CLUSTER_GLOBAL,ITEM_OTHER_PERCENT), PM_TYPE_FLOAT, PM_INDOM_NULL, PM_SEM_INSTANT, {0,0,0,0,0,0} } }; static int ndesc = (sizeof(desctab)/sizeof(desctab[0])); void pglobal_init(int dom) { init_table(ndesc, desctab, dom); } int pglobal_getdesc(pmID pmid, pmDesc *desc) { return getdesc(ndesc, desctab, pmid, desc); } int pglobal_setatom(int item, pmAtomValue *atom, int j) { /* noop */ return 0; } int pglobal_getinfo(pid_t pid, int j) { /* noop */ return 0; } int pglobal_allocbuf(int size) { /* noop */ return 0; } pcp-3.8.12ubuntu1/src/pmdas/hotproc/GNUmakefile0000664000000000000000000001051212272262501016224 0ustar # # Copyright (c) 1995-2002,2007 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs # This is just to get the source exported to the community. # 'Makefile' in particular is included only for clues it might offer, # and should almost certainly be removed from SRCFILES once # the pmda is working. LSRCFILES = fixpmns.awk general.pmie help.fmt Install \ pmns.hotproc Remove sample.conf \ general.conf help.hotproc Makefile README root SUBDIRS = src default default_pcp: install install_pcp: include $(BUILDRULES) # Remove # from start of all following lines to get pre-existing # (but currently non-functional) content #IAM = hotproc #DOMAIN = HOTPROC # #TARGETS = $(IAM) pmns help # #PROC_DIR = ../linux #PROC_SRCDIR = $(PROC_DIR)/src # #FROM_PROC_H = cluster.h pracinfo.h proc_aux.h pscred.h \ # pstatus.h pmemory.h proc.h procmem.h psinfo.h \ # psusage.h ctltab.h nameinfo.h #FROM_PROC_C = pmemory.c pracinfo.c proc_aux.c \ # pscred.c psinfo.c pstatus.c psusage.c \ # ttyname.c procmem.c nameinfo.c # #FROM_PROC = $(FROM_PROC_C) $(FROM_PROC_H) # #CFILES = $(FROM_PROC_C) \ # pglobal.c ctltab.c hotproc.c pcpu.c \ # config.c gram_node.c error.c ppred_values.c # #OBJECTS = gram.o lex.o $(CFILES:S/.c/.o/g) # #LCOPTS = -fullwarn #LCINCS = $(PCP_INC_PATH) #LCDEFS = $(DEBUG) #LLDOPTS = $(PCP_LIBS_PATH) #LLDLIBS = $(PCP_PMDALIB) # #PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) #LDIRT = domain.h *.log *.dir *.pag # #default: $(TARGETS) check_help_src # #include $(TOPDIR)/src/include/buildrules.pro # #install: default # $(INSTALL) -m 755 -d $(PMDADIR) # $(INSTALL) -lns ../../..$(PMDADIR)/pmda$(IAM) pmda$(IAM) $(PCP_SHARE_DIR)/lib # $(INSTALL) -lns ../../..$(PMDADIR) $(IAM) $(PCP_PMDAS_DIR) # $(INSTALL) -m 755 pmda$(IAM) $(PMDADIR) # $(INSTALL) -m 755 Install Remove $(PMDADIR) # $(INSTALL) -m 644 README root help pmns domain.h sample.conf general.conf general.pmie $(PMDADIR) # #$(IAM): $(OBJECTS) # #domain.h: ../../pmns/stdpmid # $(DOMAIN_MAKERULE) # #help: $(PROC_DIR)/help help.hotproc pmns # $(AWK) <$(PROC_DIR)/help '\ #$1 == "@" { want=0 }\ #$1 == "@" && $2 ~ /^proc/ { want=1 }\ #want == 1 { print }' \ # | sed -e 's/proc\./hotproc./g' \ # -e 's/number of processes/number of "interesting" processes/g' \ # | cat - help.hotproc \ # | ./help.fmt >$@ # #pmns: $(PROC_DIR)/root_linux pmns.hotproc fixpmns.awk # $(AWK) < $(PROC_DIR)/root_linux -f fixpmns.awk \ # | sed -e '/nprocs/d' -e 's/60:/HOTPROC:/g' -e 's/^proc/hotproc/g' \ # | cat - pmns.hotproc >$@ # #hotproc.o: domain.h # #config.o: gram.tab.h # #check_help_src: domain.h help root pmns # PCP_SRC_DEPTH=$(PCP_SRC_DEPTH) $(PCP_SRC_DEPTH)/buildtools/check_help_src help root # ## ## PROC_SRCDIR dependencies ## #cluster.h: $(PROC_SRCDIR)/cluster.h # ln -s $? $@ #pracinfo.h: $(PROC_SRCDIR)/pracinfo.h # ln -s $? $@ #pracinfo.c: $(PROC_SRCDIR)/pracinfo.c # ln -s $? $@ #proc_aux.h: $(PROC_SRCDIR)/proc_aux.h # ln -s $? $@ #proc_aux.c: $(PROC_SRCDIR)/proc_aux.c # ln -s $? $@ #pscred.h: $(PROC_SRCDIR)/pscred.h # ln -s $? $@ #pscred.c: $(PROC_SRCDIR)/pscred.c # ln -s $? $@ #pstatus.h: $(PROC_SRCDIR)/pstatus.h # ln -s $? $@ #pstatus.c: $(PROC_SRCDIR)/pstatus.c # ln -s $? $@ #pmemory.h: $(PROC_SRCDIR)/pmemory.h # ln -s $? $@ #pmemory.c: $(PROC_SRCDIR)/pmemory.c # ln -s $? $@ #proc.h: $(PROC_SRCDIR)/proc.h # ln -s $? $@ #procmem.h: $(PROC_SRCDIR)/procmem.h # ln -s $? $@ #procmem.c: $(PROC_SRCDIR)/procmem.c # ln -s $? $@ #psinfo.h: $(PROC_SRCDIR)/psinfo.h # ln -s $? $@ #psinfo.c: $(PROC_SRCDIR)/psinfo.c # ln -s $? $@ #psusage.h: $(PROC_SRCDIR)/psusage.h # ln -s $? $@ #psusage.c: $(PROC_SRCDIR)/psusage.c # ln -s $? $@ #ttyname.c: $(PROC_SRCDIR)/ttyname.c # ln -s $? $@ #ctltab.h: $(PROC_SRCDIR)/ctltab.h # ln -s $? $@ #nameinfo.h: $(PROC_SRCDIR)/nameinfo.h # ln -s $? $@ #nameinfo.c: $(PROC_SRCDIR)/nameinfo.c # ln -s $? $@ # # # # #default_pro : default # pcp-3.8.12ubuntu1/src/pmdas/hotproc/root0000664000000000000000000000016412272262501015062 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { hotproc } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/hotproc/help.fmt0000775000000000000000000000152712272262501015623 0ustar #!/bin/sh # # Run paragraphs of help text thru fmt(1) # Lines with tabs or double spaces are run thru fmt(1) only for that line # source the PCP configuration environment variables . $PCP_DIR/etc/pcp.env tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 trap "rm -rf $tmp; exit" 0 1 2 3 15 $PCP_AWK_PROG -v tmpfile=$tmp/fmt ' function fmt_line(l) { print l > tmpfile system("fmt -78 < " tmpfile) # format line(s) close(tmpfile) system(">" tmpfile) # truncate file } function format_line() { if (line != "") { fmt_line(line) line = "" } } BEGIN { line = "" } /^#/ || /^@/ { format_line(); print; next } / / || / / { format_line(); fmt_line($0); next } /^$/ { format_line(); print; next } { if (line == "") line = $0 else line = sprintf("%s\n%s",line,$0) } END { format_line() } ' pcp-3.8.12ubuntu1/src/pmdas/hotproc/general.conf0000664000000000000000000000156512272262501016446 0ustar #pmdahotproc Version 1.0 # this configuration is of a more general nature, and identifies # a number of "interesting" classes of processes ... it is assumed # that some other monitoring tool, like pmie, would be able to # decide which processes are members of each "interesting" class # # a sample pmie ruleset matching this hotproc configuration may # be found in $PCP_PMDAS_DIR/hotproc/general.pmie # cpuburn > 0.95 # one process using more than the equivalent of # 95% of one processor || iodemand > 500 # or more than 500 Kbytes/sec passing across the # read() and write() system call interfaces || syscalls > 100 # or more than 100 system calls/sec || iowait > 0.33 # or more than 33% of the time is waiting for # some sort of I/O || schedwait > 0.25 # or more than 25% of the time is on the run # queue waiting for the scheduler to assign # a processor pcp-3.8.12ubuntu1/src/pmdas/hotproc/general.pmie0000775000000000000000000000162312272262501016451 0ustar // this pmie configuration files assumes the hotproc PMDA has been // configured with the "general.conf" configuration file, and thus // is using as predicate something like: // // cpuburn > 0.95 || iodemand > 500 || syscalls > 100 // || iowait > 0.33 || schedwait > 0.25 // delta = 60sec; // change this if the hotproc PMDA refresh interval // is different to the default of 60 seconds some_inst 100 * hotproc.psinfo.time > 95 -> print "\nCPU: %v% busy %i"; io_bytes = "hotproc.accounting.counts"; some_inst (($io_bytes.chr + $io_bytes.chw) / 1024) > 500 -> print "\nI/O: %v Kbyte/sec %i"; some_inst hotproc.psusage.sysc > 100 -> print "\nsyscall: %v call/sec %i"; io_timers = "hotproc.accounting.timers"; some_inst 100 * ( $io_timers.bwtime + $io_timers.rwtime ) > 33 -> print "\nI/O: %v% waiting %i"; some_inst 100 * $io_timers.qwtime > 25 -> print "\nCPU: %v% runq waiting %i"; pcp-3.8.12ubuntu1/src/pmdas/hotproc/pmns.hotproc0000664000000000000000000000126412272262501016533 0ustar /* * Metrics borrowed from "proc" pmda above ... these ones are specific * to the hotproc PMDA. */ hotproc.control { refresh HOTPROC:100:1 config HOTPROC:100:8 config_gen HOTPROC:100:9 } hotproc.total { cpuidle HOTPROC:100:2 cpuburn HOTPROC:100:3 cpuother } hotproc.total.cpuother { transient HOTPROC:100:4 not_cpuburn HOTPROC:100:5 total HOTPROC:100:6 percent HOTPROC:100:7 } hotproc.predicate { syscalls HOTPROC:101:0 ctxswitch HOTPROC:101:1 virtualsize HOTPROC:101:2 residentsize HOTPROC:101:3 iodemand HOTPROC:101:4 iowait HOTPROC:101:5 schedwait HOTPROC:101:6 } pcp-3.8.12ubuntu1/src/pmdas/news/0000775000000000000000000000000012272262620013453 5ustar pcp-3.8.12ubuntu1/src/pmdas/news/pmdanews.pl0000664000000000000000000001402412272262501015625 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; my @newsgroups = ( 1, 'comp.sys.sgi', 2, 'comp.sys.sgi.graphics', 3, 'comp.sys.sgi.hardware', 4, 'sgi.bad-attitude', 5, 'sgi.engr.all', ); use vars qw( $total $news_regex %news_hash @news_count @news_last ); my ($nnrpd_count, $rn_count, $trn_count, $xrn_count, $vn_count) = (0,0,0,0,0); my $news_file = pmda_config('PCP_PMDAS_DIR') . '/news/active'; my $news_indom = 0; my $pmda; sub news_fetch # called once per ``fetch'' pdu, before callbacks { my ( $group, $cmd ); $total = 0; seek ACTIVE,0,0; while () { next unless /$news_regex/; $group = $news_hash{$1} - 1; $news_last[$group] = $2; $total += $news_count[$group] = $2 - $3; } ($nnrpd_count, $rn_count, $trn_count, $xrn_count, $vn_count) = (0,0,0,0,0); if (open(READERS, 'ps -ef |')) { while () { s/\b(:?\d\d:){2}\d\d\b/ Mmm DD /; # replace times with dates s/\s*?(\S+?\s+?){8}//; # nuke the first eight fields next unless /(\S+)\s*?/; # prepare $cmd with command name $cmd = $1; ($cmd eq 'in.nnrpd' || $cmd =~ /\/in\.nnrpd$/) && $nnrpd_count++; ($cmd eq 'rn' || $cmd =~ /\/rn$/) && $rn_count++; ($cmd eq 'trn' || $cmd =~ /\/trn$/) && $trn_count++; ($cmd eq 'xrn' || $cmd =~ /\/xrn$/) && $xrn_count++; ($cmd eq 'vn' || $cmd =~ /\/vrn$/) && $vn_count++; } close READERS; } else { $pmda->log("Cannot execute 'ps' to count news reader processes"); } } sub news_fetch_callback # must return array of value,status { my ($cluster, $item, $inst) = @_; return (PM_ERR_INST, 0) unless ( $inst == PM_IN_NULL || ( $cluster == 0 && ($item == 301 || $item == 302) && $inst > 0 && $inst <= ($#newsgroups+1)/2 ) ); if ($cluster == 0) { if ($item == 201) { ($total, 1); } # articles.total elsif ($item == 301) { ($news_count[$inst-1], 1); } # articles.count elsif ($item == 302) { ($news_last[$inst-1], 1); } # articles.last elsif ($item == 101) { ($nnrpd_count, 1); } # readers.nnrpd elsif ($item == 111) { ($rn_count, 1); } # readers.rn elsif ($item == 112) { ($trn_count, 1); } # readers.trn elsif ($item == 113) { ($xrn_count, 1); } # readers.xrn elsif ($item == 114) { ($vn_count, 1); } # readers.vn else { (PM_ERR_PMID, 0); } } else { (PM_ERR_PMID, 0); } } sub news_init { ($#newsgroups > 0 && $#newsgroups % 2 != 0) || die "Invalid newsgroups array has been specified\n"; open(ACTIVE, $news_file) || die "Can't open $news_file: $!\n"; # build regex using the given newsgroup names $_ = "^($newsgroups[1]"; $news_hash{$newsgroups[1]} = $newsgroups[0]; for (my $i = 2; $i < $#newsgroups; $i += 2) { $_ .= "|$newsgroups[$i+1]"; $news_hash{$newsgroups[$i+1]} = $newsgroups[$i]; } $news_regex = $_ . ") (\\d+) (\\d+) y\$"; } $pmda = PCP::PMDA->new('news', 28); $pmda->add_metric(pmda_pmid(0,201), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'news.articles.total', 'Total number of articles received for each newsgroup', 'Total number of articles received for each newsgroup. Note this is the historical running total, see news.articles.count for the current total of un-expired articles by newsgroup.'); $pmda->add_metric(pmda_pmid(0,301), PM_TYPE_U32, $news_indom, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'news.articles.count', 'Total number of un-expired articles in each newsgroup', ''); $pmda->add_metric(pmda_pmid(0,302), PM_TYPE_U32, $news_indom, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'news.articles.last', '', ''); $pmda->add_metric(pmda_pmid(0,101), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'news.readers.nnrpd', '', ''); $pmda->add_metric(pmda_pmid(0,111), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'news.readers.rn', '', ''); $pmda->add_metric(pmda_pmid(0,112), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'news.readers.trn', '', ''); $pmda->add_metric(pmda_pmid(0,113), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'news.readers.xrn', '', ''); $pmda->add_metric(pmda_pmid(0,114), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), 'news.readers.vn', '', ''); $pmda->add_indom($news_indom, \@newsgroups, '', ''); $pmda->set_fetch(\&news_fetch); $pmda->set_fetch_callback(\&news_fetch_callback); &news_init; $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdanews - sample Usenet news performance metrics domain agent (PMDA) =head1 DESCRIPTION B is an example Performance Metrics Domain Agent (PMDA) which exports metric values related to a set of newsgroups. =head1 INSTALLATION If you want access to the names and values for the news performance metrics, do the following as root: # cd $PCP_PMDAS_DIR/news # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/news # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/news/Install installation script for the B agent =item $PCP_PMDAS_DIR/news/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/news.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1). pcp-3.8.12ubuntu1/src/pmdas/news/README0000664000000000000000000000271412272262501014335 0ustar Usenet News PMDA ================ This PMDA is a sample, that illustrates how a simple PMDA might be constructed using the Perl PMDA API. Although the metrics supported are simple, the framework in the script pmdanews is quite general, and could be re-used to implement other PMDAs. Metrics ======= Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT news Installation ============ + # cd $PCP_PMDAS_DIR/news + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options. + By default the script pmdanews operates on a small test-case copy a news "active" file, installed from here into $PCP_PMDAS_DIR/news/active. If you wish to use a more realistic base of Usenet data, edit pmdanews.pl to make it use your "live active" groups, then # ./Install. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/news # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/news.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/news/Remove0000664000000000000000000000161712272262501014636 0ustar #! /bin/sh # # Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the news PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=news pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/news/Install0000664000000000000000000000137512272262501015010 0ustar #! /bin/sh # # Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the news PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=news perl_opt=true daemon_opt=false forced_restart=false pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/news/active0000664000000000000000000000060712272262501014652 0ustar # fake for testing # the metrics should be as follows # news.articles.total 1000 # news.articles.last 100 0 0 200 1101 3795 7130 # news.articles.count 0 0 0 100 100 700 100 comp.sys.sgi 0100 0100 y comp.sys.sgi.graphics 0000 0000 y comp.sys.sgi.hardware 0000 0000 y sgi.bad-attitude 3795 3095 y sgi.bugs.sherwood 1101 1001 y sgi.engr.all 0200 0100 y sgi.general 7130 7030 y pcp-3.8.12ubuntu1/src/pmdas/news/GNUmakefile0000664000000000000000000000301312272262501015520 0ustar #!gmake # # Copyright (c) 2000-2001,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = news PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove README active pmda$(IAM).pl LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl $(INSTALL) -m 644 README active $(PMDADIR) @$(INSTALL_MAN) default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/systemd/0000775000000000000000000000000012272262620014167 5ustar pcp-3.8.12ubuntu1/src/pmdas/systemd/README0000664000000000000000000000336312272262501015052 0ustar Systemd PMDA =========== This PMDA exports events from the systemd journal [1] as they occur. There is no configuration required. In the default (daemon) PMDA mode, the daemon switches to userid 'adm', so it can report systemwide journal entries. [1] http://www.freedesktop.org/wiki/Software/systemd Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT systemd The interesting metrics are systemd.journal.records and systemd.journal.records_raw. When a PCP client such as pmevent monitors them, each new journal entry is reported as a PCP event tuple. Each field of the journal entry is transcribed as a string or blob, including the FIELDNAME= prefix. See [2] for more details about interpretation of the fields. [2] http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html Installation ============ + # cd $PCP_PMDAS_DIR/systemd + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options -- everything else is automated. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/systemd # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/systemd.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/systemd/Remove0000775000000000000000000000134412272262501015352 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2011-2012 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the systemd PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=systemd pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/systemd/Install0000775000000000000000000000144212272262501015522 0ustar #! /bin/sh # # Copyright (c) 2011-2013 Red Hat Inc. # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the systemd PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=systemd pmda_interface=6 pipe_opt=true daemon_opt=true pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/systemd/GNUmakefile0000664000000000000000000000271612272262501016245 0ustar # # Copyright (c) 2012 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs CMDTARGET = pmdasystemd$(EXECSUFFIX) LIBTARGET = pmda_systemd.so DFILES = README CFILES = systemd.c LCFLAGS = $(SYSTEMD_CFLAGS) LLDLIBS = $(PCP_PMDALIB) $(SYSTEMD_LIBS) LSRCFILES = Install Remove pmns help $(DFILES) root IAM = systemd DOMAIN = SYSTEMD PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LDIRT = domain.h *.o $(IAM).log $(CMDTARGET) default: build-me include $(BUILDRULES) ifneq "$(PMDA_SYSTEMD)" "" build-me: domain.h $(LIBTARGET) $(CMDTARGET) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 $(DFILES) root help pmns $(PMDADIR) $(INSTALL) -m 644 domain.h $(PMDADIR)/domain.h $(INSTALL) -m 755 $(LIBTARGET) $(CMDTARGET) $(PMDADIR) else build-me: install: endif systemd.o: domain.h .NOTPARALLEL: .ORDER: domain.h $(OBJECTS) default_pcp : default install_pcp : install domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/systemd/root0000664000000000000000000000014312272262501015071 0ustar #include root { systemd } #ifndef SYSTEMD #define SYSTEMD 114 #endif #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/systemd/pmns0000664000000000000000000000176612272262501015077 0ustar /* * Metrics for systemd PMDA * * Copyright (c) 2012-2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ systemd { numclients SYSTEMD:0:0 maxmem SYSTEMD:0:1 journal } systemd.journal { records SYSTEMD:2:0 records_raw SYSTEMD:2:1 field count SYSTEMD:2:2 bytes SYSTEMD:2:3 } systemd.journal.field { cursor SYSTEMD:1:0 string SYSTEMD:1:1 /* possibly a string */ blob SYSTEMD:1:2 /* a binary blob */ } pcp-3.8.12ubuntu1/src/pmdas/systemd/systemd.c0000664000000000000000000006176512272262501016040 0ustar /* * systemd support for the systemd PMDA * * Copyright (c) 2012-2013 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * Structure based upon the logger pmda. */ #define _POSIX_C_SOURCE 200112L /* for strtoull */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include #include #include #include #include #include #include #include #include #define DEFAULT_MAXMEM (2 * 1024 * 1024) /* 2 megabytes */ long maxmem; int maxfd; fd_set fds; static int interval_expired; static struct timeval interval = { 60, 0 }; static sd_journal *journald_context; /* Used for monitoring only. */ static sd_journal *journald_context_seeky; /* Used for event detail extraction, involving seeks. */ static int queue_entries = -1; static char *username = "adm"; /* Track per-context PCP_ATTR_USERID | _GROUPID, so we can filter event records for that context. */ static int uid_gid_filter_p = 1; struct uid_gid_tuple { char wildcard_p; /* do not filter for this context. */ char uid_p; char gid_p; /* uid/gid received flags. */ int uid; int gid; }; /* uid/gid received from PCP_ATTR_* */ static struct uid_gid_tuple *ctxtab = NULL; int ctxtab_size = 0; static pmdaMetric metrictab[] = { /* numclients */ #define METRICTAB_NUMCLIENTS_PMID metrictab[0].m_desc.pmid { NULL, { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* maxmem */ #define METRICTAB_MAXMEM_PMID metrictab[1].m_desc.pmid { NULL, { PMDA_PMID(0,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* journal.field.cursor */ #define METRICTAB_JOURNAL_CURSOR_PMID metrictab[2].m_desc.pmid { NULL, { PMDA_PMID(1,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* journal.field.string */ #define METRICTAB_JOURNAL_STRING_PMID metrictab[3].m_desc.pmid { NULL, { PMDA_PMID(1,1), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* journal.field.blob */ #define METRICTAB_JOURNAL_BLOB_PMID metrictab[4].m_desc.pmid { NULL, { PMDA_PMID(1,2), PM_TYPE_AGGREGATE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* journal.records */ #define METRICTAB_JOURNAL_RECORDS_PMID metrictab[5].m_desc.pmid { NULL, { PMDA_PMID(2,0), PM_TYPE_EVENT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* journal.records_raw */ #define METRICTAB_JOURNAL_RECORDS_RAW_PMID metrictab[6].m_desc.pmid { NULL, { PMDA_PMID(2,1), PM_TYPE_EVENT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* journal.count */ #define METRICTAB_JOURNAL_COUNT_PMID metrictab[7].m_desc.pmid { NULL, { PMDA_PMID(2,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* journal.bytes */ #define METRICTAB_JOURNAL_BYTES_PMID metrictab[8].m_desc.pmid { NULL, { PMDA_PMID(2,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, }; void systemd_shutdown(void) { if (journald_context != 0) sd_journal_close (journald_context); if (journald_context_seeky != 0) sd_journal_close (journald_context_seeky); /* XXX: pmdaEvent zap queues? */ } /* Return a strndup (or NULL) of a field of the current journal entry, since sd_journal_get_data returns data that is not \0-terminated. */ char * my_sd_journal_get_data(sd_journal *j, const char *field) { int rc; const char* str; size_t str_len; assert (j != NULL); assert (field != NULL); rc = sd_journal_get_data(j, field, (const void**) & str, & str_len); if (rc < 0) return NULL; return strndup (str, str_len); } void systemd_refresh(void) { /* Absorb any changes such as inotify() messages. */ (void) sd_journal_process(journald_context); (void) sd_journal_process(journald_context_seeky); while (1) { char *cursor = NULL; char *timestamp_str = NULL; struct timeval timestamp; int rc = sd_journal_next(journald_context); if (rc == 0) /* No recent entries. */ break; if (rc < 0) { __pmNotifyErr(LOG_ERR, "sd_journal_next failure: %s", strerror(-rc)); break; } /* NB: we enqueue the journal cursor string, rather than the actual journal records. */ rc = sd_journal_get_cursor(journald_context, &cursor); if (rc < 0) { __pmNotifyErr(LOG_ERR, "sd_journal_get_cursor failure: %s", strerror(-rc)); break; } /* Extract a timestamp from the journald event fields. */ timestamp_str = my_sd_journal_get_data(journald_context, "_SOURCE_REALTIME_TIMESTAMP"); if (timestamp_str == NULL) timestamp_str = my_sd_journal_get_data(journald_context, "__REALTIME_TIMESTAMP"); if (timestamp_str == NULL) rc = -ENOMEM; else { const char* curse; unsigned long long epoch_us; /* defined in systemd.journal-fields(7) as FIELD_NAME=NNNN, where NNNN is decimal us since epoch. */ curse = strchr (timestamp_str, '='); if (curse == NULL) rc = -EINVAL; else { curse ++; epoch_us = strtoull (curse, NULL, 10); timestamp.tv_sec = epoch_us / 1000000; timestamp.tv_usec = epoch_us % 1000000; } free (timestamp_str); } /* Improvise. */ if (rc < 0) gettimeofday (& timestamp, NULL); /* Enqueue it to fresh visitors. */ rc = pmdaEventQueueAppend(queue_entries, cursor, strlen(cursor)+1 /* \0 */, ×tamp); free(cursor); /* Already copied. */ if (rc < 0) { __pmNotifyErr(LOG_ERR, "pmdaEventQueueAppend failure: %s", pmErrStr(rc)); break; } } } enum journald_field_encoding { JFE_STRING_BLOB_AUTO, JFE_BLOB_ONLY }; int systemd_journal_event_filter (void *rp, void *data, size_t size) { int rc; struct uid_gid_tuple* ugt = rp; assert (ugt == & ctxtab[pmdaGetContext()]); if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "filter (%d) uid=%d gid=%d data=%p bytes=%u\n", pmdaGetContext(), ugt->uid, ugt->gid, data, (unsigned)size); /* The data/size pair gives the object in the event queue, i.e., the systemd journal cursor string. It has not yet been turned into a PM_TYPE_EVENT tuple yet, and if we have our way, it won't be (for non-participating clients). */ /* The general filtering idea is to only feed journal records to clients if their uid matches the _UID=NNN field -or- gid matches _GID=MMM -or- the client is highly authenticated (wildcard_p) -or- per-uid filtering was turned off at the pmda level. */ /* Reminder: function rc == 0 passes the filter. */ /* Unfiltered? Everyone gets egg soup! */ if (! uid_gid_filter_p) return 0; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "filter (%d) uid%s%d gid%s%d wildcard=%d\n", pmdaGetContext(), ugt->uid_p?"=":"?", ugt->uid, ugt->gid_p?"=":"?", ugt->gid, ugt->wildcard_p); /* Superuser? May we offer some goulash? */ if (ugt->wildcard_p) return 0; /* Unauthenticated context? No soup for you! */ if (! ugt->uid_p && ! ugt->gid_p) return 1; /* OK, we need to take a look at the journal record in question. */ if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "filter cursor=%s\n", (const char*) data); (void) size; /* already known \0-terminated */ rc = sd_journal_seek_cursor(journald_context_seeky, (char*) data); if (rc < 0) { __pmNotifyErr(LOG_ERR, "filter cannot seek to cursor=%s\n", (const char*) data); return 1; /* No point trying again in systemd_journal_decoder. */ } rc = sd_journal_next(journald_context_seeky); if (rc < 0) { __pmNotifyErr(LOG_ERR, "filter cannot advance to next\n"); return 1; /* No point trying again in systemd_journal_decoder. */ } if (ugt->uid_p) { char *uid_str = my_sd_journal_get_data(journald_context_seeky, "_UID"); if (uid_str) { int uid = atoi (& uid_str[5]); /* skip over _UID= */ free (uid_str); if (uid == ugt->uid) return 0; /* You're a somebody. Here's a bowl of stew. */ } } if (ugt->gid_p) { char *gid_str = my_sd_journal_get_data(journald_context_seeky, "_GID"); if (gid_str) { int gid = atoi (& gid_str[5]); /* skip over _GID= */ free (gid_str); if (gid == ugt->gid) return 0; /* You're with pals. Here's a bowl of miso. */ } } /* No soup for you! */ return 1; } void systemd_journal_event_filter_release (void *rp) { /* NB: We have nothing to release, as we don't do memory allocation for the filter per se - we clean up during end-context time. We can't send a NULL to pmdaEventSetFilter for release purposes (since it'll blindly call it), so need this dummy function. */ (void) rp; } int systemd_journal_decoder(int eventarray, void *buffer, size_t size, struct timeval *timestamp, void *data) { int sts; pmAtomValue atom; enum journald_field_encoding jfe = * (enum journald_field_encoding *) data; sts = pmdaEventAddRecord(eventarray, timestamp, PM_EVENT_FLAG_POINT); if (sts < 0) return sts; /* Go to the cursor point enqueued for this client. The buffer is already \0-terminated. */ sts = sd_journal_seek_cursor(journald_context_seeky, (char*) buffer); if (sts < 0) { /* But see RHBZ #876654. */ return /* sts */ 0; } sts = sd_journal_next(journald_context_seeky); if (sts < 0) return sts; if (sts == 0) return -ENODATA; /* event got lost between cursor-recording and now */ /* Add the _CURSOR implicit journal field. */ atom.cp = buffer; sts = pmdaEventAddParam(eventarray, METRICTAB_JOURNAL_CURSOR_PMID, PM_TYPE_STRING, &atom); /* Add all the explicit journal fields. */ while (1) { const void *data; size_t data_len; if (sts < 0) break; sts = sd_journal_enumerate_data(journald_context_seeky, &data, &data_len); if (sts <= 0) break; /* Infer string upon absence of embedded \0's. */ if (jfe == JFE_STRING_BLOB_AUTO && (memchr (data, '\0', data_len) == NULL)) { /* Unfortunately, data may not be \0-terminated, so we can't simply pass it to atom.cp. We need to copy the bad boy first. */ atom.cp = strndup(data, data_len); if (atom.cp == NULL) sts = -ENOMEM; else { sts = pmdaEventAddParam(eventarray, METRICTAB_JOURNAL_STRING_PMID, PM_TYPE_STRING, &atom); free (atom.cp); } /* NB: we assume libpcp_pmda will not free() the field. */ } else { pmValueBlock *aggr = (pmValueBlock *)malloc(PM_VAL_HDR_SIZE + data_len); if (aggr == NULL) sts = -ENOMEM; else { aggr->vtype = PM_TYPE_AGGREGATE; if (PM_VAL_HDR_SIZE + data_len >= 1<<24) aggr->vlen = (1U<<24) - 1; /* vlen is a :24 bit field */ else aggr->vlen = PM_VAL_HDR_SIZE + data_len; memcpy (aggr->vbuf, data, data_len); atom.vbp = aggr; sts = pmdaEventAddParam(eventarray, METRICTAB_JOURNAL_BLOB_PMID, PM_TYPE_AGGREGATE, &atom); /* NB: we assume libpcp_pmda will free() aggr. */ } } } return sts < 0 ? sts : 1; /* added one event array */ } void enlarge_ctxtab(int context) { /* Grow the context table if necessary. */ if (ctxtab_size /* cardinal */ <= context /* ordinal */) { size_t need = (context + 1) * sizeof(struct uid_gid_tuple); ctxtab = realloc (ctxtab, need); if (ctxtab == NULL) __pmNoMem("systemd ctx table", need, PM_FATAL_ERR); /* Blank out new entries. */ while (ctxtab_size <= context) memset (& ctxtab[ctxtab_size++], 0, sizeof(struct uid_gid_tuple)); } } static int systemd_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int sts; (void) pmdaEventNewClient(pmda->e_context); enlarge_ctxtab(pmda->e_context); sts = pmdaEventSetFilter(pmda->e_context, queue_entries, & ctxtab[pmda->e_context], /* any non-NULL value */ systemd_journal_event_filter, systemd_journal_event_filter_release /* NULL */); if (sts < 0) return sts; return pmdaFetch(numpmid, pmidlist, resp, pmda); } static int systemd_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { pmID id = mdesc->m_desc.pmid; int sts; if (id == METRICTAB_NUMCLIENTS_PMID) { sts = pmdaEventClients(atom); } else if (id == METRICTAB_MAXMEM_PMID) { atom->ul = (unsigned long)maxmem; sts = PMDA_FETCH_STATIC; } else if (id == METRICTAB_JOURNAL_CURSOR_PMID) { sts = PMDA_FETCH_NOVALUES; } else if (id == METRICTAB_JOURNAL_STRING_PMID) { sts = PMDA_FETCH_NOVALUES; } else if (id == METRICTAB_JOURNAL_BLOB_PMID) { sts = PMDA_FETCH_NOVALUES; } else if (id == METRICTAB_JOURNAL_COUNT_PMID) { sts = pmdaEventQueueCounter(queue_entries, atom); } else if (id == METRICTAB_JOURNAL_BYTES_PMID) { sts = pmdaEventQueueBytes(queue_entries, atom); } else if (id == METRICTAB_JOURNAL_RECORDS_PMID) { enum journald_field_encoding jfe = JFE_STRING_BLOB_AUTO; sts = pmdaEventSetAccess(pmdaGetContext(), queue_entries, 1); if (sts == 0) sts = pmdaEventQueueRecords(queue_entries, atom, pmdaGetContext(), systemd_journal_decoder, & jfe); } else if (id == METRICTAB_JOURNAL_RECORDS_RAW_PMID) { enum journald_field_encoding jfe = JFE_BLOB_ONLY; sts = pmdaEventSetAccess(pmdaGetContext(), queue_entries, 1); if (sts == 0) sts = pmdaEventQueueRecords(queue_entries, atom, pmdaGetContext(), systemd_journal_decoder, & jfe); } else { sts = PM_ERR_PMID; } return sts; } static int systemd_contextAttributeCallBack(int context, int attr, const char *value, int length, pmdaExt *pmda) { static int rootlike_gids_found = 0; static int adm_gid = -1; static int wheel_gid = -1; static int systemd_journal_gid = -1; int id; /* Look up root-like gids if needed. A later PCP client that matches any of these group-id's is treated as if root/adm, i.e., journal records are not filtered for them (wildcard_p). XXX: we could examine group-membership lists and check against uid to also set wildcard_p. */ if (! rootlike_gids_found) { struct group *grp; grp = getgrnam("adm"); if (grp) adm_gid = grp->gr_gid; grp = getgrnam("wheel"); if (grp) wheel_gid = grp->gr_gid; grp = getgrnam("systemd-journal"); if (grp) systemd_journal_gid = grp->gr_gid; rootlike_gids_found = 1; } enlarge_ctxtab(context); assert (ctxtab != NULL && context < ctxtab_size); /* NB: we maintain separate uid_p and gid_p for filtering purposes; it's possible that a pcp client might send only PCP_ATTR_USERID, leaving gid=0, possibly leading us to misinterpret that as GROUPID=0 (root) and sending back _GID=0 records. */ switch (attr) { case PCP_ATTR_USERID: ctxtab[context].uid_p = 1; id = atoi(value); ctxtab[context].uid = id; if (id == 0) /* root */ ctxtab[context].wildcard_p = 1; break; case PCP_ATTR_GROUPID: ctxtab[context].gid_p = 1; id = atoi(value); ctxtab[context].gid = id; if (id == adm_gid || id == wheel_gid || id == systemd_journal_gid) ctxtab[context].wildcard_p = 1; break; } if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "attrib (%d) uid%s%d gid%s%d wildcard=%d\n", context, ctxtab[context].uid_p?"=":"?", ctxtab[context].uid, ctxtab[context].gid_p?"=":"?", ctxtab[context].gid, ctxtab[context].wildcard_p); return 0; } static void systemd_end_contextCallBack(int context) { pmdaEventEndClient(context); /* assert (ctxtab != NULL && context < ctxtab_size); */ /* NB: don't do that; this callback may be hit without any fetch calls having been performed, this ctxtab not stretching all the way to [context]. */ if (context < ctxtab_size) memset (& ctxtab[context], 0, sizeof(struct uid_gid_tuple)); } static int systemd_desc(pmID pmid, pmDesc *desc, pmdaExt *pmda) { return pmdaDesc(pmid, desc, pmda); } static int systemd_text(int ident, int type, char **buffer, pmdaExt *pmda) { return pmdaText(ident, type, buffer, pmda); } void systemd_init(pmdaInterface *dp) { int sts; int journal_fd; /* The systemwide journal may be accessed by the adm user (group); root access is not necessary. */ __pmSetProcessIdentity(username); dp->comm.flags |= PDU_FLAG_AUTH; dp->version.six.desc = systemd_desc; dp->version.six.fetch = systemd_fetch; dp->version.six.text = systemd_text; dp->version.six.attribute = systemd_contextAttributeCallBack; pmdaSetFetchCallBack(dp, systemd_fetchCallBack); pmdaSetEndContextCallBack(dp, systemd_end_contextCallBack); pmdaInit(dp, NULL, 0, metrictab, sizeof(metrictab)/sizeof(metrictab[0])); /* Initialize the systemd side. This is failure-tolerant. */ /* XXX: SD_JOURNAL_{LOCAL|RUNTIME|SYSTEM}_ONLY */ sts = sd_journal_open(& journald_context, 0); if (sts < 0) { __pmNotifyErr(LOG_ERR, "sd_journal_open failure: %s", strerror(-sts)); dp->status = sts; return; } sts = sd_journal_open(& journald_context_seeky, 0); if (sts < 0) { __pmNotifyErr(LOG_ERR, "sd_journal_open #2 failure: %s", strerror(-sts)); dp->status = sts; return; } sts = sd_journal_seek_tail(journald_context); if (sts < 0) { __pmNotifyErr(LOG_ERR, "sd_journal_seek_tail failure: %s", strerror(-sts)); } /* Work around RHBZ979487. */ sts = sd_journal_previous_skip(journald_context, 1); if (sts < 0) { __pmNotifyErr(LOG_ERR, "sd_journal_previous_skip failure: %s", strerror(-sts)); } /* Arrange to wake up for journal events. */ journal_fd = sd_journal_get_fd(journald_context); if (journal_fd < 0) { __pmNotifyErr(LOG_ERR, "sd_journal_get_fd failure: %s", strerror(-journal_fd)); /* NB: not a fatal error; the select() loop will still time out and periodically poll. This makes it ok for sd_journal_reliable_fd() to be 0. */ } else { FD_SET(journal_fd, &fds); if (journal_fd > maxfd) maxfd = journal_fd; } /* NB: One queue is used for both .records and .records_raw; they just use different decoder callbacks. */ queue_entries = pmdaEventNewQueue("systemd", maxmem); if (queue_entries < 0) __pmNotifyErr(LOG_ERR, "pmdaEventNewQueue failure: %s", pmErrStr(queue_entries)); } void systemdMain(pmdaInterface *dispatch) { int pmcdfd; pmcdfd = __pmdaInFd(dispatch); if (pmcdfd > maxfd) maxfd = pmcdfd; FD_SET(pmcdfd, &fds); for (;;) { fd_set readyfds; int nready; struct timeval select_timeout = interval; memcpy(&readyfds, &fds, sizeof(readyfds)); nready = select(maxfd+1, &readyfds, NULL, NULL, & select_timeout); if (pmDebug & DBG_TRACE_APPL2) __pmNotifyErr(LOG_DEBUG, "select: nready=%d interval=%d", nready, interval_expired); if (nready < 0) { if (neterror() != EINTR) { __pmNotifyErr(LOG_ERR, "select failure: %s", netstrerror()); exit(1); } else if (!interval_expired) { continue; } } if (nready > 0 && FD_ISSET(pmcdfd, &readyfds)) { if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "processing pmcd PDU [fd=%d]", pmcdfd); if (__pmdaMainPDU(dispatch) < 0) { exit(1); /* fatal if we lose pmcd */ } if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "completed pmcd PDU [fd=%d]", pmcdfd); } systemd_refresh(); } } static void convertUnits(char **endnum, long *maxmem) { switch ((int) **endnum) { case 'b': case 'B': break; case 'k': case 'K': *maxmem *= 1024; break; case 'm': case 'M': *maxmem *= 1024 * 1024; break; case 'g': case 'G': *maxmem *= 1024 * 1024 * 1024; break; } (*endnum)++; } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n" "Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -m memory maximum memory used per queue (default %ld bytes)\n" " -s interval default delay between iterations (default %d sec)\n" " -U username user account to run under (default \"adm\")\n" " -f disable per-uid/gid record filtering (default on)\n", pmProgname, maxmem, (int)interval.tv_sec); exit(1); } int main(int argc, char **argv) { static char helppath[MAXPATHLEN]; char *endnum; pmdaInterface desc; long minmem; int c, err = 0, sep = __pmPathSeparator(); minmem = getpagesize(); maxmem = (minmem > DEFAULT_MAXMEM) ? minmem : DEFAULT_MAXMEM; __pmSetProgname(argv[0]); snprintf(helppath, sizeof(helppath), "%s%c" "systemd" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&desc, PMDA_INTERFACE_6, pmProgname, SYSTEMD, "systemd.log", helppath); while ((c = pmdaGetOpt(argc, argv, "D:d:l:m:s:U:f?", &desc, &err)) != EOF) { switch (c) { case 'm': maxmem = strtol(optarg, &endnum, 10); if (*endnum != '\0') convertUnits(&endnum, &maxmem); if (*endnum != '\0' || maxmem < minmem) { fprintf(stderr, "%s: invalid max memory '%s' (min=%ld)\n", pmProgname, optarg, minmem); err++; } break; case 's': if (pmParseInterval(optarg, &interval, &endnum) < 0) { fprintf(stderr, "%s: -s requires a time interval: %s\n", pmProgname, endnum); free(endnum); err++; } break; case 'U': username = optarg; break; case 'f': uid_gid_filter_p = 0; break; default: err++; break; } } if (err) usage(); FD_ZERO (&fds); pmdaOpenLog(&desc); systemd_init(&desc); // sets some fds pmdaConnect(&desc); systemdMain(&desc); // sets some more fds systemd_shutdown(); exit(0); } /* Local Variables: c-basic-offset: 4 End: */ pcp-3.8.12ubuntu1/src/pmdas/systemd/help0000664000000000000000000000445412272262501015047 0ustar # # Copyright (c) 2012 Red Hat, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # systemd PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ systemd.numclients The number of attached clients The number of attached clients. @ systemd.maxmem Maximum number of queued event bytes. Maximum number of queued event bytes (apprx. 128 bytes per cursor string). @ systemd.journal.field.cursor The cursor, an implicit journald field. This is the journal entry's permanent, globally unique cursor string. @ systemd.journal.field.string A journal field that may be a string. A journal field copied verbatim, as a PM_TYPE_STRING object, presumed as a valid string (in some encoding), if the field did not contain any \0 characters. @ systemd.journal.field.blob A journal field copied verbatim. A journal field copied verbatim, as a PM_TYPE_AGGREGATE object. @ systemd.journal.records Journal entries, encoded as strings and blobs. Each new journald event field is given a systemd.parameters.cursor string to identify it, and a collection of string and blob fields (as appropriate). @ systemd.journal.records_raw Journal entries, encoded as blob parameters only. Each new journald event field is given a systemd.parameters.cursor string to identify it, and a blob fields the reproduce the FIELD=value bit-for-bit. @ systemd.journal.count Count of journal entries observed @ systemd.journal.bytes Sum of sizes of all journal entries observed pcp-3.8.12ubuntu1/src/pmdas/dbping/0000775000000000000000000000000012272262620013742 5ustar pcp-3.8.12ubuntu1/src/pmdas/dbping/Remove0000775000000000000000000000161312272262501015124 0ustar #! /bin/sh # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the Database Ping PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=dbping pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/dbping/Install0000775000000000000000000000157212272262501015301 0ustar #! /bin/sh # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the Database Ping PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=dbping dso_opt=false perl_opt=true daemon_opt=false forced_restart=false perl -e "use DBI" 2>/dev/null if test $? -ne 0; then echo "Perl database interface (DBI) is not installed" exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/dbping/GNUmakefile0000664000000000000000000000302612272262501016013 0ustar #!gmake # # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = dbping DOMAIN = DBPING PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove dbprobe.pl pmda$(IAM).pl ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) dbprobe.$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif LDIRT = domain.h root pmns *.log $(MAN_PAGES) default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) dbprobe.1: dbprobe.pl $(POD_MAKERULE) include $(BUILDRULES) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl dbprobe.pl $(PMDADIR) @$(INSTALL_MAN) default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/dbping/pmdadbping.pl0000664000000000000000000001233212272262501016403 0ustar # # Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # use strict; use warnings; use PCP::PMDA; use vars qw( $pmda $stamp $response $status $timestamp ); my $delay = $ARGV[0]; # delay in seconds between database ping's $delay = 60 unless defined($delay); my $dbprobe = pmda_config('PCP_PMDAS_DIR') . '/dbping/dbprobe.pl'; $dbprobe = "perl " . $dbprobe . " $delay"; my ( $stamp, $response, $status, $timestamp ) = ( 0, 0, 1, 0 ); sub dbping_probe_callback { ( $_ ) = @_; ($stamp, $response) = split(/\t/); # $pmda->log("dbping_probe_callback: time=$stamp resp=$response\n"); if (defined($stamp) && defined($response)) { $timestamp = $stamp; $status = 0; } else { $response = -1; $status = 1; # bad result, keep old $timestamp } } sub dbping_fetch_callback # must return array of value,status { my ($cluster, $item, $inst) = @_; # $pmda->log("dbping_fetch_callback $cluster:$item ($inst)\n"); return (PM_ERR_INST, 0) unless ($inst == PM_IN_NULL); if ($cluster == 0) { if ($item == 0) { return ($response, 1); } elsif ($item == 1) { return ($status, 1); } } elsif ($cluster == 1) { if ($item == 0) { return ($timestamp, 1); } elsif ($item == 1) { return ($delay, 1); } } return (PM_ERR_PMID, 0); } sub dbping_store_callback # must return a single value (scalar context) { my ($cluster, $item, $inst, $val) = @_; my $sts = 0; # $pmda->log("dbping_store_callback $cluster:$item ($inst) $val\n"); if ($cluster == 1 && $item == 1) { $delay = $val; return 0; } elsif ( ($cluster == 0 && ($item == 0 || $item == 1)) || ($cluster == 1 && $item == 0) ) { return PM_ERR_PERMISSION; } return PM_ERR_PMID; } $pmda = PCP::PMDA->new('dbping', 244); $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'dbping.response_time', 'Length of time taken to access the database', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'dbping.status', 'Success state of last attempt to ping the database', ''); $pmda->add_metric(pmda_pmid(1,0), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'dbping.control.timestamp', 'Time of last successful database ping', ''); $pmda->add_metric(pmda_pmid(1,1), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'dbping.control.delay', 'Time to sleep between database ping attempts', ''); $pmda->set_fetch_callback( \&dbping_fetch_callback ); $pmda->set_store_callback( \&dbping_store_callback ); $pmda->add_pipe( $dbprobe, \&dbping_probe_callback, 0 ); $pmda->set_user('pcp'); $pmda->run; =pod =head1 NAME pmdadbping - database response time and availability PMDA =head1 DESCRIPTION Simple database response time measurement PMDA. dbprobe.pl(1) should be configured to use the type of DBI appropriate for your database, which includes: RDBMS flavour, user/password, delay between "ping" requests, and the SQL statement to use. B runs dbprobe.pl(1), and exports the performance measurements it makes available as PCP metrics. =head1 INSTALLATION Configure dbprobe.pl(1) - it uses a configuration file from (in this order): =over =item * /etc/pcpdbi.conf =item * $PCP_PMDAS_DIR/dbping/dbprobe.conf =back This file can contain overridden values (Perl code) for the settings listed at the start of dbprobe.pl, namely: =over =item * database name (see DBI(3) for details) =item * database user name =item * database pass word =item * SQL statement to measure (probe) =item * delay between probes =back Once this is setup, you can access the names and values for the dbping performance metrics by doing the following as root: # cd $PCP_PMDAS_DIR/dbping # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/dbping # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/dbping/probes.stp probe configuration file for stap(1), run by B =item $PCP_PMDAS_DIR/dbping/Install installation script for the B agent =item $PCP_PMDAS_DIR/dbping/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/dbping.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1), dbprobe.pl(1) and DBI(3). pcp-3.8.12ubuntu1/src/pmdas/dbping/dbprobe.pl0000664000000000000000000000543312272262501015717 0ustar # # Copyright (c) 2008 Aconex. All Rights Reserved. # Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # use strict; use warnings; use DBI; use PCP::PMDA qw(pmda_config); use Time::HiRes qw(gettimeofday); my $database = 'DBI:mysql:mysql'; my $username = 'dbmonitor'; my $password = 'dbmonitor'; my $response = 'SELECT 1'; my $delay = $ARGV[0]; # delay in seconds between database ping's $delay = 60 unless defined($delay); # Configuration files for overriding the above settings for my $file ( '/etc/pcpdbi.conf', # system defaults (lowest priority) pmda_config('PCP_PMDAS_DIR') . '/dbping/dbprobe.conf', './dbprobe.conf' ) { # current directory (high priority) eval `cat $file` unless ! -f $file; } use vars qw( $pmda $dbh $sth ); sub dbping { # must return array of (response_time, status, time_stamp) my $before; if (!defined($dbh)) { # reconnect if necessary $dbh = DBI->connect($database, $username, $password, undef) || return; $pmda->log("Connected to database.\n"); undef $sth; } if (!defined($sth)) { # prepare SQL statement once only $sth = $dbh->prepare($response) || return; } $before = gettimeofday; $sth->execute || return; while (my @row = $sth->fetchrow_array) { ($sth->err) && return; } my $timenow = localtime; print "$timenow\t", gettimeofday - $before, "\n"; } $dbh = DBI->connect($database, $username, $password, undef) || $pmda->log("Failed initial connect: $dbh->errstr\n"); $| = 1; # IMPORTANT! Enables auto-flush, for piping hot pipes. for (;;) { dbping; sleep($delay); } =pod =head1 NAME dbprobe.pl - database response time and availability information =head1 SYNOPSIS dbprobe.pl [ delay ] =head1 DESCRIPTION The B utility is used by pmdadbping(1) to measure response time from a database. A given query is executed on the database at the requested interval (I, which defaults to 60 seconds). This response time measure can be exported via the Performance Co-Pilot framework for live and historical monitoring using pmdadbping(1). =head1 SEE ALSO pmcd(1), pmdadbping(1) and DBI(3). pcp-3.8.12ubuntu1/src/pmdas/trivial/0000775000000000000000000000000012272262620014151 5ustar pcp-3.8.12ubuntu1/src/pmdas/trivial/trivial.c0000664000000000000000000000707212272262501015773 0ustar /* * Trivial, configurable PMDA * * Copyright (c) 1995,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "domain.h" /* * Trivial PMDA * * This PMDA is a sample that illustrates how a trivial PMDA might be * constructed using libpcp_pmda. * * Although the metrics supported are trivial, the framework is quite general, * and could be extended to implement a much more complex PMDA. * * Metrics * trivial.time - time in seconds since the 1st of Jan, 1970. */ /* * all metrics supported in this PMDA - one table entry for each */ static pmdaMetric metrictab[] = { /* time */ { NULL, { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0) } } }; static char *username; static char mypath[MAXPATHLEN]; static int isDSO = 1; /* ==0 if I am a daemon */ /* * callback provided to pmdaFetch */ static int trivial_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); if (idp->cluster != 0 || idp->item != 0) return PM_ERR_PMID; else if (inst != PM_IN_NULL) return PM_ERR_INST; atom->ul = time(NULL); return 0; } /* * Initialise the agent (both daemon and DSO). */ void trivial_init(pmdaInterface *dp) { if (isDSO) { int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "trivial" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_2, "trivial DSO", mypath); } else { __pmSetProcessIdentity(username); } if (dp->status != 0) return; pmdaSetFetchCallBack(dp, trivial_fetchCallBack); pmdaInit(dp, NULL, 0, metrictab, sizeof(metrictab)/sizeof(metrictab[0])); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int c, err = 0; int sep = __pmPathSeparator(); pmdaInterface desc; isDSO = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(mypath, sizeof(mypath), "%s%c" "trivial" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&desc, PMDA_INTERFACE_2, pmProgname, TRIVIAL, "trivial.log", mypath); while ((c = pmdaGetOpt(argc, argv, "D:d:l:U:?", &desc, &err)) != EOF) { switch(c) { case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&desc); trivial_init(&desc); pmdaConnect(&desc); pmdaMain(&desc); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/trivial/README0000664000000000000000000000323012272262501015025 0ustar Trivial PMDA ============ This PMDA is a sample that illustrates how a simple PMDA might be constructed using libpcp_pmda. Although the metrics supported as simple, the framework is quite general, and could be extended to implement a much more complex PMDA. Note: This PMDA may be remade from source and hence requires IDO (or more specifically a C compiler) to be installed. Uses of make(1) may fail (without removing or clobbering files) if the C compiler cannot be found. This is most likely to happen when running the PMDA ./Install script. The only remedial action is to install the C compiler, or hand-craft changes to the Makefile. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT trivial Installation ============ + # cd $PCP_PMDAS_DIR/trivial + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options -- everything else is automated. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/trivial # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/trivial.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/trivial/Remove0000664000000000000000000000204512272262501015330 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the trivial PMDA # # source the PCP configuration environment variables . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=trivial # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/trivial/Install0000664000000000000000000000136412272262501015504 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the trivial PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=trivial pmda_interface=2 forced_restart=false pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/trivial/GNUmakefile0000664000000000000000000000246612272262501016231 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs DFILES = README CFILES = trivial.c CMDTARGET = pmdatrivial$(EXECSUFFIX) LLDLIBS = $(PCP_PMDALIB) LCFLAGS = -I. LSRCFILES = Install Remove pmns help $(DFILES) root GNUmakefile.install IAM = trivial DOMAIN = TRIVIAL PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LDIRT = domain.h *.o $(IAM).log pmda$(IAM) pmda_$(IAM).so default_pcp default: domain.h $(CMDTARGET) include $(BUILDRULES) install install_pcp: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 GNUmakefile.install $(PMDADIR)/Makefile $(INSTALL) -m 644 $(DFILES) root help pmns domain.h $(CFILES) $(PMDADIR) domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) pcp-3.8.12ubuntu1/src/pmdas/trivial/root0000664000000000000000000000016412272262501015056 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { trivial } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/trivial/GNUmakefile.install0000664000000000000000000000242512272262501017671 0ustar # # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # SHELL = sh ifdef PCP_CONF include $(PCP_CONF) else include $(PCP_DIR)/etc/pcp.conf endif include $(PCP_INC_DIR)/builddefs # remove -Lpath and -Ipath options from builddefs CFLAGS value # PCP_LIBS = TMP := $(CFLAGS:-I%=) ifdef PCP_DIR # put -Ipath and -Lpath back but use paths for run-time environment # CFLAGS = $(TMP) -I$(PCP_INC_DIR)/.. LDFLAGS = -L$(PCP_LIB_DIR) else CFLAGS = $(TMP) endif IAM = trivial CFILES = $(IAM).c LIBTARGET = pmda_$(IAM).$(DSOSUFFIX) CMDTARGET = pmda$(IAM) TARGETS = $(LIBTARGET) $(CMDTARGET) LLDLIBS = -lpcp_pmda -lpcp -lm -ldl -lpthread LDIRT = *.log help.dir help.pag default: $(TARGETS) install: default include $(PCP_INC_DIR)/buildrules pcp-3.8.12ubuntu1/src/pmdas/trivial/pmns0000664000000000000000000000154212272262501015051 0ustar /* * Metrics for trivial PMDA * * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ trivial { time TRIVIAL:0:0 } pcp-3.8.12ubuntu1/src/pmdas/trivial/help0000664000000000000000000000255412272262501015030 0ustar # # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # trivial PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ trivial.time The time in seconds since 1 Jan 1970 The time in seconds since the 1st of January, 1970. pcp-3.8.12ubuntu1/src/pmdas/txmon/0000775000000000000000000000000012272262620013644 5ustar pcp-3.8.12ubuntu1/src/pmdas/txmon/genload0000775000000000000000000000546712272262501015215 0ustar #! /bin/sh # # Copyright (c) 1997,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # micky mouse transaction load generator ... # # Get standard environment . $PCP_DIR/etc/pcp.env NUMTX=-1 while getopts n:\? c do case $c in n) NUMTX=$OPTARG;; \?) echo "Usage: genload [-n numtx] [tps [avg_serv]]" exit 1 ;; esac done shift `expr $OPTIND - 1` # target TPS [default 10] # TPS=${1-10} # mean of the mean service times [default 10 seconds] # AVG=${2-10} if [ ! -x ./txrecord ] then echo 'Error: no txrecord binary here ... try "make txrecord"?' exit 1 fi # get tx types from txmon PMDA via pmcd on the localhost, then choose tx # type with Zipfian distribution, and artifically chosen service times # ... pipe them to a record-then-sleep droid in the while loop at the # end ... rate throttling relies on O/S pipe-full synchronization # (crude, but simple and effective) # pminfo -f txmon.count \ | tr -d '"\]\[' \ | $PCP_AWK_PROG ' BEGIN { i = 0; w = 2; s = 0; numtx='$NUMTX' } /value/ { name[i] = $4; zipf[i] = s + 1 / w; s = zipf[i] i++; w *= 2 } END { if (i == 0) { print "e Cannot determine transaction type names ... is the txmon PMDA running locally?" exit } # compute mean, drawn from normal distn with mean and std dev AVG for (j=0; j= -0.69314706) x = -x m[j] = '$AVG' + '$AVG' * x if (m[j] >= 0) break } } print "i Mean service time for " name[j] " tx: " m[j] } zipf[i-1] = 1 # force upper bound of last interval while (numtx != 0) { printf "w " for (k=0; k < '$TPS' && numtx != 0; k++) { r = rand() for (j=0; j 0) numtx-- } print "" print "s" } }' \ | while read action arg do case $action in i) echo "$arg" ;; e) echo "Error: $arg" exit 1 ;; s) sleep 1 ;; w) ./txrecord $arg ;; esac done pcp-3.8.12ubuntu1/src/pmdas/txmon/README0000664000000000000000000000433512272262501014527 0ustar txmon PMDA =========== This PMDA is a sample that illustrates how a simple transaction monitor PMDA might be constructed, using a shared memory segment to transfer information about transaction activity from the applications that submit (or process) transactions and the txmon PMDA. Although the metrics supported are simple, the framework is quite general and could be extended to implement a much more complex PMDA. Note: This PMDA may be remade from source and hence requires IDO (or more specifically a C compiler) to be installed. Uses of make(1) may fail (without removing or clobbering files) if the C compiler cannot be found. This is most likely to happen when running the PMDA ./Install script. The only remedial action is to install the C compiler, or hand-craft changes to the Makefile. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT txmon Installation ============ + # cd $PCP_PMDAS_DIR/txmon + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options. You will be prompted to define the names of the transaction types to be monitored -- everything else is automated. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/txmon # ./Remove Making something happen ======================= The application ./txrecord updates the shared memory segment to add new information about transactions and their service times. Usually this would be run from the ./genload script that will continue to update the shared memory segment with data drawn from some synthetic distributions. Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/txmon.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/txmon/txmon.h0000664000000000000000000000343012272262501015160 0ustar /* * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * the txmon shm segment * * control comes at the beginning, with index[] expanded to match the * number of transaction types (control->n_tx) * * then follows one stat_t per transaction type, subject to the * constraint that each stat_t is hardware cache aligned to avoid * anti-social bus traffic */ typedef struct { int level; /* controls stats collection levels */ int n_tx; /* # of tx types */ int index[1]; /* will be expanded when allocated */ } control_t; static control_t *control; #define MAXNAMESIZE 20 typedef struct { /* managed by txmon PMDA ... do not fiddle with these! */ char type[MAXNAMESIZE]; /* tx type name */ unsigned int reset_count; /* tx count @ last reset */ /* initialized and then read by txmon PMDA, updated by txrecord */ unsigned int count; /* tx count since epoch */ float max_time; /* maximum elapsed time */ double sum_time; /* aggregate elapsed time */ } stat_t; /* arbitrary shm key */ #define KEY (key_t)0xdeadbeef pcp-3.8.12ubuntu1/src/pmdas/txmon/txrecord.c0000664000000000000000000000575712272262501015656 0ustar /* * Copyright (c) 1995-2000 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include "txmon.h" /* * Update the shm segment the is used to export metrics via the txmon PMDA */ int main(int argc, char **argv) { int shmid; int n; char *p; stat_t *sp = NULL; /* initialize to pander to gcc */ if (argc == 1 || (argc == 2 && strcmp(argv[1], "-?") == 0)) { fprintf(stderr, "Usage: txrecord tx_type servtime [tx_type servtime ...]\n" " txrecord -l\n"); exit(1); } /* * attach to the txmon PMDA shm segment ... */ if ((shmid = shmget(KEY, 0, 0)) < 0) { fprintf(stderr, "Cannot attach to shm segment, shmid: %s\n", osstrerror()); fprintf(stderr, "Is the txmon PMDA configured and running?\n"); exit(1); } if ((control = (control_t *)shmat(shmid, NULL, 0)) == (control_t *)-1) { fprintf(stderr, "Cannot attach to shm segment, shmat: %s\n", osstrerror()); fprintf(stderr, "Is the txmon PMDA configured and running?\n"); exit(1); } if (control->level == 0) { fprintf(stderr, "Stats collection disabled\n"); exit(1); } else if (control->level == 1) fprintf(stderr, "Warning: stats time collection disabled\n"); if (argc == 2 && strcmp(argv[1], "-l") == 0) { printf("txmon shared memory segment summary\n"); printf(" tx reset total maximum\n"); printf("index offset count count time time name\n"); for (n = 0; n < control->n_tx; n++) { sp = (stat_t *)((__psint_t)control + control->index[n]); printf("%5d %6d %6d %6d %9.3f %7.3f %s\n", n, control->index[n], sp->count, sp->reset_count, (float)sp->sum_time, sp->max_time, sp->type); } exit(0); } while (argc > 1) { for (n = 0; n < control->n_tx; n++) { sp = (stat_t *)((__psint_t)control + control->index[n]); if (strcmp(argv[1], sp->type) == 0) break; } argc--; argv++; if (argc == 1) { fprintf(stderr, "Missing time for tx type \"%s\"?\n", argv[0]); exit(1); } if (n == control->n_tx) fprintf(stderr, "Unknown tx type \"%s\" ... skipped\n", argv[0]); else { double e; e = strtod(argv[1], &p); if (*p != '\0') fprintf(stderr, "Time value (%s) for tx type \"%s\" is bogus ... skipped\n", argv[1], argv[0]); else { sp->count++; if (control->level == 2) { sp->sum_time += (float)e; if ((float)e > sp->max_time) sp->max_time = e; } } } argc--; argv++; } exit(0); } pcp-3.8.12ubuntu1/src/pmdas/txmon/Remove0000664000000000000000000000200712272262501015021 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the txmon PMDA # # Get standard environment . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=txmon # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/txmon/Install0000775000000000000000000000261712272262501015204 0ustar #! /bin/sh # # Copyright (c) 1997,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the txmon PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=txmon pmda_interface=2 forced_restart=false pmdaSetup if $do_pmda then # special txmon PMDA args # echo 'Welcome to the Install script for the demonstration "txmon" PMDA. This PMDA will establish a shared memory segment with one statistics structure per transaction type. You must define the names of the transaction types (the names are arbitrary strings with no embedded white space, e.g. mytx#1). ' args="" while true do $PCP_ECHO_PROG $PCP_ECHO_N "Name for transaction type? [return if no more] ""$PCP_ECHO_C" read ans [ -z "$ans" ] && break args="$args $ans" done if [ -z "$args" ] then echo "You need to specify at least one transaction type name!" exit 1 fi fi pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/txmon/GNUmakefile0000664000000000000000000000334612272262501015722 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs DFILES = README CFILES = txmon.c txrecord.c HFILES = txmon.h TARGETS = txmon$(EXECSUFFIX) txrecord$(EXECSUFFIX) LCFLAGS = -I. LLDLIBS = $(PCP_PMDALIB) SCRIPTS = Install Remove genload OTHERS = pmns help root LSRCFILES= $(SCRIPTS) $(OTHERS) GNUmakefile.install $(DFILES) IAM = txmon DOMAIN = TXMON PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LDIRT = *.o *.log *.dir *.pag domain.h $(TARGETS) default: build-me include $(BUILDRULES) ifneq "$(TARGET_OS)" "mingw" build-me: $(TARGETS) install: build-me $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) $(INSTALL) -m 755 txrecord $(SCRIPTS) $(PMDADIR) $(INSTALL) -m 644 $(DFILES) root $(HFILES) $(PMDADIR) $(INSTALL) -m 644 help pmns domain.h $(CFILES) $(PMDADIR) $(INSTALL) -m 644 GNUmakefile.install $(PMDADIR)/Makefile else build-me: install: endif domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) $(OBJECTS): domain.h txmon$(EXECSUFFIX): txmon.o $(CCF) -o $@ $(LDFLAGS) txmon.o $(LDLIBS) txrecord$(EXECSUFFIX): txrecord.o $(CCF) -o $@ $(LDFLAGS) txrecord.o $(LDLIBS) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmdas/txmon/root0000664000000000000000000000016212272262501014547 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { txmon } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/txmon/GNUmakefile.install0000664000000000000000000000270212272262501017362 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2000,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # SHELL = sh ifdef PCP_CONF include $(PCP_CONF) else PCP_DIR = $(shell echo $$PCP_DIR) include $(PCP_DIR)/etc/pcp.conf endif include $(PCP_INC_DIR)/builddefs # remove -Lpath and -Ipath options from builddefs CFLAGS value # PCP_LIBS = TMP := $(CFLAGS:-I%=) ifdef PCP_DIR # put -Ipath and -Lpath back but use paths for run-time environment # CFLAGS = $(TMP) -I$(PCP_INC_DIR)/.. LDFLAGS = -L$(PCP_LIB_DIR) else CFLAGS = $(TMP) endif IAM = txmon CFILES = $(IAM).c CMDTARGET = pmda$(IAM) TARGETS = txrecord $(CMDTARGET) LLDLIBS = -lpcp_pmda -lpcp -lm -ldl -lpthread LDIRT = *.log help.dir help.pag txrecord default: $(TARGETS) install: default pmda$(IAM): txmon.h domain.h $(CFILES) txrecord.o: txmon.h txrecord.c txrecord: txrecord.o $(CC) $(CFLAGS) -o $@ txrecord.o $(LDFLAGS) $(LDLIBS) include $(PCP_INC_DIR)/buildrules pcp-3.8.12ubuntu1/src/pmdas/txmon/pmns0000664000000000000000000000175412272262501014551 0ustar /* * Metrics for txmon PMDA * * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ txmon { count TXMON:0:0 ave_time TXMON:0:1 max_time TXMON:0:2 reset_count TXMON:0:3 control } txmon.control { level TXMON:0:4 reset TXMON:0:5 } pcp-3.8.12ubuntu1/src/pmdas/txmon/txmon.c0000664000000000000000000002207312272262501015157 0ustar /* * txmon PMDA * * Copyright (c) 2012 Red Hat. * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include "domain.h" #define CACHELINE 32 #define RND_TO_CACHE_LINE(x) (((x + CACHELINE - 1) / CACHELINE) * CACHELINE) /* * txmon PMDA * * This PMDA is a sample that illustrates how a PMDA might be * constructed with libpcp_pmda to use a System V shared memory (shm) * segment to transfer performance data between the collectors on the * application side (see ./txrecord and ./genload for a simple example) * and this PCP PMDA */ /* * list of instances ... created dynamically, after parsing cmd line options */ static pmdaInstid *tx_indom; /* * list of instance domains ... initialized after parsing cmd line options */ static pmdaIndom indomtab[] = { #define TX_INDOM 0 { TX_INDOM, 0, NULL }, }; /* * all metrics supported in this PMDA - one table entry for each */ static pmdaMetric metrictab[] = { /* count */ { NULL, { PMDA_PMID(0,0), PM_TYPE_U32, TX_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* ave_time */ { NULL, { PMDA_PMID(0,1), PM_TYPE_FLOAT, TX_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,-1,0,PM_TIME_SEC,PM_COUNT_ONE) } }, /* max_time */ { NULL, { PMDA_PMID(0,2), PM_TYPE_FLOAT, TX_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0 ) } }, /* reset_count */ { NULL, { PMDA_PMID(0,3), PM_TYPE_U32, TX_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* control.level */ { NULL, { PMDA_PMID(0,4), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, /* control.reset */ { NULL, { PMDA_PMID(0,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, }; #include "./txmon.h" static int shmid = -1; static char mypath[MAXPATHLEN]; static char *username; /* * callback provided to pmdaFetch */ static int txmon_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { stat_t *sp; __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); unsigned int real_count; if (inst != PM_IN_NULL && mdesc->m_desc.indom == PM_INDOM_NULL) return PM_ERR_INST; if (idp->cluster != 0) return PM_ERR_PMID; if (idp->item <= 3) { if (inst >= control->n_tx) return PM_ERR_INST; sp = (stat_t *)((__psint_t)control + control->index[inst]); switch (idp->item) { case 0: /* txmon.count */ if (control->level < 1) return PM_ERR_AGAIN; atom->ul = sp->count; break; case 1: /* txmon.ave_time */ if (control->level < 2) return PM_ERR_AGAIN; real_count = sp->count - sp->reset_count; atom->f = real_count > 0 ? sp->sum_time / real_count : -1; break; case 2: /* txmon.max_time */ if (control->level < 2) return PM_ERR_AGAIN; atom->f = sp->max_time; break; case 3: /* txmon.reset_count */ if (control->level < 1) return PM_ERR_AGAIN; atom->ul = sp->count - sp->reset_count; break; } } else { switch (idp->item) { case 4: /* txmon.control.level */ atom->ul = control->level; break; case 5: /* txmon.control.reset */ atom->ul = 1; break; default: return PM_ERR_PMID; } } return 0; } /* * support the storage of a value into the control metrics */ static int txmon_store(pmResult *result, pmdaExt *pmda) { int i; int n; int val; int sts = 0; pmValueSet *vsp = NULL; __pmID_int *pmidp = NULL; stat_t *sp; for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; pmidp = (__pmID_int *)&vsp->pmid; if (pmidp->cluster == 0) { /* all storable metrics are cluster 0 */ switch (pmidp->item) { case 0: /* no store for these ones */ case 1: case 2: case 3: sts = PM_ERR_PERMISSION; break; case 4: /* txmon.control.level */ val = vsp->vlist[0].value.lval; if (val < 0) { sts = PM_ERR_SIGN; val = 0; } control->level = val; break; case 5: /* txmon.control.reset */ for (n = 0; n < control->n_tx; n++) { sp = (stat_t *)((__psint_t)control + control->index[n]); sp->reset_count = sp->count; sp->sum_time = 0; sp->max_time = -1; } break; default: sts = PM_ERR_PMID; break; } } else sts = PM_ERR_PMID; } return sts; } /* * Initialise the agent */ void txmon_init(pmdaInterface *dp) { if (dp->status != 0) return; __pmSetProcessIdentity(username); dp->version.two.store = txmon_store; pmdaSetFetchCallBack(dp, txmon_fetchCallBack); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "after pmdaSetFetchCallBack() control @ %p\n", control); } #endif pmdaInit(dp, indomtab, 1, metrictab, sizeof(metrictab)/sizeof(metrictab[0])); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "after pmdaInit() control @ %p\n", control); } #endif } static void usage(void) { fprintf(stderr, "Usage: %s [options] tx_type [...]\n\n", pmProgname); fputs( "Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } /* * come here on exit() */ static void done(void) { if (shmid != -1) /* remove the shm segment */ shmctl(shmid, IPC_RMID, NULL); } /* * Set up the agent. */ int main(int argc, char **argv) { int err = 0; int sep = __pmPathSeparator(); pmdaInterface dispatch; char *p; int n; size_t index_size; size_t shm_size; stat_t *sp; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(mypath, sizeof(mypath), "%s%c" "txmon" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_2, pmProgname, TXMON, "txmon.log", mypath); pmdaOpenLog(&dispatch); while ((n = pmdaGetOpt(argc, argv, "D:d:l:U:?", &dispatch, &err)) != EOF) { switch(n) { case 'U': username = optarg; break; default: err++; } } if (err) usage(); n = argc - optind; if (n < 1) { fprintf(stderr, "No transaction types specified?\n"); usage(); } /* * create the instance domain table ... one entry per transaction type */ if ((tx_indom = (pmdaInstid *)malloc(n * sizeof(pmdaInstid))) == NULL) { fprintf(stderr, "malloc(%d): %s\n", n * (int)sizeof(pmdaInstid), osstrerror()); exit(1); } indomtab[0].it_numinst = n; indomtab[0].it_set = tx_indom; /* * size shm segment so each stat_t starts on a cache line boundary */ index_size = RND_TO_CACHE_LINE(sizeof(control->level) + sizeof(control->n_tx) + n * sizeof(control->index[0])); shm_size = index_size + n * RND_TO_CACHE_LINE(sizeof(stat_t)); /* * create the shm segment, and install exit() handler to remove it */ if ((shmid = shmget(KEY, shm_size, IPC_CREAT|0666)) < 0) { fprintf(stderr, "shmid: %s\n", osstrerror()); exit(1); } atexit(done); if ((control = (control_t *)shmat(shmid, NULL, 0)) == (control_t *)-1) { fprintf(stderr, "shmat: %s\n", osstrerror()); exit(1); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "shmat -> control @ %p\n", control); } #endif /* * set up the shm control info and directory */ control->n_tx = n; control->level = 2; /* arbitrary default stats level */ p = (char *)control; p = &p[index_size]; for (n = 0; n < control->n_tx; n++) { /* * Note: it is important that the index[] entries are byte * offsets from the start of the shm segment ... using * pointers may cause problems for 32-bit and 64-bit apps * attaching to the shm segment */ control->index[n] = p - (char *)control; sp = (stat_t *)p; strncpy(sp->type, argv[optind++], MAXNAMESIZE); sp->type[MAXNAMESIZE-1] = '\0'; /* ensure null terminated */ sp->reset_count = 0; sp->count = 0; sp->max_time = -1.0; sp->sum_time = 0.0; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "index[%d]=%d @ %p name=\"%s\"\n", n, control->index[n], p, sp->type); } #endif p += RND_TO_CACHE_LINE(sizeof(stat_t)); /* * and set up the corresponding indom table entries */ tx_indom[n].i_inst = n; tx_indom[n].i_name = sp->type; } /* * the real work is done below here ... */ txmon_init(&dispatch); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/txmon/help0000664000000000000000000000447112272262501014523 0ustar # # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # txmon PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ TXMON.0 Instance domain "transaction type name" for txmon PMDA There is one instance for each transaction type. @ txmon.count count by transaction type Count by transaction type of transactions serviced since the txmon PMDA started. @ txmon.reset_count reset count by transaction type Count by transaction type of transactions serviced since the last time the average and maximum summaries were reset. @ txmon.ave_time average time per transaction type Average recorded service time per transaction type since the last time the statistics were reset. @ txmon.max_time maximum time per transaction type Maximum recorded service time per transaction type since the last time the statistics were reset. @ txmon.control.level statistics control levels 0 => no statistics are collected 1 => transaction counts are enabled 2 => transaction counts and service times are enabled @ txmon.control.reset reset statistics This metric is a toggle-switch ... any pmStore() operation for this metric will reset all statistics except txmon.count. The value for this metric is always 1. pcp-3.8.12ubuntu1/src/pmdas/apache/0000775000000000000000000000000012272262620013720 5ustar pcp-3.8.12ubuntu1/src/pmdas/apache/README0000664000000000000000000000404712272262501014603 0ustar Apache PMDA =========== Export information from apache server info. Author: Michal Kara To use this PMDA, you must be running Apache 1.3.2 or later (for the extended statistics). First configure your apache http server to enable status support. The full procedure is documented at http://www.apache.org/docs/mod/mod_status.html Edit /etc/apache2/mods-enabled/status.conf and enable the following: SetHandler server-status Allow from all ExtendedStatus On Note: you may wish to restrict access to the server status reports to the local host only. See the Apache web site for instructions. You will need to stop and restart your Apache server after making this change: # apachectl restart Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT apache The metrics give basic information about Apache performance and about usage of server threads. Installation ============ + # cd $PCP_PMDAS_DIR/apache + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and optionally specify the port number where Apache is running. Everything else is automated. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/apache # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/apache.log) should be checked for any warnings or errors. Credits ======= Original PMDA was written by Michal Kara. This PMDA embeds a (slightly modified) lightweight "Http Fetcher" library, written by Lyle Hanson (lhanson@users.sourceforge.net) (C) 2001, 2003, 2004 http://http-fetcher.sourceforge.net pcp-3.8.12ubuntu1/src/pmdas/apache/pmlogconf.uptime0000664000000000000000000000021012272262501017120 0ustar #pmlogconf-setup 2.0 ident Apache uptime probe apache.uptime exists ? include : exclude delta 5 minutes apache.uptime apache.uptime_s pcp-3.8.12ubuntu1/src/pmdas/apache/pmlogconf.processes0000664000000000000000000000047212272262501017635 0ustar #pmlogconf-setup 2.0 ident Apache process state information probe apache.sb_waiting apache.sb_waiting apache.sb_starting apache.sb_reading apache.sb_writing_reply apache.sb_keepalive apache.sb_dns_lookup apache.sb_logging apache.sb_finishing apache.sb_open_slot apache.sb_closing apache.sb_idle_cleanup pcp-3.8.12ubuntu1/src/pmdas/apache/Apache.pmchart0000664000000000000000000000041412272262501016456 0ustar #pmchart Version 2.0 host dynamic Chart Title "Apache Hit Rate" Style plot Plot Color #-cycle Host * Metric apache.requests_per_sec Chart Title "Apache Data Rate" Style plot Plot Color #-cycle Host * Metric apache.bytes_per_sec # # Created Fri Jun 10 05:16:55 2005 pcp-3.8.12ubuntu1/src/pmdas/apache/Remove0000664000000000000000000000130312272262501015073 0ustar #!/bin/sh # # Copyright (c) 1999,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the apache PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=apache pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/apache/Install0000775000000000000000000000245412272262501015257 0ustar #!/bin/sh # # Copyright (c) 2010 Aconex. All Rights Reserved. # Copyright (c) 1999,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the apache PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=apache pmda_interface=3 forced_restart=false # Override interactive dialog from pmdaSetup in pmdaproc.sh __choose_mode() { echo "Installing the \"$iam\" Performance Metrics Domain Agent (PMDA) ..." echo } pmdaSetup if $do_pmda then args="" $PCP_ECHO_PROG $PCP_ECHO_N "Apache port number [80]? ""$PCP_ECHO_C" read value if [ "X$value" = "X" ] then : elif [ "X`expr 0 + $value 2>/dev/null`" != "X$value" ] then echo "-- Sorry, port number must be numeric (not $value), ignored --" >&2 else args="$args -P $value" fi fi pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/apache/pmlogconf.summary0000664000000000000000000000041512272262501017321 0ustar #pmlogconf-setup 2.0 ident Apache summary information probe apache.total_accesses exists ? include : exclude apache.total_accesses apache.total_kbytes apache.requests_per_sec apache.bytes_per_sec apache.bytes_per_requests apache.busy_servers apache.idle_servers pcp-3.8.12ubuntu1/src/pmdas/apache/GNUmakefile0000664000000000000000000000355612272262501016001 0ustar # # Copyright (C) 2000 Michal Kara. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = apache DOMAIN = APACHE TARGETS = $(IAM)$(EXECSUFFIX) CFILES = apache.c SCRIPTS = Install Remove DFILES = README LSRCFILES= $(SCRIPTS) pmns help root Apache.pmchart $(DFILES) \ pmlogconf.summary pmlogconf.processes pmlogconf.uptime PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) PMCHART = $(PCP_VAR_DIR)/config/pmchart LDIRT = domain.h *.o $(IAM).log pmda$(IAM) pmda_$(IAM).so $(TARGETS) LCFLAGS = -I$(TOPDIR)/src/libpcp_http/src LLDFLAGS= -L$(TOPDIR)/src/libpcp_http/src LLDLIBS = -lpcp_http $(PCP_PMDALIB) default: build-me include $(BUILDRULES) build-me: $(TARGETS) install: build-me $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) $(INSTALL) -m 755 $(SCRIPTS) $(PMDADIR) $(INSTALL) -m 644 $(DFILES) pmns help root domain.h $(PMDADIR) $(INSTALL) -m 644 Apache.pmchart $(PMCHART)/Apache $(INSTALL) -m 755 -d $(PCP_VAR_DIR)/config/pmlogconf/$(IAM) $(INSTALL) -m 644 pmlogconf.summary $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)/summary $(INSTALL) -m 644 pmlogconf.processes $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)/processes $(INSTALL) -m 644 pmlogconf.uptime $(PCP_VAR_DIR)/config/pmlogconf/$(IAM)/uptime $(IAM)$(EXECSUFFIX): $(OBJECTS) apache.o: domain.h domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmdas/apache/root0000664000000000000000000000016312272262501014624 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { apache } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/apache/pmns0000664000000000000000000000266312272262501014625 0ustar /* * Metrics for apache PMDA * * Copyright (C) 2000 Michal Kara. All Rights Reserved. * Copyright (c) 2008 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ apache { total_accesses APACHE:0:0 total_kbytes APACHE:0:1 uptime APACHE:0:2 requests_per_sec APACHE:0:3 bytes_per_sec APACHE:0:4 bytes_per_requests APACHE:0:5 busy_servers APACHE:0:6 idle_servers APACHE:0:7 sb_waiting APACHE:0:8 sb_starting APACHE:0:9 sb_reading APACHE:0:10 sb_writing_reply APACHE:0:11 sb_keepalive APACHE:0:12 sb_dns_lookup APACHE:0:13 sb_logging APACHE:0:14 sb_finishing APACHE:0:15 sb_open_slot APACHE:0:16 sb_closing APACHE:0:17 sb_idle_cleanup APACHE:0:18 uptime_s APACHE:0:19 } pcp-3.8.12ubuntu1/src/pmdas/apache/apache.c0000664000000000000000000003545512272262501015317 0ustar /* * Apache PMDA * * Copyright (C) 2012 Red Hat. * Copyright (C) 2008-2010 Aconex. All Rights Reserved. * Copyright (C) 2000 Michal Kara. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "domain.h" #include "http_fetcher.h" #include static char url[256]; static char uptime_s[64]; static char *username; static int http_port = 80; static char *http_server = "localhost"; static char *http_path = "server-status"; static pmdaMetric metrictab[] = { /* apache.total_accesses */ { NULL, { PMDA_PMID(0,0), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.total_kbytes */ { NULL, { PMDA_PMID(0,1), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(1,0,0,PM_SPACE_KBYTE,0,0) } }, /* apache.uptime */ { NULL, { PMDA_PMID(0,2), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_SEC,0) } }, /* apache.requests_per_sec */ { NULL, { PMDA_PMID(0,3), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,-1,1,0,PM_TIME_SEC,PM_COUNT_ONE) } }, /* apache.bytes_per_sec */ { NULL, { PMDA_PMID(0,4), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_SEC,0) } }, /* apache.bytes_per_request */ { NULL, { PMDA_PMID(0,5), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,-1,PM_SPACE_BYTE,0,PM_COUNT_ONE) } }, /* apache.busy_servers */ { NULL, { PMDA_PMID(0,6), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.idle_servers */ { NULL, { PMDA_PMID(0,7), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.sb_waiting */ { NULL, { PMDA_PMID(0,8), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.sb_starting */ { NULL, { PMDA_PMID(0,9), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.sb_reading */ { NULL, { PMDA_PMID(0,10), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.sb_writing_reply */ { NULL, { PMDA_PMID(0,11), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.sb_keepalive */ { NULL, { PMDA_PMID(0,12), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.sb_dns_lookup */ { NULL, { PMDA_PMID(0,13), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.sb_logging */ { NULL, { PMDA_PMID(0,14), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.sb_finishing */ { NULL, { PMDA_PMID(0,15), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.sb_open_slot */ { NULL, { PMDA_PMID(0,16), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.sb_closing */ { NULL, { PMDA_PMID(0,17), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.sb_idle_cleanup */ { NULL, { PMDA_PMID(0,18), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) } }, /* apache.uptime_s */ { NULL, { PMDA_PMID(0,19), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) } }, }; /* * To speed everything up, the PMDA is caching the data. * Values are refreshed only if older than one second. */ struct { unsigned int flags; /* Tells which values are valid */ unsigned int timeout; /* There was a timeout (a bool) */ time_t timestamp; /* Time of last attempted fetch */ __uint64_t uptime; __uint64_t total_accesses; __uint64_t total_kbytes; double requests_per_sec; double bytes_per_sec; unsigned int bytes_per_request; unsigned int busy_servers; unsigned int idle_servers; unsigned int sb_waiting; unsigned int sb_starting; unsigned int sb_reading; unsigned int sb_writing_reply; unsigned int sb_keepalive; unsigned int sb_dns_lookup; unsigned int sb_logging; unsigned int sb_finishing; unsigned int sb_open_slot; unsigned int sb_closing; unsigned int sb_idle_cleanup; } data; /* * Valid values of flags - tell us which values are currently setup. * Depending on server version and configuration, some may be missing. */ enum { ACCESSES = (1<<0), KILOBYTES = (1<<1), UPTIME = (1<<2), REQPERSEC = (1<<3), BYTESPERSEC = (1<<4), BYTESPERREQ = (1<<5), BUSYSERVERS = (1<<6), IDLESERVERS = (1<<7), SCOREBOARD = (1<<8), }; static void uptime_string(time_t now, char *s, size_t sz) { int days, hours, minutes, seconds; days = now / (60 * 60 * 24); now %= (60 * 60 * 24); hours = now / (60 * 60); now %= (60 * 60); minutes = now / 60; now %= 60; seconds = now; if (days > 1) snprintf(s, sz, "%ddays %02d:%02d:%02d", days, hours, minutes, seconds); else if (days == 1) snprintf(s, sz, "%dday %02d:%02d:%02d", days, hours, minutes, seconds); else snprintf(s, sz, "%02d:%02d:%02d", hours, minutes, seconds); } static void dumpData(void) { uptime_string(data.uptime, uptime_s, sizeof(uptime_s)); fprintf(stderr, "Apache data from %s port %d, path %s:\n", http_server, http_port, http_path); fprintf(stderr, " flags=0x%x timeout=%d timestamp=%lu\n", data.flags, data.timeout, (unsigned long)data.timestamp); fprintf(stderr, " uptime=%" PRIu64 " (%s)\n", data.uptime, uptime_s); fprintf(stderr, " accesses=%" PRIu64 " kbytes=%" PRIu64 " req/sec=%.2f b/sec=%.2f\n", data.total_accesses, data.total_kbytes, data.requests_per_sec, data.bytes_per_sec); fprintf(stderr, " b/req=%u busyserv=%u idleserv=%u\n", data.bytes_per_request, data.busy_servers, data.idle_servers); fprintf(stderr, " scoreboard: waiting=%u starting=%u reading=%u\n", data.sb_waiting, data.sb_starting, data.sb_reading); fprintf(stderr, " writing_reply=%u keepalive=%u dn_lookup=%u\n", data.sb_writing_reply, data.sb_keepalive, data.sb_dns_lookup); fprintf(stderr, " logging=%u finishing=%u open_slot=%u\n", data.sb_logging, data.sb_finishing, data.sb_open_slot); fprintf(stderr, " closing=%u idle_cleanup=%u\n", data.sb_closing, data.sb_idle_cleanup); } /* * Refresh data. Returns 1 of OK, 0 on error. */ static int refreshData(time_t now) { char *res = NULL; int len; char *s,*s2,*s3; if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "Doing http_fetch(%s)\n", url); len = http_fetch(url, &res); if (len < 0) { if (pmDebug & DBG_TRACE_APPL1) __pmNotifyErr(LOG_ERR, "HTTP fetch (stats) failed: %s\n", http_strerror()); data.timeout = http_getTimeoutError(); if (data.timeout) data.timestamp = now; /* Don't retry too soon */ if (res) free(res); return 0; /* failed */ } memset(&data, 0, sizeof(data)); for (s = res; *s; ) { s2 = s; s3 = NULL; for (; *s && *s != 10; s++) { if (*s == ':') { s3 = s + 1; if (*s3) { *s3++ = 0; s++; } } } if (*s == 10) *s++ = 0; if (strcmp(s2, "CPULoad:") == 0) /* ignored */ ; else if (strcmp(s2, "Total Accesses:") == 0) { data.total_accesses = strtoull(s3, (char **)NULL, 10); data.flags |= ACCESSES; } else if (strcmp(s2, "Total kBytes:") == 0) { data.total_kbytes = strtoull(s3, (char **)NULL, 10); data.flags |= KILOBYTES; } else if (strcmp(s2, "Uptime:") == 0) { data.uptime = strtoull(s3, (char **)NULL, 10); data.flags |= UPTIME; } else if (strcmp(s2, "ReqPerSec:") == 0) { data.requests_per_sec = strtod(s3, (char **)NULL); data.flags |= REQPERSEC; } else if (strcmp(s2, "BytesPerSec:") == 0) { data.bytes_per_sec = strtod(s3, (char **)NULL); data.flags |= BYTESPERSEC; } else if (strcmp(s2, "BytesPerReq:") == 0) { data.bytes_per_request = (unsigned int)strtoul(s3, (char **)NULL, 10); data.flags |= BYTESPERREQ; } else if ((strcmp(s2, "BusyServers:") == 0) || (strcmp(s2, "BusyWorkers:") == 0)) { data.busy_servers = (unsigned int)strtoul(s3, (char **)NULL, 10); data.flags |= BUSYSERVERS; } else if ((strcmp(s2, "IdleServers:") == 0) || (strcmp(s2, "IdleWorkers:") == 0)) { data.idle_servers = (unsigned int)strtoul(s3, (char **)NULL, 10); data.flags |= IDLESERVERS; } else if (strcmp(s2, "Scoreboard:") == 0) { data.flags |= SCOREBOARD; while(*s3) { switch(*s3) { case '_': data.sb_waiting++; break; case 'S': data.sb_starting++; break; case 'R': data.sb_reading++; break; case 'W': data.sb_writing_reply++; break; case 'K': data.sb_keepalive++; break; case 'D': data.sb_dns_lookup++; break; case 'C': data.sb_closing++; break; case 'L': data.sb_logging++; break; case 'G': data.sb_finishing++; break; case 'I': data.sb_idle_cleanup++; break; case '.': data.sb_open_slot++; break; default: if (pmDebug & DBG_TRACE_APPL1) { __pmNotifyErr(LOG_WARNING, "Unknown scoreboard character '%c'\n", *s3); } } s3++; } } else if (pmDebug & DBG_TRACE_APPL1) { __pmNotifyErr(LOG_WARNING, "Unknown value name '%s'!\n", s2); } } data.timestamp = now; if (pmDebug & DBG_TRACE_APPL2) dumpData(); free(res); return 1; } static int apache_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { time_t now = time(NULL); if (now > data.timestamp && !refreshData(now + 1)) return PM_ERR_AGAIN; if (data.timeout) return PM_ERR_AGAIN; return pmdaFetch(numpmid, pmidlist, resp, pmda); } static int apache_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); if (idp->cluster != 0) return PM_ERR_PMID; else if (inst != PM_IN_NULL) return PM_ERR_INST; switch (idp->item) { case 0: if (!(data.flags & ACCESSES)) return 0; atom->ull = data.total_accesses; break; case 1: if (!(data.flags & KILOBYTES)) return 0; atom->ull = data.total_kbytes; break; case 2: if (!(data.flags & UPTIME)) return 0; atom->ull = data.uptime; break; case 3: if (!(data.flags & REQPERSEC)) return 0; atom->d = data.requests_per_sec; break; case 4: if (!(data.flags & BYTESPERSEC)) return 0; atom->d = data.bytes_per_sec; break; case 5: if (!(data.flags & BYTESPERREQ)) return 0; atom->ul = data.bytes_per_request; break; case 6: if (!(data.flags & BUSYSERVERS)) return 0; atom->ul = data.busy_servers; break; case 7: if (!(data.flags & IDLESERVERS)) return 0; atom->ul = data.idle_servers; break; case 8: if (!(data.flags & SCOREBOARD)) return 0; atom->ul = data.sb_waiting; break; case 9: if (!(data.flags & SCOREBOARD)) return 0; atom->ul = data.sb_starting; break; case 10: if (!(data.flags & SCOREBOARD)) return 0; atom->ul = data.sb_reading; break; case 11: if (!(data.flags & SCOREBOARD)) return 0; atom->ul = data.sb_writing_reply; break; case 12: if (!(data.flags & SCOREBOARD)) return 0; atom->ul = data.sb_keepalive; break; case 13: if (!(data.flags & SCOREBOARD)) return 0; atom->ul = data.sb_dns_lookup; break; case 14: if (!(data.flags & SCOREBOARD)) return 0; atom->ul = data.sb_logging; break; case 15: if (!(data.flags & SCOREBOARD)) return 0; atom->ul = data.sb_finishing; break; case 16: if (!(data.flags & SCOREBOARD)) return 0; atom->ul = data.sb_open_slot; break; case 17: if (!(data.flags & SCOREBOARD)) return 0; atom->ul = data.sb_closing; break; case 18: if (!(data.flags & SCOREBOARD)) return 0; atom->ul = data.sb_idle_cleanup; break; case 19: if (!(data.flags & UPTIME)) return 0; uptime_string(data.uptime, uptime_s, sizeof(uptime_s)); atom->cp = uptime_s; break; default: return PM_ERR_PMID; } return 1; } void apache_init(pmdaInterface *dp) { __pmSetProcessIdentity(username); http_setTimeout(1); http_setUserAgent(pmProgname); snprintf(url, sizeof(url), "http://%s:%u/%s?auto", http_server, http_port, http_path); dp->version.two.fetch = apache_fetch; pmdaSetFetchCallBack(dp, apache_fetchCallBack); pmdaInit(dp, NULL, 0, metrictab, sizeof(metrictab)/sizeof(metrictab[0])); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -S server use remote server, instead of localhost\n" " -P port use port on server, instead of port 80\n" " -L location use location on server, instead of 'server-status'\n" " -U username user account to run under (default \"pcp\")\n" "\nExactly one of the following options may appear:\n" " -i port expect PMCD to connect on given inet port (number or name)\n" " -p expect PMCD to supply stdin/stdout (pipe)\n" " -u socket expect PMCD to connect on given unix domain socket\n" " -6 port expect PMCD to connect on given ipv6 port (number or name)\n", stderr); exit(1); } int main(int argc, char **argv) { int c, errflag = 0, sep = __pmPathSeparator(); pmdaInterface pmda; char helppath[MAXPATHLEN]; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(helppath, sizeof(helppath), "%s%c" "apache" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&pmda, PMDA_INTERFACE_3, pmProgname, APACHE, "apache.log", helppath); while ((c = pmdaGetOpt(argc, argv, "D:d:i:l:pu:L:P:S:U:6:?", &pmda, &errflag)) != EOF) { switch(c) { case 'S': http_server = optarg; break; case 'P': http_port = (int)strtol(optarg, (char **)NULL, 10); break; case 'L': if (optarg[0] == '/') optarg++; http_path = optarg; break; case 'U': username = optarg; break; default: errflag++; } } if (errflag) usage(); pmdaOpenLog(&pmda); apache_init(&pmda); pmdaConnect(&pmda); pmdaMain(&pmda); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/apache/help0000664000000000000000000000674612272262501014606 0ustar # # Copyright (C) 2000 Michal Kara. All Rights Reserved. # Copyright (c) 2008 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # apache PMDA help file in the ASCII format # @apache.total_accesses Number of accesses since Apache started Number of accesses (requests) Apache handled since start of the server. @apache.total_kbytes KBytes transferred since Apache started Number of kilobytes Apache transferred since start of the server. @apache.uptime Seconds since Apache started Number of seconds elapsed since the server was started. @apache.requests_per_sec Requests per second Average requests-per-second rate. Apache computes this as (total_accesses / uptime), so its better to use total_accesses to get current request rate. @apache.bytes_per_sec Bytes per second Average bytes-per-second rate. Apache computes this as (total_kbytes / uptime), so its better to use total_kbytes to get current throughput. @apache.bytes_per_requests Bytes per request Average number of bytes per request. Apache computes this as total_kbytes/total_accesses. @apache.busy_servers Number of working processes Number of Apache processes which are now working - reading requests, receiving data, etc. Together with idle_servers this number gives the total number of running Apache processes. @apache.idle_servers Number of idle processes Number of Apache processes which are now idle - waiting for connection. Together with busy_servers this number gives the total number of running Apache processes. @apache.sb_waiting Number of waiting processes Number of Apache processes waiting for connection. @apache.sb_starting Number of starting processes Number of Apache processes just starting. @apache.sb_reading Number of processes reading Number of Apache processes reading a request. @apache.sb_writing_reply Number of processes writing Number of Apache processes writing a reply. @apache.sb_keepalive Number of processes keeping-alive connection Number of Apache processes waiting for next request on a keep-alive connection. @apache.sb_dns_lookup Number of processes doing DNS lookup Number of Apache processes currently doing DNS lookup. @apache.sb_logging Number of processes writing to log Number of Apache processes writing to a log. @apache.sb_finishing Number of proceses finishing Number of Apache processes gracefuly finishing (becase the RequestsPerChild limit was reached). @apache.sb_open_slot Number of open slots Number of open "slots" which could be occupied by a process. Together with busy_servers and idle_servers, this gives the MaxClients value. @apache.sb_closing Number of processes closing client connections Number of Apache processes closing client connections @apache.sb_idle_cleanup Number of processes performing idle cleanup Number of Apache processes performing idle cleanup @apache.uptime_s Time since Apache started, as a string pcp-3.8.12ubuntu1/src/pmdas/samba/0000775000000000000000000000000012272262620013562 5ustar pcp-3.8.12ubuntu1/src/pmdas/samba/Remove0000775000000000000000000000125612272262501014747 0ustar #! /bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the Samba PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=samba pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/samba/Install0000775000000000000000000000227712272262501015124 0ustar #! /bin/sh # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the Samba PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=samba perl_opt=true daemon_opt=false if ! test -x /usr/sbin/smbd; then echo "Samba \"smbd\" daemon is not installed" && exit 1 fi /usr/sbin/smbd -b | egrep 'WITH_PROFILE|HAVE_PROFILE' >/dev/null if test $? -ne 0; then echo "Samba \"smbd\" not built with profiling support" && exit 1 fi if ! test -x /usr/bin/smbcontrol; then echo "Samba \"smbcontrol\" tool is not installed" && exit 1 fi /usr/bin/smbcontrol smbd profile on if test $? -ne 0; then echo "Samba \"smbcontrol\" failed to enable profiling" && exit 1 fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/samba/GNUmakefile0000664000000000000000000000242712272262501015637 0ustar #!gmake # # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = samba PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LSRCFILES = Install Remove pmda$(IAM).pl LDIRT = domain.h root pmns *.log $(MAN_PAGES) ifneq ($(POD2MAN),) MAN_SECTION = 1 MAN_PAGES = pmda$(IAM).$(MAN_SECTION) MAN_DEST = $(PCP_MAN_DIR)/man$(MAN_SECTION) endif default: check_domain $(MAN_PAGES) pmda$(IAM).1: pmda$(IAM).pl $(POD_MAKERULE) include $(BUILDRULES) ifneq "$(TARGET_OS)" "mingw" install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 pmda$(IAM).pl $(PMDADIR)/pmda$(IAM).pl @$(INSTALL_MAN) else install: endif default_pcp : default install_pcp : install check_domain: ../../pmns/stdpmid $(DOMAIN_PERLRULE) pcp-3.8.12ubuntu1/src/pmdas/samba/pmdasamba.pl0000664000000000000000000001357612272262501016056 0ustar # # Copyright (c) 2012-2013 Red Hat. # Copyright (c) 2009 Aconex. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; use vars qw( $pmda %metrics ); # # This is the main workhorse routine, both value extraction and # namespace population is under-pinned by this. The approach we # use here is to extract profile output, construct a hash (keyed # by metric ID), containing name and value pairs (array refs). # sub samba_fetch { my $item = 0; my $cluster = 0; my $prefix = ''; my $generated_cluster = 20; # start well above hard-coded ones # work around smbstatus / libpopt adverse reaction to these variables delete $ENV{'POSIXLY_CORRECT'}; delete $ENV{'POSIX_ME_HARDER'}; my $smbstats = "smbstatus --profile"; open(STATS, "$smbstats |") || $pmda->err("pmdasamba failed to open $smbstats pipe: $!"); while () { if (m/^\*\*\*\*\s+(\w+[^*]*)\**$/) { my $heading = $1; $heading =~ s/ +$//g; $item = 0; if ($heading eq 'System Calls') { $cluster = 1; $prefix = 'syscalls'; } elsif ($heading eq 'Stat Cache') { $cluster = 2; $prefix = 'statcache'; } elsif ($heading eq 'Write Cache') { $cluster = 3; $prefix = 'writecache'; } elsif ($heading eq 'SMB Calls') { $cluster = 4; $prefix = 'smb'; } elsif ($heading eq 'Pathworks Calls') { $cluster = 5; $prefix = 'pathworks'; } elsif ($heading eq 'Trans2 Calls') { $cluster = 6; $prefix = 'trans2'; } elsif ($heading eq 'NT Transact Calls') { $cluster = 7; $prefix = 'NTtransact'; } elsif ($heading eq 'ACL Calls') { $cluster = 8; $prefix = 'acl'; } elsif ($heading eq 'NMBD Calls') { $cluster = 9; $prefix = 'nmb'; } else { # samba 4.1 renames several clusters of statistics. # Let's generate cluster names instead of hard-coding them. $cluster = $generated_cluster++; $prefix = $heading; $prefix =~ s/ /_/g; $prefix =~ tr/A-Z/a-z/; } # $pmda->log("metric cluster: $cluster = $prefix"); } # we've found a real name/value pair, work out PMID and hash it elsif (m/^([\[\]\w]+):\s+(\d+)$/) { my @metric = ( $1, $2 ); my $pmid; $metric[0] =~ tr/\[\]/_/d; if ($cluster == 0) { $metric[0] = "samba.$metric[0]"; } else { $metric[0] = "samba.$prefix.$metric[0]"; } $pmid = pmda_pmid($cluster,$item++); $metrics{$pmid} = \@metric; # $pmda->log("metric: $metric[0], ID = $pmid, value = $metric[1]"); } else { $pmda->log("pmdasamba failed to parse line $_"); } } close STATS; } sub samba_fetch_callback { my ($cluster, $item, $inst) = @_; my $pmid = pmda_pmid($cluster, $item); my $value; # $pmda->log("samba_fetch_callback $metric_name $cluster:$item ($inst)\n"); if ($inst != PM_IN_NULL) { return (PM_ERR_INST, 0); } # hash lookup based on PMID, value is $metrics{$pmid}[1] $value = $metrics{$pmid}; if (!defined($value)) { return (PM_ERR_APPVERSION, 0); } return ($value->[1], 1); } $pmda = PCP::PMDA->new('samba', 76); samba_fetch(); # extract names and values into %metrics, keyed on PMIDs # hash iterate, keys are PMIDs, names and values are in @metrics{$pmid}. foreach my $pmid (sort(keys %metrics)) { my $name = $metrics{$pmid}[0]; if ($name eq 'samba.writecache.num_write_caches' || $name eq 'samba.writecache.allocated_caches') { $pmda->add_metric($pmid, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,1,0,0,PM_COUNT_ONE), $name, '', ''); } elsif ($name =~ /_time$/) { $pmda->add_metric($pmid, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_USEC,0), $name, '', ''); } else { $pmda->add_metric($pmid, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE), $name, '', ''); } # $pmda->log("pmdasamba added metric $name\n"); } # close STATS; $pmda->set_fetch(\&samba_fetch); $pmda->set_fetch_callback(\&samba_fetch_callback); # NB: needs to run as root, as smb usually does $pmda->run; =pod =head1 NAME pmdasamba - Samba performance metrics domain agent (PMDA) =head1 DESCRIPTION B is a Performance Metrics Domain Agent (PMDA) which exports metric values from Samba, a Windows SMB/CIFS server for UNIX. In order for values to be made available by this PMDA, Samba must have been built with profiling support (WITH_PROFILE in "smbd -b" output). This PMDA dynamically enumerates much of its metric hierarchy, based on the contents of "smbstatus --profile". When the agent is installed (see below), the Install script will attempt to enable Samba statistics gathering, using "smbcontrol --profile". =head1 INSTALLATION If you want access to the names and values for the samba performance metrics, do the following as root: # cd $PCP_PMDAS_DIR/samba # ./Install If you want to undo the installation, do the following as root: # cd $PCP_PMDAS_DIR/samba # ./Remove B is launched by pmcd(1) and should never be executed directly. The Install and Remove scripts notify pmcd(1) when the agent is installed or removed. =head1 FILES =over =item $PCP_PMDAS_DIR/samba/Install installation script for the B agent =item $PCP_PMDAS_DIR/samba/Remove undo installation script for the B agent =item $PCP_LOG_DIR/pmcd/samba.log default log file for error messages from B =back =head1 SEE ALSO pmcd(1), smbd(1) and samba(7). pcp-3.8.12ubuntu1/src/pmdas/summary/0000775000000000000000000000000012272262620014174 5ustar pcp-3.8.12ubuntu1/src/pmdas/summary/README0000664000000000000000000002017712272262501015061 0ustar Performance Co-Pilot PMDA for Exporting Metric Summaries ======================================================== This Performance Metrics Domain Agent (PMDA) is capable of collecting performance metrics values from other PMDAs, computing derived (summary) values, and exporting these derived values as performance metrics. This agent uses the Performance Metrics Inference Engine pmie(1) to periodically collect the data and compute the summary values. These derived values are typically computed by expressions that aggregate a number of base performance values, perhaps from a number of subsystems on the one host or even from multiple hosts, and perhaps over an extended period of time. All of the exported metrics have a singular instance and the values are "instantaneous", i.e. the exported value is the value as of the last time the summary was computed. Refer to the PMAPI(3) man page for more information about these terms. Metrics ======= See the file ./help, or install the agent and execute the command $ pminfo -fT summary Note that customization of the metrics made available by the summary PMDA is possible, as described below. Installation ============ + # cd $PCP_PMDAS_DIR/summary + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + This PMDA caches the most recent value for the performance metrics computed by pmie(1). The cached values are the ones returned via the Performance Metrics Collection Demon pmcd(1) to clients. By default pmie(1) evaluates the expressions once every 10 seconds. The installation procedure will offer you the option to change this interval. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options. You will be prompted for the necessary information to set up the summary agent. De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/summary # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/summary.log) should be checked for any warnings or errors. Customization ============= New summary metrics may be added as follows. + Choose new Performance Metric Name Space (PMNS) names for the new metrics. These must begin with "summary." and follow the rules described in pmns(4). For example summary.fs.wr_cache_hit and summary.fs.rd_cache_hit + Edit the file ./pmns to add the new PMNS names in the format described in pmns(4). You must choose a unique Performance Metric Id (PMID) for each metric ... in the ./pmns file these will appear as SYSSUMMARY:0:x for some x that is arbitrary in the range 0 to 1023 and unique in this file. For example summary { cpu disk netif /*new*/ fs } ... summary.fs { wr_cache_hit SYSSUMMARY:0:10 rd_cache_hit SYSSUMMARY:0:11 } + Use the local fake PMNS ./root and validate that the PMNS changes are correct. For example $ pminfo -n root -m summary.fs summary.fs.wr_cache_hit PMID: 27.0.10 summary.fs.rd_cache_hit PMID: 27.0.11 + Create a file (./expr.pmie in the examples below) containing the new expressions. If the name to the left of the assignment operator (=) is one of the PMNS names, then the pmie(1) expression to the right will be evaluated and returned by the summary PMDA. The expression must return a numeric value, which is exported as a double precision floating point number. If the expression has a set value, then only the first value is exported (in most cases, the pmie aggregate operators should be used to produce a scalar sum or average from a set of numeric values). The exported metric has the dimension (space, time and count) of the expression, and the scale is the canonical scale used by pmie(1), namely bytes, seconds and counts. For example // filesystem buffer cache hit percentages prefix = "kernel.all.io"; // variable, not exported summary.fs.wr_cache_hit = 100 - 100 * $prefix.bwrite / $prefix.lwrite; summary.fs.rd_cache_hit = 100 - 100 * $prefix.bread / $prefix.lread; + Run pmie in debug mode to verify the expressions are being evaluated correctly, and the values make sense. For example $ pmie -t2 -v expr.pmie summary.fs.wr_cache_hit: ? summary.fs.rd_cache_hit: ? summary.fs.wr_cache_hit: 45.83 summary.fs.rd_cache_hit: 83.2 summary.fs.wr_cache_hit: 39.22 summary.fs.rd_cache_hit: 84.51 Once you are happy with the new expressions, add them to the existing expressions in the file ./summary.pmie. + Edit the ./help file to add help text for the new metrics ... see newhelp(1) for a description of the syntax. For example @ summary.fs.wr_cache_hit Filesystem cache read hit ratio Percentage of filesystem block writes that involve a block currently found in the filesystem cache. @ summary.fs.rd_cache_hit Filesystem cache write hit ratio Percentage of filesystem block reads that involve a block currently found in the filesystem cache, and thereby avoid a physical read. + Install the new PMDA For example # ./Install You will need to choose an appropriate configuration for installation of the "summary" Performance Metrics Domain Agent (PMDA). collector collect performance statistics on this system monitor allow this system to monitor local and/or remote systems both collector and monitor configuration for this system Please enter c(ollector) or m(onitor) or b(oth) [b] Updating the Performance Metrics Name Space ... Installing pmchart view(s) ... Interval between summary expression evaluation (seconds)? [10] Terminate PMDA if already installed ... Installing files .. rm -f help.pag help.dir /usr/pcp/bin/newhelp help Updating the PMCD control file, and notifying PMCD ... Wait 15 seconds for the agent to initialize ... Check summary metrics have appeared ... 8 metrics and 8 values + Check the metrics ... For example $ pminfo -fT summary.fs summary.fs.wr_cache_hit Help: Percentage of filesystem block writes that involve a block currently found in the filesystem cache. value 11.97916666666666 summary.fs.rd_cache_hit Help: Percentage of filesystem block reads that involve a block currently found in the filesystem cache, and thereby avoid a physical read. value 74.31192660550458 $ pmval -t5 -s4 summary.fs.wr_cache_hit metric: summary.fs.wr_cache_hit host: localhost semantics: instantaneous value units: none samples: 8 interval: 5.00 sec 63.60132158590308 62.71878646441073 62.71878646441073 58.73968492123031 58.73968492123031 65.33822758259046 65.33822758259046 72.6099706744868 Note the values are being sampled here by pmval(1) every 5 seconds, but pmie(1) is only passing new values to the sample PMDA every 10 seconds. Both rates could be changed to suit the dynamics of your new metrics. + Create pmchart(1) views, pmview(1) scenes and pmlogger(1) configurations to monitor and archive your new performance metrics. For example, a pmchart view could be created using pmchart and the View->Save Configuration menu option. Copy the view from $HOME/.pcp/pmchart into $PCP_PMDAS_DIR/summary and rename it to have the suffix ".pmchart", and a prefix that identifies the view and is unique amongst the view names in $PCP_VAR_DIR/config/pmchart, e.g. Summary.FScache.pmchart Then # cp Summary.FScache.pmchart $PCP_VAR_DIR/config/pmchart/Summary.FScache will install the view in a place where pmchart(1) will be able to find it. Provided the name of the file ends in ".pmchart" in $PCP_PMDAS_DIR/summary the view will be re-installed as a side-effect of any subsequent ./Install of the summary PMDA. pcp-3.8.12ubuntu1/src/pmdas/summary/summary.pmie0000664000000000000000000000200112272262501016534 0ustar // // summary metrics // // these expressions are evaluated by pmie(1) // // use the default interval between expression evaluation (currently // 10 seconds), and re-configure via -t command line arg to pmie // (see Install) // CPU utilization // cpuse = "(kernel.percpu.cpu.sys + kernel.percpu.cpu.user)"; ncpu = "hinv.ncpu"; // average CPU utilization summary.cpu.util = avg_inst $cpuse; // proportion of CPUs that are busy summary.cpu.busy = (count_inst $cpuse > 0.7) / $ncpu; // Disk utilization // diskio = "disk.dev.total"; ndisk = "hinv.ndisk"; // average spindle activity summary.disk.iops = avg_inst ($diskio); // proportion of disk spindles that are busy summary.disk.busy = (count_inst $diskio > 40) / $ndisk; // Network interface utilization // netio = "network.interface.total.packets"; // average network interface activity summary.netif.packets = avg_inst ($netio); // proportion of network interfaces that are busy summary.netif.busy = (count_inst $netio > 400) / (count_inst $netio >= 0); pcp-3.8.12ubuntu1/src/pmdas/summary/Remove0000664000000000000000000000201312272262501015346 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Remove the summary PMDA # # Get standard environment . $PCP_DIR/etc/pcp.env # Get the common procedures and variable assignments # . $PCP_SHARE_DIR/lib/pmdaproc.sh # The name of the PMDA # iam=summary # Do it # pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/summary/Install0000664000000000000000000000250712272262501015527 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the summary PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=summary pmda_interface=2 forced_restart=false pmdaSetup if $do_pmda then if [ ! -x $PCP_BIN_DIR/pmie ] then echo \ 'Error: The "summary" PMDA requires the pmie(1) application but this does not appear to be installed.' exit 1 fi while true do $PCP_ECHO_PROG $PCP_ECHO_N "Interval between summary expression evaluation (seconds)? [10] ""$PCP_ECHO_C" read delta [ -z "$delta" ] && delta=10 [ -z "`echo $delta | tr -d '[0-9]'`" ] && break echo "Error: interval \"$delta\" must be an integer, please try again" done args="$PCP_BIN_DIR/pmie -x -t $delta $PCP_PMDAS_DIR/summary/expr.pmie" check_delay=15 fi pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/summary/GNUmakefile0000664000000000000000000000307612272262501016252 0ustar # # Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = summary DOMAIN = SYSSUMMARY TARGETS = $(IAM)$(EXECSUFFIX) HFILES = summary.h CFILES = summary.c pmda.c mainloop.c LSRCFILES = Install README Remove help pmns root summary.pmie LLDFLAGS= -L$(TOPDIR)/src/libpcp/src -L$(TOPDIR)/src/libpcp_pmda/src LLDLIBS = $(PCP_PMDALIB) LDIRT = domain.h *.log *.dir *.pag $(TARGETS) PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) default: build-me include $(TOPDIR)/src/include/buildrules ifneq "$(TARGET_OS)" "mingw" build-me: $(TARGETS) install: build-me $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 root README help pmns domain.h $(PMDADIR) $(INSTALL) -m 644 summary.pmie $(PMDADIR)/expr.pmie else build-me: install: endif $(IAM)$(EXECSUFFIX): $(OBJECTS) mainloop.o summary.o pmda.o: summary.h summary.o pmda.o: domain.h domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) default_%: default @true install_%: install @true pcp-3.8.12ubuntu1/src/pmdas/summary/root0000664000000000000000000000016412272262501015101 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { summary } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/summary/pmns0000664000000000000000000000037112272262501015073 0ustar /* * Metrics for summary PMDA */ summary { cpu disk netif } summary.cpu { util SYSSUMMARY:0:1 busy SYSSUMMARY:0:2 } summary.disk { iops SYSSUMMARY:0:3 busy SYSSUMMARY:0:4 } summary.netif { packets SYSSUMMARY:0:6 busy SYSSUMMARY:0:7 } pcp-3.8.12ubuntu1/src/pmdas/summary/summary.c0000664000000000000000000001651612272262501016044 0ustar /* * Copyright (c) 1995,2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "summary.h" #include "domain.h" #ifdef HAVE_SYS_RESOURCE_H #include #endif #ifdef HAVE_SYS_WAIT_H #include #endif int nmeta; meta_t *meta; pmResult *cachedResult; static int *freeList; static int summary_desc(pmID pmid, pmDesc *desc, pmdaExt * ex) { static int i=0; if ( i < nmeta && pmid == meta[i].desc.pmid) { found: if (meta[i].desc.type == PM_TYPE_NOSUPPORT) return PM_ERR_AGAIN; /* p76 rules ok */ *desc = meta[i].desc; /* struct assignment */ return 0; /* success */ } for (i = 0; i < nmeta; i++) { if (pmid == meta[i].desc.pmid) goto found; } return PM_ERR_PMID; } void service_client(__pmPDU *pb) { int n; int i; int j; pmDesc desc; pmDesc foundDesc; pmResult *resp; pmValueSet *vsp; __pmPDUHdr *ph = (__pmPDUHdr *)pb; switch (ph->type) { case PDU_DESC: if ((n = __pmDecodeDesc(pb, &desc)) < 0) { fprintf(stderr, "service_client: __pmDecodeDesc failed: %s\n", pmErrStr(n)); exit(1); } if (desc.indom != PM_INDOM_NULL) { fprintf(stderr, "service_client: Warning: ignored desc for pmid=%s: indom is not singular\n", pmIDStr(desc.pmid)); return; } if (summary_desc(desc.pmid, &foundDesc, NULL) == 0) { /* already in table */ fprintf(stderr, "service_client: Warning: duplicate desc for pmid=%s\n", pmIDStr(desc.pmid)); return; } nmeta++; if ((meta = (meta_t *)realloc(meta, nmeta * sizeof(meta_t))) == NULL) { __pmNoMem("service_client: meta realloc", nmeta * sizeof(meta_t), PM_FATAL_ERR); } memcpy(&meta[nmeta-1].desc, &desc, sizeof(pmDesc)); break; case PDU_RESULT: if ((n = __pmDecodeResult(pb, &resp)) < 0) { fprintf(stderr, "service_client: __pmDecodeResult failed: %s\n", pmErrStr(n)); exit(1); } if (cachedResult == NULL) { int need; need = (int)sizeof(pmResult) - (int)sizeof(pmValueSet *); if ((cachedResult = (pmResult *)malloc(need)) == NULL) { __pmNoMem("service_client: result malloc", need, PM_FATAL_ERR); } cachedResult->numpmid = 0; } /* * swap values from resp with those in cachedResult, expanding * cachedResult if there are metrics we've not seen before */ for (i = 0; i < resp->numpmid; i++) { for (j = 0; j < cachedResult->numpmid; j++) { if (resp->vset[i]->pmid == cachedResult->vset[j]->pmid) { /* found matching PMID, update this value */ break; } } if (j == cachedResult->numpmid) { /* new PMID, expand cachedResult and initialize vset */ int need; cachedResult->numpmid++; need = (int)sizeof(pmResult) + (cachedResult->numpmid-1) * (int)sizeof(pmValueSet *); if ((cachedResult = (pmResult *)realloc(cachedResult, need)) == NULL) { __pmNoMem("service_client: result realloc", need, PM_FATAL_ERR); } if ((cachedResult->vset[j] = (pmValueSet *)malloc(sizeof(pmValueSet))) == NULL) { __pmNoMem("service_client: vset[]", sizeof(pmValueSet), PM_FATAL_ERR); } cachedResult->vset[j]->pmid = resp->vset[i]->pmid; cachedResult->vset[j]->numval = 0; } /* * swap vsets */ vsp = cachedResult->vset[j]; cachedResult->vset[j] = resp->vset[i]; resp->vset[i] = vsp; } pmFreeResult(resp); break; case PDU_ERROR: if ((n = __pmDecodeError(pb, &i)) < 0) { fprintf(stderr, "service_client: __pmDecodeError failed: %s\n", pmErrStr(n)); exit(1); } fprintf(stderr, "service_client: Error PDU! %s\n", pmErrStr(i)); break; default: fprintf(stderr, "service_client: Bogus PDU type %d\n", ph->type); exit(1); } } static int summary_profile(__pmProfile *prof, pmdaExt * ex) { /* * doesn't make sense since summary metrics * always have a singular instance domain. */ return 0; } static int summary_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt * ex) { return PM_ERR_INDOM; } static void freeResultCallback(pmResult *res) { int i; /* * pmResult has now been sent to pmcd. Only free the * value sets that had no values available because * the valid ones were reused from the cachedResult. */ for (i=0; i < res->numpmid; i++) { if (freeList[i]) free(res->vset[i]); } return; } static int summary_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt * ex) { int i; /* over pmidlist[] */ int j; /* over vset->vlist[] */ int sts; int need; int validpmid; pmID pmid; pmDesc desc; static pmResult *res = NULL; static int maxnpmids = 0; if (numpmid > maxnpmids) { maxnpmids = numpmid; if (res != NULL) free(res); /* (numpmid - 1) because there's room for one valueSet in a pmResult */ need = sizeof(pmResult) + (numpmid - 1) * sizeof(pmValueSet *); if ((res = (pmResult *)malloc(need)) == NULL) return -oserror(); if (freeList != NULL) free(freeList); if ((freeList = (int *)malloc(numpmid * sizeof(int))) == NULL) return -oserror(); } res->timestamp.tv_sec = 0; res->timestamp.tv_usec = 0; res->numpmid = numpmid; for (i = 0; i < numpmid; i++) { pmid = pmidlist[i]; /* * do we know about the descriptor for this pmid? * If not, then the error is PM_ERR_PMID * regardless of whether there is an entry in * the cached result. */ sts = summary_desc(pmid, &desc, NULL); validpmid = (sts == 0); res->vset[i] = NULL; freeList[i] = 1; if (validpmid && cachedResult != NULL) { for (j=0; j < cachedResult->numpmid; j++) { if (pmid == cachedResult->vset[j]->pmid) { res->vset[i] = cachedResult->vset[j]; freeList[i] = 0; break; } } } if (!validpmid || res->vset[i] == NULL) { /* no values available or the metric has no descriptor */ if ((res->vset[i] = (pmValueSet *)malloc(sizeof(pmValueSet))) == NULL) return -oserror(); res->vset[i]->pmid = pmid; res->vset[i]->valfmt = PM_VAL_INSITU; res->vset[i]->numval = validpmid ? PM_ERR_VALUE : sts; } } *resp = res; return numpmid; } static int summary_store(pmResult *result, pmdaExt * ex) { return PM_ERR_PERMISSION; } void summary_init(pmdaInterface *dp) { void (*callback)() = freeResultCallback; dp->version.two.profile = summary_profile; dp->version.two.fetch = summary_fetch; dp->version.two.desc = summary_desc; dp->version.two.instance = summary_instance; dp->version.two.store = summary_store; mainLoopFreeResultCallback(callback); pmdaInit(dp, NULL, 0, NULL, 0); } void summary_done(void) { int st; fprintf(stderr, "summary agent pid=%" FMT_PID " done\n", getpid()); kill(clientPID, SIGINT); waitpid(clientPID, &st, 0); } pcp-3.8.12ubuntu1/src/pmdas/summary/mainloop.c0000664000000000000000000001333712272262501016163 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include "summary.h" static void (*freeResultCallback)(pmResult *) = __pmFreeResultValues; void mainLoopFreeResultCallback(void (*callback)(pmResult *res)) { freeResultCallback = callback; } void summaryMainLoop(char *pmdaname, int clientfd, pmdaInterface *dtp) { __pmPDU *pb_pmcd; __pmPDU *pb_client; int sts; pmID pmid; pmDesc desc; int npmids; pmID *pmidlist; pmResult *result; int ctxnum; __pmTimeval when; int ident; int type; pmInDom indom; int inst; char *name; __pmInResult *inres; char *buffer; __pmProfile *profile; __pmProfile *saveprofile = NULL; static fd_set readFds; int maxfd; int clientReady, pmcdReady; int infd, outfd; if (dtp->comm.pmda_interface != PMDA_INTERFACE_2) { __pmNotifyErr(LOG_CRIT, "summaryMainLoop supports PMDA protocol version 2 only, " "not %d\n", dtp->comm.pmda_interface); exit(1); } else { infd = dtp->version.two.ext->e_infd; outfd = dtp->version.two.ext->e_outfd; } maxfd = infd+1; if (clientfd >= maxfd) maxfd = clientfd+1; for ( ;; ) { FD_ZERO(&readFds); FD_SET(infd, &readFds); FD_SET(clientfd, &readFds); /* select here : block if nothing to do */ sts = select(maxfd, &readFds, NULL, NULL, NULL); clientReady = FD_ISSET(clientfd, &readFds); pmcdReady = FD_ISSET(infd, &readFds); if (sts < 0) break; if (sts == 0) continue; if (clientReady) { /* * Service the command/client */ sts = __pmGetPDU(clientfd, ANY_SIZE, TIMEOUT_NEVER, &pb_client); if (sts < 0) __pmNotifyErr(LOG_ERR, "client __pmGetPDU: %s\n", pmErrStr(sts)); if (sts <= 0) /* End of File or error */ goto done; service_client(pb_client); __pmUnpinPDUBuf(pb_client); } if (pmcdReady) { /* service pmcd */ sts = __pmGetPDU(infd, ANY_SIZE, TIMEOUT_NEVER, &pb_pmcd); if (sts < 0) __pmNotifyErr(LOG_ERR, "__pmGetPDU: %s\n", pmErrStr(sts)); if (sts <= 0) /* End of File or error */ goto done; switch (sts) { case PDU_PROFILE: /* * can ignore ctxnum, since pmcd has already used this to send * the correct profile, if required */ if ((sts = __pmDecodeProfile(pb_pmcd, &ctxnum, &profile)) >= 0) sts = dtp->version.two.profile(profile, dtp->version.two.ext); if (sts < 0) __pmSendError(outfd, FROM_ANON, sts); else { if (saveprofile != NULL) free(saveprofile); /* * need to keep the last valid one around, as the DSO * routine just remembers the address */ saveprofile = profile; } break; case PDU_FETCH: /* * can ignore ctxnum, since pmcd has already used this to send * the correct profile, if required */ sts = __pmDecodeFetch(pb_pmcd, &ctxnum, &when, &npmids, &pmidlist); /* Ignore "when"; pmcd should intercept archive log requests */ if (sts >= 0) { sts = dtp->version.two.fetch(npmids, pmidlist, &result, dtp->version.two.ext); __pmUnpinPDUBuf(pmidlist); } if (sts < 0) __pmSendError(outfd, FROM_ANON, sts); else { int st; st =__pmSendResult(outfd, FROM_ANON, result); if (st < 0) { __pmNotifyErr(LOG_ERR, "Cannot send fetch result: %s\n", pmErrStr(st)); } (*freeResultCallback)(result); } break; case PDU_DESC_REQ: if ((sts = __pmDecodeDescReq(pb_pmcd, &pmid)) >= 0) { sts = dtp->version.two.desc(pmid, &desc, dtp->version.two.ext); } if (sts < 0) __pmSendError(outfd, FROM_ANON, sts); else __pmSendDesc(outfd, FROM_ANON, &desc); break; case PDU_INSTANCE_REQ: if ((sts = __pmDecodeInstanceReq(pb_pmcd, &when, &indom, &inst, &name)) >= 0) { /* * Note: when is ignored. * If we get this far, we are _only_ dealing * with current data (pmcd handles the other * cases). */ sts = dtp->version.two.instance(indom, inst, name, &inres, dtp->version.two.ext); } if (sts < 0) __pmSendError(outfd, FROM_ANON, sts); else { __pmSendInstance(outfd, FROM_ANON, inres); __pmFreeInResult(inres); } break; case PDU_TEXT_REQ: if ((sts = __pmDecodeTextReq(pb_pmcd, &ident, &type)) >= 0) { sts = dtp->version.two.text(ident, type, &buffer, dtp->version.two.ext); } if (sts < 0) __pmSendError(outfd, FROM_ANON, sts); else __pmSendText(outfd, FROM_ANON, ident, buffer); break; case PDU_RESULT: if ((sts = __pmDecodeResult(pb_pmcd, &result)) >= 0) sts = dtp->version.two.store(result, dtp->version.two.ext); __pmSendError(outfd, FROM_ANON, sts); pmFreeResult(result); break; case PDU_ERROR: /* end of context from PMCD ... we don't care */ break; default: fprintf(stderr, "%s: bogus pdu type: 0x%0x?\n", pmdaname, sts); __pmSendError(outfd, FROM_ANON, PM_ERR_NYI); break; } __pmUnpinPDUBuf(pb_pmcd); } } done: return; } pcp-3.8.12ubuntu1/src/pmdas/summary/summary.h0000664000000000000000000000177412272262501016051 0ustar /* * Copyright (c) 1995 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ /* * exported summary metrics */ typedef struct { char *name; /* name space path */ pmDesc desc; /* descriptor, inc. pmid */ } meta_t; extern meta_t *meta; extern int nmeta; extern char *command; extern char *helpfile; extern int cmdpipe; extern pid_t clientPID; extern void summaryMainLoop(char *, int, pmdaInterface *); extern void mainLoopFreeResultCallback(void (*)(pmResult *)); extern void service_client(__pmPDU *); pcp-3.8.12ubuntu1/src/pmdas/summary/pmda.c0000664000000000000000000000740312272262501015263 0ustar /* * Copyright (c) 2012 Red Hat. * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include "pmda.h" #include #include "summary.h" #include "domain.h" extern void summary_init(pmdaInterface *); extern void summary_done(void); pid_t clientPID; int main(int argc, char **argv) { int errflag = 0; int sep = __pmPathSeparator(); char **commandArgv; pmdaInterface dispatch; int i; int len, c; int clientPipe[2]; char helpfile[MAXPATHLEN]; int cmdpipe; /* metric source/cmd pipe */ char *command = NULL; char *username; __pmSetProgname(argv[0]); __pmGetUsername(&username); __pmSetInternalState(PM_STATE_PMCS); /* we are below the PMAPI */ snprintf(helpfile, sizeof(helpfile), "%s%c" "summary" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon (&dispatch, PMDA_INTERFACE_2, pmProgname, SYSSUMMARY, "summary.log", helpfile); while ((c = pmdaGetOpt(argc, argv, "H:h:D:d:l:U:", &dispatch, &errflag)) != EOF) { switch (c) { case 'H': /* backwards compatibility, synonym for -h */ dispatch.version.two.ext->e_helptext = optarg; break; case 'U': username = optarg; break; case '?': errflag++; break; } } for (len=0, i=optind; i < argc; i++) { len += strlen(argv[i]) + 1; } if (len == 0) { fprintf(stderr, "%s: a command must be given after the options\n", pmProgname); errflag++; } else { command = (char *)malloc(len+2); command[0] = '\0'; for (i=optind; i < argc; i++) { if (i > optind) strcat(command, " "); strcat(command, argv[i]); } } commandArgv = argv + optind; if (errflag) { fprintf(stderr, "Usage: %s [options] command [arg ...]\n\n", pmProgname); fputs("Options:\n" " -h helpfile help text file\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n", stderr); exit(1); } /* force errors from here on into the log */ pmdaOpenLog(& dispatch); /* switch to alternate user account now */ __pmSetProcessIdentity(username); /* initialize */ summary_init(&dispatch); pmdaConnect(&dispatch); if (dispatch.status) { fprintf (stderr, "Cannot connect to pmcd: %s\n", pmErrStr(dispatch.status)); exit (1); } /* * open a pipe to the command */ if (pipe1(clientPipe) < 0) { perror("pipe"); exit(oserror()); } if ((clientPID = fork()) == 0) { /* child */ char cmdpath[MAXPATHLEN+5]; close(clientPipe[0]); if (dup2(clientPipe[1], fileno(stdout)) < 0) { perror("dup"); exit(oserror()); } close(clientPipe[1]); snprintf (cmdpath, sizeof(cmdpath), "exec %s", commandArgv[0]); execv(commandArgv[0], commandArgv); perror(cmdpath); exit(oserror()); } fprintf(stderr, "clientPID = %" FMT_PID "\n", clientPID); close(clientPipe[1]); cmdpipe = clientPipe[0]; /* parent/agent reads from here */ __pmSetVersionIPC(cmdpipe, PDU_VERSION2); summaryMainLoop(pmProgname, cmdpipe, &dispatch); summary_done(); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/summary/help0000664000000000000000000000425112272262501015047 0ustar # # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # summary PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ summary.cpu.util CPU utilization Fraction of time spent executing in user or system mode, averaged over all CPUs. Any time not accountered for here is spent either idle or waiting for I/O. Value in the range 0 to 1. @ summary.cpu.busy Proportion of the CPUs that are busy Fraction of the CPUs busy executing in user and/or system mode for more than 70% of the time. Value in the range 0 to 1. @ summary.disk.iops Average disk IOPS Average disk throughput in IO operations per second. @ summary.disk.busy Proportion of the disks that are busy Fraction of the disks busy serving at least 30 IOPs. Value in the range 0 to 1. @ summary.netif.packets Average network interface throughput Average network interface throughput in packets per second. @ summary.netif.busy Proportion of the network interfaces that are busy Fraction of network interfaces busy serving at least 375 packets per second). Value in the range 0 to 1. pcp-3.8.12ubuntu1/src/pmdas/bash/0000775000000000000000000000000012272262620013414 5ustar pcp-3.8.12ubuntu1/src/pmdas/bash/bashproc.sh0000775000000000000000000000514312272262501015555 0ustar # Common bash(1) procedures to be used in the Performance Co-Pilot # Bash PMDA trace instrumentation mechanism # # Copyright (c) 2012 Nathan Scott. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. pcp_trace() { command="$1" shift case "$command" in setup|init) [ -z "${PCP_TMP_DIR}" ] && return 0 # incorrect call sequence trap "pcp_trace off" 0 export PCP_TRACE_DIR="${PCP_TMP_DIR}/pmdabash" export PCP_TRACE_HEADER="${PCP_TRACE_DIR}/.$$" export PCP_TRACE_DATA="${PCP_TRACE_DIR}/$$" ;; stop|off) exec 99>/dev/null # unlink is performed by pmdabash to resolve race conditions unset BASH_XTRACEFD PCP_TRACE_DIR PCP_TRACE_HEADER PCP_TRACE_DATA ;; start|on) # series of sanity checks first [ -n "${BASH_VERSION}" ] || return 0 # wrong shell [ "${BASH_VERSINFO[0]}" -ge 4 ] || return 0 # no support [ "${BASH_VERSINFO[0]}" -ne 4 -o "${BASH_VERSINFO[1]}" -ge 2 ] || \ return 0 # no support [ -z "${PCP_TMP_DIR}" ] && return 0 # incorrect setup [ -z "${PCP_TRACE_DIR}" ] && pcp_trace init $@ # not yet tracing [ -d "${PCP_TRACE_DIR}" ] || return 0 # no pcp pmda yet # is this the child of a traced shell? [ -e /proc/self/fd/99 ] && pcp_trace init $@ trap "pcp_trace on" 13 # reset on sigpipe (consumer died) printf -v PCP_START '%(%s)T' -2 mkfifo -m 600 "${PCP_TRACE_DATA}" 2>/dev/null || return 0 # header: version, command, parent, and start time echo "version:1 ppid:${PPID} date:${PCP_START} + $@" \ > "${PCP_TRACE_HEADER}" || return 0 # setup link between xtrace & fifo exec 99>"${PCP_TRACE_DATA}" BASH_XTRACEFD=99 # magic bash environment variable set -o xtrace # start tracing from here onward # traces: time, line#, and (optionally) function PS4='time:${SECONDS} line:${LINENO} func:${FUNCNAME[0]-} + ' ;; esac } pcp-3.8.12ubuntu1/src/pmdas/bash/util.c0000664000000000000000000000372412272262501014541 0ustar /* * Utility routines for the bash tracing PMDA * * Copyright (c) 2012 Nathan Scott. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "event.h" #include "pmda.h" #include int extract_int(char *s, const char *field, size_t length, int *value) { char *endnum; int num; if (strncmp(s, field, length) != 0) return 0; num = strtol(s + length, &endnum, 10); if (*endnum != ',' && *endnum != '\0' && !isspace((int)*endnum)) return 0; *value = num; return endnum - s + 1; } int extract_str(char *s, size_t end, const char *field, size_t length, char *value, size_t vsz) { char *p; if (strncmp(s, field, length) != 0) return 0; p = s + length; while (*p != ',' && *p != '\0' && !isspace((int)*p)) p++; *p = '\0'; strncpy(value, s + length, vsz); return p - s + 1; } int extract_cmd(char *s, size_t end, const char *field, size_t length, char *value, size_t vsz) { char *start = NULL, *stop = NULL, *p; int len; /* find the start of the command */ for (p = s; p < s + end; p++) { if (strncmp(p, field, length) != 0) continue; p++; if (*p == ' ') p++; break; } if (p == s + end) return 0; start = p; /* find the command terminator */ while (*p != '\n' && *p != '\0' && p < s + end) p++; stop = p; /* truncate it if necessary */ len = stop - start; if (len > vsz - 1) len = vsz - 1; /* copy it over to "value" */ start[len] = '\0'; strncpy(value, start, len + 1); return len; } pcp-3.8.12ubuntu1/src/pmdas/bash/test-trace.sh0000775000000000000000000000155212272262501016027 0ustar #!/usr/bin/env bash # # Copyright (c) 2012 Nathan Scott. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # . $PCP_DIR/etc/pcp.sh pcp_trace on $0 $@ tired() { sleep $1 } count=0 while true do (( count++ )) echo "awoke, $count" # top level tired 2 # call a shell function branch=$(( count % 3 )) case $branch in 0) ./test-child.sh $count & ;; 2) wait ;; esac done pcp_trace off exit 0 pcp-3.8.12ubuntu1/src/pmdas/bash/Remove0000664000000000000000000000126012272262501014571 0ustar #! /bin/sh # # Copyright (c) 2012 Nathan Scott. All rights reversed. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the bash PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=bash pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/bash/Install0000664000000000000000000000163412272262501014747 0ustar #! /bin/sh # # Copyright (c) 2012 Nathan Scott. All rights reversed. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the bash PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=bash dso_opt=true socket_opt=true socket_inet_def=2082 forced_restart=false pmda_interface=5 if [ ! -e "$PCP_TMP_DIR/pmdabash" ] then echo "creating $PCP_TMP_DIR/pmdabash" mkdir -p -m 1777 "$PCP_TMP_DIR/pmdabash" fi pmdaSetup pmdaInstall exit 0 pcp-3.8.12ubuntu1/src/pmdas/bash/GNUmakefile0000664000000000000000000000313612272262501015467 0ustar # # Copyright (c) 2012 Nathan Scott. All Rights Reversed. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs IAM = bash DOMAIN = BASH TARGETS = $(IAM)$(EXECSUFFIX) LLDLIBS = $(PCP_PMDALIB) PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LDIRT = domain.h *.log *.dir *.pag so_locations $(TARGETS) CFILES = event.c bash.c util.c HFILES = event.h SCRIPTS = bashproc.sh pcp.sh SAMPLES = test-child.sh test-trace.sh LSRCFILES = Install Remove pmns help root $(SCRIPTS) $(SAMPLES) default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "mingw" build-me: install: else build-me: $(TARGETS) install: default $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) $(INSTALL) -m 755 Install Remove $(PMDADIR) $(INSTALL) -m 644 root help pmns $(PMDADIR) $(INSTALL) -m 644 domain.h $(PMDADIR)/domain.h $(INSTALL) -m 644 bashproc.sh $(PCP_SHARE_DIR)/lib/bashproc.sh $(INSTALL) -m 644 pcp.sh $(PCP_ETC_DIR)/pcp.sh endif $(IAM)$(EXECSUFFIX): $(OBJECTS) bash.o: domain.h event.o bash.o util.o: event.h domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmdas/bash/root0000664000000000000000000000016112272262501014316 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { bash } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/bash/bash.c0000664000000000000000000003226512272262501014503 0ustar /* * Bash -x trace PMDA * * Copyright (c) 2012 Red Hat. * Copyright (c) 2012 Nathan Scott. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "domain.h" #include "event.h" #include "pmda.h" #define DEFAULT_MAXMEM (2 * 1024 * 1024) /* 2 megabytes */ long bash_maxmem; static int bash_interval_expired; static struct timeval bash_interval = { 1, 0 }; static char *username; #define BASH_INDOM 0 static pmdaIndom indoms[] = { { BASH_INDOM, 0, NULL } }; #define INDOM_COUNT (sizeof(indoms)/sizeof(indoms[0])) static pmdaMetric metrics[] = { #define bash_xtrace_numclients 0 { NULL, { PMDA_PMID(0,bash_xtrace_numclients), PM_TYPE_U32, BASH_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, #define bash_xtrace_maxmem 1 { NULL, { PMDA_PMID(0,bash_xtrace_maxmem), PM_TYPE_U64, BASH_INDOM, PM_SEM_DISCRETE, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, #define bash_xtrace_queuemem 2 { NULL, { PMDA_PMID(0,bash_xtrace_queuemem), PM_TYPE_U64, BASH_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, #define bash_xtrace_count 3 { NULL, { PMDA_PMID(0,bash_xtrace_count), PM_TYPE_U32, BASH_INDOM, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, #define bash_xtrace_records 4 { NULL, { PMDA_PMID(0,bash_xtrace_records), PM_TYPE_EVENT, BASH_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, #define bash_xtrace_parameters_pid 5 { NULL, { PMDA_PMID(0,bash_xtrace_parameters_pid), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, #define bash_xtrace_parameters_parent 6 { NULL, { PMDA_PMID(0,bash_xtrace_parameters_parent), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, #define bash_xtrace_parameters_lineno 7 { NULL, { PMDA_PMID(0,bash_xtrace_parameters_lineno), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, PMDA_PMUNITS(0,0,0,0,0,0) }, }, #define bash_xtrace_parameters_function 8 { NULL, { PMDA_PMID(0,bash_xtrace_parameters_function), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, #define bash_xtrace_parameters_command 9 { NULL, { PMDA_PMID(0,bash_xtrace_parameters_command), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, }; #define METRIC_COUNT (sizeof(metrics)/sizeof(metrics[0])) static void check_processes(int context) { pmdaEventNewClient(context); event_refresh(indoms[BASH_INDOM].it_indom); } static int bash_instance(pmInDom indom, int inst, char *name, __pmInResult **result, pmdaExt *pmda) { check_processes(pmda->e_context); return pmdaInstance(indom, inst, name, result, pmda); } static int bash_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { check_processes(pmda->e_context); return pmdaFetch(numpmid, pmidlist, resp, pmda); } static int bash_trace_parser(bash_process_t *bash, bash_trace_t *trace, struct timeval *timestamp, const char *buffer, size_t size) { trace->flags = (PM_EVENT_FLAG_ID | PM_EVENT_FLAG_PARENT); /* empty event inserted into queue to signal process has exited */ if (size <= 0) { trace->flags |= PM_EVENT_FLAG_END; if (fstat(bash->fd, &bash->stat) < 0 || !S_ISFIFO(bash->stat.st_mode)) memcpy(&trace->timestamp, timestamp, sizeof(*timestamp)); else process_stat_timestamp(bash, &trace->timestamp); close(bash->fd); } else { char *p = (char *)buffer, *end = (char *)buffer + size - 1; int sz, time = -1; /* version 1 format: time, line#, function, and command line */ p += extract_int(p, "time:", sizeof("time:")-1, &time); p += extract_int(p, "line:", sizeof("line:")-1, &trace->line); p += extract_str(p, end - p, "func:", sizeof("func:")-1, trace->function, sizeof(trace->function)); sz = extract_cmd(p, end - p, "+", sizeof("+")-1, trace->command, sizeof(trace->command)); if (sz <= 0) /* wierd trace - no command */ trace->command[0] = '\0'; if (strncmp(trace->command, "pcp_trace ", 10) == 0 || strncmp(trace->function, "pcp_trace", 10) == 0) return 1; /* suppress tracing function, its white noise */ if (time != -1) { /* normal case */ trace->timestamp.tv_sec = bash->starttime.tv_sec + time; trace->timestamp.tv_usec = bash->starttime.tv_usec; } else { /* wierd trace */ memcpy(&trace->timestamp, timestamp, sizeof(*timestamp)); } if (event_start(bash, &trace->timestamp)) trace->flags |= PM_EVENT_FLAG_START; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "event parsed: flags: %x time: %d line: %d func: '%s' cmd: '%s'", trace->flags, time, trace->line, trace->function, trace->command); } return 0; } static int bash_trace_decoder(int eventarray, void *buffer, size_t size, struct timeval *timestamp, void *data) { pmAtomValue atom; bash_process_t *process = (bash_process_t *)data; bash_trace_t trace = { 0 }; pmID pmid; int sts, count = 0; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "bash_trace_decoder[%ld bytes]", (long)size); if (bash_trace_parser(process, &trace, timestamp, (const char *)buffer, size)) return 0; sts = pmdaEventAddRecord(eventarray, &trace.timestamp, trace.flags); if (sts < 0) return sts; atom.ul = process->pid; pmid = metrics[bash_xtrace_parameters_pid].m_desc.pmid; sts = pmdaEventAddParam(eventarray, pmid, PM_TYPE_U32, &atom); if (sts < 0) return sts; count++; atom.ul = process->parent; pmid = metrics[bash_xtrace_parameters_parent].m_desc.pmid; sts = pmdaEventAddParam(eventarray, pmid, PM_TYPE_U32, &atom); if (sts < 0) return sts; count++; if (trace.line) { atom.ul = trace.line; pmid = metrics[bash_xtrace_parameters_lineno].m_desc.pmid; sts = pmdaEventAddParam(eventarray, pmid, PM_TYPE_U32, &atom); if (sts < 0) return sts; count++; } if (trace.function[0] != '\0') { atom.cp = trace.function; pmid = metrics[bash_xtrace_parameters_function].m_desc.pmid; sts = pmdaEventAddParam(eventarray, pmid, PM_TYPE_STRING, &atom); if (sts < 0) return sts; count++; } if (trace.command[0] != '\0') { atom.cp = trace.command; pmid = metrics[bash_xtrace_parameters_command].m_desc.pmid; sts = pmdaEventAddParam(eventarray, pmid, PM_TYPE_STRING, &atom); if (sts < 0) return sts; count++; } return count; } static int bash_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); bash_process_t *bp; if (idp->cluster != 0) return PM_ERR_PMID; switch (idp->item) { case bash_xtrace_maxmem: atom->ull = (unsigned long long)bash_maxmem; return PMDA_FETCH_STATIC; case bash_xtrace_parameters_pid: case bash_xtrace_parameters_parent: case bash_xtrace_parameters_lineno: case bash_xtrace_parameters_function: case bash_xtrace_parameters_command: return PMDA_FETCH_NOVALUES; } if (PMDA_CACHE_ACTIVE != pmdaCacheLookup(indoms[BASH_INDOM].it_indom, inst, NULL, (void **)&bp)) return PM_ERR_INST; switch (idp->item) { case bash_xtrace_numclients: return pmdaEventQueueClients(bp->queueid, atom); case bash_xtrace_queuemem: return pmdaEventQueueMemory(bp->queueid, atom); case bash_xtrace_count: return pmdaEventQueueCounter(bp->queueid, atom); case bash_xtrace_records: return pmdaEventQueueRecords(bp->queueid, atom, pmdaGetContext(), bash_trace_decoder, bp); } return PM_ERR_PMID; } static int bash_store_metric(pmValueSet *vsp, int context) { __pmID_int *idp = (__pmID_int *)&vsp->pmid; pmInDom processes = indoms[BASH_INDOM].it_indom; int sts; if (idp->cluster != 0 || idp->item != bash_xtrace_records) return PM_ERR_PERMISSION; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "bash_store_metric walking bash set"); pmdaCacheOp(processes, PMDA_CACHE_WALK_REWIND); while ((sts = pmdaCacheOp(processes, PMDA_CACHE_WALK_NEXT)) != -1) { bash_process_t *bp; if (!pmdaCacheLookup(processes, sts, NULL, (void **)&bp)) continue; if ((sts = pmdaEventSetAccess(context, bp->queueid, 1)) < 0) return sts; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "Access granted client=%d bash=%d queueid=%d", context, bp->pid, bp->queueid); } return 0; } static int bash_store(pmResult *result, pmdaExt *pmda) { int i, sts; int context = pmda->e_context; check_processes(context); if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "bash_store called (%d)", result->numpmid); for (i = 0; i < result->numpmid; i++) { pmValueSet *vsp = result->vset[i]; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "bash_store_metric called"); if ((sts = bash_store_metric(vsp, context)) < 0) return sts; } return 0; } static void bash_end_contextCallBack(int context) { pmdaEventEndClient(context); } static void timer_expired(int sig, void *ptr) { bash_interval_expired = 1; } void bash_main(pmdaInterface *dispatch) { fd_set fds, readyfds; int maxfd, nready, pmcdfd; pmcdfd = __pmdaInFd(dispatch); maxfd = pmcdfd; FD_ZERO(&fds); FD_SET(pmcdfd, &fds); /* arm interval timer */ if (__pmAFregister(&bash_interval, NULL, timer_expired) < 0) { __pmNotifyErr(LOG_ERR, "registering event interval handler"); exit(1); } for (;;) { memcpy(&readyfds, &fds, sizeof(readyfds)); nready = select(maxfd+1, &readyfds, NULL, NULL, NULL); if (pmDebug & DBG_TRACE_APPL2) __pmNotifyErr(LOG_DEBUG, "select: nready=%d interval=%d", nready, bash_interval_expired); if (nready < 0) { if (neterror() != EINTR) { __pmNotifyErr(LOG_ERR, "select failure: %s", netstrerror()); exit(1); } else if (!bash_interval_expired) { continue; } } __pmAFblock(); if (nready > 0 && FD_ISSET(pmcdfd, &readyfds)) { if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "processing pmcd PDU [fd=%d]", pmcdfd); if (__pmdaMainPDU(dispatch) < 0) { __pmAFunblock(); exit(1); /* fatal if we lose pmcd */ } if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "completed pmcd PDU [fd=%d]", pmcdfd); } if (bash_interval_expired) { bash_interval_expired = 0; event_refresh(indoms[BASH_INDOM].it_indom); } __pmAFunblock(); } } void bash_init(pmdaInterface *dp) { __pmSetProcessIdentity(username); if (dp->status != 0) return; dp->version.four.fetch = bash_fetch; dp->version.four.store = bash_store; dp->version.four.instance = bash_instance; pmdaSetFetchCallBack(dp, bash_fetchCallBack); pmdaSetEndContextCallBack(dp, bash_end_contextCallBack); pmdaInit(dp, indoms, INDOM_COUNT, metrics, METRIC_COUNT); event_init(); } static void convertUnits(char **endnum, long *maxmem) { switch ((int) **endnum) { case 'b': case 'B': break; case 'k': case 'K': *maxmem *= 1024; break; case 'm': case 'M': *maxmem *= 1024 * 1024; break; case 'g': case 'G': *maxmem *= 1024 * 1024 * 1024; break; } (*endnum)++; } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n" "Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than the default\n" " -m memory maximum memory used per logfile (default %ld bytes)\n" " -s interval default delay between iterations (default %d sec)\n" " -U username user account to run under (default \"pcp\")\n", pmProgname, bash_maxmem, (int)bash_interval.tv_sec); exit(1); } int main(int argc, char **argv) { static char helppath[MAXPATHLEN]; char *endnum; pmdaInterface desc; long minmem; int c, err = 0, sep = __pmPathSeparator(); __pmSetProgname(argv[0]); __pmGetUsername(&username); minmem = getpagesize(); bash_maxmem = (minmem > DEFAULT_MAXMEM) ? minmem : DEFAULT_MAXMEM; snprintf(helppath, sizeof(helppath), "%s%c" "bash" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&desc, PMDA_INTERFACE_5, pmProgname, BASH, "bash.log", helppath); while ((c = pmdaGetOpt(argc, argv, "D:d:l:m:s:U:?", &desc, &err)) != EOF) { switch (c) { case 'm': bash_maxmem = strtol(optarg, &endnum, 10); if (*endnum != '\0') convertUnits(&endnum, &bash_maxmem); if (*endnum != '\0' || bash_maxmem < minmem) { fprintf(stderr, "%s: invalid max memory '%s' (min=%ld)\n", pmProgname, optarg, minmem); err++; } break; case 's': if (pmParseInterval(optarg, &bash_interval, &endnum) < 0) { fprintf(stderr, "%s: -s requires a time interval: %s\n", pmProgname, endnum); free(endnum); err++; } break; case 'U': username = optarg; break; default: err++; break; } } if (err) usage(); pmdaOpenLog(&desc); bash_init(&desc); pmdaConnect(&desc); bash_main(&desc); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/bash/pmns0000664000000000000000000000156212272262501014316 0ustar /* * Metrics for bash xtrace PMDA * * Copyright (c) 2012 Nathan Scott. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ bash { xtrace } bash.xtrace { numclients BASH:0:0 maxmem BASH:0:1 queuemem BASH:0:2 count BASH:0:3 records BASH:0:4 parameters } bash.xtrace.parameters { pid BASH:0:5 parent BASH:0:6 lineno BASH:0:7 function BASH:0:8 command BASH:0:9 } pcp-3.8.12ubuntu1/src/pmdas/bash/test-child.sh0000775000000000000000000000161012272262501016007 0ustar #!/usr/bin/env bash # # Copyright (c) 2012 Nathan Scott. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # . $PCP_DIR/etc/pcp.sh pcp_trace on $0 $@ wired() { # burn a little CPU, then sleep for i in 0 1 2 3 4 5 6 7 8 9 0 do /bin/true && /bin/true done sleep $1 } count=0 while true do (( count++ )) echo "get busy, $count" # top level wired 2 # call a shell function [ $count -ge 10 ] && break done pcp_trace off exit 0 pcp-3.8.12ubuntu1/src/pmdas/bash/pcp.sh0000775000000000000000000000111012272262501014524 0ustar # Shell interface to PCP shell event tracing PMDA if [ -z "$PCP_SH_DONE" ] then if [ -n "$PCP_CONF" ] then __CONF="$PCP_CONF" elif [ -n "$PCP_DIR" ] then __CONF="$PCP_DIR/etc/pcp.conf" else __CONF=/etc/pcp.conf fi if [ ! -f "$__CONF" ] then echo "pcp.env: Fatal Error: \"$__CONF\" not found" >&2 exit 1 fi eval `sed -e 's/"//g' $__CONF \ | awk -F= ' /^PCP_/ && NF == 2 { exports=exports" "$1 printf "%s=${%s:-\"%s\"}\n", $1, $1, $2 } END { print "export", exports }'` export PCP_ENV_DONE=y fi . $PCP_SHARE_DIR/lib/bashproc.sh pcp-3.8.12ubuntu1/src/pmdas/bash/event.c0000664000000000000000000003124312272262501014702 0ustar /* * Event support for the bash tracing PMDA * * Copyright (c) 2012 Nathan Scott. All rights reversed. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include "event.h" #include "pmda.h" static char *prefix = "pmdabash"; static char *pcptmpdir; /* probably /var/tmp */ static char pidpath[MAXPATHLEN]; /* * Extract time of creation of the trace files. Initially uses header file * as a reference since its created initially and then never modified again. * Subsequent calls will use last modification to the trace data file. */ void process_stat_timestamp(bash_process_t *process, struct timeval *timestamp) { #if defined(HAVE_ST_MTIME_WITH_E) && defined(HAVE_STAT_TIME_T) timestamp->tv_sec = process->stat.st_mtime.tv_sec; timestamp->tv_usec = process->stat.st_mtime.tv_nsec / 1000; #elif defined(HAVE_ST_MTIME_WITH_SPEC) timestamp->tv_sec = process->stat.st_mtimespec.tv_sec; timestamp->tv_usec = process->stat.st_mtimespec.tv_nsec / 1000; #elif defined(HAVE_STAT_TIMESTRUC) || defined(HAVE_STAT_TIMESPEC) || defined(HAVE_STAT_TIMESPEC_T) timestamp->tv_sec = process->stat.st_mtim.tv_sec; timestamp->tv_usec = process->stat.st_mtim.tv_nsec / 1000; #else !bozo! #endif } /* * Parse the header file (/path/.pid) containing xtrace metadata. * Helper routine, used during initialising of a tracked shell. */ static void process_head_parser(bash_process_t *verify, const char *buffer, size_t size) { char *p = (char *)buffer, *end = (char *)buffer + size - 1; char script[1024]; int version = 0; int date = 0; p += extract_int(p, "version:", sizeof("version:")-1, &version); p += extract_int(p, "ppid:", sizeof("ppid:")-1, &verify->parent); p += extract_int(p, "date:", sizeof("date:")-1, &date); extract_cmd(p, end - p, "+", sizeof("+")-1, script, sizeof(script)); if (date) { /* Use the given starttime of the script from the header */ verify->starttime.tv_sec = date; verify->starttime.tv_usec = 0; } else { /* Use a timestamp from the header as a best-effort guess */ #if defined(HAVE_ST_MTIME_WITH_E) && defined(HAVE_STAT_TIME_T) verify->starttime.tv_sec = verify->stat.st_mtime.tv_sec; verify->starttime.tv_usec = verify->stat.st_mtime.tv_nsec / 1000; #elif defined(HAVE_ST_MTIME_WITH_SPEC) verify->starttime.tv_sec = verify->stat.st_mtimespec.tv_sec; verify->starttime.tv_usec = verify->stat.st_mtimespec.tv_nsec / 1000; #elif defined(HAVE_STAT_TIMESTRUC) || defined(HAVE_STAT_TIMESPEC) || defined(HAVE_STAT_TIMESPEC_T) verify->starttime.tv_sec = verify->stat.st_mtim.tv_sec; verify->starttime.tv_usec = verify->stat.st_mtim.tv_nsec / 1000; #else !bozo! #endif } verify->version = version; size = 16 + strlen(script); /* pid and script name */ verify->instance = malloc(size); snprintf(verify->instance, size, "%u %s", verify->pid, script); if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "process header v%d: inst='%s' ppid=%d", verify->version, verify->instance, verify->parent); } /* * Verify the header file (/path/.pid) containing xtrace metadata. * Helper routine, used during initialising of a tracked shell. */ static int process_head_verify(const char *filename, bash_process_t *verify) { size_t size; char buffer[1024]; int fd = open(filename, O_RDONLY); if (fd < 0) return fd; if (fstat(fd, &verify->stat) < 0 || !S_ISREG(verify->stat.st_mode)) { close(fd); return -1; } size = read(fd, buffer, sizeof(buffer)); if (size > 0) process_head_parser(verify, buffer, size); close(fd); /* make sure we only parse header/trace file formats we understand */ if (verify->version < MINIMUM_VERSION || verify->version > MAXIMUM_VERSION) return -1; return 0; } /* * Verify the data files associated with a traced bash process. * Helper routine, used during initialising of a tracked shell. */ static int process_verify(const char *bashname, bash_process_t *verify) { int fd; char *endnum; char path[MAXPATHLEN]; struct stat stat; verify->pid = (pid_t) strtoul(bashname, &endnum, 10); if (*endnum != '\0' || verify->pid < 1) return -1; snprintf(path, sizeof(path), "%s%c.%s", pidpath, __pmPathSeparator(), bashname); if (process_head_verify(path, verify) < 0) return -1; snprintf(path, sizeof(path), "%s%c%s", pidpath, __pmPathSeparator(), bashname); if ((fd = open(path, O_RDONLY | O_NONBLOCK)) < 0) return -1; if (fstat(fd, &stat) < 0 || !S_ISFIFO(stat.st_mode)) { close(fd); return -1; } verify->fd = fd; return 0; } /* * Finally allocate memory for a verified, traced bash process. * Helper routine, used during initialising of a tracked shell. */ static bash_process_t * process_alloc(const char *bashname, bash_process_t *init, int numclients) { int queueid = pmdaEventNewActiveQueue(bashname, bash_maxmem, numclients); bash_process_t *bashful = malloc(sizeof(bash_process_t)); if (pmDebug & DBG_TRACE_APPL1) __pmNotifyErr(LOG_DEBUG, "process_alloc: %s, queueid=%d", bashname, queueid); if (!bashful) { __pmNotifyErr(LOG_ERR, "process allocation out of memory"); return NULL; } if (queueid < 0) { __pmNotifyErr(LOG_ERR, "attempt to dup queue for %s", bashname); free(bashful); return NULL; } /* Tough access situation - how to log without this? */ pmdaEventSetAccess(pmdaGetContext(), queueid, 1); bashful->fd = init->fd; bashful->pid = init->pid; bashful->parent = init->parent; bashful->queueid = queueid; bashful->exited = 0; bashful->finished = 0; bashful->noaccess = 0; bashful->version = init->version; bashful->padding = 0; memcpy(&bashful->starttime, &init->starttime, sizeof(struct timeval)); memcpy(&bashful->stat, &init->stat, sizeof(struct stat)); /* copy of first stat time, identifies first event */ process_stat_timestamp(bashful, &bashful->startstat); /* copy of pointer to dynamically allocated memory */ bashful->instance = init->instance; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "process_alloc: %s", bashful->instance); return bashful; } int event_start(bash_process_t *bp, struct timeval *timestamp) { int start = memcmp(timestamp, &bp->startstat, sizeof(*timestamp)); if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "check start event for %s (%d), %ld vs %ld", bp->instance, start, bp->startstat.tv_sec, timestamp->tv_sec); return start == 0; } /* * Initialise a bash process data structure using the header and * trace file. Ready to accept event traces from this shell on * completion of this routine - file descriptor setup, structure * filled with all metadata (exported) about this process. * Note: this is using an on-stack process structure, only if it * all checks out will we allocate memory for it, and keep it. */ static int process_init(const char *bashname, bash_process_t **bp) { bash_process_t init = { 0 }; pmAtomValue atom; pmdaEventClients(&atom); if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "process_init: %s (%d clients)", bashname, atom.ul); if (process_verify(bashname, &init) < 0) return -1; *bp = process_alloc(bashname, &init, atom.ul); if (*bp == NULL) return -1; return 0; } static int process_read(bash_process_t *process) { int j; char *s, *p; size_t offset; ssize_t bytes; struct timeval timestamp; static char *buffer; static int bufsize; /* * Using a static (global) event buffer to hold initial read. * The aim is to reduce memory allocation until we know we'll * need to keep something. */ if (!buffer) { int sts = 0; bufsize = 16 * getpagesize(); #ifdef HAVE_POSIX_MEMALIGN sts = posix_memalign((void **)&buffer, getpagesize(), bufsize); #else #ifdef HAVE_MEMALIGN buffer = (char *)memalign(getpagesize(), bufsize); if (buffer == NULL) sts = -1; #else buffer = (char *)malloc(bufsize); if (buffer == NULL) sts = -1; #endif #endif if (sts != 0) { __pmNotifyErr(LOG_ERR, "event buffer allocation failure"); return -1; } } offset = 0; multiread: if (process->fd < 0) return 0; bytes = read(process->fd, buffer + offset, bufsize - 1 - offset); /* * Ignore the error if: * - we've got EOF (0 bytes read) * - EAGAIN/EWOULDBLOCK (fd is marked nonblocking and read would block) */ if (bytes == 0) return 0; if (bytes < 0 && (errno == EBADF)) return 0; if (bytes < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) return 0; if (bytes > bash_maxmem) return 0; if (bytes < 0) { __pmNotifyErr(LOG_ERR, "read failure on process %s: %s", process->instance, strerror(errno)); return -1; } process_stat_timestamp(process, ×tamp); buffer[bufsize-1] = '\0'; for (s = p = buffer, j = 0; *s != '\0' && j < bufsize-1; s++, j++) { if (*s != '\n') continue; *s = '\0'; bytes = (s+1) - p; pmdaEventQueueAppend(process->queueid, p, bytes, ×tamp); p = s + 1; } /* did we just do a full buffer read? */ if (p == buffer) { char msg[64]; __pmNotifyErr(LOG_ERR, "Ignoring long (%d bytes) line: \"%s\"", (int) bytes, __pmdaEventPrint(p, bytes, msg, sizeof(msg))); } else if (j == bufsize - 1) { offset = bufsize-1 - (p - buffer); memmove(buffer, p, offset); goto multiread; /* read rest of line */ } return 1; } static void process_unlink(bash_process_t *process, const char *bashname) { char path[MAXPATHLEN]; snprintf(path, sizeof(path), "%s%c%s", pidpath, __pmPathSeparator(), bashname); unlink(path); snprintf(path, sizeof(path), "%s%c.%s", pidpath, __pmPathSeparator(), bashname); unlink(path); if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "process_unlink: removed %s", bashname); } static int process_drained(bash_process_t *process) { pmAtomValue value = { 0 }; if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "process_queue_drained check on queue %d (pid %d)", process->queueid, process->pid); if (pmdaEventQueueMemory(process->queueid, &value) < 0) return 1; /* error, consider it drained and cleanup */ if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "process_queue_drained: %s (%llu)", value.ll?"n":"y", (long long)value.ull); return value.ull == 0; } static void process_done(bash_process_t *process, const char *bashname) { struct timeval timestamp; if (process->exited == 0) { process->exited = (__pmProcessExists(process->pid) == 0); if (!process->exited) return; /* empty event inserted into queue to denote bash has exited */ if (!process->finished) { process->finished = 1; /* generate no further events */ process_stat_timestamp(process, ×tamp); pmdaEventQueueAppend(process->queueid, NULL, 0, ×tamp); if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_DEBUG, "process_done: marked queueid %d (pid %d) done", process->queueid, process->pid); } } if (process->finished) { /* once all clients have seen final events, clean named queue */ if (process_drained(process)) process_unlink(process, bashname); } } void event_refresh(pmInDom bash_indom) { struct dirent **files; bash_process_t *bp; int i, id, sts, num = scandir(pidpath, &files, NULL, NULL); if (pmDebug & DBG_TRACE_APPL0 && num > 2) __pmNotifyErr(LOG_DEBUG, "event_refresh: phase1: %d files", num - 2); pmdaCacheOp(bash_indom, PMDA_CACHE_INACTIVE); /* (re)activate processes that are actively generating events */ for (i = 0; i < num; i++) { char *processid = files[i]->d_name; if (processid[0] == '.') continue; /* either create or re-activate a bash process structure */ sts = pmdaCacheLookupName(bash_indom, processid, &id, (void **)&bp); if (sts != PMDA_CACHE_INACTIVE) { if (process_init(processid, &bp) < 0) continue; } pmdaCacheStore(bash_indom, PMDA_CACHE_ADD, bp->instance, (void *)bp); /* read any/all new events for this bash process, enqueue 'em */ process_read(bp); /* check if process is running and generate end marker if not */ process_done(bp, files[i]->d_name); } for (i = 0; i < num; i++) free(files[i]); if (num > 0) free(files); } void event_init(void) { pcptmpdir = pmGetConfig("PCP_TMP_DIR"); sprintf(pidpath, "%s%c%s", pcptmpdir, __pmPathSeparator(), prefix); } pcp-3.8.12ubuntu1/src/pmdas/bash/help0000664000000000000000000000305412272262501014267 0ustar # # Copyright (c) 2012 Nathan Scott. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # bash PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ BASH.0 Instance domain of traced bash processes An instance domain representing all of the currently running bash processes which are exporting trace metrics. @ bash.xtrace.numclients The number of attached clients. @ bash.xtrace.maxmem Maximum number of queued event bytes for each log file. @ bash.xtrace.queuemem @ bash.xtrace.count @ bash.xtrace.records @ bash.xtrace.parameters.pid @ bash.xtrace.parameters.parent @ bash.xtrace.parameters.lineno @ bash.xtrace.parameters.function @ bash.xtrace.parameters.command pcp-3.8.12ubuntu1/src/pmdas/bash/event.h0000664000000000000000000000374512272262501014715 0ustar /* * Event support for the bash tracing PMDA * * Copyright (c) 2012 Nathan Scott. All rights reversed. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _EVENT_H #define _EVENT_H #include #include #include "pmapi.h" #include "impl.h" typedef struct bash_process { int fd; pid_t pid; pid_t parent; int queueid; int exited : 1; /* flag: process running? */ int finished: 1; /* flag: exit event sent? */ int noaccess: 1; /* flag: store-to-access? */ int version : 8; /* pmda <-> bash xtrace version */ int padding : 21; /* filler */ struct timeval starttime; /* timestamp trace started */ struct timeval startstat; /* timestamp of first stat */ struct stat stat; /* stat of the header file */ char *instance; /* process id, space, script */ } bash_process_t; typedef struct bash_trace { int flags; struct timeval timestamp; int line; char function[64]; char command[512]; } bash_trace_t; extern long bash_maxmem; extern void event_init(void); extern void event_refresh(pmInDom); extern int event_start(bash_process_t *, struct timeval *); extern void process_stat_timestamp(bash_process_t *, struct timeval *); #define MINIMUM_VERSION 1 #define MAXIMUM_VERSION 1 extern int extract_int(char *, const char *, size_t, int *); extern int extract_str(char *, size_t, const char *, size_t, char *, size_t); extern int extract_cmd(char *, size_t, const char *, size_t, char *, size_t); #endif /* _EVENT_H */ pcp-3.8.12ubuntu1/src/pmdas/simple/0000775000000000000000000000000012272262620013770 5ustar pcp-3.8.12ubuntu1/src/pmdas/simple/README0000664000000000000000000000345212272262501014652 0ustar Simple PMDA =========== This PMDA is an example, that illustrates how a simple PMDA might be constructed. Although the metrics supported as simple, the framework is quite general, and could be extended to implement a much more complex PMDA. Note: This PMDA may be remade from source and hence requires IDO (or more specifically a C compiler) to be installed. Uses of make(1) may fail (without removing or clobbering files) if the C compiler cannot be found. This is most likely to happen when running the PMDA ./Install script. The only remedial action is to install the C compiler, or hand-craft changes to the Makefile. Metrics ======= The file ./help contains descriptions for all of the metrics exported by this PMDA. Once the PMDA has been installed, the following command will list all the available metrics and their explanatory "help" text: $ pminfo -fT simple Installation ============ + # cd $PCP_PMDAS_DIR/simple + Check that there is no clash in the Performance Metrics Domain defined in ./domain.h and the other PMDAs currently in use (see $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another domain number. + Then simply use # ./Install and choose both the "collector" and "monitor" installation configuration options. You will be prompted to choose either a daemon implementation or a DSO implementation of the PMDA, and in the case of the daemon variant to select an IPC method -- everything else is automated De-installation =============== + Simply use # cd $PCP_PMDAS_DIR/simple # ./Remove Troubleshooting =============== + After installing or restarting the agent, the PMCD log file ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file ($PCP_LOG_DIR/pmcd/simple.log) should be checked for any warnings or errors. pcp-3.8.12ubuntu1/src/pmdas/simple/Remove0000664000000000000000000000127712272262501015155 0ustar #! /bin/sh # # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Remove the simple PMDA # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=simple pmdaSetup pmdaRemove exit 0 pcp-3.8.12ubuntu1/src/pmdas/simple/pmdasimple.python0000664000000000000000000002022712272262501017367 0ustar ''' Python implementation of the "simple" Performance Metrics Domain Agent. ''' # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # import os import time import ctypes from ctypes import c_int, POINTER, cast import cpmapi as c_api from pcp.pmda import PMDA, pmdaMetric, pmdaIndom, pmdaInstid from pcp.pmapi import pmUnits, pmContext as PCP class SimplePMDA(PMDA): ''' A simple Performance Metrics Domain Agent with very simple metrics. Install it and make basic use of it, as follows: # $PCP_PMDAS_DIR/simple/Install [select python option] $ pminfo -fmdtT simple Then experiment with the simple.conf file (see simple.now metrics). ''' # simple.color instance domain red = 0 green = 100 blue = 200 colors = [pmdaInstid(0, 'red'), pmdaInstid(1, 'green'), pmdaInstid(2, 'blue')] # simple.now instance domain configfile = '' timeslices = {} times = () # simple.numfetch properties numfetch = 0 oldfetch = -1 def simple_instance(self, serial): ''' Called once per "instance request" PDU ''' # self.log("instance update for %d" % serial) if (serial == 1): self.simple_timenow_check() def simple_fetch(self): ''' Called once per "fetch" PDU, before callbacks ''' self.numfetch += 1 self.simple_timenow_check() def simple_fetch_color_callback(self, item, inst): ''' Returns a list of value,status (single pair) for color cluster Helper for the fetch callback ''' if (item == 0): if (inst != c_api.PM_IN_NULL): return [c_api.PM_ERR_INST, 0] return [self.numfetch, 1] elif (item == 1): if (inst == 0): self.red = (self.red + 1) % 255 return [self.red, 1] elif (inst == 1): self.green = (self.green + 1) % 255 return [self.green, 1] elif (inst == 2): self.blue = (self.blue + 1) % 255 return [self.blue, 1] else: return [c_api.PM_ERR_INST, 0] else: return [c_api.PM_ERR_PMID, 0] def simple_fetch_times_callback(self, item, inst): ''' Returns a list of value,status (single pair) for times cluster Helper for the fetch callback ''' if (inst != c_api.PM_IN_NULL): return [c_api.PM_ERR_INST, 0] if (self.oldfetch < self.numfetch): # get current values, if needed self.times = os.times() self.oldfetch = self.numfetch if (item == 2): return [self.times[0], 1] elif (item == 3): return [self.times[1], 1] return [c_api.PM_ERR_PMID, 0] def simple_fetch_now_callback(self, item, inst): ''' Returns a list of value,status (single pair) for "now" cluster Helper for the fetch callback ''' if (item == 4): voidp = self.inst_lookup(self.now_indom, inst) if (voidp == None): return [c_api.PM_ERR_INST, 0] valuep = cast(voidp, POINTER(c_int)) return [valuep.contents.value, 1] return [c_api.PM_ERR_PMID, 0] def simple_fetch_callback(self, cluster, item, inst): ''' Main fetch callback, defers to helpers for each cluster. Returns a list of value,status (single pair) for requested pmid/inst ''' # self.log("fetch callback for %d.%d[%d]" % (cluster, item, inst)) if (cluster == 0): return self.simple_fetch_color_callback(item, inst) elif (cluster == 1): return self.simple_fetch_times_callback(item, inst) elif (cluster == 2): return self.simple_fetch_now_callback(item, inst) return [c_api.PM_ERR_PMID, 0] def simple_store_count_callback(self, val): ''' Helper for the store callback, handles simple.numfetch ''' sts = 0 if (val < 0): sts = c_api.PM_ERR_SIGN val = 0 self.numfetch = val return sts def simple_store_color_callback(self, val, inst): ''' Helper for the store callback, handles simple.color ''' sts = 0 if (val < 0): sts = c_api.PM_ERR_SIGN val = 0 elif (val > 255): sts = c_api.PM_ERR_CONV val = 255 if (inst == 0): self.red = val elif (inst == 1): self.green = val elif (inst == 2): self.blue = val else: sts = c_api.PM_ERR_INST return sts def simple_store_callback(self, cluster, item, inst, val): ''' Store callback, executed when a request to write to a metric happens Defers to helpers for each storable metric. Returns a single value. ''' if (cluster == 0): if (item == 0): return self.simple_store_count_callback(val) elif (item == 1): return self.simple_store_color_callback(val, inst) else: return c_api.PM_ERR_PMID elif ((cluster == 1 and (item == 2 or item == 3)) or (cluster == 2 and item == 4)): return c_api.PM_ERR_PERMISSION return c_api.PM_ERR_PMID def simple_timenow_check(self): ''' Read our configuration file and update instance domain ''' self.timeslices.clear() try: cfg = open(self.configfile) fields = time.localtime() values = {'sec': c_int(fields[5]), 'min': c_int(fields[4]), 'hour': c_int(fields[3])} config = cfg.readline().strip() for key in config.split(','): if (key != '' and values[key] != None): self.timeslices[key] = values[key] finally: cfg.close() self.replace_indom(self.now_indom, self.timeslices) def __init__(self, name, domain): PMDA.__init__(self, name, domain) self.configfile = PCP.pmGetConfig('PCP_PMDAS_DIR') self.configfile += '/' + name + '/' + name + '.conf' self.color_indom = self.indom(0) self.add_indom(pmdaIndom(self.color_indom, self.colors)) self.now_indom = self.indom(1) self.add_indom(pmdaIndom(self.now_indom, self.timeslices)) self.add_metric(name + '.numfetch', pmdaMetric(self.pmid(0, 0), c_api.PM_TYPE_U32, c_api.PM_INDOM_NULL, c_api.PM_SEM_INSTANT, pmUnits(0, 0, 0, 0, 0, 0))) self.add_metric(name + '.color', pmdaMetric(self.pmid(0, 1), c_api.PM_TYPE_32, self.color_indom, c_api.PM_SEM_INSTANT, pmUnits(0, 0, 0, 0, 0, 0))) self.add_metric(name + '.time.user', pmdaMetric(self.pmid(1, 2), c_api.PM_TYPE_DOUBLE, c_api.PM_INDOM_NULL, c_api.PM_SEM_COUNTER, pmUnits(0, 1, 0, 0, c_api.PM_TIME_SEC, 0))) self.add_metric(name + '.time.sys', pmdaMetric(self.pmid(1, 3), c_api.PM_TYPE_DOUBLE, c_api.PM_INDOM_NULL, c_api.PM_SEM_COUNTER, pmUnits(0, 1, 0, 0, c_api.PM_TIME_SEC, 0))) self.add_metric(name + '.now', pmdaMetric(self.pmid(2, 4), c_api.PM_TYPE_U32, self.now_indom, c_api.PM_SEM_INSTANT, pmUnits(0, 0, 0, 0, 0, 0))) self.set_fetch(self.simple_fetch) self.set_instance(self.simple_instance) self.set_fetch_callback(self.simple_fetch_callback) self.set_store_callback(self.simple_store_callback) self.set_user(PCP.pmGetConfig('PCP_USER')) self.simple_timenow_check() if __name__ == '__main__': SimplePMDA('simple', 253).run() pcp-3.8.12ubuntu1/src/pmdas/simple/simple.conf0000664000000000000000000000001512272262501016122 0ustar sec,min,hour pcp-3.8.12ubuntu1/src/pmdas/simple/Install0000664000000000000000000000242312272262501015320 0ustar #! /bin/sh # # Copyright (c) 2013 Red Hat. # Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Install the simple PMDA and/or PMNS # . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/pmdaproc.sh iam=simple pmda_interface=2 forced_restart=false dso_opt=true perl_opt=true python_opt=true socket_opt=true socket_inet_def=2078 # Set up the simple PMDA (domain 253) InDom cache # domain=`sed -n root { simple } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/simple/GNUmakefile.install0000664000000000000000000000252412272262501017510 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2000,2003,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # SHELL = sh ifdef PCP_CONF include $(PCP_CONF) else PCP_DIR = $(shell echo $$PCP_DIR) include $(PCP_DIR)/etc/pcp.conf endif include $(PCP_INC_DIR)/builddefs # remove -Lpath and -Ipath options from builddefs CFLAGS value # PCP_LIBS = TMP := $(CFLAGS:-I%=) ifdef PCP_DIR # put -Ipath and -Lpath back but use paths for run-time environment # CFLAGS = $(TMP) -I$(PCP_INC_DIR)/.. LDFLAGS = -L$(PCP_LIB_DIR) else CFLAGS = $(TMP) endif IAM = simple CFILES = $(IAM).c LIBTARGET = pmda_$(IAM).$(DSOSUFFIX) CMDTARGET = pmda$(IAM) TARGETS = $(LIBTARGET) $(CMDTARGET) LLDLIBS = -lpcp_pmda -lpcp -lm -ldl -lpthread LDIRT = *.log help.dir help.pag default: $(TARGETS) install: default include $(PCP_INC_DIR)/buildrules pcp-3.8.12ubuntu1/src/pmdas/simple/pmdasimple.perl0000664000000000000000000001133712272262501017012 0ustar # # Copyright (c) 2012 Red Hat. # Copyright (c) 2008,2012 Aconex. All Rights Reserved. # Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # use strict; use warnings; use PCP::PMDA; use vars qw( $pmda $red $green $blue $user $system ); my ( $numfetch, $oldfetch ) = ( 0, -1 ); my ( $color_indom, $now_indom ) = ( 0, 1 ); my ( $red, $green, $blue ) = ( 0, 100, 200 ); # simple.now instance domain stuff... my $simple_config = pmda_config('PCP_PMDAS_DIR') . '/simple/simple.conf'; my %timeslices; my $file_error = 0; sub simple_instance # called once per ``instance request'' pdu { &simple_timenow_check; } sub simple_fetch # called once per ``fetch'' pdu, before callbacks { $numfetch++; &simple_timenow_check; } sub simple_fetch_callback # must return array of value,status { my ($cluster, $item, $inst) = @_; return (PM_ERR_INST, 0) unless ( $inst == PM_IN_NULL || ($cluster == 0 && $item == 1) || ($cluster == 2 && $item == 4) ); if ($cluster == 0) { if ($item == 0) { return ($numfetch, 1); } elsif ($item == 1) { if ($inst == 0) { return ($red = ($red+1) % 255, 1); } elsif ($inst == 1) { return ($green = ($green+1) % 255, 1); } elsif ($inst == 2) { return ($blue = ($blue+1) % 255, 1); } else { return (PM_ERR_INST, 0); } } else { return (PM_ERR_PMID, 0); } } elsif ($cluster == 1) { if ($oldfetch < $numfetch) { # get current values, if needed ($user, $system, undef, undef) = times; $oldfetch = $numfetch; } if ($item == 2) { return ($user, 1); } elsif ($item == 3) { return ($system, 1); } else { return (PM_ERR_PMID, 0); } } elsif ($cluster == 2 && $item == 4) { my $value = pmda_inst_lookup($now_indom, $inst); return (PM_ERR_INST, 0) unless defined($value); return ($value, 1); } return (PM_ERR_PMID, 0); } sub simple_store_callback # must return a single value (scalar context) { my ($cluster, $item, $inst, $val) = @_; my $sts = 0; if ($cluster == 0) { if ($item == 0) { if ($val < 0) { $val = 0; $sts = PM_ERR_SIGN; } $numfetch = $val; } elsif ($item == 1) { if ($val < 0) { $sts = PM_ERR_SIGN; $val = 0; } elsif ($val > 255) { $sts = PM_ERR_CONV; $val = 255; } if ($inst == 0) { $red = $val; } elsif ($inst == 1) { $green = $val; } elsif ($inst == 2) { $blue = $val; } else { $sts = PM_ERR_INST; } } else { $sts = PM_ERR_PMID; } return $sts; } elsif ( ($cluster == 1 && ($item == 2 || $item == 3)) || ($cluster == 2 && $item == 4) ) { return PM_ERR_PERMISSION; } return PM_ERR_PMID; } sub simple_timenow_check { %timeslices = (); if (open(CONFIG, $simple_config)) { my %values; ($values{'sec'}, $values{'min'}, $values{'hour'}, undef,undef,undef,undef,undef) = localtime; $_ = ; chomp; # avoid possible \n on last field foreach my $spec (split(/,/)) { $timeslices{$spec} = $values{$spec}; } close CONFIG; $file_error = 0; } else { unless ($file_error == $!) { $pmda->log("read failed on $simple_config: $!"); $file_error = $!; } } $pmda->replace_indom( $now_indom, \%timeslices); } $pmda = PCP::PMDA->new('simple', 253); $pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'simple.numfetch', '', ''); $pmda->add_metric(pmda_pmid(0,1), PM_TYPE_32, $color_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'simple.color', '', ''); $pmda->add_metric(pmda_pmid(1,2), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'simple.time.user', '', ''); $pmda->add_metric(pmda_pmid(1,3), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER, pmda_units(0,1,0,0,PM_TIME_SEC,0), 'simple.time.sys', '', ''); $pmda->add_metric(pmda_pmid(2,4), PM_TYPE_U32, $now_indom, PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0), 'simple.now', '', ''); $pmda->add_indom($color_indom, [0 => 'red', 1 => 'green', 2 => 'blue'], '', ''); $now_indom = $pmda->add_indom($now_indom, {}, '', ''); # initialized on-the-fly $pmda->set_fetch( \&simple_fetch ); $pmda->set_instance( \&simple_instance ); $pmda->set_fetch_callback( \&simple_fetch_callback ); $pmda->set_store_callback( \&simple_store_callback ); $pmda->set_user('pcp'); &simple_timenow_check; $pmda->run; pcp-3.8.12ubuntu1/src/pmdas/simple/pmns0000664000000000000000000000136612272262501014674 0ustar /* * Metrics for simple PMDA * * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ simple { numfetch SIMPLE:0:0 color SIMPLE:0:1 time now SIMPLE:2:4 } simple.time { user SIMPLE:1:2 sys SIMPLE:1:3 } pcp-3.8.12ubuntu1/src/pmdas/simple/simple.c0000664000000000000000000003316312272262501015431 0ustar /* * Simple, configurable PMDA * * Copyright (c) 2012 Red Hat. * Copyright (c) 1995,2004 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include "domain.h" #include /* * Simple PMDA * * This PMDA is a sample that illustrates how a simple PMDA might be * constructed using libpcp_pmda. * * Although the metrics supported are simple, the framework is quite general, * and could be extended to implement a much more complex PMDA. * * Metrics * simple.numfetch - number of fetches from this PMDA, * may be re-set using pmStore * simple.colors - 3 instances ("red", "green" and "blue") * of a "saw-tooth" sequence * simple.time.user - time in seconds spent executing user code * simple.time.sys - time in seconds spent executing system code * simple.now - current time of day across a dynamically * re-configurable instance domain. */ /* * list of instances */ static pmdaInstid color[] = { { 0, "red" }, { 1, "green" }, { 2, "blue" } }; /* * instance domains * COLOR_INDOM uses the classical indomtab[] method * NOW_INDOM uses the more recent pmdaCache methods, but also appears in * indomtab[] so that the initialization of the pmInDom and the pmDescs * in metrictab[] is completed by pmdaInit */ static pmdaIndom indomtab[] = { #define COLOR_INDOM 0 /* serial number for "color" instance domain */ { COLOR_INDOM, sizeof(color)/sizeof(color[0]), color }, #define NOW_INDOM 1 /* serial number for "now" instance domain */ { NOW_INDOM, 0, NULL }, }; /* this is merely a convenience */ static pmInDom *now_indom = &indomtab[NOW_INDOM].it_indom; /* * All metrics supported in this PMDA - one table entry for each. * The 4th field specifies the serial number of the instance domain * for the metric, and must be either PM_INDOM_NULL (denoting a * metric that only ever has a single value), or the serial number * of one of the instance domains declared in the instance domain table * (i.e. in indomtab, above). */ static pmdaMetric metrictab[] = { /* numfetch */ { NULL, { PMDA_PMID(0,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* color */ { NULL, { PMDA_PMID(0,1), PM_TYPE_32, COLOR_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* time.user */ { NULL, { PMDA_PMID(1,2), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0) }, }, /* time.sys */ { NULL, { PMDA_PMID(1,3), PM_TYPE_DOUBLE, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0, 1, 0, 0, PM_TIME_SEC, 0) }, }, /* now */ { NULL, { PMDA_PMID(2,4), PM_TYPE_U32, NOW_INDOM, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, }; static int numfetch = 0; /* number of pmFetch operations */ static int red = 0; /* current red value */ static int green = 100; /* current green value */ static int blue = 200; /* current blue value */ static int isDSO = 1; /* =0 I am a daemon */ static char *username; /* data and function prototypes for dynamic instance domain handling */ static struct timeslice { int tm_field; int inst_id; char *tm_name; } timeslices[] = { { 0, 1, "sec" }, { 0, 60, "min" }, { 0, 3600, "hour" } }; static int num_timeslices = sizeof(timeslices)/sizeof(timeslices[0]); #define SIMPLE_BUFSIZE 256 static struct stat file_change; /* has time of last configuration change */ static void simple_timenow_clear(void); static void simple_timenow_init(void); static void simple_timenow_refresh(void); static void simple_timenow_check(void); static char mypath[MAXPATHLEN]; /* * callback provided to pmdaFetch */ static int simple_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { int sts; static int oldfetch; static double usr, sys; __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); if (inst != PM_IN_NULL && !(idp->cluster == 0 && idp->item == 1) && !(idp->cluster == 2 && idp->item == 4)) return PM_ERR_INST; if (idp->cluster == 0) { if (idp->item == 0) { /* simple.numfetch */ atom->l = numfetch; } else if (idp->item == 1) { /* simple.color */ switch (inst) { case 0: /* red */ red = (red + 1) % 256; atom->l = red; break; case 1: /* green */ green = (green + 1) % 256; atom->l = green; break; case 2: /* blue */ blue = (blue + 1) % 256; atom->l = blue; break; default: return PM_ERR_INST; } } else return PM_ERR_PMID; } else if (idp->cluster == 1) { /* simple.time */ if (oldfetch < numfetch) { __pmProcessRunTimes(&usr, &sys); oldfetch = numfetch; } if (idp->item == 2) /* simple.time.user */ atom->d = usr; else if (idp->item == 3) /* simple.time.sys */ atom->d = sys; else return PM_ERR_PMID; } else if (idp->cluster == 2) { if (idp->item == 4) { /* simple.now */ struct timeslice *tsp; if ((sts = pmdaCacheLookup(*now_indom, inst, NULL, (void *)&tsp)) != PMDA_CACHE_ACTIVE) { if (sts < 0) __pmNotifyErr(LOG_ERR, "pmdaCacheLookup failed: inst=%d: %s", inst, pmErrStr(sts)); return PM_ERR_INST; } atom->l = tsp->tm_field; } else return PM_ERR_PMID; } else return PM_ERR_PMID; return 0; } /* * wrapper for pmdaFetch which increments the fetch count and checks for * a change to the NOW instance domain. * * This routine is called once for each pmFetch(3) operation, so is a * good place to do once-per-fetch functions, such as value caching or * instance domain evaluation (as we do in simple_timenow_check). */ static int simple_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { numfetch++; simple_timenow_check(); simple_timenow_refresh(); return pmdaFetch(numpmid, pmidlist, resp, pmda); } /* * wrapper for pmdaInstance which we need to ensure is called with the * _current_ contents of the NOW instance domain. */ static int simple_instance(pmInDom indom, int foo, char *bar, __pmInResult **iresp, pmdaExt *pmda) { simple_timenow_check(); return pmdaInstance(indom, foo, bar, iresp, pmda); } /* * Re-evaluate the NOW instance domain. * * Refer to the help text for simple.now for an explanation of how * this indom can be modified, or just read the code ... */ static void simple_timenow_check(void) { struct stat statbuf; static int last_error = 0; int sep = __pmPathSeparator(); /* stat the file & check modification time has changed */ snprintf(mypath, sizeof(mypath), "%s%c" "simple" "%c" "simple.conf", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); if (stat(mypath, &statbuf) == -1) { if (oserror() != last_error) { last_error = oserror(); __pmNotifyErr(LOG_ERR, "stat failed on %s: %s\n", mypath, pmErrStr(-last_error)); } simple_timenow_clear(); } else { last_error = 0; #if defined(HAVE_ST_MTIME_WITH_E) if (statbuf.st_mtime != file_change.st_mtime) { #elif defined(HAVE_ST_MTIME_WITH_SPEC) if (statbuf.st_mtimespec.tv_sec != file_change.st_mtimespec.tv_sec || statbuf.st_mtimespec.tv_nsec != file_change.st_mtimespec.tv_nsec) { #else if (statbuf.st_mtim.tv_sec != file_change.st_mtim.tv_sec || statbuf.st_mtim.tv_nsec != file_change.st_mtim.tv_nsec) { #endif simple_timenow_clear(); simple_timenow_init(); file_change = statbuf; } } } /* * get values for time.now metric instances */ static void simple_timenow_refresh(void) { time_t t = time(NULL); struct tm *tptr; tptr = localtime(&t); timeslices[0].tm_field = tptr->tm_sec; timeslices[1].tm_field = tptr->tm_min; timeslices[2].tm_field = tptr->tm_hour; } /* * clear the time.now metric instance domain */ static void simple_timenow_clear(void) { int sts; sts = pmdaCacheOp(*now_indom, PMDA_CACHE_INACTIVE); if (sts < 0) __pmNotifyErr(LOG_ERR, "pmdaCacheOp(INACTIVE) failed: indom=%s: %s", pmInDomStr(*now_indom), pmErrStr(sts)); #ifdef DESPERATE __pmdaCacheDump(stderr, *now_indom, 1); #endif } /* * parse the configuration file for the time.now metric instance domain */ static void simple_timenow_init(void) { int i; int sts; int sep = __pmPathSeparator(); FILE *fp; char *p, *q; char buf[SIMPLE_BUFSIZE]; snprintf(mypath, sizeof(mypath), "%s%c" "simple" "%c" "simple.conf", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); if ((fp = fopen(mypath, "r")) == NULL) { __pmNotifyErr(LOG_ERR, "fopen on %s failed: %s\n", mypath, pmErrStr(-oserror())); return; } if ((p = fgets(&buf[0], SIMPLE_BUFSIZE, fp)) == NULL) { __pmNotifyErr(LOG_ERR, "fgets on %s found no data\n", mypath); fclose(fp); return; } if ((q = strchr(p, '\n')) != NULL) *q = '\0'; /* remove eol character */ q = strtok(p, ","); /* and refresh using the updated file */ while (q != NULL) { for (i = 0; i < num_timeslices; i++) { if (strcmp(timeslices[i].tm_name, q) == 0) { sts = pmdaCacheStore(*now_indom, PMDA_CACHE_ADD, q, ×lices[i]); if (sts < 0) { __pmNotifyErr(LOG_ERR, "pmdaCacheStore failed: %s", pmErrStr(sts)); fclose(fp); return; } break; } } if (i == num_timeslices) __pmNotifyErr(LOG_WARNING, "ignoring \"%s\" in %s", q, mypath); q = strtok(NULL, ","); } #ifdef DESPERATE __pmdaCacheDump(stderr, *now_indom, 1); #endif if (pmdaCacheOp(*now_indom, PMDA_CACHE_SIZE_ACTIVE) < 1) __pmNotifyErr(LOG_WARNING, "\"timenow\" instance domain is empty"); fclose(fp); } /* * support the storage of a value into the number of fetches count */ static int simple_store(pmResult *result, pmdaExt *pmda) { int i; int j; int val; int sts = 0; pmValueSet *vsp = NULL; __pmID_int *pmidp = NULL; /* a store request may affect multiple metrics at once */ for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; pmidp = (__pmID_int *)&vsp->pmid; if (pmidp->cluster == 0) { /* all storable metrics are cluster 0 */ switch (pmidp->item) { case 0: /* simple.numfetch */ val = vsp->vlist[0].value.lval; if (val < 0) { sts = PM_ERR_SIGN; val = 0; } numfetch = val; break; case 1: /* simple.color */ /* a store request may affect multiple instances at once */ for (j = 0; j < vsp->numval && sts == 0; j++) { val = vsp->vlist[j].value.lval; if (val < 0) { sts = PM_ERR_SIGN; val = 0; } if (val > 255) { sts = PM_ERR_CONV; val = 255; } switch (vsp->vlist[j].inst) { case 0: /* red */ red = val; break; case 1: /* green */ green = val; break; case 2: /* blue */ blue = val; break; default: sts = PM_ERR_INST; } } break; default: sts = PM_ERR_PMID; break; } } else if ((pmidp->cluster == 1 && (pmidp->item == 2 || pmidp->item == 3)) || (pmidp->cluster == 2 && pmidp->item == 4)) { sts = PM_ERR_PERMISSION; break; } else { sts = PM_ERR_PMID; break; } } return sts; } /* * Initialise the agent (both daemon and DSO). */ void simple_init(pmdaInterface *dp) { if (isDSO) { int sep = __pmPathSeparator(); snprintf(mypath, sizeof(mypath), "%s%c" "simple" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_2, "simple DSO", mypath); } else { __pmSetProcessIdentity(username); } if (dp->status != 0) return; dp->version.any.fetch = simple_fetch; dp->version.any.store = simple_store; dp->version.any.instance = simple_instance; pmdaSetFetchCallBack(dp, simple_fetchCallBack); pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), metrictab, sizeof(metrictab)/sizeof(metrictab[0])); } static void usage(void) { fprintf(stderr, "Usage: %s [options]\n\n", pmProgname); fputs("Options:\n" " -d domain use domain (numeric) for metrics domain of PMDA\n" " -l logfile write log into logfile rather than using default log name\n" " -U username user account to run under (default \"pcp\")\n" "\nExactly one of the following options may appear:\n" " -i port expect PMCD to connect on given inet port (number or name)\n" " -p expect PMCD to supply stdin/stdout (pipe)\n" " -u socket expect PMCD to connect on given unix domain socket\n" " -6 port expect PMCD to connect on given ipv6 port (number or name)\n", stderr); exit(1); } /* * Set up the agent if running as a daemon. */ int main(int argc, char **argv) { int c, err = 0; int sep = __pmPathSeparator(); pmdaInterface dispatch; isDSO = 0; __pmSetProgname(argv[0]); __pmGetUsername(&username); snprintf(mypath, sizeof(mypath), "%s%c" "simple" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDaemon(&dispatch, PMDA_INTERFACE_2, pmProgname, SIMPLE, "simple.log", mypath); while ((c = pmdaGetOpt(argc, argv, "D:d:i:l:pu:6:U:?", &dispatch, &err)) != EOF) { switch(c) { case 'U': username = optarg; break; default: err++; } } if (err) usage(); pmdaOpenLog(&dispatch); simple_init(&dispatch); simple_timenow_check(); pmdaConnect(&dispatch); pmdaMain(&dispatch); exit(0); } pcp-3.8.12ubuntu1/src/pmdas/simple/help0000664000000000000000000000626012272262501014645 0ustar # # Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # simple PMDA help file in the ASCII format # # lines beginning with a # are ignored # lines beginning @ introduce a new entry of the form # @ metric_name oneline-text # help test goes # here over multiple lines # ... # # the metric_name is decoded against the default PMNS -- as a special case, # a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an # instance domain identification, and the text describes the instance domain # # blank lines before the @ line are ignored # @ SIMPLE.0 Instance domain "colour" for simple PMDA Universally 3 instances, "red" (0), "green" (1) and "blue" (3). @ SIMPLE.1 Dynamic instance domain "time" for simple PMDA An instance domain which is computed on-the-fly for exporting current time information. Refer to the help text for simple.now for a more complete explanation. @ simple.numfetch Number of pmFetch operations. The cumulative number of pmFetch operations directed to the "simple" PMDA. This counter may be modified with pmstore(1). @ simple.color Metrics which increment with each fetch This metric has 3 instances, designated "red", "green" and "blue". The value of the metric is monotonic increasing in the range 0 to 255, then back to 0. The different instances have different starting values, namely 0 (red), 100 (green) and 200 (blue). The metric values my be altered using pmstore(1). @ simple.time.user Time agent has spent executing user code The time in seconds that the CPU has spent executing user code for the agent. @ simple.time.sys Time agent has spent executing system code The time in seconds that the CPU has spent executing system code for the agent. @ simple.now Time of day with a configurable instance domain The value reflects the current time of day through a dynamically reconfigurable instance domain. On each metric value fetch request, the agent checks to see whether the configuration file in $PCP_PMDAS_DIR/simple/simple.conf has been modified - if it has then the file is re-parsed and the instance domain for this metric is again constructed according to its contents. This configuration file contains a single line of comma-separated time tokens from this set: "sec" (seconds after the minute), "min" (minutes after the hour), "hour" (hour since midnight). An example configuration file could be: sec,min,hour and in this case the simple.now metric would export values for the three instances "sec", "min" and "hour" corresponding respectively to the components seconds, minutes and hours of the current time of day. The instance domain reflects each token present in the file, and the values reflect the time at which the PMDA processes the fetch. pcp-3.8.12ubuntu1/src/pmdas/etw/0000775000000000000000000000000012272262620013276 5ustar pcp-3.8.12ubuntu1/src/pmdas/etw/util.c0000664000000000000000000001406712272262501014425 0ustar /* * Event Trace for Windows utility routines. * * Copyright (c) 2011, Nathan Scott. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #define INITGUID #include #include #include #include #include "util.h" struct { ULONG flag; char *name; } kernelFlags[] = { { EVENT_TRACE_FLAG_PROCESS, "process" }, { EVENT_TRACE_FLAG_THREAD, "thread" }, { EVENT_TRACE_FLAG_IMAGE_LOAD, "image_load" }, { EVENT_TRACE_FLAG_DISK_IO, "disk_io" }, { EVENT_TRACE_FLAG_DISK_FILE_IO, "disk_file_io" }, { EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS, "memory_page_faults" }, { EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS, "memory_hard_faults" }, { EVENT_TRACE_FLAG_NETWORK_TCPIP, "network_tcpip" }, { EVENT_TRACE_FLAG_REGISTRY, "registry" }, { EVENT_TRACE_FLAG_DBGPRINT, "dbgprint" }, { EVENT_TRACE_FLAG_PROCESS_COUNTERS, "process_counters" }, { EVENT_TRACE_FLAG_CSWITCH, "cswitch" }, { EVENT_TRACE_FLAG_DPC, "dpc" }, { EVENT_TRACE_FLAG_INTERRUPT, "interrupt" }, { EVENT_TRACE_FLAG_SYSTEMCALL, "syscall" }, { EVENT_TRACE_FLAG_DISK_IO_INIT, "disk_io_init" }, { EVENT_TRACE_FLAG_ALPC, "alpc" }, { EVENT_TRACE_FLAG_SPLIT_IO, "split_io" }, { EVENT_TRACE_FLAG_DRIVER, "driver" }, { EVENT_TRACE_FLAG_PROFILE, "profile" }, { EVENT_TRACE_FLAG_FILE_IO, "file_io" }, { EVENT_TRACE_FLAG_FILE_IO_INIT, "file_io_init" }, { EVENT_TRACE_FLAG_DISPATCHER, "dispatcher" }, { EVENT_TRACE_FLAG_VIRTUAL_ALLOC, "virtual_alloc" }, { EVENT_TRACE_FLAG_EXTENSION, "extension" }, { EVENT_TRACE_FLAG_FORWARD_WMI, "forward_wmi" }, { EVENT_TRACE_FLAG_ENABLE_RESERVE, "enable_reserve" }, }; void dumpKernelTraceFlags(FILE *output, const char *prefix, const char *suffix) { int i; for (i = 0; i < sizeof(kernelFlags)/sizeof(kernelFlags[0]); i++) fprintf(output, "%s%s%s", prefix, kernelFlags[i].name, (i+1 == sizeof(kernelFlags)/sizeof(kernelFlags[0])) ? "\0" : suffix); } ULONG kernelTraceFlag(const char *name) { int i; for (i = 0; i < sizeof(kernelFlags)/sizeof(kernelFlags[0]); i++) if (strcmp(kernelFlags[i].name, name) == 0) return kernelFlags[i].flag; fprintf(stderr, "Unrecognised kernel trace flag: %s\n", name); fprintf(stderr, "List of all known options:\n"); dumpKernelTraceFlags(stderr, "\t", "\n"); fprintf(stderr, "\n\n"); exit(1); } const char * eventPropertyFlags(USHORT flags) { if (flags & EVENT_HEADER_PROPERTY_XML) return "XML"; if (flags & EVENT_HEADER_PROPERTY_FORWARDED_XML) return "forwarded XML"; if (flags & EVENT_HEADER_PROPERTY_LEGACY_EVENTLOG) return "legacy WMI MOF"; return "none"; } const char * eventHeaderFlags(USHORT flags) { static char buffer[128]; char *p = &buffer[0]; *p = '\0'; if (flags & EVENT_HEADER_FLAG_EXTENDED_INFO) strcat(p, "extended info,"); if (flags & EVENT_HEADER_FLAG_PRIVATE_SESSION) strcat(p, "private session,"); if (flags & EVENT_HEADER_FLAG_STRING_ONLY) strcat(p, "string,"); if (flags & EVENT_HEADER_FLAG_TRACE_MESSAGE) strcat(p, "TraceMessage,"); if (flags & EVENT_HEADER_FLAG_NO_CPUTIME) strcat(p, "no cputime,"); if (flags & EVENT_HEADER_FLAG_32_BIT_HEADER) strcat(p, "32bit,"); if (flags & EVENT_HEADER_FLAG_64_BIT_HEADER) strcat(p, "64bit,"); if (flags & EVENT_HEADER_FLAG_CLASSIC_HEADER) strcat(p, "classic,"); buffer[strlen(buffer)-1] = '\0'; return buffer; } const char * tdherror(ULONG code) { switch (code){ case ERROR_ACCESS_DENIED: return "Insufficient privileges for requested operation"; case ERROR_ALREADY_EXISTS: return "A sessions with the same name or GUID already exists"; case ERROR_BAD_LENGTH: return "Insufficient space or size for a parameter"; case ERROR_BAD_PATHNAME: return "Given path parameter is not valid"; case ERROR_CANCELLED: return "Consumer cancelled processing via buffer callback"; case ERROR_FILE_NOT_FOUND: return "Unable to find the requested file"; case ERROR_INSUFFICIENT_BUFFER: return "Size of buffer is too small"; case ERROR_INVALID_HANDLE: return "Element of array is not a valid event tracing session handle"; case ERROR_INVALID_PARAMETER: return "One or more of the parameters is not valid"; case ERROR_INVALID_TIME: return "EndTime is less than StartTime"; case ERROR_NOACCESS: return "An exception occurred in one of the event callback routines"; case ERROR_NOT_FOUND: return "Requested class or field type not found"; case ERROR_NOT_SUPPORTED: return "The requested field type is not supported"; case ERROR_OUTOFMEMORY: return "Insufficient memory"; case ERROR_WMI_INSTANCE_NOT_FOUND: return "Session from which realtime events to be consumed not running"; case ERROR_WMI_ALREADY_ENABLED: return "Handle array contains more than one realtime session handle"; case ERROR_SUCCESS: return "Success"; } return strerror(code); } const char * strguid(LPGUID guidPointer) { static char stringBuffer[64]; snprintf(stringBuffer, sizeof(stringBuffer), "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", guidPointer->Data1, guidPointer->Data2, guidPointer->Data3, guidPointer->Data4[0], guidPointer->Data4[1], guidPointer->Data4[2], guidPointer->Data4[3], guidPointer->Data4[4], guidPointer->Data4[5], guidPointer->Data4[6], guidPointer->Data4[7]); return stringBuffer; } void * BufferAllocate(ULONG size) { return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); } void BufferFree(void *buffer) { if (buffer) HeapFree(GetProcessHeap(), 0, buffer); } pcp-3.8.12ubuntu1/src/pmdas/etw/pcp.xml0000664000000000000000000032211412272262501014603 0ustar ÿþ<?xml version="1.0" encoding="UTF-16"?> <DataCollectorSet> <Status>1</Status> <Duration>0</Duration> <Description> </Description> <DescriptionUnresolved> </DescriptionUnresolved> <DisplayName> </DisplayName> <DisplayNameUnresolved> </DisplayNameUnresolved> <SchedulesEnabled>-1</SchedulesEnabled> <LatestOutputLocation> </LatestOutputLocation> <Name>PCP Collector Set</Name> <OutputLocation>C:\Glider\var\log\etw\</OutputLocation> <RootPath>C:\Glider\var\log\etw</RootPath> <Segment>0</Segment> <SegmentMaxDuration>0</SegmentMaxDuration> <SegmentMaxSize>0</SegmentMaxSize> <SerialNumber>1</SerialNumber> <Server> </Server> <Subdirectory> </Subdirectory> <SubdirectoryFormat>0</SubdirectoryFormat> <SubdirectoryFormatPattern> </SubdirectoryFormatPattern> <Task> </Task> <TaskArguments> </TaskArguments> <TaskUserTextArguments> </TaskUserTextArguments> <UserAccount> </UserAccount> <Security>O:BAG:BAD:(A;;0x800;;;WD)(A;;0x120fff;;;SY)(A;;0x120fff;;;LS)(A;;0x120fff;;;NS)(A;;0x120fff;;;BA)(A;;0xee5;;;LU)(A;;LC;;;MU)</Security> <TraceDataCollector> <DataCollectorType>1</DataCollectorType> <Name>PCP Collector Set</Name> <FileName>PCP Collector Set</FileName> <FileNameFormat>0</FileNameFormat> <FileNameFormatPattern> </FileNameFormatPattern> <LogAppend>0</LogAppend> <LogCircular>0</LogCircular> <LogOverwrite>0</LogOverwrite> <LatestOutputLocation>C:\Glider\var\log\etw\PCP Collector Set.etl</LatestOutputLocation> <Guid>{B96AC871-7D43-4C0C-87CC-982CA804F822}</Guid> <BufferSize>8</BufferSize> <BuffersLost>0</BuffersLost> <BuffersWritten>5</BuffersWritten> <ClockType>1</ClockType> <EventsLost>0</EventsLost> <ExtendedModes>0</ExtendedModes> <FlushTimer>1</FlushTimer> <FreeBuffers>5</FreeBuffers> <MaximumBuffers>25</MaximumBuffers> <MinimumBuffers>3</MinimumBuffers> <NumberOfBuffers>5</NumberOfBuffers> <PreallocateFile>0</PreallocateFile> <ProcessMode>0</ProcessMode> <RealTimeBuffersLost>0</RealTimeBuffersLost> <SessionName>PCP Collector Set</SessionName> <SessionThreadId>2728</SessionThreadId> <StreamMode>3</StreamMode> <TraceDataProvider> <DisplayName>{DD5EF90A-6398-47A4-AD34-4DCECDEF795F}</DisplayName> <FilterEnabled>0</FilterEnabled> <FilterType>0</FilterType> <Level> <Description>Events up to this level are enabled</Description> <ValueMapType>1</ValueMapType> <Value>255</Value> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>255</Value> </ValueMapItem> </Level> <KeywordsAny> <Description>Events with any of these keywords are enabled</Description> <ValueMapType>2</ValueMapType> <Value>0xffffffffffffffff</Value> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000000000</Value> </ValueMapItem> </KeywordsAny> <KeywordsAll> <Description>Events with all of these keywords are enabled</Description> <ValueMapType>2</ValueMapType> <Value>0x0</Value> </KeywordsAll> <Properties> <Description>These additional data fields will be collected with each event</Description> <ValueMapType>2</ValueMapType> <Value>0</Value> </Properties> <Guid>{DD5EF90A-6398-47A4-AD34-4DCECDEF795F}</Guid> </TraceDataProvider> <TraceDataProvider> <DisplayName>{22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716}</DisplayName> <FilterEnabled>0</FilterEnabled> <FilterType>0</FilterType> <Level> <Description>Events up to this level are enabled</Description> <ValueMapType>1</ValueMapType> <Value>255</Value> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>255</Value> </ValueMapItem> </Level> <KeywordsAny> <Description>Events with any of these keywords are enabled</Description> <ValueMapType>2</ValueMapType> <Value>0xffffffffffffffff</Value> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000000000</Value> </ValueMapItem> </KeywordsAny> <KeywordsAll> <Description>Events with all of these keywords are enabled</Description> <ValueMapType>2</ValueMapType> <Value>0x0</Value> </KeywordsAll> <Properties> <Description>These additional data fields will be collected with each event</Description> <ValueMapType>2</ValueMapType> <Value>0</Value> </Properties> <Guid>{22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716}</Guid> </TraceDataProvider> <TraceDataProvider> <DisplayName>{A68CA8B7-004F-D7B6-A698-07E2DE0F1F5D}</DisplayName> <FilterEnabled>0</FilterEnabled> <FilterType>0</FilterType> <Level> <Description>Events up to this level are enabled</Description> <ValueMapType>1</ValueMapType> <Value>255</Value> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>255</Value> </ValueMapItem> </Level> <KeywordsAny> <Description>Events with any of these keywords are enabled</Description> <ValueMapType>2</ValueMapType> <Value>0xffffffffffffffff</Value> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000000000</Value> </ValueMapItem> </KeywordsAny> <KeywordsAll> <Description>Events with all of these keywords are enabled</Description> <ValueMapType>2</ValueMapType> <Value>0x0</Value> </KeywordsAll> <Properties> <Description>These additional data fields will be collected with each event</Description> <ValueMapType>2</ValueMapType> <Value>0</Value> </Properties> <Guid>{A68CA8B7-004F-D7B6-A698-07E2DE0F1F5D}</Guid> </TraceDataProvider> <TraceDataProvider> <DisplayName>{7B6BC78C-898B-4170-BBF8-1A469EA43FC5}</DisplayName> <FilterEnabled>0</FilterEnabled> <FilterType>0</FilterType> <Level> <Description>Events up to this level are enabled</Description> <ValueMapType>1</ValueMapType> <Value>255</Value> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>255</Value> </ValueMapItem> </Level> <KeywordsAny> <Description>Events with any of these keywords are enabled</Description> <ValueMapType>2</ValueMapType> <Value>0xffffffffffffffff</Value> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x10000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x80000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x100000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x200000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x400000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000000000</Value> </ValueMapItem> </KeywordsAny> <KeywordsAll> <Description>Events with all of these keywords are enabled</Description> <ValueMapType>2</ValueMapType> <Value>0x0</Value> </KeywordsAll> <Properties> <Description>These additional data fields will be collected with each event</Description> <ValueMapType>2</ValueMapType> <Value>0</Value> </Properties> <Guid>{7B6BC78C-898B-4170-BBF8-1A469EA43FC5}</Guid> </TraceDataProvider> <TraceDataProvider> <DisplayName>{FC65DDD8-D6EF-4962-83D5-6E5CFE9CE148}</DisplayName> <FilterEnabled>0</FilterEnabled> <FilterType>0</FilterType> <Level> <Description>Events up to this level are enabled</Description> <ValueMapType>1</ValueMapType> <Value>4</Value> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>4</Value> </ValueMapItem> </Level> <KeywordsAny> <Description>Events with any of these keywords are enabled</Description> <ValueMapType>2</ValueMapType> <Value>0xf800000000060000</Value> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x20000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x40000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x800000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000000000</Value> </ValueMapItem> </KeywordsAny> <KeywordsAll> <Description>Events with all of these keywords are enabled</Description> <ValueMapType>2</ValueMapType> <Value>0x0</Value> </KeywordsAll> <Properties> <Description>These additional data fields will be collected with each event</Description> <ValueMapType>2</ValueMapType> <Value>0</Value> </Properties> <Guid>{FC65DDD8-D6EF-4962-83D5-6E5CFE9CE148}</Guid> </TraceDataProvider> <TraceDataProvider> <DisplayName>{36C23E18-0E66-11D9-BBEB-505054503030}</DisplayName> <FilterEnabled>0</FilterEnabled> <FilterType>0</FilterType> <Level> <Description>Events up to this level are enabled</Description> <ValueMapType>1</ValueMapType> <Value>4</Value> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>4</Value> </ValueMapItem> </Level> <KeywordsAny> <Description>Events with any of these keywords are enabled</Description> <ValueMapType>2</ValueMapType> <Value>0xe000000000000003</Value> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x1</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x2000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x4000000000000000</Value> </ValueMapItem> <ValueMapItem> <Key> </Key> <Description> </Description> <Enabled>-1</Enabled> <Value>0x8000000000000000</Value> </ValueMapItem> </KeywordsAny> <KeywordsAll> <Description>Events with all of these keywords are enabled</Description> <ValueMapType>2</ValueMapType> <Value>0x0</Value> </KeywordsAll> <Properties> <Description>These additional data fields will be collected with each event</Description> <ValueMapType>2</ValueMapType> <Value>0</Value> </Properties> <Guid>{36C23E18-0E66-11D9-BBEB-505054503030}</Guid> </TraceDataProvider> </TraceDataCollector> </DataCollectorSet> pcp-3.8.12ubuntu1/src/pmdas/etw/tdhlist.c0000664000000000000000000001674712272262501015132 0ustar /* * List Event Traces Providers or sessions for Windows events. * * Copyright (c) 2011, Nathan Scott. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include "util.h" #define MAX_SESSIONS (ULONG)64 #define MAX_SESSION_NAME_LEN 1024 #define MAX_LOGFILE_PATH_LEN 1024 void PrintFieldInfo(PBYTE buffer, PPROVIDER_FIELD_INFO fieldInfo, int id, EVENT_FIELD_TYPE eventFieldType) { PWCHAR stringBuffer; printf("\tField %u\n", id); switch (eventFieldType) { case EventKeywordInformation: printf("\t\tType: KeywordInformation\n"); break; case EventLevelInformation: printf("\t\tType: LevelInformation\n"); break; case EventChannelInformation: printf("\t\tType: ChannelInformation\n"); break; case EventTaskInformation: printf("\t\tType: TaskInformation\n"); break; case EventOpcodeInformation: printf("\t\tType: OpcodeInformation\n"); break; default: break; } printf("\t\tValue: %" PRIu64 "\n", fieldInfo->Value); if (fieldInfo->NameOffset) { stringBuffer = (PWCHAR)(buffer + fieldInfo->NameOffset); printf("\t\tField: %ls\n", stringBuffer); } if (fieldInfo->DescriptionOffset) { stringBuffer = (PWCHAR)(buffer + fieldInfo->DescriptionOffset); printf("\t\tDescription: %ls\n", stringBuffer); } } void PrintFieldElements(PPROVIDER_FIELD_INFOARRAY buffer, EVENT_FIELD_TYPE eventFieldType) { PPROVIDER_FIELD_INFO traceFieldInfo; ULONG i; for (i = 0; i < buffer->NumberOfElements; i++) { traceFieldInfo = &buffer->FieldInfoArray[i]; PrintFieldInfo((PBYTE)buffer, traceFieldInfo, i, eventFieldType); } } void EnumerateProviderFieldInformation(LPGUID guidPointer, EVENT_FIELD_TYPE eventFieldType) { PPROVIDER_FIELD_INFOARRAY buffer = NULL; ULONG sts, size = 0; sts = TdhEnumerateProviderFieldInformation(guidPointer, eventFieldType, buffer, &size); do { if (sts == ERROR_INSUFFICIENT_BUFFER) { BufferFree(buffer); buffer = (PPROVIDER_FIELD_INFOARRAY)BufferAllocate(size); if (!buffer) return; sts = TdhEnumerateProviderFieldInformation(guidPointer, eventFieldType, buffer, &size); } else if (sts == ERROR_SUCCESS) { PrintFieldElements(buffer, eventFieldType); break; } else if (sts == ERROR_NOT_FOUND) { break; } else { fprintf(stderr, "TdhEnumerateProviderFieldInformation: %s (%lu)\n", tdherror(sts), sts); break; } } while (1); BufferFree(buffer); } void PrintTraceProviderInfo(PBYTE buffer, PTRACE_PROVIDER_INFO traceProviderInfo) { LPGUID guidPointer = &traceProviderInfo->ProviderGuid; PWCHAR stringBuffer; ULONG i; if (traceProviderInfo->ProviderNameOffset) { stringBuffer = (PWCHAR)(buffer + traceProviderInfo->ProviderNameOffset); printf("Name: %ls\n", stringBuffer); } printf("Guid: %s\n", strguid(guidPointer)); printf("SchemaSource: %ld (%s)\n", traceProviderInfo->SchemaSource, traceProviderInfo->SchemaSource==0 ? "XML manifest" : "WMI MOF class"); for (i = EventKeywordInformation; i <= EventChannelInformation; i++) { EnumerateProviderFieldInformation(guidPointer, (EVENT_FIELD_TYPE)i); } } void PrintProviderEnumeration(PPROVIDER_ENUMERATION_INFO buffer) { PTRACE_PROVIDER_INFO traceProviderInfo; ULONG i; for (i = 0; i < buffer->NumberOfProviders; i++) { traceProviderInfo = &buffer->TraceProviderInfoArray[i]; PrintTraceProviderInfo((PBYTE)buffer, traceProviderInfo); } } ULONG EnumerateProviders(void) { PROVIDER_ENUMERATION_INFO providerEnumerationInfo; PPROVIDER_ENUMERATION_INFO buffer; ULONG size, sts; buffer = &providerEnumerationInfo; size = sizeof(providerEnumerationInfo); sts = TdhEnumerateProviders(buffer, &size); do { if (sts == ERROR_INSUFFICIENT_BUFFER) { if (buffer != &providerEnumerationInfo) BufferFree(buffer); buffer = (PPROVIDER_ENUMERATION_INFO)BufferAllocate(size); if (!buffer) return ERROR_NOT_ENOUGH_MEMORY; sts = TdhEnumerateProviders(buffer, &size); } else if (sts == ERROR_SUCCESS) { PrintProviderEnumeration(buffer); break; } else { fprintf(stderr, "TdhEnumerateProviders failed: %s (=%lu)\n", tdherror(sts), sts); break; } } while (1); if (buffer != &providerEnumerationInfo) BufferFree(buffer); return sts; } ULONG EnumerateSessions(void) { PEVENT_TRACE_PROPERTIES pSessions[MAX_SESSIONS]; PEVENT_TRACE_PROPERTIES pBuffer = NULL; ULONG PropertiesSize = 0; ULONG SessionCount = 0; ULONG BufferSize = 0; ULONG i, sts = ERROR_SUCCESS; PropertiesSize = sizeof(EVENT_TRACE_PROPERTIES) + (MAX_SESSION_NAME_LEN * sizeof(WCHAR)) + (MAX_LOGFILE_PATH_LEN * sizeof(WCHAR)); BufferSize = PropertiesSize * MAX_SESSIONS; pBuffer = (PEVENT_TRACE_PROPERTIES) malloc(BufferSize); if (pBuffer) { ZeroMemory(pBuffer, BufferSize); for (i = 0; i < MAX_SESSIONS; i++) { pSessions[i] = (EVENT_TRACE_PROPERTIES *)((BYTE *)pBuffer + (i * PropertiesSize)); pSessions[i]->Wnode.BufferSize = PropertiesSize; pSessions[i]->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); pSessions[i]->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) + (MAX_SESSION_NAME_LEN * sizeof(WCHAR)); } } else { fprintf(stderr, "Error allocating memory for properties.\n"); return ENOMEM; } sts = QueryAllTraces(pSessions, MAX_SESSIONS, &SessionCount); if (sts == ERROR_SUCCESS || sts == ERROR_MORE_DATA) { printf("Requested session count, %ld. Actual session count, %ld.\n\n", MAX_SESSIONS, SessionCount); for (i = 0; i < SessionCount; i++) { LPCSTR l, f; l = (LPCSTR)((char *)pSessions[i] + pSessions[i]->LoggerNameOffset); f = (LPCSTR)((char*)pSessions[i] + pSessions[i]->LogFileNameOffset); printf("Session GUID: %s\nSession ID: %"PRIu64"\n", strguid(&pSessions[i]->Wnode.Guid), pSessions[i]->Wnode.HistoricalContext); if (pSessions[i]->LogFileNameOffset == 0) printf("Realtime session name: %s\n", l); else printf("Log session name: %s\nLog file: %s\n", l, f); if (memcmp(&SystemTraceControlGuid, &pSessions[i]->Wnode.Guid, sizeof(GUID)) == 0) { printf("Enable Flags: "); dumpKernelTraceFlags(stdout, "", ","); printf("\n"); } printf("flush timer: %ld\n" "min buffers: %ld\n" "max buffers: %ld\n" "buffers: %ld\n" "buffers written: %ld\n" "buffers lost: %ld\n" "events lost: %ld\n\n", pSessions[i]->FlushTimer, pSessions[i]->MinimumBuffers, pSessions[i]->MaximumBuffers, pSessions[i]->NumberOfBuffers, pSessions[i]->BuffersWritten, pSessions[i]->LogBuffersLost, pSessions[i]->EventsLost); } } else { fprintf(stderr, "Error calling QueryAllTraces: %s (%ld)\n", tdherror(sts), sts); } free(pBuffer); return sts; } int main(int argc, char **argv) { ULONG sts; if (argc > 1 && strcmp(argv[1], "-s") == 0) sts = EnumerateSessions(); else sts = EnumerateProviders(); return sts; } pcp-3.8.12ubuntu1/src/pmdas/etw/GNUmakefile0000664000000000000000000000446512272262501015357 0ustar # # Copyright (c) 2011, Nathan Scott. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs WINDIR = $(TOPDIR)/src/win32ctl IAM = etw DOMAIN = ETW CFILES = util.c event.c pmda.c HFILES = util.h event.h LSRCFILES = tdhlist.c tdhconsume.c pcp.xml pmns root help LCFLAGS = -I$(WINDIR)/include -D_WIN32_WINNT=0x0600 -DFORCEINLINE="static inline" LLDFLAGS = -L$(WINDIR)/lib LLDLIBS = $(PCP_PMDALIB) -lpcp_tdh PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) LIBTARGET = pmda_etw.dll EXTRATARGETS = tdhlist.exe tdhconsume.exe help.dir help.pag LDIRT = $(EXTRATARGETS) root_etw domain.h $(IAM).log CONF_LINE = "etw 87 dso etw_init $(PCP_PMDAS_DIR)/etw/pmda_etw.dll" default: build-me include $(BUILDRULES) ifeq "$(TARGET_OS)" "mingw" build-me: root_etw $(LSRCFILES) $(LIBTARGET) $(EXTRATARGETS) @if [ `grep -c $(CONF_LINE) ../pmcd.conf` -eq 0 ]; then \ echo $(CONF_LINE) >> ../pmcd.conf ; \ fi install: build-me $(INSTALL) -m 755 -d $(PMDADIR) $(INSTALL) -m 755 tdhlist.exe $(PMDADIR)/tdhlist.exe $(INSTALL) -m 644 pmns $(PMDADIR)/root $(INSTALL) -m 644 domain.h help.dir help.pag help $(PMDADIR) $(INSTALL) -m 644 root_etw $(PCP_VAR_DIR)/pmns/root_etw else build-me: install: endif help.dir help.pag : help root_etw $(RUN_IN_BUILD_ENV) $(TOPDIR)/src/newhelp/newhelp -n root_etw -v 2 -o help < help default_pcp: default install_pcp: install root_etw: ../../pmns/stdpmid $(PMNS) rm -f root_etw sed -e 's;;"../../pmns/stdpmid";' root_etw domain.h: ../../pmns/stdpmid $(DOMAIN_MAKERULE) $(OBJECTS): domain.h util.h tdhlist.exe: tdhlist.o util.o $(CCF) -o tdhlist.exe tdhlist.o util.o $(LLDFLAGS) -lpcp_tdh tdhconsume.exe: tdhconsume.o util.o $(CCF) -o tdhconsume.exe tdhconsume.o util.o $(LLDFLAGS) -lpcp_tdh -lwsock32 pcp-3.8.12ubuntu1/src/pmdas/etw/root0000664000000000000000000000017212272262501014202 0ustar /* * fake "root" for validating the local PMNS subtree */ #include root { etw } #include "pmns" pcp-3.8.12ubuntu1/src/pmdas/etw/pmns0000664000000000000000000000477012272262501014204 0ustar /* * Event Tracing for Windows performance metrics namespace * * Copyright (c) 2011 Nathan Scott. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ etw { kernel } etw.kernel { process } etw.kernel.process { start exit thread image_load image_unload } etw.kernel.process.start { count ETW:0:0 records ETW:0:1 numclients ETW:0:2 queuemem ETW:0:3 params } etw.kernel.process.start.params { activityid ETW:0:10 pid ETW:0:11 parentid ETW:0:12 starttime ETW:0:13 session ETW:0:14 image_name ETW:0:15 } etw.kernel.process.exit { count ETW:0:20 records ETW:0:21 numclients ETW:0:22 queuemem ETW:0:23 params } etw.kernel.process.exit.params { activityid ETW:0:30 pid ETW:0:31 parentid ETW:0:32 starttime ETW:0:33 exittime ETW:0:34 exitcode ETW:0:35 handle_count ETW:0:36 commit_charge ETW:0:37 commit_peak ETW:0:38 image_name ETW:0:39 } etw.kernel.process.thread { start stop } etw.kernel.process.thread.start { count ETW:0:50 records ETW:0:51 numclients ETW:0:52 queuemem ETW:0:53 params } etw.kernel.process.thread.start.params { activityid ETW:0:60 tid ETW:0:61 pid ETW:0:62 } etw.kernel.process.thread.stop { count ETW:0:70 records ETW:0:71 numclients ETW:0:72 queuemem ETW:0:73 params } etw.kernel.process.thread.stop.params { activityid ETW:0:80 tid ETW:0:81 pid ETW:0:82 } etw.kernel.process.image_load { count ETW:0:90 records ETW:0:91 numclients ETW:0:92 queuemem ETW:0:93 params } etw.kernel.process.image_load.params { activityid ETW:0:100 pid ETW:0:101 name ETW:0:102 size ETW:0:103 } etw.kernel.process.image_unload { count ETW:0:110 records ETW:0:111 numclients ETW:0:112 queuemem ETW:0:113 params } etw.kernel.process.image_unload.params { activityid ETW:0:120 pid ETW:0:121 name ETW:0:122 size ETW:0:123 } pcp-3.8.12ubuntu1/src/pmdas/etw/util.h0000664000000000000000000000175012272262501014425 0ustar /* * Trace Data Helper utility routines. * * Copyright (c) 2011, Nathan Scott. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef UTIL_H #define UTIL_H extern void dumpKernelTraceFlags(FILE *, const char *, const char *); extern ULONG kernelTraceFlag(const char *); extern const char *eventHeaderFlags(USHORT); extern const char *eventPropertyFlags(USHORT); extern const char *strguid(LPGUID); extern const char *tdherror(ULONG); extern void *BufferAllocate(ULONG); extern void BufferFree(void *); #endif pcp-3.8.12ubuntu1/src/pmdas/etw/pmda.c0000664000000000000000000005103312272262501014363 0ustar /* * Event Tracing for Windows PMDA * * Copyright (c) 2011 Nathan Scott. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "event.h" #include "domain.h" #include "util.h" etw_event_t eventtab[] = { { EVENT_PROCESS_START, 0, 1, EVENT_TRACE_FLAG_PROCESS, NULL, "process.start", &SystemTraceControlGuid, KERNEL_LOGGER_NAME, sizeof(KERNEL_LOGGER_NAME) }, { EVENT_PROCESS_EXIT, 2, 1, EVENT_TRACE_FLAG_PROCESS, NULL, "process.exit", &SystemTraceControlGuid, KERNEL_LOGGER_NAME, sizeof(KERNEL_LOGGER_NAME) }, { EVENT_THREAD_START, 3, 1, EVENT_TRACE_FLAG_THREAD, NULL, "thread.start", &SystemTraceControlGuid, KERNEL_LOGGER_NAME, sizeof(KERNEL_LOGGER_NAME) }, { EVENT_THREAD_STOP, 4, 1, EVENT_TRACE_FLAG_THREAD, NULL, "thread.stop", &SystemTraceControlGuid, KERNEL_LOGGER_NAME, sizeof(KERNEL_LOGGER_NAME) }, { EVENT_IMAGE_LOAD, 5, 1, EVENT_TRACE_FLAG_IMAGE_LOAD, NULL, "image.load", &SystemTraceControlGuid, KERNEL_LOGGER_NAME, sizeof(KERNEL_LOGGER_NAME) }, { EVENT_IMAGE_UNLOAD, 6, 1, EVENT_TRACE_FLAG_IMAGE_LOAD, NULL, "image.unload", &SystemTraceControlGuid, KERNEL_LOGGER_NAME, sizeof(KERNEL_LOGGER_NAME) }, }; #if 0 static etw_event_t etwevents[] = { { CLUSTER_KERNEL_PROCESS, 0, EVENT_TRACE_FLAG_PROCESS, { CLUSTER_KERNEL_THREAD, 0, EVENT_TRACE_FLAG_THREAD, "kernel.thread" }, { CLUSTER_KERNEL_IMAGE_LOAD, 0, EVENT_TRACE_FLAG_IMAGE_LOAD, "kernel.image_load" }, { CLUSTER_KERNEL_DISK_IO, 0, EVENT_TRACE_FLAG_DISK_IO, "kernel.disk_io" }, { CLUSTER_KERNEL_DISK_FILE_IO, 0, EVENT_TRACE_FLAG_DISK_FILE_IO, "kernel.disk_file_io" }, { CLUSTER_KERNEL_MEMORY_PAGE_FAULTS, 0, EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS, "kernel.memory_page_faults" }, { CLUSTER_KERNEL_MEMORY_HARD_FAULTS, 0, EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS, "kernel.memory_hard_faults" }, { CLUSTER_KERNEL_NETWORK_TCPIP, 0, EVENT_TRACE_FLAG_NETWORK_TCPIP, "kernel.network_tcpip" }, { CLUSTER_KERNEL_REGISTRY, 0, EVENT_TRACE_FLAG_REGISTRY, "kernel.registry" }, { CLUSTER_KERNEL_DBGPRINT, 0, EVENT_TRACE_FLAG_DBGPRINT, "kernel.dbgprint" }, { CLUSTER_KERNEL_PROCESS_COUNTERS, 0, EVENT_TRACE_FLAG_PROCESS_COUNTERS, "kernel.process_counters" }, { CLUSTER_KERNEL_CSWITCH, 0, EVENT_TRACE_FLAG_CSWITCH, "kernel.cswitch" }, { CLUSTER_KERNEL_DPC, 0, EVENT_TRACE_FLAG_DPC, "kernel.dpc" }, { CLUSTER_KERNEL_INTERRUPT, 0, EVENT_TRACE_FLAG_INTERRUPT, "kernel.interrupt" }, { CLUSTER_KERNEL_SYSTEMCALL, 0, EVENT_TRACE_FLAG_SYSTEMCALL, "kernel.syscall" }, { CLUSTER_KERNEL_DISK_IO_INIT, 0, EVENT_TRACE_FLAG_DISK_IO_INIT, "kernel.disk_io_init" }, { CLUSTER_KERNEL_ALPC, 0, EVENT_TRACE_FLAG_ALPC, "kernel.alpc" }, { CLUSTER_KERNEL_SPLIT_IO, 0, EVENT_TRACE_FLAG_SPLIT_IO, "kernel.split_io" }, { CLUSTER_KERNEL_DRIVER, 0, EVENT_TRACE_FLAG_DRIVER, "kernel.driver" }, { CLUSTER_KERNEL_PROFILE, 0, EVENT_TRACE_FLAG_PROFILE, "kernel.profile" }, { CLUSTER_KERNEL_FILE_IO, 0, EVENT_TRACE_FLAG_FILE_IO, "kernel.file_io" }, { CLUSTER_KERNEL_FILE_IO_INIT, 0, EVENT_TRACE_FLAG_FILE_IO_INIT, "kernel.file_io_init" }, { CLUSTER_KERNEL_DISPATCHER, 0, EVENT_TRACE_FLAG_DISPATCHER, "kernel.dispatcher" }, { CLUSTER_KERNEL_VIRTUAL_ALLOC, 0, EVENT_TRACE_FLAG_VIRTUAL_ALLOC, "kernel.virtual_alloc" }, { CLUSTER_KERNEL_EXTENSION, 0, EVENT_TRACE_FLAG_EXTENSION, "kernel.extension" }, { CLUSTER_KERNEL_FORWARD_WMI, 0, EVENT_TRACE_FLAG_FORWARD_WMI, "kernel.forward_wmi" }, { CLUSTER_KERNEL_ENABLE_RESERVE, 0, EVENT_TRACE_FLAG_ENABLE_RESERVE, "kernel.enable_reserve" }, { CLUSTER_SQLSERVER_RPC_STARTING, 0, 0, "sqlserver.rpc.starting" }, { CLUSTER_SQLSERVER_BATCH_STARTING, 0, 0, "sqlserver.sql.batch_starting" }, }; static int numqueues = sizeof(etwevents)/sizeof(etw_event_t); #endif static pmdaMetric metrictab[] = { /* etw.kernel.process.start.count */ { &eventtab[EVENT_PROCESS_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,0), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* etw.kernel.process.start.records */ { &eventtab[EVENT_PROCESS_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,1), PM_TYPE_EVENT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.start.numclients */ { &eventtab[EVENT_PROCESS_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,2), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* etw.kernel.process.start.queuemem */ { &eventtab[EVENT_PROCESS_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,3), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* etw.kernel.process.start.params.activityid */ { &eventtab[EVENT_PROCESS_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,10), PM_TYPE_AGGREGATE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.start.params.pid */ { &eventtab[EVENT_PROCESS_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,11), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.start.params.parentid */ { &eventtab[EVENT_PROCESS_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,12), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.start.params.starttime */ { &eventtab[EVENT_PROCESS_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,13), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_USEC,0) }, }, /* etw.kernel.process.start.params.session */ { &eventtab[EVENT_PROCESS_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,14), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.start.params.image_name */ { &eventtab[EVENT_PROCESS_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,15), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.exit.count */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,20), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* etw.kernel.process.exit.records */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,21), PM_TYPE_EVENT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.exit.numclients */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,22), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* etw.kernel.process.exit.queuemem */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,23), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* etw.kernel.process.exit.params.activityid */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,30), PM_TYPE_AGGREGATE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.exit.params.pid */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,31), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.exit.params.parentid */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,32), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.exit.params.starttime */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,33), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_USEC,0) }, }, /* etw.kernel.process.exit.params.exittime */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,34), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,1,0,0,PM_TIME_USEC,0) }, }, /* etw.kernel.process.exit.params.exitcode */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,35), PM_TYPE_32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.exit.params.handle_count */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,36), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.exit.params.commit_charge */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,37), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.exit.params.commit_peak */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,38), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.exit.params.image_name */ { &eventtab[EVENT_PROCESS_EXIT], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,39), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.thread.start.count */ { &eventtab[EVENT_THREAD_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,50), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* etw.kernel.process.thread.start.records */ { &eventtab[EVENT_THREAD_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,51), PM_TYPE_EVENT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.thread.start.numclients */ { &eventtab[EVENT_THREAD_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,52), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* etw.kernel.process.thread.start.queuemem */ { &eventtab[EVENT_THREAD_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,53), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* etw.kernel.process.thread.start.params.activityid */ { &eventtab[EVENT_THREAD_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,60), PM_TYPE_AGGREGATE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.thread.start.params.tid */ { &eventtab[EVENT_THREAD_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,61), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.thread.start.params.pid */ { &eventtab[EVENT_THREAD_START], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,62), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.thread.stop.count */ { &eventtab[EVENT_THREAD_STOP], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,70), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* etw.kernel.process.thread.stop.records */ { &eventtab[EVENT_THREAD_STOP], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,71), PM_TYPE_EVENT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.thread.stop.numclients */ { &eventtab[EVENT_THREAD_STOP], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,72), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* etw.kernel.process.thread.stop.queuemem */ { &eventtab[EVENT_THREAD_STOP], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,73), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* etw.kernel.process.thread.stop.params.activityid */ { &eventtab[EVENT_THREAD_STOP], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,80), PM_TYPE_AGGREGATE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.thread.stop.params.tid */ { &eventtab[EVENT_THREAD_STOP], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,81), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.thread.stop.params.pid */ { &eventtab[EVENT_THREAD_STOP], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,82), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.image_load.count */ { &eventtab[EVENT_IMAGE_LOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,90), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* etw.kernel.process.image_load.records */ { &eventtab[EVENT_IMAGE_LOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,91), PM_TYPE_EVENT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.image_load.numclients */ { &eventtab[EVENT_IMAGE_LOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,92), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* etw.kernel.process.image_load.queuemem */ { &eventtab[EVENT_IMAGE_LOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,93), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* etw.kernel.process.image_load.params.activityid */ { &eventtab[EVENT_IMAGE_LOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,100), PM_TYPE_AGGREGATE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.image_load.params.pid */ { &eventtab[EVENT_IMAGE_LOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,101), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.image_load.params.name */ { &eventtab[EVENT_IMAGE_LOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,102), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.image_load.params.size */ { &eventtab[EVENT_IMAGE_LOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,103), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.image_unload.count */ { &eventtab[EVENT_IMAGE_UNLOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,110), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_COUNTER, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* etw.kernel.process.image_unload.records */ { &eventtab[EVENT_IMAGE_UNLOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,111), PM_TYPE_EVENT, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.image_unload.numclients */ { &eventtab[EVENT_IMAGE_UNLOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,112), PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,1,0,0,PM_COUNT_ONE) }, }, /* etw.kernel.process.image_unload.queuemem */ { &eventtab[EVENT_IMAGE_UNLOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,113), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) }, }, /* etw.kernel.process.image_unload.params.activityid */ { &eventtab[EVENT_IMAGE_UNLOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,120), PM_TYPE_AGGREGATE, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.image_unload.params.pid */ { &eventtab[EVENT_IMAGE_UNLOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,121), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.image_unload.params.name */ { &eventtab[EVENT_IMAGE_UNLOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,122), PM_TYPE_STRING, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, /* etw.kernel.process.image_unload.params.size */ { &eventtab[EVENT_IMAGE_UNLOAD], { PMDA_PMID(CLUSTER_KERNEL_PROCESS,123), PM_TYPE_U64, PM_INDOM_NULL, PM_SEM_INSTANT, PMDA_PMUNITS(0,0,0,0,0,0) }, }, }; static int etw_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *atom) { __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); etw_event_t *etw; int sts = PMDA_FETCH_STATIC; __pmNotifyErr(LOG_WARNING, "called %s, mdesc=%p", __FUNCTION__, mdesc); switch (idp->cluster) { case CLUSTER_KERNEL_PROCESS: if ((etw = ((mdesc != NULL) ? mdesc->m_user : NULL)) == NULL) return PM_ERR_PMID; switch (idp->item) { case 0: /* etw.kernel.process.start.count */ case 20: /* etw.kernel.process.exit.count */ case 50: /* etw.kernel.thread.start.count */ case 70: /* etw.kernel.thread.stop.count */ case 90: /* etw.kernel.process.image_load.count */ case 110: /* etw.kernel.process.image_unload.count */ sts = pmdaEventQueueCounter(etw->queueid, atom); break; case 1: /* etw.kernel.process.start.records */ case 21: /* etw.kernel.process.exit.records */ case 51: /* etw.kernel.thread.start.records */ case 71: /* etw.kernel.thread.stop.records */ case 91: /* etw.kernel.process.image_load.records */ case 111: /* etw.kernel.process.image_unload.records */ event_queue_lock(etw); sts = pmdaEventQueueRecords(etw->queueid, atom, pmdaGetContext(), event_decoder, &etw); event_queue_unlock(etw); break; case 2: /* etw.kernel.process.start.numclients */ case 22: /* etw.kernel.process.exit.numclients */ case 52: /* etw.kernel.thread.start.numclients */ case 72: /* etw.kernel.thread.stop.numclients */ case 92: /* etw.kernel.process.image_load.numclients */ case 112: /* etw.kernel.process.image_unload.numclients */ sts = pmdaEventQueueClients(etw->queueid, atom); break; case 3: /* etw.kernel.process.start.queuemem */ case 23: /* etw.kernel.process.exit.queuemem */ case 53: /* etw.kernel.thread.start.queuemem */ case 73: /* etw.kernel.thread.stop.queuemem */ case 93: /* etw.kernel.process.image_load.queuemem */ case 113: /* etw.kernel.process.image_unload.queuemem */ sts = pmdaEventQueueMemory(etw->queueid, atom); break; default: return PM_ERR_PMID; } break; case CLUSTER_CONFIGURATION: switch (idp->item) { case 0: /* etw.numclients */ sts = pmdaEventClients(atom); break; default: return PM_ERR_PMID; } break; default: break; } return sts; } static int etw_profile(__pmProfile *prof, pmdaExt *pmda) { pmdaEventNewClient(pmda->e_context); return 0; } static int etw_fetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { __pmNotifyErr(LOG_WARNING, "called %s", __FUNCTION__); pmdaEventNewClient(pmda->e_context); return pmdaFetch(numpmid, pmidlist, resp, pmda); } static int etw_store(pmResult *result, pmdaExt *pmda) { pmdaEventNewClient(pmda->e_context); return PM_ERR_PERMISSION; } static void etw_end_contextCallBack(int context) { __pmNotifyErr(LOG_WARNING, "called %s", __FUNCTION__); pmdaEventEndClient(context); } static int etw_text(int ident, int type, char **buffer, pmdaExt *pmda) { pmdaEventNewClient(pmda->e_context); return pmdaText(ident, type, buffer, pmda); } static int event_equal(etw_event_t *event, LPGUID provider, int eventid, int version) { if (memcmp(event->provider, provider, sizeof(GUID)) != 0) return 0; return (event->eventid == eventid && event->version == version); } etw_event_t * event_table_lookup(LPGUID guid, int eventid, int version) { static int last; /* punt on previous type of event reoccurring */ int i = last; if (event_equal(&eventtab[i], guid, eventid, version)) return &eventtab[i]; for (i = 0; i < sizeof(eventtab)/sizeof(eventtab[0]); i++) { etw_event_t *e = &eventtab[i]; if (event_equal(e, guid, eventid, version)) { last = i; return e; } } return NULL; } int event_table_init(void) { int i, id; for (i = 0; i < sizeof(eventtab)/sizeof(eventtab[0]); i++) { HANDLE mutex = CreateMutex(NULL, FALSE, NULL); etw_event_t *e = &eventtab[i]; if (!mutex) { __pmNotifyErr(LOG_WARNING, "failed to create mutex for event %s", e->pmnsname); } else if ((id = pmdaEventNewQueue(e->pmnsname, DEFAULT_MAXMEM)) < 0) { __pmNotifyErr(LOG_WARNING, "failed to create queue for event %s", e->pmnsname); } else { e->queueid = id; e->mutex = mutex; } } return 0; } void etw_init(pmdaInterface *dp, const char *configfile) { char helppath[MAXPATHLEN]; int sep = __pmPathSeparator(); snprintf(helppath, sizeof(helppath), "%s%c" "etw" "%c" "help", pmGetConfig("PCP_PMDAS_DIR"), sep, sep); pmdaDSO(dp, PMDA_INTERFACE_5, "etw DSO", helppath); if (dp->status != 0) return; if (event_table_init() < 0) return; if (event_init() < 0) return; dp->version.four.fetch = etw_fetch; dp->version.four.store = etw_store; dp->version.four.profile = etw_profile; dp->version.four.text = etw_text; pmdaSetFetchCallBack(dp, etw_fetchCallBack); pmdaSetEndContextCallBack(dp, etw_end_contextCallBack); pmdaInit(dp, NULL, 0, metrictab, sizeof(metrictab)/sizeof(metrictab[0])); } pcp-3.8.12ubuntu1/src/pmdas/etw/tdhconsume.c0000664000000000000000000006460712272262501015626 0ustar /* * Event Trace Consumer for Windows events on the current platform. * * Copyright (c) 2011, Nathan Scott. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include #include #include #include #include "util.h" #define PROPERTY_BUFFER 1024 #define MAX_SESSIONS 64 #define PCP_SESSION "PCP Collector Set" static int verbose; /* Get the event metadata */ static DWORD GetEventInformation(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO *pInfoPointer) { PTRACE_EVENT_INFO pInfo = NULL; DWORD sts = ERROR_SUCCESS; DWORD size = 0; sts = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &size); if (sts == ERROR_INSUFFICIENT_BUFFER) { pInfo = (TRACE_EVENT_INFO *)malloc(size); if (pInfo == NULL) { fprintf(stderr, "Failed to allocate memory for event info (size=%lu).\n", size); sts = ERROR_OUTOFMEMORY; } else { /* Retrieve event metadata */ sts = TdhGetEventInformation(pEvent, 0, NULL, pInfo, &size); } } else if (sts != ERROR_SUCCESS && verbose) { fprintf(stderr, "TdhGetEventInformation failed: %s (%lu)\n", tdherror(sts), sts); } *pInfoPointer = pInfo; return sts; } static void PrintMapString(PEVENT_MAP_INFO pMapInfo, PBYTE pData) { BOOL MatchFound = FALSE; DWORD i; if ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP) == EVENTMAP_INFO_FLAG_MANIFEST_VALUEMAP || ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_VALUEMAP) == EVENTMAP_INFO_FLAG_WBEM_VALUEMAP && (pMapInfo->Flag & (~EVENTMAP_INFO_FLAG_WBEM_VALUEMAP)) != EVENTMAP_INFO_FLAG_WBEM_FLAG)) { if ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_NO_MAP) == EVENTMAP_INFO_FLAG_WBEM_NO_MAP) { printf("%s\n", ((PBYTE)pMapInfo + pMapInfo->MapEntryArray[*(PULONG)pData].OutputOffset)); } else { for (i = 0; i < pMapInfo->EntryCount; i++) { if (pMapInfo->MapEntryArray[i].Value == *(PULONG)pData) { printf("%s\n", ((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset)); MatchFound = TRUE; break; } } if (MatchFound == FALSE) printf("%lu\n", *(PULONG)pData); } } else if ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_MANIFEST_BITMAP) == EVENTMAP_INFO_FLAG_MANIFEST_BITMAP || (pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_BITMAP) == EVENTMAP_INFO_FLAG_WBEM_BITMAP || ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_VALUEMAP) == EVENTMAP_INFO_FLAG_WBEM_VALUEMAP && (pMapInfo->Flag & (~EVENTMAP_INFO_FLAG_WBEM_VALUEMAP)) == EVENTMAP_INFO_FLAG_WBEM_FLAG)) { if ((pMapInfo->Flag & EVENTMAP_INFO_FLAG_WBEM_NO_MAP) == EVENTMAP_INFO_FLAG_WBEM_NO_MAP) { DWORD BitPosition = 0; for (i = 0; i < pMapInfo->EntryCount; i++) { BitPosition = (1 << i); if ((*(PULONG)pData & BitPosition) == BitPosition) { printf("%s%s", (MatchFound) ? " | " : "", ((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset)); MatchFound = TRUE; } } } else { for (i = 0; i < pMapInfo->EntryCount; i++) { if ((pMapInfo->MapEntryArray[i].Value & *(PULONG)pData) == pMapInfo->MapEntryArray[i].Value) { printf("%s%s", (MatchFound) ? " | " : "", ((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset)); MatchFound = TRUE; } } } if (MatchFound) { printf("\n"); } else { printf("%lu\n", *(PULONG)pData); } } } static DWORD FormatAndPrintData(PEVENT_RECORD pEvent, USHORT InType, USHORT OutType, PBYTE pData, DWORD DataSize, PEVENT_MAP_INFO pMapInfo) { DWORD i, sts = ERROR_SUCCESS; size_t StringLength = 0; switch (InType) { case TDH_INTYPE_UNICODESTRING: case TDH_INTYPE_COUNTEDSTRING: case TDH_INTYPE_REVERSEDCOUNTEDSTRING: case TDH_INTYPE_NONNULLTERMINATEDSTRING: if (TDH_INTYPE_COUNTEDSTRING == InType) StringLength = *(PUSHORT)pData; else if (TDH_INTYPE_REVERSEDCOUNTEDSTRING == InType) StringLength = MAKEWORD( HIBYTE((PUSHORT)pData), LOBYTE((PUSHORT)pData)); else if (TDH_INTYPE_NONNULLTERMINATEDSTRING == InType) StringLength = DataSize; else StringLength = wcslen((LPWSTR)pData); printf("%.*s\n", StringLength, pData); break; case TDH_INTYPE_ANSISTRING: case TDH_INTYPE_COUNTEDANSISTRING: case TDH_INTYPE_REVERSEDCOUNTEDANSISTRING: case TDH_INTYPE_NONNULLTERMINATEDANSISTRING: if (TDH_INTYPE_COUNTEDANSISTRING == InType) StringLength = *(PUSHORT)pData; else if (TDH_INTYPE_REVERSEDCOUNTEDANSISTRING == InType) StringLength = MAKEWORD( HIBYTE((PUSHORT)pData), LOBYTE((PUSHORT)pData)); else if (TDH_INTYPE_NONNULLTERMINATEDANSISTRING == InType) StringLength = DataSize; else StringLength = strlen((LPSTR)pData); printf("%.*s\n", StringLength, pData); break; case TDH_INTYPE_INT8: printf("%hd\n", *(PCHAR)pData); break; case TDH_INTYPE_UINT8: if (TDH_OUTTYPE_HEXINT8 == OutType) printf("0x%x\n", *(PBYTE)pData); else printf("%hu\n", *(PBYTE)pData); break; case TDH_INTYPE_INT16: printf("%hd\n", *(PSHORT)pData); break; case TDH_INTYPE_UINT16: if (TDH_OUTTYPE_HEXINT16 == OutType) printf("0x%x\n", *(PUSHORT)pData); else if (TDH_OUTTYPE_PORT == OutType) printf("%hu\n", ntohs(*(PUSHORT)pData)); else printf("%hu\n", *(PUSHORT)pData); break; case TDH_INTYPE_INT32: if (TDH_OUTTYPE_HRESULT == OutType) printf("0x%lx\n", *(PLONG)pData); else printf("%ld\n", *(PLONG)pData); break; case TDH_INTYPE_UINT32: if (TDH_OUTTYPE_HRESULT == OutType || TDH_OUTTYPE_WIN32ERROR == OutType || TDH_OUTTYPE_NTSTATUS == OutType || TDH_OUTTYPE_HEXINT32 == OutType) printf("0x%lx\n", *(PULONG)pData); else if (TDH_OUTTYPE_IPV4 == OutType) printf("%ld.%ld.%ld.%ld\n", (*(PLONG)pData >> 0) & 0xff, (*(PLONG)pData >> 8) & 0xff, (*(PLONG)pData >> 16) & 0xff, (*(PLONG)pData >> 24) & 0xff); else if (pMapInfo) PrintMapString(pMapInfo, pData); else printf("%lu\n", *(PULONG)pData); break; case TDH_INTYPE_INT64: printf("%I64d\n", *(PLONGLONG)pData); break; case TDH_INTYPE_UINT64: if (TDH_OUTTYPE_HEXINT64 == OutType) printf("0x%I64x\n", *(PULONGLONG)pData); else printf("%I64u\n", *(PULONGLONG)pData); break; case TDH_INTYPE_FLOAT: printf("%f\n", *(PFLOAT)pData); break; case TDH_INTYPE_DOUBLE: printf("%f\n", *(double*)pData); break; case TDH_INTYPE_BOOLEAN: printf("%s\n", ((PBOOL)pData == 0) ? "false" : "true"); break; case TDH_INTYPE_BINARY: if (TDH_OUTTYPE_IPV6 == OutType) break; else { for (i = 0; i < DataSize; i++) printf("%.2x", pData[i]); printf("\n"); } break; case TDH_INTYPE_GUID: printf("%s\n", strguid((GUID *)pData)); break; case TDH_INTYPE_POINTER: case TDH_INTYPE_SIZET: if (EVENT_HEADER_FLAG_32_BIT_HEADER == (pEvent->EventHeader.Flags & EVENT_HEADER_FLAG_32_BIT_HEADER)) printf("0x%I32x\n", *(PULONG)pData); else printf("0x%I64x\n", *(PULONGLONG)pData); case TDH_INTYPE_FILETIME: break; case TDH_INTYPE_SYSTEMTIME: break; case TDH_INTYPE_SID: break; case TDH_INTYPE_HEXINT32: printf("0x%I32x\n", *(PULONG)pData); break; case TDH_INTYPE_HEXINT64: printf("0x%I64x\n", *(PULONGLONG)pData); break; case TDH_INTYPE_UNICODECHAR: printf("%c\n", *(PWCHAR)pData); break; case TDH_INTYPE_ANSICHAR: printf("%C\n", *(PCHAR)pData); break; case TDH_INTYPE_WBEMSID: break; default: sts = ERROR_NOT_FOUND; } return sts; } /* * Get the size of the array. * For MOF-based events, the size is specified in the declaration or using * the MAX qualifier. For manifest-based events, the property can specify * the size of the array using the count attribute. * The count attribue can specify the size directly or specify the name * of another property in the event data that contains the size. */ static void GetArraySize(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, PUSHORT ArraySize) { PROPERTY_DATA_DESCRIPTOR DataDescriptor; DWORD size = 0; if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyParamCount) == PropertyParamCount) { DWORD cnt = 0; /* expecting count to be defined as uint16 or uint32 */ DWORD j = pInfo->EventPropertyInfoArray[i].countPropertyIndex; ZeroMemory(&DataDescriptor, sizeof(PROPERTY_DATA_DESCRIPTOR)); DataDescriptor.PropertyName = (ULONGLONG)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[j].NameOffset); DataDescriptor.ArrayIndex = ULONG_MAX; TdhGetPropertySize(pEvent, 0, NULL, 1, &DataDescriptor, &size); TdhGetProperty(pEvent, 0, NULL, 1, &DataDescriptor, size, (PBYTE)&cnt); *ArraySize = (USHORT)cnt; } else { *ArraySize = pInfo->EventPropertyInfoArray[i].count; } } /* * Mapped string values defined in a manifest will contain a trailing space * in the EVENT_MAP_ENTRY structure. Replace the trailing space with a null- * terminating character, so that bit mapped strings are correctly formatted. */ static void RemoveTrailingSpace(PEVENT_MAP_INFO pMapInfo) { SIZE_T ByteLength = 0; DWORD i; for (i = 0; i < pMapInfo->EntryCount; i++) { ByteLength = (wcslen((LPWSTR)((PBYTE)pMapInfo + pMapInfo->MapEntryArray[i].OutputOffset)) - 1) * 2; *((LPWSTR)((PBYTE)pMapInfo + (pMapInfo->MapEntryArray[i].OutputOffset + ByteLength))) = L'\0'; } } /* * Both MOF-based events and manifest-based events can specify name/value maps. * The map values can be integer values or bit values. * If the property specifies a value map, get the map. */ static DWORD GetMapInfo(PEVENT_RECORD pEvent, LPWSTR pMapName, DWORD DecodingSource, PEVENT_MAP_INFO pMapInfo) { DWORD sts = ERROR_SUCCESS; DWORD size = 0; /* Retrieve required buffer size for map info */ sts = TdhGetEventMapInformation(pEvent, pMapName, pMapInfo, &size); if (sts == ERROR_INSUFFICIENT_BUFFER) { pMapInfo = (PEVENT_MAP_INFO)malloc(size); if (pMapInfo == NULL) { fprintf(stderr, "Failed to allocate map info memory (size=%lu).\n", size); return ERROR_OUTOFMEMORY; } /* Retrieve the map info */ sts = TdhGetEventMapInformation(pEvent, pMapName, pMapInfo, &size); } if (sts == ERROR_SUCCESS) { if (DecodingSourceXMLFile == DecodingSource) RemoveTrailingSpace(pMapInfo); } else if (sts == ERROR_NOT_FOUND) { sts = ERROR_SUCCESS; } else { fprintf(stderr, "TdhGetEventMapInformation failed: %s (%ld)\n", tdherror(sts), sts); } return sts; } static DWORD PrintProperties(PEVENT_RECORD pEvent, PTRACE_EVENT_INFO pInfo, USHORT i, LPWSTR pStructureName, USHORT StructIndex) { DWORD sts = ERROR_SUCCESS; DWORD LastMember = 0; USHORT ArraySize = 0; PEVENT_MAP_INFO pMapInfo = NULL; PROPERTY_DATA_DESCRIPTOR DataDescriptors[2]; ULONG DescriptorsCount = 0; USHORT k, j; static DWORD size; static PBYTE pData; if (pData == NULL) { if ((pData = malloc(PROPERTY_BUFFER)) != NULL) size = PROPERTY_BUFFER; } /* Get the size of the array (if the property is an array) */ GetArraySize(pEvent, pInfo, i, &ArraySize); for (k = 0; k < ArraySize; k++) { wprintf(L"%*s%s: ", (pStructureName) ? 4 : 0, L"", (LPWSTR) ((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset)); /* If the property is a structure, print the members of the structure */ if ((pInfo->EventPropertyInfoArray[i].Flags & PropertyStruct) == PropertyStruct) { printf("\n"); LastMember = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex + pInfo->EventPropertyInfoArray[i].structType.NumOfStructMembers; for (j = pInfo->EventPropertyInfoArray[i].structType.StructStartIndex; j < LastMember; j++) { sts = PrintProperties(pEvent, pInfo, j, (LPWSTR)((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset), k); if (sts != ERROR_SUCCESS) { fprintf(stderr, "Printing the members of the structure failed\n"); goto cleanup; } } } else { ZeroMemory(&DataDescriptors, sizeof(DataDescriptors)); /* * To retrieve a member of a structure, you need to specify * an array of descriptors. The first descriptor in the array * identifies the name of the structure and the second * descriptor defines the member of the structure whose data * you want to retrieve. */ if (pStructureName) { DataDescriptors[0].PropertyName = (ULONGLONG)pStructureName; DataDescriptors[0].ArrayIndex = StructIndex; DataDescriptors[1].PropertyName = (ULONGLONG) ((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset); DataDescriptors[1].ArrayIndex = k; DescriptorsCount = 2; } else { DataDescriptors[0].PropertyName = (ULONGLONG) ((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].NameOffset); DataDescriptors[0].ArrayIndex = k; DescriptorsCount = 1; } /* * TDH API does not support IPv6 addresses. * If the output type is TDH_OUTTYPE_IPV6, you will be unable * to consume the rest of the event. * If you try to consume the remainder of the event, you will * get ERROR_EVT_INVALID_EVENT_DATA. */ if (TDH_INTYPE_BINARY == pInfo->EventPropertyInfoArray[i].nonStructType.InType && TDH_OUTTYPE_IPV6 == pInfo->EventPropertyInfoArray[i].nonStructType.OutType) { fprintf(stderr, "Event contains an IPv6 address. Skipping.\n"); sts = ERROR_EVT_INVALID_EVENT_DATA; break; } else { retry: sts = TdhGetProperty(pEvent, 0, NULL, DescriptorsCount, &DataDescriptors[0], size, pData); if (sts == ERROR_INSUFFICIENT_BUFFER) { /* TdhGetPropertySize failing on Win2008, so do this: */ pData = realloc(pData, size *= 2); goto retry; } else if (sts != ERROR_SUCCESS) { fprintf(stderr, "TdhGetProperty failed: %s (%ld)\n", tdherror(sts), sts); goto cleanup; } /* * Get the name/value map if the property specifies a value map. */ sts = GetMapInfo(pEvent, (PWCHAR) ((PBYTE)(pInfo) + pInfo->EventPropertyInfoArray[i].nonStructType.MapNameOffset), pInfo->DecodingSource, pMapInfo); if (sts != ERROR_SUCCESS) { fprintf(stderr, "GetMapInfo failed\n"); goto cleanup; } sts = FormatAndPrintData(pEvent, pInfo->EventPropertyInfoArray[i].nonStructType.InType, pInfo->EventPropertyInfoArray[i].nonStructType.OutType, pData, size, pMapInfo); if (sts != ERROR_SUCCESS) { fprintf(stderr, "FormatAndPrintData failed\n"); goto cleanup; } if (pMapInfo) { free(pMapInfo); pMapInfo = NULL; } } } } cleanup: if (pMapInfo) { free(pMapInfo); pMapInfo = NULL; } return sts; } void PrintHeader(PEVENT_RECORD pEvent) { /* Note: EventHeader.ProcessId is defined as ULONG */ printf("Event HEADER (size=%u) flags=%s type=%s\npid=%lu tid=%ld eid=%u\n", pEvent->EventHeader.Size, eventHeaderFlags(pEvent->EventHeader.Flags), eventPropertyFlags(pEvent->EventHeader.EventProperty), pEvent->EventHeader.ThreadId, pEvent->EventHeader.ProcessId, pEvent->EventHeader.EventDescriptor.Id); if (pEvent->EventHeader.Flags & (EVENT_HEADER_FLAG_PRIVATE_SESSION|EVENT_HEADER_FLAG_NO_CPUTIME)) { printf("Time processor=%"PRIu64"\n", pEvent->EventHeader.ProcessorTime); } else { printf("Time: sys=%lu usr=%lu\n", pEvent->EventHeader.KernelTime, pEvent->EventHeader.UserTime); } printf("Event PROVIDER %s\n", strguid(&pEvent->EventHeader.ProviderId)); printf("Event ACTIVITY %s\n", strguid(&pEvent->EventHeader.ActivityId)); } void PrintTimestamp(PEVENT_RECORD pEvent) { ULONGLONG TimeStamp = 0; ULONGLONG Nanoseconds = 0; SYSTEMTIME st; SYSTEMTIME stLocal; FILETIME ft; /* Print the time stamp for when the event occurred */ ft.dwHighDateTime = pEvent->EventHeader.TimeStamp.HighPart; ft.dwLowDateTime = pEvent->EventHeader.TimeStamp.LowPart; FileTimeToSystemTime(&ft, &st); SystemTimeToTzSpecificLocalTime(NULL, &st, &stLocal); TimeStamp = pEvent->EventHeader.TimeStamp.QuadPart; Nanoseconds = (TimeStamp % 10000000) * 100; printf("Event TIMESTAMP: %02d/%02d/%02d %02d:%02d:%02d.%I64u\n", stLocal.wMonth, stLocal.wDay, stLocal.wYear, stLocal.wHour, stLocal.wMinute, stLocal.wSecond, Nanoseconds); } void PrintEventInfo(PTRACE_EVENT_INFO pInfo) { if (DecodingSourceWbem == pInfo->DecodingSource) printf("EventInfo: MOF class event\n"); else if (DecodingSourceXMLFile == pInfo->DecodingSource) printf("EventInfo: XML manifest event\n"); else if (DecodingSourceWPP == pInfo->DecodingSource) printf("EventInfo: WPP event\n"); printf("Event GUID: %s\n", strguid(&pInfo->EventGuid)); if (pInfo->ProviderNameOffset > 0) wprintf(L"Provider name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->ProviderNameOffset)); if (DecodingSourceXMLFile == pInfo->DecodingSource) wprintf(L"Event ID: %hu\n", pInfo->EventDescriptor.Id); wprintf(L"Version: %d\n", pInfo->EventDescriptor.Version); if (pInfo->ChannelNameOffset > 0) wprintf(L"Channel name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->ChannelNameOffset)); if (pInfo->LevelNameOffset > 0) wprintf(L"Level name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->LevelNameOffset)); else wprintf(L"Level: %hu\n", pInfo->EventDescriptor.Level); if (DecodingSourceXMLFile == pInfo->DecodingSource) { if (pInfo->OpcodeNameOffset > 0) wprintf(L"Opcode name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->OpcodeNameOffset)); } else wprintf(L"Type: %hu\n", pInfo->EventDescriptor.Opcode); if (DecodingSourceXMLFile == pInfo->DecodingSource) { if (pInfo->TaskNameOffset > 0) wprintf(L"Task name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->TaskNameOffset)); } else wprintf(L"Task: %hu\n", pInfo->EventDescriptor.Task); wprintf(L"Keyword mask: 0x%x\n", pInfo->EventDescriptor.Keyword); if (pInfo->KeywordsNameOffset) { LPWSTR pKeyword = (LPWSTR)((PBYTE)(pInfo) + pInfo->KeywordsNameOffset); for (; *pKeyword != 0; pKeyword += (wcslen(pKeyword) + 1)) wprintf(L" Keyword name: %s\n", pKeyword); } if (pInfo->EventMessageOffset > 0) wprintf(L"Event message: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->EventMessageOffset)); if (pInfo->ActivityIDNameOffset > 0) wprintf(L"Activity ID name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->ActivityIDNameOffset)); if (pInfo->RelatedActivityIDNameOffset > 0) wprintf(L"Related activity ID name: %s\n", (LPWSTR)((PBYTE)(pInfo) + pInfo->RelatedActivityIDNameOffset)); } /* Callback that receives the events */ VOID WINAPI ProcessEvent(PEVENT_RECORD pEvent) { DWORD sts = ERROR_SUCCESS; PTRACE_EVENT_INFO pInfo = NULL; USHORT i; PrintHeader(pEvent); PrintTimestamp(pEvent); /* * Process the event. * The pEvent->UserData member is a pointer to the event specific data, * if any exists. */ sts = GetEventInformation(pEvent, &pInfo); if (sts != ERROR_SUCCESS) goto cleanup; PrintEventInfo(pInfo); if (DecodingSourceWPP == pInfo->DecodingSource) /* Not handling the WPP case, unless just an inline string */ if (!(pEvent->EventHeader.Flags & EVENT_HEADER_FLAG_STRING_ONLY)) goto cleanup; /* * Print the event data for all the top-level properties. * Metadata for all the top-level properties comes before structure * member properties in the property information array. * If the EVENT_HEADER_FLAG_STRING_ONLY flag is set, the event data * is a null-terminated string, so just print it. */ if (EVENT_HEADER_FLAG_STRING_ONLY == (pEvent->EventHeader.Flags & EVENT_HEADER_FLAG_STRING_ONLY)) { printf("Embedded: %s\n", (char *)pEvent->UserData); } else { for (i = 0; i < pInfo->TopLevelPropertyCount; i++) { sts = PrintProperties(pEvent, pInfo, i, NULL, 0); if (sts != ERROR_SUCCESS) { fprintf(stderr, "Printing top level properties failed, property %u.\n", i); } } } cleanup: fflush(stdout); if (pInfo) free(pInfo); } static struct { EVENT_TRACE_PROPERTIES *properties; TRACEHANDLE session; LPTSTR name; } sessions[MAX_SESSIONS]; static int sCount; static void stopSession(TRACEHANDLE session, LPTSTR name, PEVENT_TRACE_PROPERTIES properties) { if (session != INVALID_PROCESSTRACE_HANDLE) { ULONG sts = ControlTrace(session, name, properties, EVENT_TRACE_CONTROL_STOP); if (sts != ERROR_SUCCESS) fprintf(stderr, "ControlTrace failed (%s): %s\n", name, tdherror(sts)); else fprintf(stderr, "Stopped %s event tracing session\n", name); } } static void __attribute__((constructor)) initTracing() { int i; for (i = 0; i < sizeof(sessions) / sizeof(sessions[0]); i++) sessions[i].session = INVALID_PROCESSTRACE_HANDLE; } static void __attribute__((destructor)) stopTracing() { int i; for (i = 0; i < sCount; i++) { sessions[i].properties->EnableFlags = 0; stopSession(sessions[i].session, sessions[i].name, sessions[i].properties); } } void enableEventTrace(LPTSTR name, ULONG namelen, const GUID *guid, ULONG enableFlags, BOOL useGlobalSequence) { TRACEHANDLE session; EVENT_TRACE_PROPERTIES *properties; ULONG size, sts = ERROR_SUCCESS; int retryStartTrace = 0; size = sizeof(EVENT_TRACE_PROPERTIES) + namelen; properties = malloc(size); if (properties == NULL) { fprintf(stderr, "Insufficient memory: %lu bytes\n", size); exit(1); } sessions[sCount].properties = properties; sessions[sCount].session = session; sessions[sCount].name = name; sCount++; retrySession: ZeroMemory(properties, size); properties->Wnode.BufferSize = size; properties->Wnode.Flags = WNODE_FLAG_TRACED_GUID; properties->Wnode.ClientContext = 1; properties->Wnode.Guid = *guid; properties->EnableFlags = enableFlags; properties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE; if (useGlobalSequence == TRUE) properties->LogFileMode |= EVENT_TRACE_USE_GLOBAL_SEQUENCE; properties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); sts = StartTrace(&session, name, properties); if (sts != ERROR_SUCCESS) { if (retryStartTrace == 1) { fprintf(stderr, "Cannot start %s session (in use)\n", name); } else if (sts == ERROR_ALREADY_EXISTS) { fprintf(stderr, "%s session is in use - retry ... (flags=%lx)\n", name, enableFlags); stopTracing(); retryStartTrace = 1; goto retrySession; } else { fprintf(stderr, "StartTrace: %s\n", tdherror(sts)); } exit(1); } } ULONG bufferCount, buffersRead, bufferTotal, bufferBytes, eventsLost, sysCount; ULONG WINAPI BufferCallback(PEVENT_TRACE_LOGFILE mode) { buffersRead += mode->BuffersRead; bufferTotal += mode->BufferSize; bufferBytes += mode->Filled; eventsLost += mode->EventsLost; sysCount += mode->IsKernelTrace; bufferCount++; printf("Event BUFFER (size=%lu) all reads=%lu bytes=%lu lost=%lu sys=%lu\n", mode->Filled, buffersRead, bufferBytes, eventsLost, sysCount); return TRUE; } LPGUID LookupGuidInBuffer(LPTSTR name, PPROVIDER_ENUMERATION_INFO buffer) { PTRACE_PROVIDER_INFO traceProviderInfo; PWCHAR stringPointer; char s[1024]; LPGUID guidPointer; PBYTE bufferPointer = (PBYTE)buffer; ULONG i; for (i = 0; i < buffer->NumberOfProviders; i++) { traceProviderInfo = &buffer->TraceProviderInfoArray[i]; if (traceProviderInfo->ProviderNameOffset == 0) continue; guidPointer = &traceProviderInfo->ProviderGuid; stringPointer = (PWCHAR) (bufferPointer + traceProviderInfo->ProviderNameOffset); WideCharToMultiByte(CP_ACP, 0, stringPointer, -1, s, 1024, NULL, NULL); if (strcmp(s, name) == 0) return guidPointer; } return NULL; } ULONG ProviderGuid(LPTSTR name, LPGUID guidPointer) { PROVIDER_ENUMERATION_INFO providerEnumerationInfo; PPROVIDER_ENUMERATION_INFO buffer; ULONG size, sts; buffer = &providerEnumerationInfo; size = sizeof(providerEnumerationInfo); sts = TdhEnumerateProviders(buffer, &size); do { if (sts == ERROR_INSUFFICIENT_BUFFER) { if (buffer != &providerEnumerationInfo) BufferFree(buffer); buffer = (PPROVIDER_ENUMERATION_INFO)BufferAllocate(size); if (!buffer) return ERROR_NOT_ENOUGH_MEMORY; sts = TdhEnumerateProviders(buffer, &size); } else if (sts == ERROR_SUCCESS) { guidPointer = LookupGuidInBuffer(name, buffer); break; } else { fprintf(stderr, "TdhEnumerateProviders failed: %s (=%lu)\n", tdherror(sts), sts); break; } } while (1); if (buffer != &providerEnumerationInfo) BufferFree(buffer); return sts; } TRACEHANDLE openTraceHandle(LPTSTR name) { TRACEHANDLE handle; EVENT_TRACE_LOGFILE traceMode; ZeroMemory(&traceMode, sizeof(EVENT_TRACE_LOGFILE)); traceMode.LoggerName = name; traceMode.BufferCallback = (PEVENT_TRACE_BUFFER_CALLBACK)BufferCallback; traceMode.EventRecordCallback = (PEVENT_RECORD_CALLBACK)ProcessEvent; traceMode.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME; handle = OpenTrace(&traceMode); if (handle == INVALID_PROCESSTRACE_HANDLE) { ULONG sts = GetLastError(); fprintf(stderr, "OpenTrace: %s (%lu)\n", tdherror(sts), sts); CloseTrace(handle); exit(1); } return handle; } static char *options = "k:v?"; static char usage[] = "Usage: %s [options] tracename\n\n" "Options:\n" " -k subsys kernel subsystem to trace\n" " -g use global sequence numbers\n" " -v verbose diagnostics (errors)\n"; int main(int argc, LPTSTR *argv) { BOOL useGlobalSequence = FALSE; TRACEHANDLE session; ULONG sts, sysFlags = 0; int c; while ((c = getopt(argc, argv, options)) != EOF) { switch (c) { case 'g': useGlobalSequence = TRUE; break; case 'k': sysFlags |= kernelTraceFlag(optarg); break; case 'v': verbose++; break; case '?': default: fprintf(stderr, usage, argv[0]); exit(1); } } if (sysFlags) { enableEventTrace(KERNEL_LOGGER_NAME, sizeof(KERNEL_LOGGER_NAME), &SystemTraceControlGuid, sysFlags, useGlobalSequence); session = openTraceHandle(KERNEL_LOGGER_NAME); } else { session = openTraceHandle(PCP_SESSION); } sts = ProcessTrace(&session, 1, NULL, NULL); if (sts == ERROR_CANCELLED) sts = ERROR_SUCCESS; if (sts != ERROR_SUCCESS) fprintf(stderr, "ProcessTrace: %s (%lu)\n", tdherror(sts), sts); return sts; } pcp-3.8.12ubuntu1/src/pmdas/etw/event.c0000664000000000000000000001612612272262501014567 0ustar /* * Event queue support for the ETW PMDA * * Copyright (c) 2011 Nathan Scott. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "event.h" #include "util.h" static struct { TRACEHANDLE session; EVENT_TRACE_PROPERTIES properties; EVENT_TRACE_LOGFILE tracemode; BOOL sequence; ULONG enabled; /* session stats */ ULONG buffer_count; ULONG buffer_size; ULONG buffer_bytes; ULONG buffer_reads; ULONG events_lost; } sys; ULONG WINAPI event_buffer_callback(PEVENT_TRACE_LOGFILE mode) { sys.buffer_count++; sys.buffer_size = mode->BufferSize; sys.buffer_reads += mode->BuffersRead; sys.buffer_bytes += mode->Filled; sys.events_lost += mode->EventsLost; return TRUE; } /* Difference in seconds between 1/1/1970 and 1/1/1601 */ #define EPOCH_DELTA_IN_MICROSEC 11644473600000000ULL static void event_decode_timestamp(PEVENT_RECORD event, struct timeval *tv) { FILETIME ft; /* 100-nanosecond intervals since 1/1/1601 */ ft.dwHighDateTime = event->EventHeader.TimeStamp.HighPart; ft.dwLowDateTime = event->EventHeader.TimeStamp.LowPart; __uint64_t tmp = 0; tmp |= ft.dwHighDateTime; tmp <<= 32; tmp |= ft.dwLowDateTime; tmp /= 10; /* convert to microseconds */ tmp -= EPOCH_DELTA_IN_MICROSEC; /* convert Win32 -> Unix epoch */ tv->tv_sec = tmp / 1000000UL; tv->tv_usec = tmp % 1000000UL; } void event_duplicate_record(PEVENT_RECORD source, PEVENT_RECORD target) { memcpy(source, target, sizeof(EVENT_RECORD)); } void event_duplicate_buffer(PEVENT_RECORD source, char *buffer, size_t *bytes) { PTRACE_EVENT_INFO pinfo = (PTRACE_EVENT_INFO)buffer; DWORD size = DEFAULT_MAXMEM, sts; sts = TdhGetEventInformation(source, 0, NULL, pinfo, &size); if (sts == ERROR_INSUFFICIENT_BUFFER) { *bytes = 0; /* too large for us, too bad, bail out */ } else { *bytes = size; } } /* * This is the main event callback routine. It uses a fixed * maximally sized buffer to capture and do minimal decoding * of the event, before passing it into a queue. Avoid any * memory allocation and/or copying here where possible, as * this is the event arrival fast path. * Note: if there are no clients, the queuing code will drop * this event (within pmdaEventQueueAppend), so don't waste * time here - basically just lookup the queue and dispatch. */ VOID WINAPI event_record_callback(PEVENT_RECORD event) { size_t bytes; struct timeval timestamp; struct { EVENT_RECORD record; char buffer[DEFAULT_MAXMEM]; } localevent; etw_event_t *entry; LPGUID guid = &event->EventHeader.ProviderId; int eventid = event->EventHeader.EventDescriptor.Id; int version = event->EventHeader.EventDescriptor.Version; if ((entry = event_table_lookup(guid, eventid, version)) != NULL) { event_decode_timestamp(event, ×tamp); event_duplicate_record(event, &localevent.record); event_duplicate_buffer(event, &localevent.buffer[0], &bytes); bytes += sizeof(EVENT_RECORD); event_queue_lock(entry); pmdaEventQueueAppend(entry->queueid, &localevent, bytes, ×tamp); event_queue_unlock(entry); } else { __pmNotifyErr(LOG_ERR, "failed to enqueue event %d:%d from provider %s", eventid, version, strguid(guid)); } } static void event_sys_setup(void) { ULONG size = sizeof(EVENT_TRACE_PROPERTIES) + sizeof(KERNEL_LOGGER_NAME); sys.properties.Wnode.BufferSize = size; sys.properties.Wnode.Flags = WNODE_FLAG_TRACED_GUID; sys.properties.Wnode.ClientContext = 1; sys.properties.Wnode.Guid = SystemTraceControlGuid; sys.properties.EnableFlags = sys.enabled; sys.properties.LogFileMode = EVENT_TRACE_REAL_TIME_MODE; if (sys.sequence) sys.properties.LogFileMode |= EVENT_TRACE_USE_GLOBAL_SEQUENCE; sys.properties.LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); sys.tracemode.LoggerName = KERNEL_LOGGER_NAME; sys.tracemode.BufferCallback = event_buffer_callback; sys.tracemode.EventRecordCallback = event_record_callback; sys.tracemode.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME; } /* Kernel tracing thread main() */ static DWORD WINAPI event_trace_sys(LPVOID ptr) { ULONG sts, retried = 0; TRACEHANDLE trace; retry_session: event_sys_setup(); sts = StartTrace(&sys.session, KERNEL_LOGGER_NAME, &sys.properties); if (sts != ERROR_SUCCESS) { if (retried) { __pmNotifyErr(LOG_ERR, "Cannot start session (in use)"); } else if (sts == ERROR_ALREADY_EXISTS) { __pmNotifyErr(LOG_WARNING, "%s session in use, retry.. (flags=%lx)", KERNEL_LOGGER_NAME, sys.enabled); sys.properties.EnableFlags = 0; ControlTrace(sys.session, KERNEL_LOGGER_NAME, &sys.properties, EVENT_TRACE_CONTROL_STOP); retried = 1; goto retry_session; } return sts; } trace = OpenTrace(&sys.tracemode); if (trace == INVALID_PROCESSTRACE_HANDLE) { sts = GetLastError(); __pmNotifyErr(LOG_ERR, "failed to open kernel trace: %s (%lu)", tdherror(sts), sts); return sts; } sts = ProcessTrace(&trace, 1, NULL, NULL); /* blocks, awaiting events */ if (sts == ERROR_CANCELLED) sts = ERROR_SUCCESS; if (sts != ERROR_SUCCESS) __pmNotifyErr(LOG_ERR, "failed to process kernel traces: %s (%lu)", tdherror(sts), sts); return sts; } void event_queue_lock(etw_event_t *entry) { WaitForSingleObject(entry->mutex, INFINITE); } void event_queue_unlock(etw_event_t *entry) { ReleaseMutex(entry->mutex); } int event_init(void) { HANDLE thread; __pmNotifyErr(LOG_INFO, "%s: Starting up tracing ...", __FUNCTION__); thread = CreateThread(NULL, 0, event_trace_sys, &sys, 0, NULL); if (thread == NULL) return -ECHILD; CloseHandle(thread); /* no longer need the handle */ return 0; } void __attribute__((constructor)) event_startup(void) { sys.session = INVALID_PROCESSTRACE_HANDLE; } void __attribute__((destructor)) event_shutdown(void) { __pmNotifyErr(LOG_INFO, "%s: Shutting down tracing ...", __FUNCTION__); if (sys.session != INVALID_PROCESSTRACE_HANDLE) { sys.properties.EnableFlags = 0; ControlTrace(sys.session, 0, &sys.properties, EVENT_TRACE_CONTROL_STOP); sys.session = INVALID_PROCESSTRACE_HANDLE; } } int event_decoder(int eventarray, void *buffer, size_t size, struct timeval *timestamp, void *data) { int sts; /* , handle = *(int *)data; */ pmAtomValue atom; pmID pmid = 0; /* TODO */ sts = pmdaEventAddRecord(eventarray, timestamp, PM_EVENT_FLAG_POINT); if (sts < 0) return sts; atom.cp = buffer; sts = pmdaEventAddParam(eventarray, pmid, PM_TYPE_STRING, &atom); if (sts < 0) return sts; return 1; /* simple decoder, added just one event array */ } pcp-3.8.12ubuntu1/src/pmdas/etw/help0000664000000000000000000000537412272262501014160 0ustar /* * Event Tracing for Windows PMDA * * Copyright (c) 2011 Nathan Scott. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ @ etw.kernel.process.start.count @ etw.kernel.process.start.records @ etw.kernel.process.start.numclients @ etw.kernel.process.start.queuemem @ etw.kernel.process.start.params.activityid @ etw.kernel.process.start.params.pid @ etw.kernel.process.start.params.parentid @ etw.kernel.process.start.params.starttime @ etw.kernel.process.start.params.session @ etw.kernel.process.start.params.image_name @ etw.kernel.process.exit.count @ etw.kernel.process.exit.numclients @ etw.kernel.process.exit.queuemem @ etw.kernel.process.exit.params.activityid @ etw.kernel.process.exit.params.pid @ etw.kernel.process.exit.params.parentid @ etw.kernel.process.exit.params.starttime @ etw.kernel.process.exit.params.exittime @ etw.kernel.process.exit.params.exitcode @ etw.kernel.process.exit.params.handle_count @ etw.kernel.process.exit.params.commit_charge @ etw.kernel.process.exit.params.commit_peak @ etw.kernel.process.exit.params.image_name @ etw.kernel.process.thread.start.count @ etw.kernel.process.thread.start.records @ etw.kernel.process.thread.start.numclients @ etw.kernel.process.thread.start.queuemem @ etw.kernel.process.thread.start.params.tid @ etw.kernel.process.thread.start.params.pid @ etw.kernel.process.thread.stop.count @ etw.kernel.process.thread.stop.records @ etw.kernel.process.thread.stop.numclients @ etw.kernel.process.thread.stop.queuemem @ etw.kernel.process.thread.stop.params.activityid @ etw.kernel.process.thread.stop.params.tid @ etw.kernel.process.thread.stop.params.pid @ etw.kernel.process.image_load.count @ etw.kernel.process.image_load.records @ etw.kernel.process.image_load.numclients @ etw.kernel.process.image_load.queuemem @ etw.kernel.process.image_load.params.activityid @ etw.kernel.process.image_load.params.pid @ etw.kernel.process.image_load.params.name @ etw.kernel.process.image_load.params.size @ etw.kernel.process.image_unload.count @ etw.kernel.process.image_unload.records @ etw.kernel.process.image_unload.numclients @ etw.kernel.process.image_unload.queuemem @ etw.kernel.process.image_unload.params.activityid @ etw.kernel.process.image_unload.params.pid @ etw.kernel.process.image_unload.params.name @ etw.kernel.process.image_unload.params.size pcp-3.8.12ubuntu1/src/pmdas/etw/event.h0000664000000000000000000000520212272262501014565 0ustar /* * Event queue support for the ETW PMDA * * Copyright (c) 2011 Nathan Scott. All rights reversed. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef _EVENT_H #define _EVENT_H #include "pmapi.h" #include "impl.h" #include "pmda.h" #include #include enum { CLUSTER_KERNEL_PROCESS = 0, CLUSTER_KERNEL_THREAD = 1, CLUSTER_KERNEL_IMAGE_LOAD = 2, CLUSTER_KERNEL_DISK_IO = 3, CLUSTER_KERNEL_DISK_FILE_IO = 4, CLUSTER_KERNEL_MEMORY_PAGE_FAULTS = 5, CLUSTER_KERNEL_MEMORY_HARD_FAULTS = 6, CLUSTER_KERNEL_NETWORK_TCPIP = 7, CLUSTER_KERNEL_REGISTRY = 8, CLUSTER_KERNEL_DBGPRINT = 9, CLUSTER_KERNEL_PROCESS_COUNTERS = 10, CLUSTER_KERNEL_CSWITCH = 11, CLUSTER_KERNEL_DPC = 12, CLUSTER_KERNEL_INTERRUPT = 13, CLUSTER_KERNEL_SYSTEMCALL = 14, CLUSTER_KERNEL_DISK_IO_INIT = 15, CLUSTER_KERNEL_ALPC = 16, CLUSTER_KERNEL_SPLIT_IO = 17, CLUSTER_KERNEL_DRIVER = 18, CLUSTER_KERNEL_PROFILE = 19, CLUSTER_KERNEL_FILE_IO = 20, CLUSTER_KERNEL_FILE_IO_INIT = 21, CLUSTER_KERNEL_DISPATCHER = 22, CLUSTER_KERNEL_VIRTUAL_ALLOC = 23, CLUSTER_KERNEL_EXTENSION = 24, CLUSTER_KERNEL_FORWARD_WMI = 25, CLUSTER_KERNEL_ENABLE_RESERVE = 26, CLUSTER_SQLSERVER_RPC_STARTING = 30, CLUSTER_SQLSERVER_BATCH_STARTING = 31, CLUSTER_CONFIGURATION = 250 }; enum { EVENT_PROCESS_START, EVENT_PROCESS_EXIT, EVENT_THREAD_START, EVENT_THREAD_STOP, EVENT_IMAGE_LOAD, EVENT_IMAGE_UNLOAD, }; #define DEFAULT_MAXMEM (128 * 1024) /* 128K per event queue */ typedef struct { int queueid; int eventid; int version; ULONG flags; HANDLE mutex; char pmnsname[64]; const GUID *provider; LPTSTR pname; ULONG plen; } etw_event_t; extern etw_event_t eventtab[]; extern int event_init(void); extern void event_shutdown(void); extern int event_decoder(int arrayid, void *buffer, size_t size, struct timeval *timestamp, void *data); extern etw_event_t *event_table_lookup(LPGUID guid, int eventid, int version); void event_queue_lock(etw_event_t *entry); void event_queue_unlock(etw_event_t *entry); #endif /* _EVENT_H */ pcp-3.8.12ubuntu1/src/pmval/0000775000000000000000000000000012272262620012512 5ustar pcp-3.8.12ubuntu1/src/pmval/GNUmakefile0000664000000000000000000000164512272262501014570 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmval.c LLDFLAGS = -L$(TOPDIR)/src/libpcp_gui/src LLDLIBS = $(PCP_GUILIB) $(LIB_FOR_MATH) CMDTARGET = pmval$(EXECSUFFIX) default: $(CMDTARGET) include $(BUILDRULES) install: $(CMDTARGET) $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmval/pmval.c0000664000000000000000000010531212272262501013775 0ustar /* * pmval - simple performance metrics value dumper * * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2008-2009 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "pmapi.h" #include "impl.h" #include "pmtime.h" /*************************************************************************** * constants ***************************************************************************/ #define ALL_SAMPLES -1 static char *options = "A:a:D:df:gh:i:K:n:O:p:rs:S:t:T:U:w:zZ:?"; static char usage[] = "Usage: %s [options] metricname\n\n" "Options:\n" " -A align align sample times on natural boundaries\n" " -a archive metrics source is a PCP log archive (interpolate values)\n" " -d delay, pause between updates for archive replay\n" " -f N fixed precision output format with N digits to the\n" " right of the decimal point\n" " -g start in GUI mode with new time control\n" " -h host metrics source is PMCD on host\n" " -i instance metric instance or list of instances - elements in an\n" " instance list are separated by commas or whitespace\n" " -K spec optional additional PMDA spec for local connection\n" " spec is of the form op,domain,dso-path,init-routine\n" " -n pmnsfile use an alternative PMNS\n" " -O offset initial offset into the time window\n" " -p port port number for connection to existing time control\n" " -r output raw counter values\n" " -S starttime start of the time window\n" " -s samples terminate after this many samples\n" " -T endtime end of the time window\n" " -t interval sample interval [default 1 second]\n" " -U archive metrics source is a PCP log archive (do not interpolate\n" " and -t option ignored)\n" " -w width set the width of each column of output\n" " -Z timezone set reporting timezone\n" " -z set reporting timezone to local time of metrics source\n"; /*************************************************************************** * type definitions ***************************************************************************/ /* instance id - instance name association */ typedef struct { int id; char *name; } InstPair; /* full description of a performance metric */ typedef struct { /* external (printable) description */ char *host; /* name of host */ char *metric; /* name of metric */ int iall; /* all instances */ int inum; /* number of instances */ char **inames; /* list of instance names */ /* internal description */ int handle; /* context handle */ pmID pmid; /* metric identifier */ pmDesc desc; /* metric description */ float scale; /* conversion factor for rate */ int *iids; /* list of instance ids */ /* internal-external association */ InstPair *ipairs; /* sorted array of id-name */ } Context; /*************************************************************************** * Globals ***************************************************************************/ static char *archive; static pmLogLabel label; static char *pmnsfile = PM_NS_DEFAULT; static char *rpt_tz; static char *rpt_tz_label; static int pauseFlag; static int raw; static int ahtype = PM_CONTEXT_HOST; /* archive or host? */ /* have previous sample, so could compute rate if required */ static int havePrev = 0; static int amode = PM_MODE_INTERP; /* archive scan mode */ static char local[] = "local:"; static int gui; static int rawarchive; static int port = -1; static pmTime *pmtime; static pmTimeControls controls; static struct timeval last = {INT_MAX, 999999}; /* end time for log */ static int fixed = -1; /*************************************************************************** * processing fetched values ***************************************************************************/ /* Compare two InstPair's on their id fields. - This function is passed as an argument to qsort, hence the ugly casts. */ static int /* -1 less, 0 equal, 1 greater */ compare(const void *pair1, const void *pair2) { if (((InstPair *)pair1)->id < ((InstPair *)pair2)->id) return -1; if (((InstPair *)pair1)->id > ((InstPair *)pair2)->id) return 1; return 0; } /* Does the Context have names for all instances in the pmValueSet? */ static int /* 1 yes, 0 no */ chkinsts(Context *x, pmValueSet *vs) { int i, j; if (x->desc.indom == PM_INDOM_NULL) return 1; for (i = 0; i < vs->numval; i++) { for (j = 0; j < x->inum; j++) { if (vs->vlist[i].inst == x->ipairs[j].id) break; } if (j == x->inum) return 0; } return 1; } /*************************************************************************** * interface to performance metrics API ***************************************************************************/ /* Fill in current instances into given Context. Instances sorted by instance identifier. */ static void initinsts(Context *x) { int *ip; char **np; InstPair *pp; int n; int e; int i; if (x->desc.indom == PM_INDOM_NULL) x->inum = 0; else { /* fill in instance ids for given profile */ if (! x->iall) { n = x->inum; np = x->inames; ip = (int *)malloc(n * sizeof(int)); if (ip == NULL) { __pmNoMem("pmval.ip", n * sizeof(int), PM_FATAL_ERR); } x->iids = ip; for (i = 0; i < n; i++) { if (ahtype == PM_CONTEXT_ARCHIVE) e = pmLookupInDomArchive(x->desc.indom, *np); else e = pmLookupInDom(x->desc.indom, *np); if (e < 0) { printf("%s: instance %s not available\n", pmProgname, *np); exit(EXIT_FAILURE); } *ip = e; np++; ip++; } ip = x->iids; np = x->inames; if ((e = pmAddProfile(x->desc.indom, x->inum, x->iids)) < 0) { fprintf(stderr, "%s: pmAddProfile: %s\n", pmProgname, pmErrStr(e)); exit(EXIT_FAILURE); } } /* find all available instances */ else { if (ahtype == PM_CONTEXT_ARCHIVE) n = pmGetInDomArchive(x->desc.indom, &ip, &np); else n = pmGetInDom(x->desc.indom, &ip, &np); if (n < 0) { fprintf(stderr, "%s: pmGetInDom(%s): %s\n", pmProgname, pmInDomStr(x->desc.indom), pmErrStr(n)); exit(EXIT_FAILURE); } x->inum = n; x->iids = ip; x->inames = np; } /* build InstPair list and sort */ pp = (InstPair *)malloc(n * sizeof(InstPair)); if (pp == NULL) { __pmNoMem("pmval.pp", n * sizeof(InstPair), PM_FATAL_ERR); } x->ipairs = pp; for (i = 0; i < n; i++) { pp->id = *ip; pp->name = *np; ip++; np++; pp++; } qsort(x->ipairs, (size_t)n, sizeof(InstPair), compare); } } /* Initialize API and fill in internal description for given Context. */ static void initapi(Context *x) { int e; x->handle = pmWhichContext(); if (pmnsfile != PM_NS_DEFAULT) { if ((e = pmLoadNameSpace(pmnsfile)) < 0) { fprintf(stderr, "%s: pmLoadNameSpace: %s\n", pmProgname, pmErrStr(e)); exit(EXIT_FAILURE); } } if ((e = pmLookupName(1, &(x->metric), &(x->pmid))) < 0) { fprintf(stderr, "%s: pmLookupName(%s): %s\n", pmProgname, x->metric, pmErrStr(e)); exit(EXIT_FAILURE); } if ((e = pmLookupDesc(x->pmid, &(x->desc))) < 0) { fprintf(stderr, "%s: pmLookupDesc: %s\n", pmProgname, pmErrStr(e)); exit(EXIT_FAILURE); } if (x->desc.sem == PM_SEM_COUNTER) { if (x->desc.units.dimTime == 0) x->scale = 1.0; else { if (x->desc.units.scaleTime > PM_TIME_SEC) x->scale = pow(60, (PM_TIME_SEC - x->desc.units.scaleTime)); else x->scale = pow(1000, (PM_TIME_SEC - x->desc.units.scaleTime)); } } } /* Fetch metric values. */ static int getvals(Context *x, /* in - full pm description */ pmResult **vs) /* alloc - pm values */ { pmResult *r; int e; int i; if (rawarchive) { /* * for -U mode, read until we find either a pmResult with the * pmid we are after, or a mark record */ for ( ; ; ) { e = pmFetchArchive(&r); if (e < 0) break; if (r->numpmid == 0) { if (gui || archive != NULL) __pmPrintStamp(stdout, &r->timestamp); printf(" Archive logging suspended\n"); pmFreeResult(r); return -1; } for (i = 0; i < r->numpmid; i++) { if (r->vset[i]->pmid == x->pmid) break; } if (i != r->numpmid) break; pmFreeResult(r); } } else { e = pmFetch(1, &(x->pmid), &r); i = 0; } if (e < 0) { if (e == PM_ERR_EOL && gui) { pmTimeStateBounds(&controls, pmtime); return -1; } if (rawarchive) fprintf(stderr, "\n%s: pmFetchArchive: %s\n", pmProgname, pmErrStr(e)); else fprintf(stderr, "\n%s: pmFetch: %s\n", pmProgname, pmErrStr(e)); exit(EXIT_FAILURE); } if (gui) pmTimeStateAck(&controls, pmtime); if ((double)r->timestamp.tv_sec + (double)r->timestamp.tv_usec/1000000 > (double)last.tv_sec + (double)last.tv_usec/1000000) { pmFreeResult(r); return -2; } if (r->vset[i]->numval == 0) { if (gui || archive != NULL) { __pmPrintStamp(stdout, &r->timestamp); printf(" "); } printf("No values available\n"); pmFreeResult(r); return -1; } else if (r->vset[i]->numval < 0) { if (rawarchive) fprintf(stderr, "\n%s: pmFetchArchive: %s\n", pmProgname, pmErrStr(r->vset[i]->numval)); else fprintf(stderr, "\n%s: pmFetch: %s\n", pmProgname, pmErrStr(r->vset[i]->numval)); pmFreeResult(r); return -1; } *vs = r; qsort(r->vset[i]->vlist, (size_t)r->vset[i]->numval, sizeof(pmValue), compare); return i; } static void timestep(struct timeval delta) { /* time moved, may need to wait for previous value again */ havePrev = 0; } /*************************************************************************** * output ***************************************************************************/ /* How many print positions required for value of given type? */ static int howide(int type) { switch (type) { case PM_TYPE_32: return 11; case PM_TYPE_U32: return 11; case PM_TYPE_64: return 21; case PM_TYPE_U64: return 21; case PM_TYPE_FLOAT: return 13; case PM_TYPE_DOUBLE: return 21; case PM_TYPE_STRING: return 21; case PM_TYPE_AGGREGATE: return 21; default: fprintf(stderr, "pmval: unknown performance metric value type %s\n", pmTypeStr(type)); exit(EXIT_FAILURE); } } /* Print parameter values as output header. */ static void printhdr(Context *x, long smpls, struct timeval delta, struct timeval first) { pmUnits units; char tbfr[26]; const char *u; /* metric name */ printf("metric: %s\n", x->metric); /* live host */ if (archive == NULL) printf("host: %s\n", pmGetContextHostName(x->handle)); /* archive */ else { printf("archive: %s\n", archive); printf("host: %s\n", label.ll_hostname); printf("start: %s", pmCtime(&first.tv_sec, tbfr)); if (last.tv_sec != INT_MAX) printf("end: %s", pmCtime(&last.tv_sec, tbfr)); } /* semantics */ printf("semantics: "); switch (x->desc.sem) { case PM_SEM_COUNTER: printf("cumulative counter"); if (! raw) printf(" (converting to rate)"); break; case PM_SEM_INSTANT: printf("instantaneous value"); break; case PM_SEM_DISCRETE: printf("discrete instantaneous value"); break; default: printf("unknown"); } putchar('\n'); /* units */ units = x->desc.units; u = pmUnitsStr(&units); printf("units: %s", *u == '\0' ? "none" : u); if ((! raw) && (x->desc.sem == PM_SEM_COUNTER)) { printf(" (converting to "); if (units.dimTime == 0) units.scaleTime = PM_TIME_SEC; units.dimTime--; if ((units.dimSpace == 0) && (units.dimTime == 0) && (units.dimCount == 0)) printf("time utilization)"); else { u = pmUnitsStr(&units); printf("%s)", *u == '\0' ? "none" : u); } } putchar('\n'); /* sample count and interval */ if (smpls == ALL_SAMPLES) printf("samples: all\n"); else printf("samples: %ld\n", smpls); if (smpls != ALL_SAMPLES && smpls > 1 && (ahtype != PM_CONTEXT_ARCHIVE || amode == PM_MODE_INTERP)) printf("interval: %1.2f sec\n", __pmtimevalToReal(&delta)); } /* Print instance identifier names as column labels. */ static void printlabels(Context *x, int cols) { int n = x->inum; InstPair *pairs = x->ipairs; int i; static int style = -1; if (style == -1) { InstPair *ip = pairs; style = 0; for (i = 0; i < n; i++) { if (strlen(ip->name) > cols) { style = 2; /* too wide */ break; } if (strlen(ip->name) > cols-3) style = 1; /* wide enough to change shift */ ip++; } if (style == 2) { ip = pairs; for (i = 0; i < n; i++) { printf("full label for instance[%d]: %s\n", i, ip->name); ip++; } } } putchar('\n'); for (i = 0; i < n; i++) { if ((gui || archive != NULL) && i == 0) printf(" "); if (raw || (x->desc.sem != PM_SEM_COUNTER) || style != 0) printf("%*.*s ", cols, cols, pairs->name); else { if (fixed == -1) { /* shift left by 3 places for decimal points in rate */ printf("%*.*s ", cols-3, cols-3, pairs->name); } else { /* no shift for fixed format */ printf("%*.*s ", cols, cols, pairs->name); } } pairs++; } if (n > 0) putchar('\n'); } void printreal(double v, int minwidth) { char *fmt; /* * <-- minwidth --> * xxxxxxxxxxxxxxxxx * ! no value * x.xxxE-xx < 0.1 * 0.0___ 0 * x.xxxx 0.1 ... 0.9999 * x.xxx_ 1 ... 9.999 * xx.xx__ 10 ... 99.99 * xxx.x___ 100 ... 999.9 * xxxx.____ 1000 ... 9999 * x.xxxE+xx > 9999 */ if (fixed != -1) { printf("%*.*f", minwidth, fixed, v); } else { if (v < 0.0) printf("%*s", minwidth, "!"); else { if (v == 0) { fmt = "%*.0f.0 "; minwidth -= 5; } else if (v < 0.1 || v > 9999) fmt = "%*.3E"; else if (v <= 0.9999) fmt = "%*.4f"; else if (v <= 9.999) { fmt = "%*.3f "; minwidth -= 1; } else if (v <= 99.99) { fmt = "%*.2f "; minwidth -= 2; } else if (v <= 999.9) { fmt = "%*.1f "; minwidth -= 3; } else { fmt = "%*.0f. "; minwidth -= 5; } printf(fmt, minwidth, v); } } } /* Print performance metric values */ static void printvals(Context *x, pmValueSet *vset, int cols) { int i, j; pmAtomValue av; int doreal = 0; if (x->desc.type == PM_TYPE_FLOAT || x->desc.type == PM_TYPE_DOUBLE) doreal = 1; /* null instance domain */ if (x->desc.indom == PM_INDOM_NULL) { if (vset->numval == 1) { if (doreal) { pmExtractValue(vset->valfmt, &vset->vlist[0], x->desc.type, &av, PM_TYPE_DOUBLE); printreal(av.d, cols); } else pmPrintValue(stdout, vset->valfmt, x->desc.type, &vset->vlist[0], cols); } else printf("%*s", cols, "?"); putchar('\n'); } /* non-null instance domain */ else { for (i = 0; i < x->inum; i++) { for (j = 0; j < vset->numval; j++) { if (vset->vlist[j].inst == x->ipairs[i].id) break; } if (j < vset->numval) { if (doreal) { pmExtractValue(vset->valfmt, &vset->vlist[j], x->desc.type, &av, PM_TYPE_DOUBLE); printreal(av.d, cols); } else pmPrintValue(stdout, vset->valfmt, x->desc.type, &vset->vlist[j], cols); } else printf("%*s", cols, "?"); putchar(' '); } putchar('\n'); for (j = 0; j < vset->numval; j++) { for (i = 0; i < x->inum; i++) { if (vset->vlist[j].inst == x->ipairs[i].id) break; } if (x->iall == 1 && i == x->inum) { printf("Warning: value="); if (doreal) { pmExtractValue(vset->valfmt, &vset->vlist[j], x->desc.type, &av, PM_TYPE_DOUBLE); printreal(av.d, 1); } else pmPrintValue(stdout, vset->valfmt, x->desc.type, &vset->vlist[j], 1); printf(", but instance=%d is unknown\n", vset->vlist[j].inst); } } } } /* print single performance metric rate value */ static void printrate(int valfmt, /* from pmValueSet */ int type, /* from pmDesc */ pmValue *val1, /* current value */ pmValue *val2, /* previous value */ double delta, /* time difference between samples */ int minwidth) /* output is at least this wide */ { pmAtomValue a, b; double v; static int dowrap = -1; pmExtractValue(valfmt, val1, type, &a, PM_TYPE_DOUBLE); pmExtractValue(valfmt, val2, type, &b, PM_TYPE_DOUBLE); v = a.d - b.d; if (v < 0.0) { if (dowrap == -1) { /* PCP_COUNTER_WRAP in environment enables "counter wrap" logic */ if (getenv("PCP_COUNTER_WRAP") == NULL) dowrap = 0; else dowrap = 1; } if (dowrap) { switch (type) { case PM_TYPE_32: case PM_TYPE_U32: v += (double)UINT_MAX+1; break; case PM_TYPE_64: case PM_TYPE_U64: v += (double)ULONGLONG_MAX+1; break; } } } v /= delta; printreal(v, minwidth); } /* Print performance metric rates */ static void printrates(Context *x, pmValueSet *vset1, struct timeval stamp1, /* current values */ pmValueSet *vset2, struct timeval stamp2, /* previous values */ int cols) { int i, j; double delta; /* compute delta from timestamps and convert units */ delta = x->scale * (__pmtimevalToReal(&stamp1) - __pmtimevalToReal(&stamp2)); /* null instance domain */ if (x->desc.indom == PM_INDOM_NULL) { if ((vset1->numval == 1) && (vset2->numval == 1)) printrate(vset1->valfmt, x->desc.type, &vset1->vlist[0], &vset2->vlist[0], delta, cols); else printf("%*s", cols, "?"); putchar('\n'); } /* non-null instance domain */ else { for (i = 0; i < x->inum; i++) { for (j = 0; j < vset1->numval; j++) { if (vset1->vlist[j].inst == x->ipairs[i].id) break; } if ((j < vset1->numval) && (j < vset2->numval) && (vset1->vlist[j].inst == vset2->vlist[j].inst)) printrate(vset1->valfmt, x->desc.type, &vset1->vlist[j], &vset2->vlist[j], delta, cols); else printf("%*s", cols, "?"); putchar(' '); } putchar('\n'); for (j = 0; j < vset1->numval; j++) { for (i = 0; i < x->inum; i++) { if (vset1->vlist[j].inst == x->ipairs[i].id) break; } if (x->iall == 1 && i == x->inum && j < vset2->numval && vset1->vlist[j].inst == vset2->vlist[j].inst) { printf("Warning: value="); printrate(vset1->valfmt, x->desc.type, &vset1->vlist[j], &vset2->vlist[j], delta, 1); printf(", but instance=%d is unknown\n", vset1->vlist[j].inst); } } } } /*************************************************************************** * command line processing ***************************************************************************/ #define WHITESPACE ", \t\n" static int isany(char *p, char *set) { if (p != NULL && *p) { while (*set) { if (*p == *set) return 1; set++; } } return 0; } /* * like strtok, but smarter */ static char * getinstance(char *p) { static char *save; char quot; char *q; char *start; if (p == NULL) q = save; else q = p; while (isany(q, WHITESPACE)) q++; if (*q == '\0') return NULL; else if (*q == '"' || *q == '\'') { quot = *q; start = ++q; while (*q && *q != quot) q++; if (*q == quot) *q++ = '\0'; } else { start = q; while (*q && !isany(q, WHITESPACE)) q++; } if (*q) *q++ = '\0'; save = q; return start; } /* extract command line arguments - exits on error */ static void getargs(int argc, /* in - command line argument count */ char *argv[], /* in - argument strings */ Context *cntxt, /* out - full pm description */ struct timeval *posn, /* out - first sample time */ struct timeval *delta, /* out - sample interval */ long *smpls, /* out - number of samples */ int *cols) /* out - output column width */ { int c; char *subopt; long d; int errflag = 0; int i; int src = 0; char *host = local; int sts; char *endnum; char *errmsg; char *Sflag = NULL; /* argument of -S flag */ char *Tflag = NULL; /* argument of -T flag */ char *Aflag = NULL; /* argument of -A flag */ char *Oflag = NULL; /* argument of -O flag */ int zflag = 0; /* for -z */ char *tz = NULL; /* for -Z timezone */ int tzh; /* initial timezone handle */ struct timeval logStart; struct timeval first; pmMetricSpec *msp; char *msg; /* fill in default values */ cntxt->iall = 1; delta->tv_sec = 1; *smpls = ALL_SAMPLES; *cols = 0; /* extract command-line arguments */ while ((c = getopt(argc, argv, options)) != EOF) { switch (c) { case 'A': /* sample alignment */ Aflag = optarg; break; case 'a': /* interpolate archive */ if (++src > 1) { fprintf(stderr, "%s: at most one of -a and -h allowed\n", pmProgname); errflag++; } ahtype = PM_CONTEXT_ARCHIVE; archive = optarg; break; case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case 'd': pauseFlag = 1; break; case 'f': /* fixed format count */ d = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0' || d < 0) { fprintf(stderr, "%s: -f requires +ve numeric argument\n", pmProgname); errflag++; } fixed = d; break; case 'g': gui = 1; break; case 'h': /* host name */ if (++src > 1) { fprintf(stderr, "%s: at most one of -a and -h allowed\n", pmProgname); errflag++; } cntxt->host = host = optarg; break; case 'i': /* instance names */ cntxt->iall = 0; i = cntxt->inum; subopt = getinstance(optarg); while (subopt != NULL) { i++; cntxt->inames = (char **)realloc(cntxt->inames, i * (sizeof (char *))); if (cntxt->inames == NULL) { __pmNoMem("pmval.ip", i * sizeof(char *), PM_FATAL_ERR); } *(cntxt->inames + i - 1) = subopt; subopt = getinstance(NULL); } cntxt->inum = i; break; case 'K': /* update local PMDA table */ if ((errmsg = __pmSpecLocalPMDA(optarg)) != NULL) { fprintf(stderr, "%s: __pmSpecLocalPMDA failed\n%s\n", pmProgname, errmsg); errflag++; } break; case 'n': /* alternative name space file */ pmnsfile = optarg; break; case 'O': /* sample offset */ Oflag = optarg; break; case 'p': /* port for slave of existing time control */ port = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0' || port < 0) { fprintf(stderr, "%s: Error: invalid pmtime port \"%s\": %s\n", pmProgname, optarg, pmErrStr(-oserror())); errflag++; } break; case 'r': /* raw */ raw = 1; break; case 's': /* sample count */ d = (int)strtol(optarg, &endnum, 10); if (Tflag) { fprintf(stderr, "%s: at most one of -s and -T allowed\n", pmProgname); errflag++; } else if (*endnum != '\0' || d < 0) { fprintf(stderr, "%s: -s requires +ve numeric argument\n", pmProgname); errflag++; } else *smpls = d; break; case 'S': /* start run time */ Sflag = optarg; break; case 't': /* sampling interval */ if (pmParseInterval(optarg, delta, &msg) < 0) { fputs(msg, stderr); free(msg); errflag++; } break; case 'T': /* run time */ if (*smpls != ALL_SAMPLES) { fprintf(stderr, "%s: at most one of -T and -s allowed\n", pmProgname); errflag++; } Tflag = optarg; break; case 'U': /* non-interpolated archive (undocumented) */ if (++src > 1) { fprintf(stderr, "%s: at most one of -a, -h and -U allowed\n", pmProgname); errflag++; } ahtype = PM_CONTEXT_ARCHIVE; amode = PM_MODE_FORW; archive = optarg; rawarchive = 1; break; case 'w': /* output column width */ setoserror(0); d = atol(optarg); if (oserror() || d < 1) errflag++; else *cols = d; break; case 'z': /* timezone from host */ if (tz != NULL) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); errflag++; } zflag++; break; case 'Z': /* $TZ timezone */ if (zflag) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); errflag++; } tz = optarg; break; case '?': fprintf(stderr, usage, pmProgname); exit(EXIT_FAILURE); default: errflag++; } } /* parse uniform metric spec */ if (optind >= argc) { fprintf(stderr, "Error: no metricname specified\n\n"); errflag++; } else if (optind < argc-1) { fprintf(stderr, "Error: pmval can only process one metricname at a time\n\n"); errflag++; } else { if (ahtype == PM_CONTEXT_HOST) { if (pmParseMetricSpec(argv[optind], 0, host, &msp, &msg) < 0) { fputs(msg, stderr); free(msg); errflag++; } } else { /* must be archive */ if (pmParseMetricSpec(argv[optind], 1, archive, &msp, &msg) < 0) { fputs(msg, stderr); free(msg); errflag++; } } } if (errflag) { fprintf(stderr, usage, pmProgname); exit(EXIT_FAILURE); } if (msp->isarch == 1) { archive = msp->source; ahtype = PM_CONTEXT_ARCHIVE; } else if (msp->isarch == 2) { ahtype = PM_CONTEXT_LOCAL; } if (ahtype != PM_CONTEXT_ARCHIVE) { if (pauseFlag) { fprintf(stderr, "%s: -d can only be used with -a\n", pmProgname); errflag++; } } else { if (gui == 1 && port != -1) { fprintf(stderr, "%s: -g cannot be used with -p\n", pmProgname); errflag++; } if (gui == 1 && pauseFlag) { fprintf(stderr, "%s: -g cannot be used with -d\n", pmProgname); errflag++; } } if (errflag) { fprintf(stderr, usage, pmProgname); exit(EXIT_FAILURE); } cntxt->metric = msp->metric; if (msp->ninst > 0) { cntxt->inum = msp->ninst; cntxt->iall = (cntxt->inum == 0); cntxt->inames = &msp->inst[0]; } if (msp->isarch == 1) { /* open connection to archive */ if ((sts = pmNewContext(PM_CONTEXT_ARCHIVE, msp->source)) < 0) { fprintf(stderr, "%s: Cannot open archive \"%s\": %s\n", pmProgname, msp->source, pmErrStr(sts)); exit(EXIT_FAILURE); } if ((sts = pmGetArchiveLabel(&label)) < 0) { fprintf(stderr, "%s: Cannot get archive label record: %s\n", pmProgname, pmErrStr(sts)); exit(EXIT_FAILURE); } logStart = label.ll_start; if ((sts = pmGetArchiveEnd(&last)) < 0) { fprintf(stderr, "%s: Cannot determine end of archive: %s", pmProgname, pmErrStr(sts)); exit(EXIT_FAILURE); } } else { /* open connection to host or local context */ if ((sts = pmNewContext(ahtype, msp->source)) < 0) { if (ahtype == PM_CONTEXT_HOST) fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", pmProgname, msp->source, pmErrStr(sts)); else fprintf(stderr, "%s: Cannot establish local context: %s\n", pmProgname, pmErrStr(sts)); exit(EXIT_FAILURE); } cntxt->host = msp->source; __pmtimevalNow(&logStart); } if (zflag) { if ((tzh = pmNewContextZone()) < 0) { fprintf(stderr, "%s: Cannot set context timezone: %s\n", pmProgname, pmErrStr(tzh)); exit(EXIT_FAILURE); } if (ahtype == PM_CONTEXT_ARCHIVE) { printf("Note: timezone set to local timezone of host \"%s\" from archive\n\n", label.ll_hostname); rpt_tz_label = label.ll_hostname; } else { printf("Note: timezone set to local timezone of host \"%s\"\n\n", host); rpt_tz_label = host; } } else if (tz != NULL) { if ((tzh = pmNewZone(tz)) < 0) { fprintf(stderr, "%s: Cannot set timezone to \"%s\": %s\n", pmProgname, tz, pmErrStr(tzh)); exit(EXIT_FAILURE); } printf("Note: timezone set to \"TZ=%s\"\n\n", tz); } else printf("\n"); pmWhichZone(&rpt_tz); if (!rpt_tz_label) rpt_tz_label = local; if (pmParseTimeWindow(Sflag, Tflag, Aflag, Oflag, &logStart, &last, &first, &last, posn, &msg) < 0) { fprintf(stderr, "%s", msg); free(msg); exit(EXIT_FAILURE); } initapi(cntxt); initinsts(cntxt); if (!(gui || port != -1) && *smpls == ALL_SAMPLES && last.tv_sec != INT_MAX && amode != PM_MODE_FORW) { *smpls = (long)((__pmtimevalToReal(&last) - __pmtimevalToReal(posn)) / __pmtimevalToReal(delta)); if (*smpls < 0) /* if end is before start, no samples thanks */ *smpls = 0; else { /* * p stands for posn * + p + p+delta + p+2*delta + p+3*delta + last * | | | | | | * +-----------+-----------+-----------+-- ...... ----+---+---> time * 1 2 3 smpls * * So we will perform smpls+1 fetches ... the number of reported * values cannot be determined as it is usually (but not always * thanks to interpolation mode in archives) one less for * PM_SEM_COUNTER metrics. * * samples: as reported in the header output is the number * of fetches to be attempted. */ (*smpls)++; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { char tbfr[26]; char *tp; fprintf(stderr, "getargs: first=%.6f", __pmtimevalToReal(&first)); tp = pmCtime(&first.tv_sec, tbfr); /* * tp -> Ddd Mmm DD HH:MM:SS YYYY\n * 0 4 8 1 1 2 2 2 * 1 8 0 3 4 */ fprintf(stderr, "[%8.8s]\n", &tp[11]); fprintf(stderr, "getargs: posn=%.6f", __pmtimevalToReal(posn)); tp = pmCtime(&posn->tv_sec, tbfr); fprintf(stderr, "[%8.8s]\n", &tp[11]); fprintf(stderr, "getargs: last=%.6f", __pmtimevalToReal(&last)); tp = pmCtime(&last.tv_sec, tbfr); fprintf(stderr, "[%8.8s]\n", &tp[11]); fprintf(stderr, "getargs: delta=%.6f samples=%ld\n", __pmtimevalToReal(delta), *smpls); } #endif } if (gui || port != -1) { /* set up pmtime control */ pmtime = pmTimeStateSetup(&controls, ahtype, port, *delta, *posn, first, last, rpt_tz, rpt_tz_label); controls.stepped = timestep; gui = 1; /* we're using pmtime control from here on */ } else if (ahtype == PM_CONTEXT_ARCHIVE) /* no time control, go it alone */ pmTimeStateMode(amode, *delta, posn); } /*************************************************************************** * main ***************************************************************************/ int main(int argc, char *argv[]) { struct timeval delta = { 0 }; /* sample interval */ long smpls; /* number of samples */ int cols; /* width of output column */ struct timeval now = { 0 }; /* current task start time */ Context cntxt = { 0 }; /* performance metric description */ pmResult *rslt1; /* current values */ pmResult *rslt2; /* previous values */ int forever; int idx1; int idx2 = 0; /* initialize to pander to gcc */ int no_values = 0; __pmSetProgname(argv[0]); setlinebuf(stdout); getargs(argc, argv, &cntxt, &now, &delta, &smpls, &cols); if (cntxt.desc.type == PM_TYPE_EVENT) { fprintf(stderr, "%s: Cannot display values for PM_TYPE_EVENT metrics\n", pmProgname); exit(EXIT_FAILURE); } forever = (smpls == ALL_SAMPLES || gui); if (cols <= 0) cols = howide(cntxt.desc.type); if ((fixed == 0 && fixed > cols) || (fixed > 0 && fixed > cols - 2)) { fprintf(stderr, "%s: -f %d too large for column width %d\n", pmProgname, fixed, cols); exit(EXIT_FAILURE); } printhdr(&cntxt, smpls, delta, now); /* wait till time for first sample */ if (archive == NULL) __pmtimevalPause(now); /* main loop fetching and printing sample values */ while (forever || (smpls-- > 0)) { if (gui) pmTimeStateVector(&controls, pmtime); if (havePrev == 0) { /* * We don't yet have a value at the previous time point ... * save this value so we can use it to compute the rate if * the metric has counter semantics and we're doing rate * conversion. */ if ((idx2 = getvals(&cntxt, &rslt2)) >= 0) { /* previous value success */ havePrev = 1; if (cntxt.desc.indom != PM_INDOM_NULL) printlabels(&cntxt, cols); if (raw || (cntxt.desc.sem != PM_SEM_COUNTER)) { /* not doing rate conversion, report this value immediately */ if (gui || archive != NULL) __pmPrintStamp(stdout, &rslt2->timestamp); printvals(&cntxt, rslt2->vset[idx2], cols); continue; } else if (no_values) { if (gui || archive != NULL) { __pmPrintStamp(stdout, &rslt2->timestamp); printf(" "); } printf("No values available\n"); } no_values = 0; if (gui) /* pmtime controls timing */ continue; } else if (idx2 == -2) /* out the end of the window */ break; else no_values = 1; } /* wait till time for sample */ if (!gui && (pauseFlag || archive == NULL)) __pmtimevalSleep(delta); if (havePrev == 0) continue; /* keep trying to get the previous sample */ /* next sample */ if ((idx1 = getvals(&cntxt, &rslt1)) == -2) /* out the end of the window */ break; else if (idx1 < 0) { /* * Fall back to trying to get an initial sample because * although we got the previous sample, we failed to get the * next sample. */ havePrev = 0; continue; } /* refresh instance names */ if (cntxt.iall && ! chkinsts(&cntxt, rslt1->vset[idx1])) { free(cntxt.iids); if (cntxt.iall) free(cntxt.inames); free(cntxt.ipairs); initinsts(&cntxt); printlabels(&cntxt, cols); } /* print values */ if (gui || archive != NULL) __pmPrintStamp(stdout, &rslt1->timestamp); if (raw || (cntxt.desc.sem != PM_SEM_COUNTER)) printvals(&cntxt, rslt1->vset[idx1], cols); else printrates(&cntxt, rslt1->vset[idx1], rslt1->timestamp, rslt2->vset[idx2], rslt2->timestamp, cols); /* * discard previous and save current result, so this value * becomes the previous value at the next iteration */ pmFreeResult(rslt2); rslt2 = rslt1; idx2 = idx1; } /* * All serious error conditions have explicit exit() calls, so * if we get this far, all has gone well. */ return 0; } pcp-3.8.12ubuntu1/src/pminfo/0000775000000000000000000000000012272262620012663 5ustar pcp-3.8.12ubuntu1/src/pminfo/GNUmakefile0000664000000000000000000000154612272262501014741 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pminfo.c CMDTARGET = pminfo$(EXECSUFFIX) LLDLIBS = $(PCPLIB) default : $(CMDTARGET) include $(BUILDRULES) install : default $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pminfo/pminfo.c0000664000000000000000000004545312272262501014330 0ustar /* * Copyright (c) 2013 Red Hat. * Copyright (c) 1995-2001,2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include static int p_mid; /* Print metric IDs of leaf nodes */ static int p_fullmid; /* Print verbose metric IDs of leaf nodes */ static int p_desc; /* Print descriptions for metrics */ static int verify; /* Only print error messages */ static int p_oneline; /* fetch oneline text? */ static int p_help; /* fetch help text? */ static int p_value; /* pmFetch and print value(s)? */ static int p_force; /* pmFetch and print value(s)? for non-enumerable indoms too */ static int need_context; /* set if need a pmapi context */ static int need_pmid; /* set if need to lookup names */ static int type; static char *hostname; static char *pmnsfile = PM_NS_DEFAULT; static int dupok = 0; static char **namelist; static pmID *pmidlist; static int batchsize = 20; static int batchidx; static char *Oflag; /* argument of -O flag */ static int xflag; /* for -x */ static int zflag; /* for -z */ static char *tz; /* for -Z timezone */ static struct timeval start; /* start of time window */ static void myeventdump(pmValueSet *, int); /* * stolen from pmprobe.c ... cache all of the most recently requested * pmInDom ... */ static char * lookup(pmInDom indom, int inst) { static pmInDom last = PM_INDOM_NULL; static int numinst = -1; static int *instlist; static char **namelist; int i; if (indom != last) { if (numinst > 0) { free(instlist); free(namelist); } numinst = pmGetInDom(indom, &instlist, &namelist); last = indom; } for (i = 0; i < numinst; i++) { if (instlist[i] == inst) return namelist[i]; } return NULL; } /* * we only ever have one metric */ static void mydump(pmDesc *dp, pmValueSet *vsp, char *indent) { int j; char *p; if (indent != NULL) printf("%s", indent); if (vsp->numval == 0) { printf("No value(s) available!\n"); return; } else if (vsp->numval < 0) { printf("Error: %s\n", pmErrStr(vsp->numval)); return; } for (j = 0; j < vsp->numval; j++) { pmValue *vp = &vsp->vlist[j]; if (dp->indom != PM_INDOM_NULL) { if ((p = lookup(dp->indom, vp->inst)) == NULL) { if (p_force) { /* the instance disappeared; ignore it */ printf(" inst [%d \"%s\"]\n", vp->inst, "DISAPPEARED"); continue; } else { /* report the error and give up */ printf("pmNameIndom: indom=%s inst=%d: %s\n", pmInDomStr(dp->indom), vp->inst, pmErrStr(PM_ERR_INST)); printf(" inst [%d]", vp->inst); } } else printf(" inst [%d or \"%s\"]", vp->inst, p); } else printf(" "); printf(" value "); pmPrintValue(stdout, vsp->valfmt, dp->type, vp, 1); putchar('\n'); if (dp->type == PM_TYPE_EVENT && xflag) myeventdump(vsp, j); } } static void myeventdump(pmValueSet *vsp, int inst) { int r; /* event records */ int p; /* event parameters */ int nrecords; int flags; pmResult **res; static pmID pmid_flags; static pmID pmid_missed; nrecords = pmUnpackEventRecords(vsp, inst, &res); if (nrecords < 0) { fprintf(stderr, "pmUnpackEventRecords: %s\n", pmErrStr(nrecords)); return; } if (pmid_flags == 0) { /* * get PMID for event.flags and event.missed * note that pmUnpackEventRecords() will have called * __pmRegisterAnon(), so the anonymous metrics * should now be in the PMNS */ char *name_flags = "event.flags"; char *name_missed = "event.missed"; int sts; sts = pmLookupName(1, &name_flags, &pmid_flags); if (sts < 0) { /* should not happen! */ fprintf(stderr, "Warning: cannot get PMID for %s: %s\n", name_flags, pmErrStr(sts)); /* avoid subsequent warnings ... */ __pmid_int(&pmid_flags)->item = 1; } sts = pmLookupName(1, &name_missed, &pmid_missed); if (sts < 0) { /* should not happen! */ fprintf(stderr, "Warning: cannot get PMID for %s: %s\n", name_missed, pmErrStr(sts)); /* avoid subsequent warnings ... */ __pmid_int(&pmid_missed)->item = 1; } } for (r = 0; r < nrecords; r++) { printf(" --- event record [%d] timestamp ", r); __pmPrintStamp(stdout, &res[r]->timestamp); if (res[r]->numpmid == 0) { printf(" ---\n"); printf(" No parameters\n"); continue; } if (res[r]->numpmid < 0) { printf(" ---\n"); printf(" Error: illegal number of parameters (%d)\n", res[r]->numpmid); continue; } flags = 0; for (p = 0; p < res[r]->numpmid; p++) { pmValueSet *xvsp = res[r]->vset[p]; int sts; pmDesc desc; char *name; if (pmNameID(xvsp->pmid, &name) >= 0) { if (p == 0) { if (xvsp->pmid == pmid_flags) { flags = xvsp->vlist[0].value.lval; printf(" flags 0x%x", flags); printf(" (%s) ---\n", pmEventFlagsStr(flags)); free(name); continue; } else printf(" ---\n"); } if ((flags & PM_EVENT_FLAG_MISSED) && (p == 1) && (xvsp->pmid == pmid_missed)) { printf(" ==> %d missed event records\n", xvsp->vlist[0].value.lval); free(name); continue; } printf(" %s (%s)\n", name, pmIDStr(xvsp->pmid)); free(name); } else printf(" PMID: %s\n", pmIDStr(xvsp->pmid)); if ((sts = pmLookupDesc(xvsp->pmid, &desc)) < 0) { printf(" pmLookupDesc: %s\n", pmErrStr(sts)); continue; } mydump(&desc, xvsp, " "); } } if (nrecords >= 0) pmFreeEventResult(res); } static void report(void) { int i; int sts; pmDesc desc; pmResult *result = NULL; pmResult *xresult = NULL; pmValueSet *vsp = NULL; char *buffer; int all_count; int *all_inst; char **all_names; if (batchidx == 0) return; /* Lookup names. * Cull out names that were unsuccessfully looked up. * However, it is unlikely to fail because names come from a traverse PMNS. */ if (need_pmid) { if ((sts = pmLookupName(batchidx, namelist, pmidlist)) < 0) { int j = 0; for (i = 0; i < batchidx; i++) { if (pmidlist[i] == PM_ID_NULL) { printf("%s: pmLookupName: %s\n", namelist[i], pmErrStr(sts)); free(namelist[i]); } else { /* assert(j <= i); */ pmidlist[j] = pmidlist[i]; namelist[j] = namelist[i]; j++; } } batchidx = j; } } if (p_value || verify) { if (type == PM_CONTEXT_ARCHIVE) { if ((sts = pmSetMode(PM_MODE_FORW, &start, 0)) < 0) { fprintf(stderr, "%s: pmSetMode failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } } if ((sts = pmFetch(batchidx, pmidlist, &result)) < 0) { for (i = 0; i < batchidx; i++) printf("%s: pmFetch: %s\n", namelist[i], pmErrStr(sts)); goto done; } } for (i = 0; i < batchidx; i++) { if (p_desc || p_value || verify) { if ((sts = pmLookupDesc(pmidlist[i], &desc)) < 0) { printf("%s: pmLookupDesc: %s\n", namelist[i], pmErrStr(sts)); continue; } } if (p_desc || p_help || p_value) /* Not doing verify, output separator */ putchar('\n'); if (p_value || verify) { vsp = result->vset[i]; if (p_force) { if (result->vset[i]->numval == PM_ERR_PROFILE) { /* indom is non-enumerable; try harder */ if ((all_count = pmGetInDom(desc.indom, &all_inst, &all_names)) > 0) { pmDelProfile(desc.indom, 0, NULL); pmAddProfile(desc.indom, all_count, all_inst); if (xresult != NULL) { pmFreeResult(xresult); xresult = NULL; } if (type == PM_CONTEXT_ARCHIVE) { if ((sts = pmSetMode(PM_MODE_FORW, &start, 0)) < 0) { fprintf(stderr, "%s: pmSetMode failed: %s\n", pmProgname, pmErrStr(sts)); exit(1); } } if ((sts = pmFetch(1, &pmidlist[i], &xresult)) < 0) { printf("%s: pmFetch: %s\n", namelist[i], pmErrStr(sts)); continue; } vsp = xresult->vset[0]; /* leave the profile in the default state */ free(all_inst); free(all_names); pmDelProfile(desc.indom, 0, NULL); pmAddProfile(desc.indom, 0, NULL); } else if (all_count == 0) { printf("%s: pmGetIndom: No instances?\n", namelist[i]); continue; } else { printf("%s: pmGetIndom: %s\n", namelist[i], pmErrStr(all_count)); continue; } } } } if (verify) { if (desc.type == PM_TYPE_NOSUPPORT) printf("%s: Not Supported\n", namelist[i]); else if (vsp->numval < 0) printf("%s: %s\n", namelist[i], pmErrStr(vsp->numval)); else if (vsp->numval == 0) printf("%s: No value(s) available\n", namelist[i]); continue; } else /* not verify */ printf("%s", namelist[i]); if (p_mid) printf(" PMID: %s", pmIDStr(pmidlist[i])); if (p_fullmid) printf(" = %d = 0x%x", pmidlist[i], pmidlist[i]); if (p_oneline) { if ((sts = pmLookupText(pmidlist[i], PM_TEXT_ONELINE, &buffer)) == 0) { if (p_fullmid) printf("\n "); else putchar(' '); printf("[%s]", buffer); free(buffer); } else printf(" One-line Help: Error: %s\n", pmErrStr(sts)); } putchar('\n'); if (p_desc) __pmPrintDesc(stdout, &desc); if (p_help) { if ((sts = pmLookupText(pmidlist[i], PM_TEXT_HELP, &buffer)) == 0) { char *p; for (p = buffer; *p; p++) ; while (p > buffer && p[-1] == '\n') { p--; *p = '\0'; } if (*buffer != '\0') { printf("Help:\n"); printf("%s", buffer); putchar('\n'); } else printf("Help: \n"); free(buffer); } else printf("Full Help: Error: %s\n", pmErrStr(sts)); } if (p_value) { mydump(&desc, vsp, NULL); } } if (result != NULL) { pmFreeResult(result); result = NULL; } if (xresult != NULL) { pmFreeResult(xresult); xresult = NULL; } done: for (i = 0; i < batchidx; i++) free(namelist[i]); batchidx = 0; } static void dometric(const char *name) { if (*name == '\0') { printf("PMNS appears to be empty!\n"); return; } namelist[batchidx]= strdup(name); if (namelist[batchidx] == NULL) { fprintf(stderr, "%s: namelist string malloc: %s\n", pmProgname, osstrerror()); exit(1); } batchidx++; if (batchidx >= batchsize) report(); } static void PrintUsage(void) { fprintf(stderr, "Usage: %s [options] [metricname ...]\n\ \n\ Options:\n\ -a archive metrics source is a PCP log archive\n\ -b batchsize fetch this many metrics at a time for -f or -v (default 20)\n\ -c dmfile load derived metric definitions from dmfile\n\ -d get and print metric description\n\ -f fetch and print value(s) for all instances\n\ -F fetch and print values for non-enumerable indoms too\n\ -h host metrics source is PMCD on host\n\ -K spec optional additional PMDA spec for local connection\n\ spec is of the form op,domain,dso-path,init-routine\n\ -L metrics source is local connection to PMDA, no PMCD\n\ -m print PMID\n\ -M print PMID in verbose format\n\ -n pmnsfile use an alternative PMNS\n\ -N pmnsfile use an alternative PMNS (duplicate PMIDs are allowed)\n\ -O time origin for a fetch from the archive\n\ -t get and display (terse) oneline text\n\ -T get and display (verbose) help text\n\ -v verify mode, be quiet and only report errors\n\ (forces other output control options off)\n\ -x like -f and expand event records\n\ -Z timezone set timezone for -O\n\ -z set timezone for -O to local time for host from -a\n", pmProgname); } static void ParseOptions(int argc, char *argv[]) { int c; int sts; int errflag = 0; char *endnum; char *errmsg; char *opts = "a:b:c:dD:Ffh:K:LMmN:n:O:tTvxzZ:?"; while ((c = getopt(argc, argv, opts)) != EOF) { switch (c) { case 'a': /* archive name */ if (type != 0) { fprintf(stderr, "%s: at most one of -a, -h and -L allowed\n", pmProgname); errflag++; } type = PM_CONTEXT_ARCHIVE; hostname = optarg; need_context = 1; break; case 'b': /* batchsize */ batchsize = (int)strtol(optarg, &endnum, 10); if (*endnum != '\0') { fprintf(stderr, "%s: -b requires numeric argument\n", pmProgname); errflag++; } break; case 'c': /* derived metrics config file */ sts = pmLoadDerivedConfig(optarg); if (sts < 0) { fprintf(stderr, "%s: -c error: %s\n", pmProgname, pmErrStr(sts)); /* errors are not necessarily fatal ... */ } break; case 'd': p_desc = 1; need_context = 1; need_pmid = 1; break; case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case 'F': p_force = p_value = 1; need_context = 1; need_pmid = 1; break; case 'f': p_value = 1; need_context = 1; need_pmid = 1; break; case 'h': /* contact PMCD on this hostname */ if (type != 0) { fprintf(stderr, "%s: at most one of -a, -h and -L allowed\n", pmProgname); errflag++; } hostname = optarg; type = PM_CONTEXT_HOST; need_context = 1; break; case 'K': /* update local PMDA table */ if ((errmsg = __pmSpecLocalPMDA(optarg)) != NULL) { fprintf(stderr, "%s: __pmSpecLocalPMDA failed: %s\n", pmProgname, errmsg); errflag++; } break; case 'L': /* local PMDA connection, no PMCD */ if (type != 0) { fprintf(stderr, "%s: at most one of -a, -h and -L allowed\n", pmProgname); errflag++; } hostname = NULL; type = PM_CONTEXT_LOCAL; need_context = 1; break; case 'M': p_fullmid = 1; p_mid = 1; need_pmid = 1; break; case 'm': p_mid = 1; need_pmid = 1; break; case 'N': dupok = 1; /*FALLTHROUGH*/ case 'n': pmnsfile = optarg; break; case 'O': /* sample origin */ Oflag = optarg; break; case 'T': p_help = 1; need_context = 1; need_pmid = 1; break; case 't': p_oneline = 1; need_context = 1; need_pmid = 1; break; case 'v': verify = 1; need_context = 1; need_pmid = 1; break; case 'x': xflag = p_value = 1; need_context = 1; need_pmid = 1; break; case 'z': /* timezone from host */ if (tz != NULL) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); errflag++; } zflag++; break; case 'Z': /* $TZ timezone */ if (zflag) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); errflag++; } tz = optarg; break; case '?': if (errflag == 0) { PrintUsage(); exit(0); } } } if (zflag && type == 0) { fprintf(stderr, "%s: -z requires an explicit -a or -h option\n", pmProgname); errflag++; } if (errflag) { PrintUsage(); exit(1); } if (type != PM_CONTEXT_ARCHIVE && Oflag != NULL) { fprintf(stderr, "%s: Warning: -O option requires archive source, and will be ignored\n", pmProgname); Oflag = NULL; } if (type == PM_CONTEXT_ARCHIVE) /* * for archives, one metric per batch and start at beginning of * archive for each batch so metric will be found if it is in * the archive */ batchsize = 1; if (verify) p_desc = p_mid = p_fullmid = p_help = p_oneline = p_value = p_force = 0; } /*****************************************************************************/ int main(int argc, char **argv) { int sts; int exitsts = 0; pmLogLabel label; char *host; char *msg; struct timeval first; /* initial sample time */ struct timeval last; /* final sample time */ __pmSetProgname(argv[0]); ParseOptions(argc, argv); if ((namelist = (char **)malloc(batchsize * sizeof(char *))) == NULL) { fprintf(stderr, "%s: namelist malloc: %s\n", pmProgname, osstrerror()); exit(1); } if ((pmidlist = (pmID *)malloc(batchsize * sizeof(pmID))) == NULL) { fprintf(stderr, "%s: pmidlist malloc: %s\n", pmProgname, osstrerror()); exit(1); } if (pmnsfile != PM_NS_DEFAULT) { if ((sts = pmLoadASCIINameSpace(pmnsfile, dupok)) < 0) { fprintf(stderr, "%s: Error loading namespace: %s\n", pmProgname, pmErrStr(sts)); exit(1); } } else { need_context = 1; /* atleast for PMNS */ } if (need_context) { if (type == 0) { type = PM_CONTEXT_HOST; hostname = "local:"; } if ((sts = pmNewContext(type, hostname)) < 0) { if (type == PM_CONTEXT_HOST) fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", pmProgname, hostname, pmErrStr(sts)); else if (type == PM_CONTEXT_LOCAL) fprintf(stderr, "%s: Cannot make standalone connection on localhost: %s\n", pmProgname, pmErrStr(sts)); else fprintf(stderr, "%s: Cannot open archive \"%s\": %s\n", pmProgname, hostname, pmErrStr(sts)); exit(1); } if (type == PM_CONTEXT_ARCHIVE) { pmTrimNameSpace(); if ((sts = pmGetArchiveLabel(&label)) < 0) { fprintf(stderr, "%s: Cannot get archive label record: %s\n", pmProgname, pmErrStr(sts)); exit(1); } first = label.ll_start; host = label.ll_hostname; if ((sts = pmGetArchiveEnd(&last)) < 0) { last.tv_sec = INT_MAX; last.tv_usec = 0; fflush(stdout); fprintf(stderr, "%s: Cannot locate end of archive: %s\n", pmProgname, pmErrStr(sts)); fprintf(stderr, "\nWARNING: This archive is sufficiently damaged that it may not be possible to\n"); fprintf(stderr, " produce complete information. Continuing and hoping for the best.\n\n"); fflush(stderr); } if (zflag) { if ((sts = pmNewContextZone()) < 0) { fprintf(stderr, "%s: Cannot set context timezone: %s\n", pmProgname, pmErrStr(sts)); exit(1); } printf("Note: timezone set to local timezone of host \"%s\"\n\n", host); } else if (tz != NULL) { if ((sts = pmNewZone(tz)) < 0) { fprintf(stderr, "%s: Cannot set timezone to \"%s\": %s\n", pmProgname, tz, pmErrStr(sts)); exit(1); } printf("Note: timezone set to \"TZ=%s\"\n\n", tz); } else { pmNewContextZone(); } if (pmParseTimeWindow(NULL, NULL, NULL, Oflag, &first, &last, &last, &first, &start, &msg) < 0) { fprintf(stderr, "%s: %s", pmProgname, msg); exit(1); } } } if (optind >= argc) { sts = pmTraversePMNS("", dometric); if (sts < 0) { fprintf(stderr, "Error: %s\n", pmErrStr(sts)); exitsts = 1; } } else { int a; for (a = optind; a < argc; a++) { sts = pmTraversePMNS(argv[a], dometric); if (sts < 0) { fprintf(stderr, "Error: %s: %s\n", argv[a], pmErrStr(sts)); exitsts = 1; } } } report(); exit(exitsts); } pcp-3.8.12ubuntu1/src/pmmgr/0000775000000000000000000000000012272262620012515 5ustar pcp-3.8.12ubuntu1/src/pmmgr/config/0000775000000000000000000000000012272262620013762 5ustar pcp-3.8.12ubuntu1/src/pmmgr/config/pmlogger0000664000000000000000000000000012272262501015505 0ustar pcp-3.8.12ubuntu1/src/pmmgr/config/target-discovery.example-avahi0000664000000000000000000000000612272262501021712 0ustar avahi pcp-3.8.12ubuntu1/src/pmmgr/config/pmieconf0000664000000000000000000000000012272262501015471 0ustar pcp-3.8.12ubuntu1/src/pmmgr/config/README0000664000000000000000000000122012272262501014633 0ustar This is the default built-in configuration directory for pmmgr. See man pmmgr(1) for details of the individual files that are read to extract configuration lines. Other files in this directory are for documentation / examples. The default built-in configuration items for pmmgr are almost sufficient to act as a system's primary pmlogger and pmie. The exceptions are the actual enablement of pmlogger & pmie, and their auto-generated configuration, which are enabled by some empty files here. Additional possible but non-default configurations are given in .example* files here. Rename them to drop the .example* filename extension to activate them. pcp-3.8.12ubuntu1/src/pmmgr/config/pmie0000664000000000000000000000000012272262501014623 0ustar pcp-3.8.12ubuntu1/src/pmmgr/config/pmlogmerge0000664000000000000000000000000012272262501016027 0ustar pcp-3.8.12ubuntu1/src/pmmgr/config/GNUmakefile0000664000000000000000000000173612272262501016041 0ustar #!gmake # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # LLDIRT = TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs LSRCFILES = pmie pmieconf pmlogconf pmlogger pmlogmerge \ README target-discovery.example-avahi PMMGR_SYSCONF_DIR=$(PCP_SYSCONF_DIR)/pmmgr default: build-me: include $(BUILDRULES) install: $(INSTALL) -m 755 -d $(PMMGR_SYSCONF_DIR) for file in $(LSRCFILES); do \ $(INSTALL) -m 644 $$file $(PMMGR_SYSCONF_DIR)/$$file; \ done default_pcp : default install_pcp : install pcp-3.8.12ubuntu1/src/pmmgr/config/pmlogconf0000664000000000000000000000000012272262501015655 0ustar pcp-3.8.12ubuntu1/src/pmmgr/pmmgr.h0000664000000000000000000000701612272262501014012 0ustar /* -*- C++ -*- * Copyright (c) 2013-2014 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #ifndef PMMGR_H #define PMMGR_H extern "C" { #include "pmapi.h" } #include #include #include #include #include #include typedef std::string pcp_context_spec; // pmNewContext PM_CONTEXT_HOST parameter typedef std::string pmmgr_hostid; // a unique id for a pmcd // Instances of pmmgr_configurable represent a configurable object, // which reads one or more lines of djb-style directories. class pmmgr_configurable { protected: pmmgr_configurable(const std::string& dir); virtual ~pmmgr_configurable() {} std::vector get_config_multi(const std::string&) const; std::string get_config_single(const std::string&) const; bool get_config_exists(const std::string&) const; // private: maybe? std::string config_directory; std::ostream& timestamp(std::ostream&); }; // Instances of pmmgr_daemon represent a possibly-live, restartable daemon. class pmmgr_daemon: public pmmgr_configurable { public: pmmgr_daemon(const std::string& config_directory, const pmmgr_hostid& hostid, const pcp_context_spec& spec); virtual ~pmmgr_daemon(); void poll(); protected: pmmgr_hostid hostid; pcp_context_spec spec; int pid; virtual std::string daemon_command_line() = 0; }; class pmmgr_pmlogger_daemon: public pmmgr_daemon { public: pmmgr_pmlogger_daemon(const std::string& config_directory, const pmmgr_hostid& hostid, const pcp_context_spec& spec); protected: std::string daemon_command_line(); }; class pmmgr_pmie_daemon: public pmmgr_daemon { public: pmmgr_pmie_daemon(const std::string& config_directory, const pmmgr_hostid& hostid, const pcp_context_spec& spec); protected: std::string daemon_command_line(); }; // An instance of a pmmgr_job_spec represents a pmmgr // configuration item to monitor some set of pcp target patterns // (which collectively map to a varying set of pmcd's), and a // corresponding set of daemons to keep running for each of them. // // The pmcds are identified by a configurable algorithm that collects // site-specific metrics into a single string, which is then sanitized // to make it typeable, portable, useful as a directory name. // // It is configured from a djb-style control directory with files containing // 100% pure content. Multiple values within the files, where permitted, // are newline-separated. class pmmgr_job_spec: pmmgr_configurable { public: pmmgr_job_spec(const std::string& config_directory); ~pmmgr_job_spec(); // shut down all daemons void poll(); // check targets, daemons private: std::map parsed_metric_cache; pmMetricSpec* parse_metric_spec(const std::string&); pmmgr_hostid compute_hostid (const pcp_context_spec&); std::map known_targets; void note_new_hostid(const pmmgr_hostid&, const pcp_context_spec&); void note_dead_hostid(const pmmgr_hostid&); std::multimap daemons; }; #endif pcp-3.8.12ubuntu1/src/pmmgr/rc_pmmgr0000664000000000000000000001533112272262521014251 0ustar #! /bin/sh # # Copyright (c) 2013 Red Hat. # Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Start or Stop the Performance Co-Pilot (PCP) daemon manager # # The following is for chkconfig on RedHat based systems # chkconfig: 2345 95 05 # description: pmmgr is a daemon manager for the Performance Co-Pilot (PCP) # # The following is for insserv(1) based systems, # e.g. SuSE, where chkconfig is a perl script. ### BEGIN INIT INFO # Provides: pmmgr # Required-Start: $remote_fs # Should-Start: $local_fs $network $syslog $time $pmcd # Required-Stop: $remote_fs # Should-Stop: $local_fs $network $syslog $pmcd # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Control pmmgr (daemon manager for PCP) # Description: Configure and control pmmgr (a daemon manager for the Performance Co-Pilot) ### END INIT INFO . $PCP_DIR/etc/pcp.env . $PCP_SHARE_DIR/lib/rc-proc.sh PMMGR=$PCP_BINADM_DIR/pmmgr PMMGROPTS=$PCP_PMMGROPTIONS_PATH RUNDIR=$PCP_LOG_DIR/pmmgr pmprog=$PCP_RC_DIR/pmmgr prog=$PCP_RC_DIR/`basename $0` tmp=`mktemp -d /var/tmp/pcp.XXXXXXXXX` || exit 1 status=1 trap "rm -rf $tmp; exit \$status" 0 1 2 3 15 if [ $pmprog = $prog ] then VERBOSE_CTL=on else VERBOSE_CTL=off fi case "$PCP_PLATFORM" in mingw) # nothing we can usefully do here, skip the test # ;; *) # standard Unix/Linux style test # ID=id test -f /usr/xpg4/bin/id && ID=/usr/xpg4/bin/id IAM=`$ID -u 2>/dev/null` if [ -z "$IAM" ] then # do it the hardway # IAM=`$ID | sed -e 's/.*uid=//' -e 's/(.*//'` fi ;; esac _shutdown() { # Is pmmgr running? # _get_pids_by_name pmmgr >$tmp/tmp if [ ! -s $tmp/tmp ] then [ "$1" = verbose ] && echo "$pmprog: pmmgr not running" return 0 fi # Send pmmgr a SIGTERM, which is noted as a pending shutdown. # When finished the currently active request, pmmgr will close any # connections and then exit. # Wait for pmmgr to terminate. # pmsignal -a -s TERM pmmgr > /dev/null 2>&1 $ECHO $PCP_ECHO_N "Waiting for pmmgr to terminate ...""$PCP_ECHO_C" gone=0 for i in 1 2 3 4 5 6 do sleep 3 _get_pids_by_name pmmgr >$tmp/tmp if [ ! -s $tmp/tmp ] then gone=1 break fi # If pmmgr doesn't go in 15 seconds, SIGKILL and sleep 1 more time # to allow any clients reading from pmmgr sockets to fail so that # socket doesn't end up in TIME_WAIT or somesuch. # if [ $i = 5 ] then $ECHO echo "Process ..." $PCP_PS_PROG $PCP_PS_ALL_FLAGS >$tmp/ps sed 1q $tmp/ps for pid in `cat $tmp/tmp` do $PCP_AWK_PROG <$tmp/ps "\$2 == $pid { print }" done echo "$prog: Warning: Forcing pmmgr to terminate!" pmsignal -a -s KILL pmmgr > /dev/null 2>&1 else $ECHO $PCP_ECHO_N ".""$PCP_ECHO_C" fi done if [ $gone != 1 ] # It just WON'T DIE, give up. then echo "Process ..." cat $tmp/tmp echo "$prog: Warning: pmmgr won't die!" exit fi $RC_STATUS -v pmpost "stop pmmgr from $pmprog" } _usage() { echo "Usage: $pmprog [-v] {start|restart|condrestart|stop|status|reload|force-reload}" } while getopts v c do case $c in v) # force verbose VERBOSE_CTL=on ;; *) _usage exit 1 ;; esac done shift `expr $OPTIND - 1` if [ $VERBOSE_CTL = on ] then # For a verbose startup and shutdown ECHO=$PCP_ECHO_PROG else # For a quiet startup and shutdown ECHO=: fi if [ "$IAM" != 0 -a "$1" != "status" ] then if [ -n "$PCP_DIR" ] then : running in a non-default installation, do not need to be root else echo "$prog:"' Error: You must be root (uid 0) to start or stop the PCP pmmgr daemon.' exit fi fi # First reset status of this service $RC_RESET # Return values acc. to LSB for all commands but status: # 0 - success # 1 - misc error # 2 - invalid or excess args # 3 - unimplemented feature (e.g. reload) # 4 - insufficient privilege # 5 - program not installed # 6 - program not configured # # Note that starting an already running service, stopping # or restarting a not-running service as well as the restart # with force-reload (in case signalling is not supported) are # considered a success. case "$1" in 'start'|'restart'|'condrestart'|'reload'|'force-reload') if [ "$1" = "condrestart" ] && ! is_chkconfig_on pmmgr then status=0 exit fi _shutdown quietly # pmmgr messages should go to stderr, not the GUI notifiers # unset PCP_STDERR if [ -x $PMMGR ] then if [ ! -f $PMMGROPTS ] then echo "$prog:"' Error: pmmgr control file "$PMMGROPTS" is missing, cannot start pmmgr.' exit fi if [ ! -d "$RUNDIR" ] then mkdir -p -m 775 "$RUNDIR" chown $PCP_USER:$PCP_GROUP "$RUNDIR" fi cd $RUNDIR # salvage the previous versions of any pmmgr # if [ -f pmmgr.log ] then rm -f pmmgr.log.prev mv pmmgr.log pmmgr.log.prev fi $ECHO $PCP_ECHO_N "Performance Co-Pilot starting pmmgr (logfile is $RUNDIR/pmmgr.log) ..." "$PCP_ECHO_C" # options file processing ... # only consider lines which start with a hyphen # get rid of the -f option # ensure multiple lines concat onto 1 line OPTS=`sed <$PMMGROPTS 2>/dev/null \ -e '/^[^-]/d' \ -e 's/^/ /' \ -e 's/$/ /' \ -e 's/ -f / /g' \ -e 's/^ //' \ -e 's/ $//' \ | tr '\012' ' ' ` # environment stuff # eval `sed -e 's/"/\\"/g' $PMMGROPTS \ | awk -F= ' BEGIN { exports="" } /^[A-Z]/ && NF == 2 { exports=exports" "$1 printf "%s=${%s:-\"%s\"}\n", $1, $1, $2 } END { if (exports != "") print "export", exports }'` $PMMGR -l pmmgr.log $OPTS & $RC_STATUS -v pmpost "start pmmgr from $pmprog" fi status=0 ;; 'stop') _shutdown status=0 ;; 'status') # NOTE: $RC_CHECKPROC returns LSB compliant status values. $ECHO $PCP_ECHO_N "Checking for pmmgr:" "$PCP_ECHO_C" if [ -r /etc/rc.status ] then # SuSE $RC_CHECKPROC $PMMGR $RC_STATUS -v status=$? else # not SuSE $RC_CHECKPROC $PMMGR status=$? if [ $status -eq 0 ] then $ECHO running else $ECHO stopped fi fi ;; *) _usage ;; esac pcp-3.8.12ubuntu1/src/pmmgr/GNUmakefile0000664000000000000000000000300012272262501014556 0ustar #!gmake # # Copyright (c) 2013 Red Hat. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # LLDIRT = TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs LSRCFILES=TODO rc_pmmgr pmmgr.options SUBDIRS = config CXXMDTARGET = pmmgr$(EXECSUFFIX) HFILES = pmmgr.h CXXFILES = pmmgr.cxx LLDLIBS = $(PCPLIB) $(LIB_FOR_PTHREADS) LLDFLAGS += $(RDYNAMIC_FLAG) $(PIELDFLAGS) LCFLAGS += $(PIECFLAGS) default: build-me ifeq ($(BUILD_PMMGR),yes) build-me: $(SUBDIRS) $(CXXMDTARGET) $(SUBDIRS_MAKERULE) install: $(SUBDIRS) $(CXXMDTARGET) $(SUBDIRS_MAKERULE) $(INSTALL) -m 755 -d `dirname $(PCP_PMMGROPTIONS_PATH)` $(INSTALL) -m 644 pmmgr.options $(PCP_PMMGROPTIONS_PATH) $(INSTALL) -m 755 rc_pmmgr $(PCP_RC_DIR)/pmmgr $(INSTALL) -m 755 $(CXXMDTARGET) $(PCP_BINADM_DIR)/$(CXXMDTARGET) $(INSTALL) -m 775 -o $(PCP_USER) -g $(PCP_USER) -d $(PCP_LOG_DIR)/pmmgr else build-me: @echo not building pmmgr install: @echo not installing pmmgr endif $(OBJECTS): $(HFILES) include $(BUILDRULES) default_pcp : default install_pcp : install # Hey, does anyone have a spare vowel? .PHONY: build-me pcp-3.8.12ubuntu1/src/pmmgr/TODO0000664000000000000000000000035712272262501013210 0ustar - pmlogrewrite - log aging without logmerge (which is high on I/O) - old log compression (until we get libpcp zlib or something) - email error reporting? - test buildability on non-linux - qa - port to mingw? - pmlogger/pmie .log rotation pcp-3.8.12ubuntu1/src/pmmgr/pmmgr.options0000664000000000000000000000113412272262521015253 0ustar # command-line options and environment variables for pmmgr # uncomment/edit lines as required # note: environment variables are *not* expanded - use full path # make log more verbose # -v # poll less frequently # -p 300 # add more configuration directories # -c DIR1 # -c DIR2 # assume identity of some user other than "pcp" # -U foobar # make log go someplace else # -l /some/place/else # setting of environment variables for pmmgr # timeouts for interactions with pmcd on behalf of clients # PMCD_CONNECT_TIMEOUT=10 # PMCD_RECONNECT_TIMEOUT=10,20,30 # PMCD_REQUEST_TIMEOUT=10 HOME=/var/lib/pcp pcp-3.8.12ubuntu1/src/pmmgr/pmmgr.cxx0000664000000000000000000007657312272262521014405 0ustar /* * Copyright (c) 2013-2014 Red Hat. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmmgr.h" #include "impl.h" #include #include #include #include #include extern "C" { #include #include #include #include #ifdef HAVE_PTHREAD_H #include #endif #ifdef IS_LINUX #include #endif } using namespace std; // ------------------------------------------------------------------------ int quit; // ------------------------------------------------------------------------ // Create a string that is safe to pass to system(3), i.e., sh -c, // by quoting metacharacters. This transform generally should be // applied only once. string sh_quote(const string& input) { string output; for (unsigned i=0; iinst - ((pmValue *)b)->inst; } extern "C" void * pmmgr_daemon_poll_thread (void* a) { pmmgr_daemon* d = (pmmgr_daemon*) a; d->poll(); return 0; } // ------------------------------------------------------------------------ pmmgr_configurable::pmmgr_configurable(const string& dir): config_directory(dir) { } vector pmmgr_configurable::get_config_multi(const string& file) const { vector lines; string complete_filename = config_directory + (char)__pmPathSeparator() + file; ifstream f (complete_filename.c_str()); while (f.good()) { string line; getline(f, line); if (! f.good()) break; if (line != "") lines.push_back(line); } return lines; } bool pmmgr_configurable::get_config_exists(const string& file) const { string complete_filename = config_directory + (char)__pmPathSeparator() + file; ifstream f (complete_filename.c_str()); return (f.good()); } string pmmgr_configurable::get_config_single(const string& file) const { vector lines = get_config_multi (file); if (lines.size() == 1) return lines[0]; else return ""; } ostream& pmmgr_configurable::timestamp(ostream& o) { return ::timestamp(o) << config_directory << ": "; } // ------------------------------------------------------------------------ pmMetricSpec* pmmgr_job_spec::parse_metric_spec (const string& spec) { if (parsed_metric_cache.find(spec) != parsed_metric_cache.end()) return parsed_metric_cache[spec]; const char* specstr = spec.c_str(); pmMetricSpec* pms = 0; char *errmsg; char dummy_host[] = ""; int rc = pmParseMetricSpec (specstr, 0, dummy_host, /* both ignored */ & pms, & errmsg); if (rc < 0) { timestamp(cerr) << "hostid-metrics '" << specstr << "' parse error: " << errmsg << endl; free (errmsg); } parsed_metric_cache[spec] = pms; return pms; } pmmgr_hostid pmmgr_job_spec::compute_hostid (const pcp_context_spec& ctx) { int pmc = pmNewContext (PM_CONTEXT_HOST, ctx.c_str()); if (pmc < 0) return ""; // parse all the hostid metric specifications vector hostid_specs = get_config_multi("hostid-metrics"); if (hostid_specs.size() == 0) hostid_specs.push_back(string("pmcd.hostname")); // fetch all hostid metrics in sequence vector hostid_fields; for (unsigned i=0; imetric, &pmid); if (rc < 0) continue; pmDesc desc; rc = pmLookupDesc (pmid, & desc); if (rc < 0) continue; if (desc.type != PM_TYPE_STRING) continue; if ((desc.indom != PM_INDOM_NULL) && pms->ninst > 0) { // reset the indom to include all elements rc = pmDelProfile(desc.indom, 0, (int *)0); if (rc < 0) continue; int *inums = (int *) malloc (pms->ninst * sizeof(int)); if (inums == NULL) continue; // NB: after this point, 'continue' must also free(inums); // map the instance names to instance numbers unsigned numinums_used = 0; for (int j=0; jninst; j++) { int inum = pmLookupInDom (desc.indom, pms->inst[j]); if (inum < 0) continue; inums[numinums_used++] = inum; } // add the selected instances to the profile rc = pmAddProfile (desc.indom, numinums_used, inums); free (inums); if (rc < 0) continue; } // fetch the values pmResult *r; rc = pmFetch (1, &pmid, &r); if (rc < 0) continue; // NB: after this point, 'continue' must also pmFreeResult(r) // only vset[0] will be set, for csb->pmid if (r->vset[0]->numval > 0) { // in-place sort value list by indom number qsort (r->vset[0]->vlist, (size_t) r->vset[0]->numval, sizeof(pmValue), pmValue_compare); for (int j=0; jvset[0]->numval; j++) // iterate over instances { // fetch the string value pmAtomValue av; rc = pmExtractValue(r->vset[0]->valfmt, & r->vset[0]->vlist[j], PM_TYPE_STRING, & av, PM_TYPE_STRING); if (rc < 0) continue; // at last! we have a string we can accumulate hostid_fields.push_back (av.cp); free (av.cp); } } (void) pmFreeResult (r); } (void) pmDestroyContext (pmc); // Sanitize the host-id metric values into a single string that is // suitable for posix-portable-filenames, and not too ugly for // someone to look at or type in. // // http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap03.html string sanitized; for (unsigned i=0; i::iterator it = parsed_metric_cache.begin(); it != parsed_metric_cache.end(); ++it) free (it->second); // aka pmFreeMetricSpec // kill all our daemons created during poll() for (map::iterator it = known_targets.begin(); it != known_targets.end(); ++it) note_dead_hostid (it->first); } // ------------------------------------------------------------------------ void pmmgr_job_spec::poll() { if (quit) return; // phase 1: run all discovery/probing functions to collect context-spec's set new_specs; vector target_hosts = get_config_multi("target-host"); for (unsigned i=0; i target_discovery = get_config_multi("target-discovery"); for (unsigned i=0; i old_known_targets = known_targets; known_targets.clear(); // phase 3: map the context-specs to hostids to find new hosts for (set::iterator it = new_specs.begin(); it != new_specs.end(); ++it) { pmmgr_hostid hostid = compute_hostid (*it); if (hostid != "") // verified existence/liveness known_targets[hostid] = *it; // NB: for hostid's with multiple specs, this logic will pick an // *arbitrary* one. Perhaps we want to tie-break deterministically. } // phase 4a: compare old_known_targets vs. known_targets: look for any recently died for (map::const_iterator it = old_known_targets.begin(); it != old_known_targets.end(); ++it) { const pmmgr_hostid& hostid = it->first; if (known_targets.find(hostid) == known_targets.end()) note_dead_hostid (hostid); } // phase 4b: compare new known_targets & old_known_targets: look for recently born for (map::const_iterator it = known_targets.begin(); it != known_targets.end(); ++it) { const pmmgr_hostid& hostid = it->first; if (old_known_targets.find(hostid) == old_known_targets.end()) note_new_hostid (hostid, known_targets[hostid]); } // phase 5: poll all the live daemons // NB: there is a parallelism opportunity, as running many pmlogconf/etc.'s in series // is a possible bottleneck. #ifdef HAVE_PTHREAD_H vector threads; #endif for (multimap::iterator it = daemons.begin(); it != daemons.end(); ++it) { #ifdef HAVE_PTHREAD_H pthread_t foo; int rc = pthread_create(&foo, NULL, &pmmgr_daemon_poll_thread, it->second); if (rc == 0) threads.push_back (foo); #else int rc = -ENOSUPP; #endif if (rc) // threading failed or running single-threaded it->second->poll(); } #ifdef HAVE_PTHREAD_H for (unsigned i=0; iWe've got one!!!!! timestamp(cout) << "gc subdirectory " << item_name << endl; string cleanup_cmd = "/bin/rm -rf " + sh_quote(item_name); if (pmDebug & DBG_TRACE_APPL0) timestamp(cout) << "running " << cleanup_cmd << endl; rc = system(cleanup_cmd.c_str()); if (rc != 0) timestamp(cerr) << "system(" << cleanup_cmd << ") failed: rc=" << rc << endl; } } } globfree (& the_blob); } // ------------------------------------------------------------------------ void pmmgr_job_spec::note_new_hostid(const pmmgr_hostid& hid, const pcp_context_spec& spec) { timestamp(cout) << "new hostid " << hid << " at " << string(spec) << endl; if (get_config_exists("pmlogger")) daemons.insert(make_pair(hid, new pmmgr_pmlogger_daemon(config_directory, hid, spec))); if (get_config_exists("pmie")) daemons.insert(make_pair(hid, new pmmgr_pmie_daemon(config_directory, hid, spec))); } void pmmgr_job_spec::note_dead_hostid(const pmmgr_hostid& hid) { timestamp(cout) << "dead hostid " << hid << endl; pair::iterator, multimap::iterator> range = daemons.equal_range(hid); for (multimap::iterator it = range.first; it != range.second; ++it) delete (it->second); daemons.erase(range.first, range.second); } // ------------------------------------------------------------------------ pmmgr_daemon::pmmgr_daemon(const std::string& config_directory, const pmmgr_hostid& hostid, const pcp_context_spec& spec): pmmgr_configurable(config_directory), hostid(hostid), spec(spec), pid(0) { } pmmgr_pmlogger_daemon::pmmgr_pmlogger_daemon(const std::string& config_directory, const pmmgr_hostid& hostid, const pcp_context_spec& spec): pmmgr_daemon(config_directory, hostid, spec) { } pmmgr_pmie_daemon::pmmgr_pmie_daemon(const std::string& config_directory, const pmmgr_hostid& hostid, const pcp_context_spec& spec): pmmgr_daemon(config_directory, hostid, spec) { } pmmgr_daemon::~pmmgr_daemon() { if (pid != 0) { int ignored; (void) kill ((pid_t) pid, SIGTERM); (void) waitpid ((pid_t) pid, &ignored, 0); // collect zombie if (pmDebug & DBG_TRACE_APPL0) timestamp(cout) << "daemon pid " << pid << " killed" << endl; } } void pmmgr_daemon::poll() { if (quit) return; if (pid != 0) // test if it's still alive { // reap it if it might have died int ignored; int rc = waitpid ((pid_t) pid, &ignored, WNOHANG); rc = kill ((pid_t) pid, 0); if (rc < 0) { if (pmDebug & DBG_TRACE_APPL0) timestamp(cout) << "daemon pid " << pid << " found dead" << endl; pid = 0; // we will try again immediately } } if (pid == 0) // needs a restart { string commandline = daemon_command_line(); if (pmDebug & DBG_TRACE_APPL0) timestamp(cout) << "fork/exec sh -c " << commandline << endl; pid = fork(); if (pid == 0) // child process { int rc = execl ("/bin/sh", "sh", "-c", commandline.c_str(), NULL); timestamp(cerr) << "failed to execl sh -c " << commandline << " rc=" << rc << endl; _exit (1); // parent will try again at next poll } else if (pid < 0) // failed fork { timestamp(cerr) << "failed to fork for sh -c " << commandline << endl; pid = 0; // we will try again at next poll } else // congratulations! we're apparently a parent { if (pmDebug & DBG_TRACE_APPL0) timestamp(cout) << "daemon pid " << pid << " started: " << commandline << endl; } } } std::string pmmgr_pmlogger_daemon::daemon_command_line() { string default_log_dir = string(pmGetConfig("PCP_LOG_DIR")) + (char)__pmPathSeparator() + "pmmgr"; string log_dir = get_config_single ("log-directory"); if (log_dir == "") log_dir = default_log_dir; else if(log_dir[0] != '/') log_dir = config_directory + (char)__pmPathSeparator() + log_dir; (void) mkdir2 (log_dir.c_str(), 0777); // implicitly consults umask(2) string host_log_dir = log_dir + (char)__pmPathSeparator() + hostid; (void) mkdir2 (host_log_dir.c_str(), 0777); // (errors creating actual files under host_log_dir will be noted shortly) string pmlogger_command = string(pmGetConfig("PCP_BIN_DIR")) + (char)__pmPathSeparator() + "pmlogger"; string pmlogger_options = sh_quote(pmlogger_command); pmlogger_options += " " + get_config_single ("pmlogger"); // run pmlogconf if requested if (get_config_exists("pmlogconf")) { string pmlogconf_output_file = host_log_dir + (char)__pmPathSeparator() + "config.pmlogger"; (void) unlink (pmlogconf_output_file.c_str()); string pmlogconf_command = string(pmGetConfig("PCP_BINADM_DIR")) + (char)__pmPathSeparator() + "pmlogconf"; string pmlogconf_options = sh_quote(pmlogconf_command) + " -c -r -h " + sh_quote(spec) + " " + get_config_single ("pmlogconf") + " " + sh_quote(pmlogconf_output_file) + " >/dev/null"; // pmlogconf is too chatty if (pmDebug & DBG_TRACE_APPL0) timestamp(cout) << "running " << pmlogconf_options << endl; int rc = system(pmlogconf_options.c_str()); if (rc != 0) timestamp(cerr) << "system(" << pmlogconf_options << ") failed: rc=" << rc << endl; pmlogger_options += " -c " + sh_quote(pmlogconf_output_file); } // collect -h direction pmlogger_options += " -h " + sh_quote(spec); // hard-code -r to report metrics & expected disk usage rate pmlogger_options += " -r"; // collect subsidiary pmlogger diagnostics pmlogger_options += " -l " + sh_quote(host_log_dir + (char)__pmPathSeparator() + "pmlogger.log"); // do log merging if (get_config_exists ("pmlogmerge")) { string pmlogextract_command = string(pmGetConfig("PCP_BIN_DIR")) + (char)__pmPathSeparator() + "pmlogextract"; string pmlogcheck_command = string(pmGetConfig("PCP_BIN_DIR")) + (char)__pmPathSeparator() + "pmlogcheck"; string pmlogextract_options = sh_quote(pmlogextract_command); string retention = get_config_single ("pmlogmerge-retain"); if (retention == "") retention = "14days"; pmlogextract_options += " -S -" + sh_quote(retention); // Arrange our new pmlogger to kill itself after the given // period, to give us a chance to rerun. string period = get_config_single ("pmlogmerge"); if (period == "") period = "24hours"; pmlogger_options += " -s " + sh_quote(period); // Find prior archives by globbing for *.index files, // just like pmlogger_merge does vector old_archives; glob_t the_blob; string glob_pattern = host_log_dir + (char)__pmPathSeparator() + "*.index"; int rc = glob (glob_pattern.c_str(), GLOB_NOESCAPE, NULL, & the_blob); if (rc == 0) { for (unsigned i=0; i/dev/null"; if (pmDebug & DBG_TRACE_APPL0) timestamp(cout) << "running " << pmlogcheck_options << endl; rc = system(pmlogcheck_options.c_str()); if (rc != 0) { timestamp(cerr) << "system(" << pmlogcheck_options << ") failed: rc=" << rc << endl; timestamp(cerr) << "corrupt archive " << base_name << " preserved." << endl; continue; } // XXX: pmlogrewrite here old_archives.push_back (base_name); } globfree (& the_blob); } string timestr = "merged-archive"; time_t now2 = time(NULL); struct tm *now = gmtime(& now2); if (now != NULL) { char timestr2[100]; int rc = strftime(timestr2, sizeof(timestr2), "-%Y%m%d.%H%M%S", now); if (rc > 0) timestr += timestr2; } string merged_archive_name = host_log_dir + (char)__pmPathSeparator() + timestr; if (old_archives.size() > 1) // 1 or 0 are not worth merging! { // assemble final bits of pmlogextract command line: the inputs and the output for (unsigned i=0; i 0) timestr += timestr2; } // last argument pmlogger_options += " " + sh_quote(host_log_dir + (char)__pmPathSeparator() + timestr); return pmlogger_options; } std::string pmmgr_pmie_daemon::daemon_command_line() { string default_log_dir = string(pmGetConfig("PCP_LOG_DIR")) + (char)__pmPathSeparator() + "pmmgr"; string log_dir = get_config_single ("log-directory"); if (log_dir == "") log_dir = default_log_dir; else if(log_dir[0] != '/') log_dir = config_directory + (char)__pmPathSeparator() + log_dir; (void) mkdir2 (log_dir.c_str(), 0777); // implicitly consults umask(2) string host_log_dir = log_dir + (char)__pmPathSeparator() + hostid; (void) mkdir2 (host_log_dir.c_str(), 0777); // (errors creating actual files under host_log_dir will be noted shortly) string pmie_command = string(pmGetConfig("PCP_BIN_DIR")) + (char)__pmPathSeparator() + "pmie"; string pmie_options = sh_quote (pmie_command); pmie_options += " " + get_config_single ("pmie"); // run pmieconf if requested if (get_config_exists ("pmieconf")) { string pmieconf_output_file = host_log_dir + (char)__pmPathSeparator() + "config.pmie"; string pmieconf_command = string(pmGetConfig("PCP_BIN_DIR")) + (char)__pmPathSeparator() + "pmieconf"; // NB: pmieconf doesn't take a host name as an argument, unlike pmlogconf string pmieconf_options = sh_quote(pmieconf_command) + " -F -c " + get_config_single ("pmieconf") + " -f " + sh_quote(pmieconf_output_file); if (pmDebug & DBG_TRACE_APPL0) timestamp(cout) << "running " << pmieconf_options << endl; int rc = system(pmieconf_options.c_str()); if (rc != 0) timestamp(cerr) << "system(" << pmieconf_options << ") failed: rc=" << rc << endl; pmie_options += "-c " + sh_quote(pmieconf_output_file); } // collect -h direction pmie_options += " -h " + sh_quote(spec); // collect -f, to get it to run in the foreground, avoid setuid pmie_options += " -f"; // collect subsidiary pmlogger diagnostics pmie_options += " -l " + sh_quote(host_log_dir + (char)__pmPathSeparator() + "pmie.log"); return pmie_options; } // ------------------------------------------------------------------------ extern "C" void handle_interrupt (int sig) { // Propagate signal to inferior processes (just once, to prevent // recursive signals or whatnot, despite sa_mask in // setup_signals()). if (quit == 0) kill(-getpid(), sig); quit ++; if (quit > 2) { char msg[] = "Too many interrupts received, exiting.\n"; int rc = write (2, msg, sizeof(msg)-1); if (rc) {/* Do nothing; we don't care if our last gasp went out. */ ;} // XXX: send a suicide signal to the process group? _exit (1); } } extern "C" void ignore_signal (int sig) { (void) sig; } void setup_signals() { // NB: we eschew __pmSetSignalHandler, since it uses signal(3), // whose behavior is less predictable than sigaction(2). struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = handle_interrupt; sigemptyset (&sa.sa_mask); sigaddset (&sa.sa_mask, SIGHUP); sigaddset (&sa.sa_mask, SIGPIPE); sigaddset (&sa.sa_mask, SIGINT); sigaddset (&sa.sa_mask, SIGTERM); sigaddset (&sa.sa_mask, SIGXFSZ); sigaddset (&sa.sa_mask, SIGXCPU); sa.sa_flags = SA_RESTART; sigaction (SIGHUP, &sa, NULL); sigaction (SIGPIPE, &sa, NULL); sigaction (SIGINT, &sa, NULL); sigaction (SIGTERM, &sa, NULL); sigaction (SIGXFSZ, &sa, NULL); sigaction (SIGXCPU, &sa, NULL); } // ------------------------------------------------------------------------ int main (int argc, char *argv[]) { __pmSetProgname(argv[0]); setup_signals(); string default_config_dir = string(pmGetConfig("PCP_SYSCONF_DIR")) + (char)__pmPathSeparator() + "pmmgr"; vector js; int c; int polltime = 60; char* username_str; __pmGetUsername(& username_str); string username = username_str; char* output_filename = NULL; while ((c = getopt(argc, argv, "D:c:vp:U:l:h")) != EOF) { switch (c) { case 'D': // undocumented (void) __pmParseDebug(optarg); break; case 'l': output_filename = optarg; break; case 'v': pmDebug |= DBG_TRACE_APPL0; break; case 'p': polltime = atoi(optarg); if (polltime <= 0) { cerr << "Poll time too short." << endl; exit(1); } break; case 'c': js.push_back (new pmmgr_job_spec(optarg)); break; case 'U': username = optarg; break; case 'h': default: cerr << "Usage: " << pmProgname << " [options] ..." << endl << "Options:" << endl << " -c DIR add another configuration directory " << "(default " << default_config_dir << ")" << endl << " -p NUM set pmcd polling interval " << "(default " << polltime << ")" << endl << " -U USER switch to userid " << "(default " << username << ")" << endl << " -v verbose diagnostics to stderr" << endl << endl; exit (1); } } // default if (js.size() == 0) js.push_back (new pmmgr_job_spec(default_config_dir)); // lose root privileges if we have them __pmSetProcessIdentity(username.c_str()); // (re)create log file, redirect stdout/stderr // NB: must be done after __pmSetProcessIdentity() for proper file permissions if (output_filename) { int fd; (void) unlink (output_filename); // in case one's left over from a previous other-uid run fd = open (output_filename, O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, 0666); if (fd < 0) timestamp(cerr) << "Cannot re-create logfile " << output_filename << endl; else { int rc; // Move the new file descriptors on top of stdout/stderr rc = dup2 (fd, STDOUT_FILENO); if (rc < 0) // rather unlikely timestamp(cerr) << "Cannot redirect logfile to stdout" << endl; rc = dup2 (fd, STDERR_FILENO); if (rc < 0) // rather unlikely timestamp(cerr) << "Cannot redirect logfile to stderr" << endl; rc = close (fd); if (rc < 0) // rather unlikely timestamp(cerr) << "Cannot close logfile fd" << endl; } } timestamp(cout) << "Log started" << endl; while (1) { // In this section, we must not fidget with SIGCHLD, due to use of system(3). for (unsigned i=0; ipoll(); if (quit) break; // We want to respond quickly if a child daemon process dies. (void) signal (SIGCHLD, ignore_signal); (void) signal (SIGALRM, ignore_signal); alarm (polltime); pause (); alarm (0); (void) signal (SIGCHLD, SIG_DFL); (void) signal (SIGALRM, SIG_DFL); } for (unsigned i=0; inext) (*func)(q, depth, path); if (depth > 0) (*func)(NULL, -1, NULL); /* end of level */ /* descend */ for (q = p; q != NULL; q = q->next) { if (q->first != NULL) { newpath = (char *)malloc(strlen(path)+strlen(q->name)+2); if (depth == 0) *newpath = '\0'; else if (depth == 1) strcpy(newpath, q->name); else { strcpy(newpath, path); strcat(newpath, "."); strcat(newpath, q->name); } pmns_traverse(q->first, depth+1, newpath, func); free(newpath); } } } } /* * generate an ASCII PMNS from the internal format produced by * pmLoadNameSpace and friends */ static void output(__pmnsNode *p, int depth, char *path) { static int lastdepth = -1; if (depth == 0) { fprintf(outf, "root {\n"); lastdepth = 1; return; } else if (depth < 0) { if (lastdepth > 0) fprintf(outf, "}\n"); lastdepth = -1; return; } else if (depth != lastdepth) fprintf(outf, "\n%s {\n", path); lastdepth = depth; if (p->first != NULL) fprintf(outf, "\t%s\n", p->name); else { if (pmid_domain(p->pmid) == DYNAMIC_PMID && pmid_item(p->pmid) == 0) fprintf(outf, "\t%s\t%d:*:*\n", p->name, pmid_cluster(p->pmid)); else fprintf(outf, "\t%s\t%d:%d:%d\n", p->name, pmid_domain(p->pmid), pmid_cluster(p->pmid), pmid_item(p->pmid)); } } void pmns_output(__pmnsNode *root, FILE *f) { outf = f; pmns_traverse(root, 0, "", output); output(NULL, -2, NULL); /* special hack for null PMNS */ } pcp-3.8.12ubuntu1/src/pmns/stdpmid.local0000664000000000000000000000011412272262501015022 0ustar # Domain numbers for local PMDAs # # PMDA Name Domain Number # #EXAMPLE 123 pcp-3.8.12ubuntu1/src/pmns/pmnsmerge.c0000664000000000000000000001564512272262501014522 0ustar /* * pmnsmerge [-adfv] infile [...] outfile * * Merge PCP PMNS files * * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include "pmapi.h" #include "impl.h" #include "pmnsutil.h" static FILE *outf; /* output */ static __pmnsNode *root; /* result so far */ static char *fullname; /* full PMNS pathname for newbie */ static int verbose = 0; typedef struct { char *fname; char *date; } datestamp_t; #define STAMP "_DATESTAMP" static int sortcmp(const void *a, const void *b) { datestamp_t *pa = (datestamp_t *)a; datestamp_t *pb = (datestamp_t *)b; if (pa->date == NULL) return -1; if (pb->date == NULL) return 1; return strcmp(pa->date, pb->date); } /* * scan for #define _DATESTAMP and re-order args accordingly */ static void sortargs(char **argv, int argc) { FILE *f; datestamp_t *tab; char *p; char *q; int i; char lbuf[40]; tab = (datestamp_t *)malloc(argc * sizeof(datestamp_t)); for (i = 0; i 1) printf("arg[%d] %s _DATESTAMP=%s\n", i, tab[i].fname, tab[i].date); } free(tab); } static void addpmns(__pmnsNode *base, char *name, __pmnsNode *p) { char *tail; ptrdiff_t nch; __pmnsNode *np; __pmnsNode *lastp = NULL; for (tail = name; *tail && *tail != '.'; tail++) ; nch = tail - name; for (np = base->first; np != NULL; np = np->next) { if (strlen(np->name) == nch && strncmp(name, np->name, (int)nch) == 0) break; lastp = np; } if (np == NULL) { /* no match ... add here */ np = (__pmnsNode *)malloc(sizeof(__pmnsNode)); if (base->first) { lastp->next = np; np->parent = lastp->parent; } else { base->first = np; np->parent = base; } np->first = np->next = NULL; np->hash = NULL; /* we do not need this here */ np->name = (char *)malloc(nch+1); strncpy(np->name, name, nch); np->name[nch] = '\0'; if (*tail == '\0') { np->pmid = p->pmid; return; } np->pmid = PM_ID_NULL; } else if (*tail == '\0') { /* complete match */ if (np->pmid != p->pmid) { fprintf(stderr, "%s: Warning: performance metric \"%s\" has multiple PMIDs.\n... using PMID %s and ignoring PMID", pmProgname, fullname, pmIDStr(np->pmid)); fprintf(stderr, " %s\n", pmIDStr(p->pmid)); } return; } /* descend */ addpmns(np, tail+1, p); } /* * merge, adding new nodes if required */ static void merge(__pmnsNode *p, int depth, char *path) { char *name; if (depth < 1 || p->pmid == PM_ID_NULL || p->first != NULL) return; name = (char *)malloc(strlen(path)+strlen(p->name)+2); if (*path == '\0') strcpy(name, p->name); else { strcpy(name, path); strcat(name, "."); strcat(name, p->name); } fullname = name; addpmns(root, name, p); free(name); } int main(int argc, char **argv) { int sts; int first = 1; int c; int j; int force = 0; int asis = 0; int dupok = 0; int errflag = 0; __pmnsNode *tmp; umask((mode_t)022); /* anything else is pretty silly */ __pmSetProgname(argv[0]); while ((c = getopt(argc, argv, "aD:dfv?")) != EOF) { switch (c) { case 'a': asis = 1; break; case 'd': /* duplicate PMIDs are OK */ dupok = 1; break; case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case 'f': /* force ... unlink file first */ force = 1; break; case 'v': verbose++; break; case '?': default: errflag++; break; } } if (errflag || optind > argc-2) { fprintf(stderr, "Usage: %s [options] infile [...] outfile\n\ \n\ Options:\n\ -a process files in order, ignoring embedded _DATESTAMP control lines\n\ -d duplicate PMIDs are acceptable\n\ -f force overwriting of an existing output file, if it exists\n\ -v verbose, echo input file names as processed\n", pmProgname); exit(1); } if (force) unlink(argv[argc-1]); if (access(argv[argc-1], F_OK) == 0) { fprintf(stderr, "%s: Error: output PMNS file \"%s\" already exists!\nYou must either remove it first, or use -f\n", pmProgname, argv[argc-1]); exit(1); } /* * from here on, ignore SIGHUP, SIGINT and SIGTERM to protect * the integrity of the new ouput file */ __pmSetSignalHandler(SIGHUP, SIG_IGN); __pmSetSignalHandler(SIGINT, SIG_IGN); __pmSetSignalHandler(SIGTERM, SIG_IGN); if ((outf = fopen(argv[argc-1], "w+")) == NULL) { fprintf(stderr, "%s: Error: cannot create output PMNS file \"%s\": %s\n", pmProgname, argv[argc-1], osstrerror()); exit(1); } if (!asis) sortargs(&argv[optind], argc - optind - 1); j = optind; while (j < argc-1) { if (verbose) printf("%s:\n", argv[j]); if ((sts = pmLoadASCIINameSpace(argv[j], dupok)) < 0) { fprintf(stderr, "%s: Error: pmLoadNameSpace(%s): %s\n", pmProgname, argv[j], pmErrStr(sts)); exit(1); } { __pmnsTree *t; t = __pmExportPMNS(); if (t == NULL) { /* sanity check - shouldn't ever happen */ fprintf(stderr, "Exported PMNS is NULL !"); exit(1); } tmp = t->root; } if (first) { root = tmp; first = 0; } else { pmns_traverse(tmp, 0, "", merge); } j++; } pmns_output(root, outf); fclose(outf); /* * now load the merged PMNS to check for errors ... */ if ((sts = pmLoadASCIINameSpace(argv[argc-1], dupok)) < 0) { fprintf(stderr, "%s: Error: pmLoadNameSpace(%s): %s\n", pmProgname, argv[argc-1], pmErrStr(sts)); exit(1); } exit(0); } pcp-3.8.12ubuntu1/src/pmns/Make.stdpmid0000775000000000000000000000765312272262501014627 0ustar #!/bin/sh # # Copyright (c) 1995,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # source the PCP configuration environment variables . $PCP_DIR/etc/pcp.env if [ -d "$PCP_TMPFILE_DIR" ] then tmp=`mktemp -d "$PCP_TMPFILE_DIR/pcp.XXXXXXXXX"` || exit 1 else # if configure --prefix is used in a the build, then $PCP_TMPFILE_DIR # may not yet exist ... /tmp is a safe bet # tmp=`mktemp -d /tmp/pcp.XXXXXXXXX` || exit 1 fi status=1 trap "rm -rf $tmp; exit \$status" 0 1 2 3 15 prog=`basename $0` OLD=stdpmid NEW=$tmp/new SOURCE="" for file in `echo stdpmid.*` do case $file in stdpmid.'*'|stdpmid.O|stdpmid.O.*|stdpmid.N|stdpmid.N.*|stdpmid.rpmorig|stdpmid.*.rpmorig) ;; *) SOURCE="$SOURCE $file" ;; esac done [ -z "$SOURCE" ] && exit # nothing to do - the norm nowadays # post-processing with sed ... # - removes comments # - maps white space to a single space # - performs domain re-numbering that occured for LAB and ASH # between PCP 2.0 and PCP 2.1 to avoid duplicates in the interim # # Note on sort. Used to be "sort -n +1 -2", but changed to "sort -n -k2,3" # to avoid problems with more recent Linux coreutils versions. # for file in $SOURCE do sed <$file \ -e '/^#/d' \ -e 's/[ ][ ]*/ /' \ -e '/^LAB /s/254/246/' \ -e '/^ASH /s/7/11/' done \ | sort -n -k2,3 \ | uniq >$tmp/tmp if [ -s "$tmp/tmp" ] then error=false else echo "$prog: Error: failed to create temporary file" exit fi # scan for duplicate domain name, but different domain number # $PCP_AWK_PROG '{ print $1 }' <$tmp/tmp \ | sort \ | uniq -c \ | while read cnt domain do [ $cnt -eq 1 ] && continue echo "$prog: Error: duplicate for domain name \"$domain\" ..." grep "^$domain[ ]" $SOURCE | sed -e 's/^/ /' error=true done # scan for duplicate domain number, but different domain name # $PCP_AWK_PROG '{ print $2 }' <$tmp/tmp \ | sort \ | uniq -c \ | while read cnt number do [ $cnt -eq 1 ] && continue echo "$prog: Error: duplicate for domain number \"$number\" ..." grep "[ ]$number\$" $SOURCE | sed -e 's/^/ /' error=true done $error && exit # preamble # cat <<'End-of-File' >$NEW /* * NOTE: * Do not edit this file (it is re-created by Make.stdpmid). * To make changes, edit one of the stdpmid.* files, most probably * stdpmid.local, and as root * # make stdpmid * * The following domain number assignments are assumed to apply * * Domain Number Range Use * 0 reserved -- DO NOT USE * 1-31 production PMDAs from PCP packages (#1) * 32-39 ORACLE DBMS PMDAs * 40-47 Sybase DBMS PMDAs * 48-55 Informix DBMS PMDAs * 56-58 SNMP Gateway PMDA * 59-63 Linux PMDAs * 64-69 ISV PMDAs * 70-128 production PMDAs from PCP packages (#2) * 129-510 End-User PMDAs and demo PMDAs * 511 reserved for dynamic PMNS entries -- DO NOT USE * * A Performance Metrics Identifier (PMID) is internally encoded as * 1 bits - flag reserved for internal use * 9 bits - the Performance Metric Domain Agent (PMDA) domain number * from the list below * 12 bits - cluster within domain * 10 bits - serial within cluster */ #ifndef __STDPMID #define __STDPMID End-of-File cat $tmp/tmp \ | while read domain number do echo "#define $domain $number" >>$NEW done echo ' #endif' >>$NEW # only update if it has changed # if [ -f $OLD ] then if cmp -s $OLD $NEW >/dev/null 2>&1 then rm -f $NEW fi fi if [ -f $NEW ] then cp $NEW $OLD chmod 444 $NEW fi status=0 exit pcp-3.8.12ubuntu1/src/pmns/pmnsdel.c0000664000000000000000000001172012272262501014155 0ustar /* * pmnsdel [-d] [-n pmnsfile ] metricpath [...] * * Cull subtree(s) from a PCP PMNS * * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include #include "pmapi.h" #include "impl.h" #include "pmnsutil.h" static FILE *outf; /* output */ static __pmnsNode *root; /* result so far */ static char *fullname; /* full PMNS pathname for newbie */ static void delpmns(__pmnsNode *base, char *name) { char *tail; ptrdiff_t nch; __pmnsNode *np; __pmnsNode *lastp = NULL; for (tail = name; *tail && *tail != '.'; tail++) ; nch = tail - name; for (np = base->first; np != NULL; np = np->next) { if (strlen(np->name) == nch && strncmp(name, np->name, (int)nch) == 0) break; lastp = np; } if (np == NULL) { /* no match ... */ fprintf(stderr, "%s: Error: metricpath \"%s\" not defined in the PMNS\n", pmProgname, fullname); exit(1); } else if (*tail == '\0') { /* complete match */ if (np == base->first) { /* deleted node is first at this level */ base->first = np->next; /* * remove predecessors that only exist to connect * deleted node to the rest of the PMNS */ np = base; while (np->first == NULL && np->parent != NULL) { if (np->parent->first == np) { /* victim is the only one at this level ... */ np->parent->first = np->next; np = np->parent; } else { /* victim has at least one sibling at this level */ lastp = np->parent->first; while (lastp->next != np) lastp = lastp->next; lastp->next = np->next; break; } } } else /* link around deleted node */ lastp->next = np->next; return; } /* descend */ delpmns(np, tail+1); } int main(int argc, char **argv) { int sep = __pmPathSeparator(); int sts; int c; int dupok = 0; int errflag = 0; char *p; char pmnsfile[MAXPATHLEN]; char outfname[MAXPATHLEN]; struct stat sbuf; __pmSetProgname(argv[0]); if ((p = getenv("PMNS_DEFAULT")) != NULL) strcpy(pmnsfile, p); else snprintf(pmnsfile, sizeof(pmnsfile), "%s%c" "pmns" "%c" "root", pmGetConfig("PCP_VAR_DIR"), sep, sep); while ((c = getopt(argc, argv, "dD:n:?")) != EOF) { switch (c) { case 'd': /* duplicate PMIDs are OK */ dupok = 1; break; case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } else pmDebug |= sts; break; case 'n': /* alternative name space file */ strcpy(pmnsfile, optarg); break; case '?': default: errflag++; break; } } if (errflag || optind > argc-1) { fprintf(stderr, "Usage: %s [-d] [-n pmnsfile ] metricpath [...]\n", pmProgname); exit(1); } if ((sts = pmLoadASCIINameSpace(pmnsfile, dupok)) < 0) { fprintf(stderr, "%s: Error: pmLoadNameSpace(%s): %s\n", pmProgname, pmnsfile, pmErrStr(sts)); exit(1); } { __pmnsTree *t; t = __pmExportPMNS(); if (t == NULL) { /* sanity check - shouldn't ever happen */ fprintf(stderr, "Exported PMNS is NULL !"); exit(1); } root = t->root; } while (optind < argc) { delpmns(root, fullname = argv[optind]); optind++; } /* * from here on, ignore SIGHUP, SIGINT and SIGTERM to protect * the integrity of the new ouput file */ __pmSetSignalHandler(SIGHUP, SIG_IGN); __pmSetSignalHandler(SIGINT, SIG_IGN); __pmSetSignalHandler(SIGTERM, SIG_IGN); snprintf(outfname, sizeof(outfname), "%s.new", pmnsfile); if ((outf = fopen(outfname, "w")) == NULL) { fprintf(stderr, "%s: Error: cannot open PMNS file \"%s\" for writing: %s\n", pmProgname, outfname, osstrerror()); exit(1); } if (stat(pmnsfile, &sbuf) == 0) { /* * preserve the mode and ownership of any existing PMNS file */ chmod(outfname, sbuf.st_mode & ~S_IFMT); #if defined(HAVE_CHOWN) if (chown(outfname, sbuf.st_uid, sbuf.st_gid) < 0) fprintf(stderr, "%s: chown(%s, ...) failed: %s\n", pmProgname, outfname, osstrerror()); #endif } pmns_output(root, outf); fclose(outf); /* rename the PMNS */ if (rename2(outfname, pmnsfile) == -1) { fprintf(stderr, "%s: cannot rename \"%s\" to \"%s\": %s\n", pmProgname, outfname, pmnsfile, osstrerror()); /* remove the new PMNS */ unlink(outfname); exit(1); } exit(0); } pcp-3.8.12ubuntu1/src/pmns/GNUmakefile0000664000000000000000000000523712272262521014431 0ustar # # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs -include ./GNUlocaldefs PMNS_VAR_DIR = $(PCP_VAR_DIR)/pmns PMNS_BIN_DIR = $(PCP_BINADM_DIR) PMNS_LIB_DIR = $(PCP_SHARE_DIR)/lib # Take control here ... do not need to search in libpcp_pmda directory # for libpcp_pmda DSO, and it is not even built yet for a virgin make. # PCPLIB_LDFLAGS = -L$(TOPDIR)/src/libpcp/src CFILES = pmnsmerge.c pmnsutil.c pmnsdel.c HFILES = pmnsutil.h TARGETS = pmnsmerge$(EXECSUFFIX) pmnsdel$(EXECSUFFIX) SCRIPTS = pmnsadd LOCKERS = lockpmns unlockpmns STDPMID = stdpmid.pcp stdpmid.local LSRCFILES = Make.stdpmid GNUmakefile.install Rebuild ReplacePmnsSubtree \ $(STDPMID) $(SCRIPTS) $(LOCKERS) LLDLIBS = $(PCPLIB) LDIRT = *.log *.pmns stdpmid .NeedRebuild build.script $(TARGETS) default: $(SCRIPTS) $(LOCKERS) $(TARGETS) \ GNUmakefile.install .NeedRebuild Rebuild ReplacePmnsSubtree stdpmid include $(BUILDRULES) pmnsmerge$(EXECSUFFIX): pmnsmerge.o pmnsutil.o $(CCF) -o $@ $(LDFLAGS) pmnsmerge.o pmnsutil.o $(LDLIBS) pmnsdel$(EXECSUFFIX): pmnsdel.o pmnsutil.o $(CCF) -o $@ $(LDFLAGS) pmnsdel.o pmnsutil.o $(LDLIBS) .NeedRebuild: echo "This file flags the rc scripts to rebuild the PMNS" > .NeedRebuild # All PMNS config stuff goes in $PCP_VAR_DIR/pmns # For platforms that want it, the .NeedRebuild hook is added there, # else a manual touch(1) here is as close as it gets unfortunately. # install: default $(INSTALL) -m 755 $(TARGETS) $(SCRIPTS) $(PMNS_BIN_DIR) $(INSTALL) -m 755 $(LOCKERS) ReplacePmnsSubtree $(PMNS_LIB_DIR) $(INSTALL) -m 644 GNUmakefile.install $(PMNS_VAR_DIR)/Makefile $(INSTALL) -m 755 Rebuild $(PMNS_VAR_DIR)/Rebuild $(INSTALL) -m 755 Make.stdpmid $(PMNS_VAR_DIR)/Make.stdpmid $(INSTALL) -m 644 $(STDPMID) $(PMNS_VAR_DIR) ifeq (, $(filter redhat debian, $(PACKAGE_DISTRIBUTION))) $(INSTALL) -m 644 .NeedRebuild $(PMNS_VAR_DIR)/.NeedRebuild endif stdpmid: $(STDPMID) rm -f build.script $(AWK) build.script '\ /^. \$$PCP_DIR/ { print "PCP_CONF=../include/pcp.conf"; print ". ../include/pcp.env"; next }\ { print }' sh ./build.script default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmns/GNUmakefile.install0000664000000000000000000000210512272262501016063 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Makefile to rebuild the Performance Metrics Names Space (PMNS) (root) # and the standard Performance Metric Domain numbers (stdpmid) # TARGETS = root PMNS != echo root_* STDPMID != echo stdpmid.* default: root stdpmid root: $(PMNS) ./Rebuild stdpmid: $(STDPMID) ./Make.stdpmid clobber: rm -f stdpmid pcp-3.8.12ubuntu1/src/pmns/Rebuild0000775000000000000000000001762012272262501013670 0ustar #!/bin/sh # # Copyright (c) 2000-2001,2003 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Rebuild the PMNS, handling assorted errors # # Note. has to be run from where the PMNS files are installed as local # file names (not full paths) are used # # source the PCP configuration environment variables . $PCP_DIR/etc/pcp.env tmp=`mktemp -d ./pcp.XXXXXXXXX` || exit 1 status=1 $PCP_SHARE_DIR/lib/lockpmns root trap "$PCP_SHARE_DIR/lib/unlockpmns root; rm -rf $tmp; exit \$status" 0 1 2 3 15 _trace() { if $silent then : else if $nochanges then echo "$*" else echo "$*" >>$tmp/trace fi fi } _trace_file() { if $silent then : else if $nochanges then cat $1 else cat $1 >>$tmp/trace fi fi } _syslog() { $PCP_SYSLOG_PROG -p user.alert -t PCP "$*" _trace "$*" } _die() { [ -f $tmp/trace ] && cat $tmp/trace rm -f root.new exit } prog=`basename $0` debug=false nochanges=false root=root root_updated=false update=false verbose="" dupok=false silent=false _usage() { _trace "Usage: Rebuild [-dnsuv]" _trace "Options:" _trace " -d allow duplicate PMIDs in the PMNS" _trace " -n dry run, show me what would be done" _trace " -s silent, exit status says it all" _trace " -u once only upgrade processing for a new PCP version" _trace " -v verbose, for the paranoid" } # Fixup "root" after PCP upgrade # _upgrade_root() { [ ! -f root ] && return _trace "Rebuild: PCP upgrade processing for \"root\" PMNS changes ..." $nochanges && _trace "+ cull root_* names from PMNS ... $tmp/root" # Cull root to remove all metrics from root_* files, so only metrics # for optional PMDAs remain # If there are deprecated top-level names (below "root") that are # no longer in a root_* file, add them here ... EXCLUDE="pagebuf origin" if [ "$PCP_PLATFORM" = linux ] then # If we're on Linux and the proc PMDA is _not_ included in # the pmcd configuration file, add the top-level metrics # that migrated from the linux PMDA to the proc PMDA # if [ -f $PCP_PMCDCONF_PATH ] then if grep '^proc[ ]' $PCP_PMCDCONF_PATH >/dev/null then # proc PMDA is installed # : else EXCLUDE="$EXCLUDE proc cgroup" fi else EXCLUDE="$EXCLUDE proc cgroup" fi else EXCLUDE="$EXCLUDE proc cgroup" fi # now gather top-level names from root_* files # if [ "`echo root_*`" != "root_*" ] then EXCLUDE_TMP=`for file in root_* do $PCP_AWK_PROG <$file ' $1 == "}" { exit } in_root==1 { printf "%s ",$1 } $1 == "root" && $2 == "{" { in_root = 1 }' done` EXCLUDE="$EXCLUDE $EXCLUDE_TMP" fi if [ ! -z "$verbose" -a ! -z "$EXCLUDE" ] then _trace "Exclude these top-level names ..." _trace "`echo $EXCLUDE | fmt | sed -e 's/^/ /'`" fi $PCP_AWK_PROG $tmp/root ' BEGIN { # exclude these top-level names and all their descendents # n = split("'"$EXCLUDE"'", e) for (i=1; i <= n; i++) { not_in_root[e[i]] = 1 } in_root = 0 skip = 0 } $1 == "root" && $2 == "{" { in_root = 1 } $1 == "}" { in_root = 0 } in_root { if (!($1 in not_in_root)) print next } $2 == "{" { n = split($1, name, ".") if (n > 0 && name[1] in not_in_root) skip = 1 } skip && $1 == "}" { skip = 0; next } skip { next } { print }' if cmp -s root $tmp/root >/dev/null 2>&1 then # no changes ... already been here? : else # we will usually end up here root=$tmp/root root_updated=true fi } while getopts dnusv\? c do case $c in d) dupok=true ;; n) nochanges=true echo "$prog: Warning: dry run, no changes will be made" ;; u) update=true ;; s) silent=true ;; v) verbose="-v" ;; \?) _usage status=0 _die ;; esac done shift `expr $OPTIND - 1` # some preliminary checks # for file in $PCP_BINADM_DIR/pmnsmerge do if [ ! -x $file ] then _syslog "$prog: $file is missing. Cannot proceed." _die fi done # remove all trace of old binary pmns (not used in PCP 3.6 or later) # rm -f root.bin here=`pwd` _trace "Rebuilding the Performance Metrics Name Space (PMNS) in $here ..." if [ $# -ne 0 ] then _usage _die fi if $nochanges then CP="_trace + cp" MV="_trace + mv" LN="_trace + ln" RM="_trace + rm" PMNSMERGE="_trace + pmnsmerge ..." else CP=cp MV=mv LN=ln RM=rm PMNSMERGE= if [ ! -w `pwd` ] then _syslog "$prog: cannot write in directory `pwd`, script should be run as \"root\"?" _die fi if [ ! -f root ] then echo "root {" >root echo "}" >>root chmod 644 root fi if [ ! -w root ] then _syslog "$prog: cannot write file \"root\" in directory `pwd`, script should be run as \"root\"?" _die fi fi if $update then # PCP upgrade fix ups # _upgrade_root fi if [ -f $root ] then haveroot=true else haveroot=false if $nochanges then _trace "+ create empty root PMNS ..." else root=$tmp/root cat <$root root { } EOFEOF fi fi # Merge $root and root_* to produce the new root. # Each root_* file should be a complete namespace, # i.e. it should include an entry for root. # mergelist="" if [ "`echo root_*`" != "root_*" ] then mergelist=`ls -1 root_* | $PCP_AWK_PROG ' /root_web/ {next} {print}'` fi _trace "$prog: merging the following PMNS files: " _trace $root $mergelist | fmt | sed -e 's/^/ /' rm -f root.new eval $PMNSMERGE if $dupok then pmnsmerge $verbose -d $root $mergelist root.new >$tmp/out 2>&1 else pmnsmerge $verbose $root $mergelist root.new >$tmp/out 2>&1 fi if [ $? != 0 ] then cat $tmp/out _syslog "$prog: pmnsmerge failed" _trace " \"root\" has not been changed." _die fi # Multiple Rebuilds in succession should be a no-op. # if [ -f root ] then if $dupok then pminfo -m -N root 2>/dev/null | sort >$tmp/list.old else pminfo -m -n root 2>/dev/null | sort >$tmp/list.old fi fi if [ ! -s $tmp/list.old ] then if $dupok then pminfo -m -N $root 2>/dev/null | sort >$tmp/list.old else pminfo -m -n $root 2>/dev/null | sort >$tmp/list.old fi fi if $dupok then pminfo -m -N root.new | sort >$tmp/list.new else pminfo -m -n root.new | sort >$tmp/list.new fi if cmp -s $tmp/list.old $tmp/list.new > /dev/null 2>&1 then [ ! -f root ] && eval $MV root.new root _trace "$prog: PMNS is unchanged." else # Install the new root # [ ! -z "$verbose" ] && _trace_file $tmp/out if $haveroot then _trace "$prog: PMNS \"$here/root\" updated." _trace "... previous version saved as \"$here/root.prev\"" eval $MV root root.prev else _trace "$prog: new PMNS \"$here/root\" created." fi eval $MV root.new root # signal pmcd if it is running # pminfo -v pmcd.version >/dev/null 2>&1 && pmsignal -a -s HUP pmcd if [ ! -z "$verbose" ] && $haveroot then _trace "+ PMNS differences ..." diff -c $tmp/list.old $tmp/list.new >$tmp/diff _trace_file $tmp/diff _trace _trace "+ root differences ..." diff -c root.prev root >$tmp/diff _trace_file $tmp/diff fi fi rm -f root.new # remake stdpmid # [ -f Make.stdpmid ] && ./Make.stdpmid [ X"$verbose" = X-v -a -f $tmp/trace ] && cat $tmp/trace status=0 exit pcp-3.8.12ubuntu1/src/pmns/lockpmns0000664000000000000000000000235312272262501014122 0ustar #!/bin/sh # # Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA # # Lock the PMNS against concurrent transactional updates # . $PCP_DIR/etc/pcp.env lock=${1-$PCP_VAR_DIR/pmns/root}.lock i=0 while true do if pmlock $lock then # lock acquired # #DEBUG# echo "pmnslock: `date; ls -li $lock`" break fi if [ $i -eq 20 ] then echo "lockpmns: Warning: Unable to acquire lock ($lock)" echo " after 120 seconds ... continuing anyway" exit 1 fi sleep 5 i=`expr $i + 1` done exit 0 pcp-3.8.12ubuntu1/src/pmns/ReplacePmnsSubtree0000664000000000000000000001150312272262501016034 0ustar #!/bin/sh # # Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Replace a subtree in a performance metrics namespace (PMNS) with a new # subtree read from a file. The file is moved (note: not copied) into the # PMNS and given the same name as the subtree. # # Usage: ReplacePmnsSubtree [-n namespace] pmns-subtree replacement-file # # Refer to the NOTE at the bottom of the file for important locking details. # . $PCP_DIR/etc/pcp.env namespace=$PCP_VAR_DIR/pmns/root # Print usage message to stderr and exit with status provided (default 1) usageExit() { echo "Usage: $prog [-n namespace] pmns-subtree replacement-file" 1>&2 exit ${1:-1} } # Sanity check options, parameters, namespace, etc. prog=`basename $0` while getopts n:\? c do case "$c" in n) if [ "x$OPTARG" = x ] then echo "$prog: -n requires a namespace" 1>&2 exit 1 else namespace="$OPTARG" fi ;; \?) usageExit 0 ;; esac done if [ ! -f $namespace ] then echo "$prog: namespace doesn't exist: $namespace" 1>&2 exit 1 fi [ $# != 2 ] && usageExit subtree=$1 newSubtreeFile=$2 namespaceDir=`dirname $namespace` if [ ! -w $namespaceDir ] then echo "$prog: can't write namespace directory $namespaceDir" 1>&2 exit 1 fi if [ ! -f $newSubtreeFile ] then echo "$prog: can't read replacement namespace subtree file for $subtree:" \ "$newSubtreeFile" 1>&2 exit 1 fi # variables for back-up/restore of namespace files affected by this script backups="root" [ -f "$namespaceDir/$subtree" ] && backups="$backups $subtree" backSuffix="$prog-$$-backup" restore=false # restore backup namespace files in cleanup() # Signal and exit handler to clean/restore namespace (lock and backups). haveLock=false # signals we need to be careful of ... HUP, INT, QUIT, PIPE, ALRM, TERM # STD_SIGNALS="1 2 3 13 14 15" cleanup() { # Release namespace lock as early as possible. Ignore signals to avoid # releasing a lock already released. trap "" $STD_SIGNALS if $restore then for f in $backups do [ -f "$namespaceDir/.$f-$backSuffix" ] && \ mv "$namespaceDir/.$f-$backSuffix" "$namespaceDir/$f" done $haveLock && unlockpmns $namespace haveLock=false else $haveLock && unlockpmns $namespace haveLock=false for f in $backups do rm -f "$namespaceDir/.$f-$backSuffix" done fi } trap "cleanup; exit" 0 $STD_SIGNALS # "haveLock=true" is duplicated in both "if" and "else" to minimise the window # for a signal leaving an orphaned lock if the "else" condition fires (we # stole an existing lock). See note at bottom of script for details. if lockpmns $namespace then haveLock=true # duplicate: minimise race condition (see note above) else haveLock=true # duplicate: minimise race condition (see note above) $PCP_BINADM_DIR/pmpost "PCP: PMNS lock stolen by: $*" fi # Namespace is locked, back up affected files. Once backup completes, enable # namespace restore during error handling. backupErr=false for f in $backups do dest="$namespaceDir/.$f-$backSuffix" if cp "$namespaceDir/$f" "$dest" then : else echo "error creating namespace backup for $f" 1>&2 backupErr=true fi done $backupErr && exit 1 restore=true # pmnsdel leaves any file corresponding to the deleted subtree in place after # it runs, regardless of whether it succeeds or fails. Allow pmnsdel to fail # (there may be no existing subtree). Return 0 only if the entire replacement # succeeds. sts=0 pmnsdel -n $namespace $subtree >/dev/null 2>&1 if pmnsadd -n $namespace $newSubtreeFile >/dev/null 2>&1 then mv -f $newSubtreeFile $namespaceDir/$subtree sts=$? else sts=1 fi [ $sts = 0 ] && restore=false exit $sts ############################################################################## # NOTE # # If a signal occurs in the very short window between pmnslock returning and # setting haveLock, the lock is not released by cleanup(). Any subsequent # process calling pmnslock will block until its pmnslock steals the lock # (currently after 120 secs). That window is carefully minimised. # # Past versions of similar scripts (e.g. Rebuild) unconditionally unlocked the # namespace when a signal was caught. This could potentially happen while # still waiting to acquire the lock, breaking a lock held by another process! # # Consider locking and backup/restore implications carefully if making changes. pcp-3.8.12ubuntu1/src/pmns/pmnsadd0000775000000000000000000000553412272262501013731 0ustar #!/bin/sh # # Copyright (c) 1997-2001 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # Add a subtree of new names into the namespace in the current directory # # source the PCP configuration environment variables . $PCP_DIR/etc/pcp.env umask 22 # anything else is pretty silly exitsts=1 tmp=`mktemp -d $PCP_TMPFILE_DIR/pcp.XXXXXXXXX` || exit 1 prog=`basename $0` trap "rm -rf $tmp; exit \$exitsts" 0 1 2 3 15 _usage() { echo "Usage: pmnsadd [-d] [-n namespace] file" } namespace=${PMNS_DEFAULT-$PCP_VAR_DIR/pmns/root} dupok="" while getopts dn:\? c do case $c in d) dupok="-d" ;; n) namespace=$OPTARG ;; \?) _usage exitsts=0 exit ;; esac done shift `expr $OPTIND - 1` if [ $# -ne 1 ] then _usage exit fi if [ ! -f $namespace ] then echo "$prog: cannot find PMNS file \"$root\"" exit fi if [ ! -w $namespace ] then echo "$prog: cannot open PMNS file \"$root\" for writing" exit fi if [ ! -f "$1" ] then echo "$prog: cannot find input file \"$1\"" exit fi if grep '^root {' "$1" >/dev/null then # Special case ... if the PMDA only supplies metrics at the root of # the PMNS, e.g. the MMV PMDA with all dynamic metrics, the input # PMNS contains 'root {' already, so just use that without any need # to construct the upper levels of the PMNS # cp "$1" $tmp/tmp else # Normal case ... find PMNS pathname for base of new subtree # (subroot), construct upper levels of PMNS as required and hand-off # to pmnsmerge # subroot=`$PCP_AWK_PROG <"$1" 'NF >= 2 && $2 == "{" { print $1 ; exit }'` echo 'root {' >$tmp/tmp path="" for name in `echo "$subroot" | tr '.' ' '` do [ ! -z "$path" ] && echo "$path {" >>$tmp/tmp echo " $name" >>$tmp/tmp echo "}" >>$tmp/tmp if [ -z "$path" ] then path="$name" else path="$path.$name" fi done cat "$1" >>$tmp/tmp fi # try to preserve mode, owner and group for the new output files # rm -f $namespace.new [ -f $namespace ] && cp -p $namespace $namespace.new $PCP_BINADM_DIR/pmnsmerge -f $dupok $namespace $tmp/tmp $namespace.new exitsts=$? # from here on, ignore SIGINT, SIGHUP and SIGTERM to protect # the integrity of the new ouput files # trap "" 1 2 15 if [ $exitsts = 0 ] then mv $namespace.new $namespace else echo "$prog: No changes have been made to the PMNS file \"$namespace\"" rm -f $namespace.new fi pcp-3.8.12ubuntu1/src/pmns/stdpmid.pcp0000664000000000000000000000266012272262501014522 0ustar # Domain numbers for PMDAs in the base PCP product # # PMDA Name Domain Number # IRIX 1 PMCD 2 PROC 3 ENVIRON 4 CISCO 5 HIPPI 6 HOTPROC 7 NETPROBE 8 MAILQ 9 TRACE 10 XFS 11 FSAFE 12 MPI 13 DMF 14 SENDMAIL 15 XVM 16 BROCADE 17 ESPPING 18 SHPING 19 HPUX 20 WEBPING 21 WEBSERVER 22 ARRAY0 23 ARRAY1 24 ARRAY2 25 ARRAY3 26 SYSSUMMARY 27 NEWS 28 SAMPLE 29 SAMPLEDSO 30 KERN_DEV 31 ORACLE 32 SYBASE 40 INFORMIX 48 SNMP 56 LOCKSTAT 59 LINUX 60 MYRINET 61 SNIA 63 CLUSTER 65 MYSQL 66 LOGTAIL 67 APACHE 68 ROOMTEMP 69 MMV 70 PROCESS 71 MOUNTS 72 SNIFF 73 LMSENSORS 74 SOLARIS 75 SAMBA 76 NFS 77 DARWIN 78 WINDOWS 79 AIX 80 TG3 81 CXFS 82 FCSW 83 CPUSET 84 FREEBSD 85 RPCBIND 86 ETW 87 SYSTEMTAP 88 MEMCACHE 89 VMWARE 90 IB 91 ISCSI 92 LUSTRECOMM 93 SDR 94 KVM 95 BONDING 96 NETFILTER 97 ZIMBRA 98 UV 99 NAMED 100 PDNS 101 DTSRUN 102 POSTFIX 103 IPMI 104 GPSD 105 LOGGER 106 RSYSLOG 107 ELASTICSEARCH 108 MSSQL 109 POSTGRESQL 110 CTDB 111 /* Clustered Trivial Database (samba.org) */ BASH 112 FIBRECHANNEL 113 SYSTEMD 114 GFS2 115 NETBSD 116 NGINX 117 GLUSTER 118 PANASAS 119 NVML 120 CIFS 121 JBD2 122 RPM 123 ### NEXT FREE SLOT ### DBPING 244 PMI_DOMAIN 245 LAB 246 DYNAMIC 247 TXMON 248 BROKEN 249 TRIVIAL 250 SYBPING 251 INFMXPING 252 SIMPLE 253 ORAPING 254 ### MORE FREE SLOTS ### # # 511 is REALLY reserved ... see DYNAMIC_PMID in impl.h # RESERVED_DO_NOT_USE 511 pcp-3.8.12ubuntu1/src/pmns/pmnsutil.h0000664000000000000000000000165012272262501014374 0ustar /* * Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ extern void pmns_traverse(__pmnsNode *, int , char *, void(*)(__pmnsNode *, int, char *)); extern void pmns_output(__pmnsNode *, FILE *); pcp-3.8.12ubuntu1/src/pmcpp/0000775000000000000000000000000012272262620012512 5ustar pcp-3.8.12ubuntu1/src/pmcpp/GNUmakefile0000664000000000000000000000153212272262501014563 0ustar # # Copyright (c) 2011 Ken McDonell. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmcpp.c LLDLIBS = $(PCPLIB) CMDTARGET = pmcpp$(EXECSUFFIX) default: $(CMDTARGET) include $(BUILDRULES) install: $(CMDTARGET) $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BINADM_DIR)/$(CMDTARGET) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmcpp/pmcpp.c0000664000000000000000000003067112272262501014002 0ustar /* * * Simple cpp replacement to be used to pre-process a PMNS from * pmLoadNameSpace() in libpcp. * * Supports ... * - #define name value * no spaces in value, no quotes or escapes * name begins with an alpha or _, then zero or more alphanumeric or _ * value is optional and defaults to the empty string * - macro substitution * - standard C-style comment stripping * - #include "file" or #include * up to a depth of 5 levels, for either syntax the directory search * is hard-wired to , the directory of command line file (if any) * and then $PCP_VAR_DIR/pmns * - #ifdef ... #endif and #ifndef ... #endif * * Does NOT support ... * - #if * - nested #ifdef * - error recovery - first error is fatal * - C++ style // comments * * Copyright (c) 2011 Ken McDonell. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmapi.h" #include "impl.h" #include #include static char ibuf[256]; /* input line buffer */ /* optind #include file control * allow MAXLEVEL-1 levels of #include */ #define MAXLEVEL 5 static struct { char *fname; FILE *fin; int lineno; } file_ctl[MAXLEVEL], *currfile = NULL; /* * macro definitions via #define */ typedef struct { int len; char *name; char *value; } macro_t; static macro_t *macro = NULL; static int nmacro = 0; static void err(char *) __attribute__((noreturn)); /* * use pmprintf for fatal messages as we're usually run from * pmLoadNameSpace() in libpcp */ static void err(char *msg) { fflush(stdout); if (currfile != NULL) { if (currfile->lineno > 0) pmprintf("pmcpp: %s[%d]: %s", currfile->fname, currfile->lineno, ibuf); else pmprintf("pmcpp: %s:\n", currfile->fname); } pmprintf("pmcpp: Error: %s\n", msg); pmflush(); exit(1); } #define OP_DEFINE 1 #define OP_UNDEF 2 #define OP_IFDEF 3 #define OP_IFNDEF 4 #define OP_ENDIF 5 #define IF_FALSE 0 #define IF_TRUE 1 #define IF_NONE 2 /* * handle # cpp directives * - return 0 for do nothing and include following lines * - return 1 to skip following lines */ static int directive(void) { char *ip; char *name = NULL; char *value = NULL; int namelen = 0; /* pander to gcc */ int valuelen = 0; /* pander to gcc */ int op; int i; static int in_if = IF_NONE; if (strncmp(ibuf, "#define", strlen("#define")) == 0) { ip = &ibuf[strlen("#define")]; op = OP_DEFINE; } else if (strncmp(ibuf, "#undef", strlen("#undef")) == 0) { ip = &ibuf[strlen("#undef")]; op = OP_UNDEF; } else if (strncmp(ibuf, "#ifdef", strlen("#ifdef")) == 0) { ip = &ibuf[strlen("#ifdef")]; op = OP_IFDEF; } else if (strncmp(ibuf, "#ifndef", strlen("#ifndef")) == 0) { ip = &ibuf[strlen("#ifndef")]; op = OP_IFNDEF; } else if (strncmp(ibuf, "#endif", strlen("#endif")) == 0) { ip = &ibuf[strlen("#endif")]; op = OP_ENDIF; } else { err("Unrecognized control line"); /*NOTREACHED*/ } while (*ip && isblank((int)*ip)) ip++; if (op != OP_ENDIF) { if (*ip == '\n' || *ip == '\0') { err("Missing macro name"); /*NOTREACHED*/ } name = ip; for ( ;*ip && !isblank((int)*ip); ip++) { if (isalpha((int)*ip) || *ip == '_') continue; if (ip > name && (isdigit((int)*ip) || *ip == '_')) continue; break; } if (!isspace((int)*ip)) { err("Illegal character in macro name"); /*NOTREACHED*/ } namelen = ip - name; if (op == OP_DEFINE) { if (*ip == '\n' || *ip == '\0') { value = ""; valuelen = 0; } else { while (*ip && isblank((int)*ip)) ip++; value = ip; while (!isspace((int)*ip)) ip++; valuelen = ip - value; } } } while (*ip && isblank((int)*ip)) ip++; if (*ip != '\n' && *ip != '\0') { err("Unexpected extra text in a control line"); /*NOTREACHED*/ } if (op == OP_ENDIF) { if (in_if != IF_NONE) in_if = IF_NONE; else { err("No matching #ifdef or #ifndef for #endif"); /*NOTREACHED*/ } return 0; } if (op == OP_IFDEF || op == OP_IFNDEF) { if (in_if != IF_NONE) { err("Nested #ifdef or #ifndef"); /*NOTREACHED*/ } } if (in_if == IF_FALSE) /* skipping, waiting for #endif to match #if[n]def */ return 1; for (i = 0; i < nmacro; i++) { if (macro[i].len != namelen || strncmp(name, macro[i].name, macro[i].len) != 0) continue; /* found a match */ if (op == OP_IFDEF) { in_if = IF_TRUE; return 0; } else if (op == OP_IFNDEF) { in_if = IF_FALSE; return 1; } else if (op == OP_UNDEF) { macro[i].len = 0; return 0; } else { err("Macro redefinition"); /*NOTREACHED*/ } } /* no matching macro name */ if (op == OP_IFDEF) { in_if = IF_FALSE; return 1; } else if (op == OP_IFNDEF) { in_if = IF_TRUE; return 0; } else if (op == OP_UNDEF) /* silently accept #undef for something that was not defined */ return 0; else { /* OP_DEFINE case */ macro = (macro_t *)realloc(macro, (nmacro+1)*sizeof(macro_t)); if (macro == NULL) { __pmNoMem("pmcpp: macro[]", (nmacro+1)*sizeof(macro_t), PM_FATAL_ERR); /*NOTREACHED*/ } macro[nmacro].len = namelen; macro[nmacro].name = (char *)malloc(namelen+1); if (macro[nmacro].name == NULL) { __pmNoMem("pmcpp: name", namelen+1, PM_FATAL_ERR); /*NOTREACHED*/ } strncpy(macro[nmacro].name, name, namelen); macro[nmacro].name[namelen] = '\0'; macro[nmacro].value = (char *)malloc(valuelen+1); if (macro[nmacro].value == NULL) { __pmNoMem("pmcpp: value", valuelen+1, PM_FATAL_ERR); /*NOTREACHED*/ } if (value && valuelen) strncpy(macro[nmacro].value, value, valuelen); macro[nmacro].value[valuelen] = '\0'; nmacro++; return 0; } } static void do_macro(void) { /* * break line into words at white space or '.' or ':' boundaries * and apply macro substitution to each word */ char *ip = ibuf; /* next from ibuf[] to be copied */ char *w; /* start of word */ int len; char tmp[256]; /* copy output line here */ char *op = tmp; int sub = 0; /* true if any substitution made */ while (*ip && isblank((int)*ip)) *op++ = *ip++; w = ip; for ( ; ; ) { if (isspace((int)*ip) || *ip == '.' || *ip == ':' || *ip == '\0') { len = ip - w; // printf("word=|%*.*s|\n", len, len, w); if (len > 0) { int i; int match = 0; for (i = 0; i < nmacro; i++) { if (len == macro[i].len && strncmp(w, macro[i].name, len) == 0) { match = 1; sub++; strcpy(op, macro[i].value); op += strlen(macro[i].value); break; } } if (match == 0) { strncpy(op, w, len); op += len; } } *op++ = *ip; if (*ip == '\n' || *ip == '\0') break; ip++; while (*ip && isblank((int)*ip)) *op++ = *ip++; w = ip; } ip++; } if (sub) { *op = '\0'; strcpy(ibuf, tmp); } } /* * Open a regular file for reading, checking that its regular and accessible */ FILE * openfile(const char *fname) { struct stat sbuf; FILE *fp = fopen(fname, "r"); if (!fp) return NULL; if (fstat(fileno(fp), &sbuf) < 0) { fclose(fp); return NULL; } if (!S_ISREG(sbuf.st_mode)) { fclose(fp); setoserror(ENOENT); return NULL; } return fp; } int main(int argc, char **argv) { int c; int errflag = 0; int skip_if_false = 0; int incomment = 0; char *ip; currfile = &file_ctl[0]; while ((c = getopt(argc, argv, "D:?")) != EOF) { switch (c) { case 'D': /* define */ for (ip = optarg; *ip; ip++) { if (*ip == '=') *ip = ' '; } snprintf(ibuf, sizeof(ibuf), "#define %s\n", optarg); currfile->fname = ""; currfile->lineno = optind; directive(); break; case '?': default: errflag++; break; } } if (errflag || optind < argc - 1) { pmprintf("Usage: pmcpp [-Dname ...] [file]\n"); pmflush(); exit(1); } currfile->lineno = 0; if (optind == argc) { currfile->fname = ""; currfile->fin = stdin; } else { currfile->fname = argv[optind]; currfile->fin = openfile(currfile->fname); if (currfile->fin == NULL) { err((char *)pmErrStr(-oserror())); /*NOTREACHED*/ } } printf("# %d \"%s\"\n", currfile->lineno+1, currfile->fname); for ( ; ; ) { if (fgets(ibuf, sizeof(ibuf), currfile->fin) == NULL) { fclose(currfile->fin); if (currfile == &file_ctl[0]) break; free(currfile->fname); currfile--; printf("# %d \"%s\"\n", currfile->lineno+1, currfile->fname); continue; } currfile->lineno++; /* strip comments ... */ for (ip = ibuf; *ip ; ip++) { if (incomment) { if (*ip == '*' && ip[1] == '/') { /* end of comment */ incomment = 0; *ip++ = ' '; *ip = ' '; } else *ip = ' '; } else { if (*ip == '/' && ip[1] == '*') { /* start of comment */ incomment = currfile->lineno; *ip++ = ' '; *ip = ' '; } } } ip--; while (ip >= ibuf && isspace((int)*ip)) ip--; *++ip = '\n'; *++ip = '\0'; if (incomment && ibuf[0] == '\n') { printf("\n"); continue; } if (ibuf[0] == '#') { /* cpp control line */ if (strncmp(ibuf, "#include", strlen("#include")) == 0) { char *p; char *pend; char c; FILE *f; static char tmpbuf[MAXPATHLEN]; if (skip_if_false) { printf("\n"); continue; } p = &ibuf[strlen("#include")]; while (*p && isblank((int)*p)) p++; if (*p != '"' && *p != '<') { err("Expected \" or < after #include"); /*NOTREACHED*/ } pend = ++p; while (*pend && *pend != '\n' && ((p[-1] != '"' || *pend != '"') && (p[-1] != '<' || *pend != '>'))) pend++; if (p[-1] == '"' && *pend != '"') { err("Expected \" after file name"); /*NOTREACHED*/ } if (p[-1] == '<' && *pend != '>') { err("Expected > after file name"); /*NOTREACHED*/ } if (currfile == &file_ctl[MAXLEVEL-1]) { err("#include nesting too deep"); /*NOTREACHED*/ } if (pend[1] != '\n' && pend[1] != '\0') { err("Unexpected extra text in #include line"); /*NOTREACHED*/ } c = *pend; *pend = '\0'; f = openfile(p); if (f == NULL && file_ctl[0].fin != stdin) { /* check in directory of file from command line */ static int sep; static char *dir = NULL; if (dir == NULL) { /* * some versions of dirname() clobber the input * argument, some do not ... hence the obscurity * here */ static char *dirbuf; dirbuf = strdup(file_ctl[0].fname); if (dirbuf == NULL) { __pmNoMem("pmcpp: dir name alloc", strlen(file_ctl[0].fname)+1, PM_FATAL_ERR); /*NOTREACHED*/ } dir = dirname(dirbuf); sep = __pmPathSeparator(); } snprintf(tmpbuf, sizeof(tmpbuf), "%s%c%s", dir, sep, p); f = openfile(tmpbuf); if (f != NULL) p = tmpbuf; } if (f == NULL) { /* check in $PCP_VAR_DIR/pmns */ static int sep; static char *var_dir = NULL; if (var_dir == NULL) { var_dir = pmGetConfig("PCP_VAR_DIR"); sep = __pmPathSeparator(); } snprintf(tmpbuf, sizeof(tmpbuf), "%s%cpmns%c%s", var_dir, sep, sep, p); f = openfile(tmpbuf); if (f != NULL) p = tmpbuf; } if (f == NULL) { *pend = c; err("Cannot open file for #include"); /*NOTREACHED*/ } currfile++; currfile->lineno = 0; currfile->fin = f; currfile->fname = strdup(p); *pend = c; if (currfile->fname == NULL) { __pmNoMem("pmcpp: file name alloc", strlen(p)+1, PM_FATAL_ERR); /*NOTREACHED*/ } printf("# %d \"%s\"\n", currfile->lineno+1, currfile->fname); } else { /* expect other cpp control ... */ skip_if_false = directive(); printf("\n"); } continue; } if (skip_if_false) printf("\n"); else { if (nmacro > 0) do_macro(); printf("%s", ibuf); } } /* EOF for the top level file */ if (incomment) { char msgbuf[80]; snprintf(msgbuf, sizeof(msgbuf), "Comment at line %d not terminated before end of file", incomment); currfile->lineno = 0; err(msgbuf); exit(1); } exit(0); } pcp-3.8.12ubuntu1/src/pmerr/0000775000000000000000000000000012272262620012520 5ustar pcp-3.8.12ubuntu1/src/pmerr/GNUmakefile0000664000000000000000000000154112272262501014571 0ustar # # Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CFILES = pmerr.c CMDTARGET = pmerr$(EXECSUFFIX) LLDLIBS = $(PCPLIB) default: $(CMDTARGET) include $(BUILDRULES) install: default $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmerr/pmerr.c0000664000000000000000000000403312272262501014007 0ustar /* * Copyright (c) 1995-2001,2003 Silicon Graphics, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "pmapi.h" #include extern void __pmDumpErrTab(FILE *); int main(int argc, char **argv) { int code; int sts; char *p; char *q; if (argc > 1 && strcmp(argv[1], "-l") == 0) { __pmDumpErrTab(stdout); exit(1); } else if (argc > 1 && strcmp(argv[1], "-?") == 0) { argc = 0; } else if (argc > 1 && argv[1][0] == '-' && !isxdigit((int)argv[1][1])) { fprintf(stderr, "Illegal option -- %s\n", &argv[1][1]); argc = 0; } if (argc == 0) { fprintf(stderr, "Usage: pmerr [options] [code]\n\n" " -l causes all known error codes to be listed\n"); exit(1); } while (argc > 1) { sts = 0; p = argv[1]; if (*p == '0' && (p[1] == 'x' || p[1] == 'X')) { p = &p[2]; for (q = p; isxdigit((int)*q); q++) ; if (*q == '\0') sts = sscanf(p, "%x", &code); } if (sts < 1) sts = sscanf(argv[1], "%d", &code); if (sts != 1) { printf("Cannot decode \"%s\" - neither decimal nor hexadecimal\n", argv[1]); goto next; } if (code > 0) { code = -code; printf("Code is positive, assume you mean %d\n", code); } printf("Code: %d 0x%x Text: %s\n", code, code, pmErrStr(code)); next: argc--; argv++; } return 0; } pcp-3.8.12ubuntu1/src/pmwebapi/0000775000000000000000000000000012272262620013177 5ustar pcp-3.8.12ubuntu1/src/pmwebapi/pmresapi.c0000664000000000000000000001274512272262501015172 0ustar /* * JSON web bridge for PMAPI. * * Copyright (c) 2011-2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "pmwebapi.h" /* ------------------------------------------------------------------------ */ static const char *guess_content_type (const char* filename) { const char *extension = rindex (filename, '.'); if (extension == NULL) return NULL; /* One could go all out and parse /etc/mime.types, or one can do this ... */ if (0 == strcasecmp (extension, "html")) return "text/html"; if (0 == strcasecmp (extension, "js")) return "text/javascript"; if (0 == strcasecmp (extension, "json")) return "application/json"; if (0 == strcasecmp (extension, "txt")) return "text/plain"; if (0 == strcasecmp (extension, "xml")) return "text/xml"; if (0 == strcasecmp (extension, "svg")) return "image/svg+xml"; if (0 == strcasecmp (extension, "png")) return "image/png"; if (0 == strcasecmp (extension, "jpg")) return "image/jpg"; return NULL; } static const char *create_rfc822_date (time_t t) { static char datebuf[80]; /* if-threaded: unstaticify */ struct tm *now = gmtime (& t); size_t rc = strftime (datebuf, sizeof(datebuf), "%a, %d %b %Y %T %z", now); if (rc <= 0 || rc >= sizeof(datebuf)) return NULL; return datebuf; } /* Respond to a GET request, not under the pmwebapi URL prefix. This is a mini fileserver, just for small standalone installations of pmwebapi-based web front-ends. */ int pmwebres_respond (void *cls, struct MHD_Connection *connection, const char* url) { int fd = -1; int rc; char filename [PATH_MAX]; struct stat fds; unsigned int resp_code = MHD_HTTP_OK; struct MHD_Response *resp; const char *ctype = NULL; static const char error_page[] = "PMRESAPI error"; /* could also be an actual error page... */ (void) cls; assert (resourcedir != NULL); /* facility is enabled at all */ assert (url[0] == '/'); rc = snprintf (filename, sizeof(filename), "%s%s", resourcedir, url); if (rc < 0 || rc >= (int)sizeof(filename)) goto error_response; /* Reject some obvious ways of escaping resourcedir. */ if (NULL != strstr (filename, "/../")) { pmweb_notify (LOG_ERR, connection, "pmwebres suspicious url %s\n", url); goto error_response; } fd = open (filename, O_RDONLY); if (fd < 0) { pmweb_notify (LOG_ERR, connection, "pmwebres open %s failed (%d)\n", filename, fd); resp_code = MHD_HTTP_NOT_FOUND; goto error_response; } rc = fstat (fd, &fds); if (rc < 0) { pmweb_notify (LOG_ERR, connection, "pmwebres stat %s failed (%d)\n", filename, rc); close (fd); goto error_response; } /* XXX: handle if-modified-since */ if (! S_ISREG (fds.st_mode)) { pmweb_notify (LOG_ERR, connection, "pmwebres non-file %s attempted\n", filename); close (fd); /* XXX: list directory, or redirect to index.html instead? */ resp_code = MHD_HTTP_FORBIDDEN; goto error_response; } if (verbosity > 2) pmweb_notify (LOG_INFO, connection, "pmwebres serving file %s.\n", filename); resp = MHD_create_response_from_fd_at_offset (fds.st_size, fd, 0); /* auto-closes fd */ if (resp == NULL) { pmweb_notify (LOG_ERR, connection, "MHD_create_response_from_callback failed\n"); goto error_response; } /* Guess at a suitable MIME content-type. */ ctype = guess_content_type (filename); if (ctype) (void) MHD_add_response_header (resp, "Content-Type", ctype); /* And since we're generous to a fault, supply a timestamp field to assist caching. */ ctype = create_rfc822_date (fds.st_mtime); if (ctype) (void) MHD_add_response_header (resp, "Last-Modified", ctype); /* Add a 5-minute expiry. */ ctype = create_rfc822_date (time(0) + 300); /* XXX: configure */ if (ctype) (void) MHD_add_response_header (resp, "Expires", ctype); (void) MHD_add_response_header (resp, "Cache-Control", "public"); rc = MHD_queue_response (connection, resp_code, resp); MHD_destroy_response (resp); return rc; error_response: resp = MHD_create_response_from_buffer (strlen(error_page), (char*)error_page, MHD_RESPMEM_PERSISTENT); if (resp == NULL) { pmweb_notify (LOG_ERR, connection, "MHD_create_response_from_callback failed\n"); return MHD_NO; } (void) MHD_add_response_header (resp, "Content-Type", "text/plain"); rc = MHD_queue_response (connection, resp_code, resp); MHD_destroy_response (resp); if (rc != MHD_YES) { pmweb_notify (LOG_ERR, connection, "MHD_queue_response failed\n"); return MHD_NO; } return rc; } pcp-3.8.12ubuntu1/src/pmwebapi/pmwebapi.c0000664000000000000000000012737112272262501015160 0ustar /* * JSON web bridge for PMAPI. * * Copyright (c) 2011-2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "pmwebapi.h" #include #include #include #include /* ------------------------------------------------------------------------ */ struct webcontext { /* __pmHashNode key is unique randomized web context key, [1,INT_MAX] */ /* XXX: optionally bind session to a particular IP address? */ char *userid; /* NULL, or strdup'd username */ char *password; /* NULL, or strdup'd password */ unsigned mypolltimeout; time_t expires; /* poll timeout, 0 if never expires */ int context; /* PMAPI context handle, 0 if deleted/free */ }; /* if-threaded: pthread_mutex_t context_lock; */ static __pmHashCtl contexts; struct web_gc_iteration { time_t now; time_t soonest; /* 0 => no context pending gc */ }; static __pmHashWalkState pmwebapi_gc_fn (const __pmHashNode *kv, void *cdata) { const struct webcontext *value = kv->data; struct web_gc_iteration *t = (struct web_gc_iteration *) cdata; if (! value->expires) return PM_HASH_WALK_NEXT; /* Expired. */ if (value->expires < t->now) { int rc; if (verbosity) __pmNotifyErr (LOG_INFO, "context (web%d=pm%d) expired.\n", kv->key, value->context); rc = pmDestroyContext (value->context); if (rc) __pmNotifyErr (LOG_ERR, "pmDestroyContext (%d) failed: %d\n", value->context, rc); free (value->userid); free (value->password); return PM_HASH_WALK_DELETE_NEXT; } /* Expiring soon? */ if (t->soonest == 0) t->soonest = value->expires; else if (t->soonest > value->expires) t->soonest = value->expires; return PM_HASH_WALK_NEXT; } /* Check whether any contexts have been unpolled so long that they should be considered abandoned. If so, close 'em, free 'em, yak 'em, smack 'em. Return the number of seconds to the next good time to check for garbage. */ unsigned pmwebapi_gc () { struct web_gc_iteration t; (void) time (& t.now); t.soonest = 0; /* if-multithread: Lock contexts. */ __pmHashWalkCB (pmwebapi_gc_fn, & t, & contexts); /* if-multithread: Unlock contexts. */ return t.soonest ? (unsigned)(t.soonest - t.now) : maxtimeout; } static __pmHashWalkState pmwebapi_deallocate_all_fn (const __pmHashNode *kv, void *cdata) { struct webcontext *value = kv->data; int rc; (void) cdata; if (verbosity) __pmNotifyErr (LOG_INFO, "context (web%d=pm%d) deleted.\n", kv->key, value->context); rc = pmDestroyContext (value->context); if (rc) __pmNotifyErr (LOG_ERR, "pmDestroyContext (%d) failed: %d\n", value->context, rc); free (value->userid); free (value->password); free (value); return PM_HASH_WALK_DELETE_NEXT; } void pmwebapi_deallocate_all () { /* if-multithread: Lock contexts. */ __pmHashWalkCB (pmwebapi_deallocate_all_fn, NULL, & contexts); /* if-multithread: Unlock contexts. */ } /* Allocate an zeroed webcontext structure, and enroll it in the hash table with the given context#. */ static int webcontext_allocate (int webapi_ctx, struct webcontext** wc) { if (__pmHashSearch (webapi_ctx, & contexts) != NULL) return -EEXIST; /* Allocate & clear our webapi context. */ assert (wc); *wc = calloc(1, sizeof(struct webcontext)); if (! *wc) return -ENOMEM; int rc = __pmHashAdd(webapi_ctx, *wc, & contexts); if (rc < 0) { free (*wc); return rc; } return 0; } int pmwebapi_bind_permanent (int webapi_ctx, int pcp_context) { struct webcontext* c; int rc = webcontext_allocate (webapi_ctx, &c); if (rc < 0) return rc; assert (c); assert (pcp_context >= 0); c->context = pcp_context; c->mypolltimeout = ~0; c->expires = 0; return 0; } /* Print a best-effort message as a plain-text http response; anything to avoid a dreaded MHD_NO, which results in a 500 return code. That in turn could be interpreted by a web client as an invitation to try, try again. */ static int pmwebapi_notify_error (struct MHD_Connection *connection, int rc) { char error_message [1000]; char pmmsg [PM_MAXERRMSGLEN]; struct MHD_Response *resp; (void) pmErrStr_r (rc, pmmsg, sizeof(pmmsg)); (void) snprintf (error_message, sizeof(error_message), "PMWEBAPI error, code %d: %s", rc, pmmsg); resp = MHD_create_response_from_buffer (strlen(error_message), error_message, MHD_RESPMEM_MUST_COPY); if (resp == NULL) { pmweb_notify (LOG_ERR, connection, "MHD_create_response_from_buffer failed\n"); return MHD_NO; } (void) MHD_add_response_header (resp, "Content-Type", "text/plain"); rc = MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, resp); MHD_destroy_response (resp); if (rc != MHD_YES) { pmweb_notify (LOG_ERR, connection, "MHD_queue_response failed\n"); return MHD_NO; } return MHD_YES; } static int pmwebapi_respond_new_context (struct MHD_Connection *connection) { /* Create a context. */ const char *val; int rc = 0; int context = -EINVAL; char http_response [30]; char context_description [512] = ""; /* for logging */ unsigned polltimeout; struct MHD_Response *resp; int webapi_ctx; int iterations = 0; char *userid = NULL; char *password = NULL; val = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "hostspec"); if (val == NULL) /* backward compatibility alias */ val = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "hostname"); if (val) { pmHostSpec *hostSpec; int hostSpecCount; __pmHashCtl hostAttrs; char *hostAttrsError; __pmHashInit (& hostAttrs); rc = __pmParseHostAttrsSpec (val, & hostSpec, & hostSpecCount, & hostAttrs, & hostAttrsError); if (rc == 0) { __pmHashNode *node; node = __pmHashSearch (PCP_ATTR_USERNAME, & hostAttrs); /* XXX: PCP_ATTR_AUTHNAME? */ if (node) userid = strdup (node->data); node = __pmHashSearch (PCP_ATTR_PASSWORD, & hostAttrs); if (node) password = strdup (node->data); __pmFreeHostAttrsSpec (hostSpec, hostSpecCount, & hostAttrs); __pmHashClear (& hostAttrs); } else { /* Ignore the parse error at this stage; pmNewContext will give it to us. */ free (hostAttrsError); } context = pmNewContext (PM_CONTEXT_HOST, val); /* XXX: limit access */ snprintf (context_description, sizeof(context_description), "PM_CONTEXT_HOST %s", val); } else { val = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "archivefile"); if (val) { char archive_fullpath[PATH_MAX]; snprintf(archive_fullpath, sizeof(archive_fullpath), "%s%c%s", archivesdir, __pmPathSeparator(), val); /* Block some basic ways of escaping archive_dir */ if (NULL != strstr (archive_fullpath, "/../")) { pmweb_notify (LOG_ERR, connection, "pmwebapi suspicious archive path %s\n", archive_fullpath); rc = -EINVAL; goto out; } context = pmNewContext (PM_CONTEXT_ARCHIVE, archive_fullpath); snprintf (context_description, sizeof(context_description), "PM_CONTEXT_ARCHIVE %s", val); } else if (MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "local")) { /* Note we need to use a dummy parameter to local=FOO, since the MHD_lookup* API does not differentiate between an absent argument vs. an argument given without a parameter value. */ context = pmNewContext (PM_CONTEXT_LOCAL, NULL); snprintf (context_description, sizeof(context_description), "PM_CONTEXT_LOCAL"); } else { /* context remains -something */ } } if (context < 0) { pmweb_notify (LOG_ERR, connection, "new context failed (%s)\n", pmErrStr (context)); rc = context; goto out; } /* Process optional ?polltimeout=SECONDS field. If broken/missing, assume maxtimeout. */ val = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "polltimeout"); if (val) { long pt; char *endptr; errno = 0; pt = strtol(val, &endptr, 0); if (errno != 0 || *endptr != '\0' || pt <= 0 || pt > (long)maxtimeout) { polltimeout = maxtimeout; } else polltimeout = (unsigned) pt; } else { polltimeout = maxtimeout; } struct webcontext* c = NULL; /* Create a new context key for the webapi. We just use a random integer within a reasonable range: 1..INT_MAX */ while (1) { /* Preclude infinite looping here, for example due to a badly behaving random(3) implementation. */ iterations ++; if (iterations > 100) { pmweb_notify (LOG_ERR, connection, "webapi_ctx allocation failed\n"); pmDestroyContext (context); rc = -EMFILE; goto out; } webapi_ctx = random(); /* we hope RAND_MAX is large enough */ if (webapi_ctx <= 0) continue; rc = webcontext_allocate (webapi_ctx, & c); if (rc == 0) break; /* This may already exist. We loop in case the key id already exists. */ } assert (c); c->context = context; time (& c->expires); c->mypolltimeout = polltimeout; c->expires += c->mypolltimeout; c->userid = userid; /* may be NULL; otherwise, will be freed at context release. */ c->password = password; /* ditto */ /* Errors beyond this point don't require instant cleanup; the periodic context GC will do it all. */ if (verbosity) { const char* context_hostname = pmGetContextHostName (context); pmweb_notify (LOG_INFO, connection, "context %s%s%s%s (web%d=pm%d) created%s%s, expires in %us.\n", context_description, context_hostname ? " (" : "", context_hostname ? context_hostname : "", context_hostname ? ")" : "", webapi_ctx, context, userid ? ", user=" : "", userid ? userid : "", polltimeout); } rc = snprintf (http_response, sizeof(http_response), "{ \"context\": %d }", webapi_ctx); assert (rc >= 0 && rc < (int)sizeof(http_response)); resp = MHD_create_response_from_buffer (strlen(http_response), http_response, MHD_RESPMEM_MUST_COPY); if (resp == NULL) { pmweb_notify (LOG_ERR, connection, "MHD_create_response_from_buffer failed\n"); rc = -ENOMEM; goto out; } rc = MHD_add_response_header (resp, "Content-Type", "application/json"); if (rc != MHD_YES) { MHD_destroy_response (resp); rc = -ENOMEM; pmweb_notify (LOG_ERR, connection, "MHD_add_response_header failed\n"); goto out; } rc = MHD_queue_response (connection, MHD_HTTP_OK, resp); MHD_destroy_response (resp); if (rc != MHD_YES) { pmweb_notify (LOG_ERR, connection, "MHD_queue_response failed\n"); rc = -ENOMEM; goto out; } return MHD_YES; out: return pmwebapi_notify_error (connection, rc); } /* ------------------------------------------------------------------------ */ /* Buffer for building a MHD_Response incrementally. libmicrohttpd does not provide such a facility natively. */ struct mhdb { size_t buf_size; size_t buf_used; char *buf; /* malloc/realloc()'d. If NULL, mhdbuf is a loser: Attempt no landings there. */ }; /* Create a MHD response buffer of given initial size. Upon failure, leave the buffer unallocated, which will block any mhdb_printfs, and cause mhdb_fini_response to fail. */ static void mhdb_init (struct mhdb *md, size_t size) { md->buf_size = size; md->buf_used = 0; md->buf = malloc (md->buf_size); /* may be NULL => loser */ } /* Add a given formatted string to the end of the MHD response buffer. Extend/realloc the buffer if needed. If unable, free the buffer, which will block any further mhdb_vsprintfs, and cause the mhdb_fini_response to fail. */ static void mhdb_printf(struct mhdb *md, const char *fmt, ...) __attribute__((format(printf, 2, 3))); static void mhdb_printf(struct mhdb *md, const char *fmt, ...) { va_list vl; int n; int buf_remaining = md->buf_size - md->buf_used; if (md->buf == NULL) return; /* reject loser */ va_start (vl, fmt); n = vsnprintf (md->buf + md->buf_used, buf_remaining, fmt, vl); va_end (vl); if (n >= buf_remaining) { /* complex case: buffer overflow */ void *nbuf; md->buf_size += n*128; /* pad it to discourage reoffense */ buf_remaining += n*128; nbuf = realloc (md->buf, md->buf_size); if (nbuf == NULL) { /* ENOMEM */ free (md->buf); /* realloc left it alone */ md->buf = NULL; /* tag loser */ } else { /* success */ md->buf = nbuf; /* Try vsnprintf again into the new buffer. */ va_start (vl, fmt); n = vsnprintf (md->buf + md->buf_used, buf_remaining, fmt, vl); va_end (vl); assert (n >= 0 && n < buf_remaining); /* should not fail */ md->buf_used += n; } } else if (n < 0) { /* simple case: other vsprintf error */ free (md->buf); md->buf = NULL; /* tag loser */ } else { /* normal case: vsprintf success */ md->buf_used += n; } } /* Print a string with JSON quoting. Replace non-ASCII characters with \uFFFD "REPLACEMENT CHARACTER". */ static void mhdb_print_qstring(struct mhdb *md, const char *value) { const char *c; mhdb_printf(md, "\""); for (c = value; *c; c++) { if (! isascii(*c)) mhdb_printf(md, "\\uFFFD"); else if (isalnum(*c)) mhdb_printf(md, "%c", *c); else if (ispunct(*c) && !iscntrl(*c) && (*c != '\\' && *c != '\"')) mhdb_printf(md, "%c", *c); else if (*c == ' ') mhdb_printf(md, "%c", *c); else mhdb_printf(md, "\\u00%02x", *c); } mhdb_printf(md, "\""); } /* A convenience function to print a vanilla-ascii key and an unknown ancestry value as a JSON pair. Add given suffix, which is likely to be a comma or a \n. */ static void mhdb_print_key_value(struct mhdb *md, const char *key, const char *value, const char *suffix) { mhdb_printf(md, "\"%s\":", key); mhdb_print_qstring(md, value); mhdb_printf(md, "%s", suffix); } #if 0 /* unused */ /* Ensure that any recent mhdb_printfs are canceled, and that the final mhdb_fini_response will fail. */ static void mhdb_unprintf(struct mhdb *md) { if (md->buf) { free (md->buf); md->buf = NULL; } } #endif /* Create a MHD_Response from the mhdb, now that we're done with it. If the buffer overflowed earlier (was unable to be extended), or if the MHD_create_response* function fails, return NULL. Ensure that the buffer will be freed either by us here, or later by a successful MHD_create_response* function. */ static struct MHD_Response* mhdb_fini_response(struct mhdb *md) { struct MHD_Response *r; if (md->buf == NULL) return NULL; /* reject loser */ r = MHD_create_response_from_buffer (md->buf_used, md->buf, MHD_RESPMEM_MUST_FREE); if (r == NULL) { free (md->buf); /* we need to free it ourselves */ /* fall through */ } return r; } /* ------------------------------------------------------------------------ */ struct metric_list_traverse_closure { struct MHD_Connection *connection; struct webcontext *c; struct mhdb mhdb; unsigned num_metrics; }; static void metric_list_traverse (const char* metric, void *closure) { struct metric_list_traverse_closure *mltc = closure; pmID metric_id; pmDesc metric_desc; int rc; char *metric_text; char *metrics[1] = { (char*) metric }; assert (mltc != NULL); rc = pmLookupName (1, metrics, & metric_id); if (rc != 1) { /* Quietly skip this metric. */ return; } assert (metric_id != PM_ID_NULL); rc = pmLookupDesc (metric_id, & metric_desc); if (rc != 0) { /* Quietly skip this metric. */ return; } if (mltc->num_metrics > 0) mhdb_printf (& mltc->mhdb, ",\n"); mhdb_printf (& mltc->mhdb, "{ "); mhdb_print_key_value (& mltc->mhdb, "name", metric, ","); rc = pmLookupText (metric_id, PM_TEXT_ONELINE, & metric_text); if (rc == 0) { mhdb_print_key_value (& mltc->mhdb, "text-oneline", metric_text, ","); free (metric_text); } rc = pmLookupText (metric_id, PM_TEXT_HELP, & metric_text); if (rc == 0) { mhdb_print_key_value (& mltc->mhdb, "text-help", metric_text, ","); free (metric_text); } mhdb_printf (& mltc->mhdb, "\"pmid\":%lu, ", (unsigned long) metric_id); if (metric_desc.indom != PM_INDOM_NULL) mhdb_printf (& mltc->mhdb, "\"indom\":%lu, ", (unsigned long) metric_desc.indom); mhdb_print_key_value (& mltc->mhdb, "sem", (metric_desc.sem == PM_SEM_COUNTER ? "counter" : metric_desc.sem == PM_SEM_INSTANT ? "instant" : metric_desc.sem == PM_SEM_DISCRETE ? "discrete" : "unknown"), ","); mhdb_print_key_value (& mltc->mhdb, "units", pmUnitsStr (& metric_desc.units), ","); mhdb_print_key_value (& mltc->mhdb, "type", pmTypeStr (metric_desc.type), ""); mhdb_printf (& mltc->mhdb, "}"); mltc->num_metrics ++; } static int pmwebapi_respond_metric_list (struct MHD_Connection *connection, struct webcontext *c) { struct metric_list_traverse_closure mltc; const char* val; struct MHD_Response* resp; int rc; mltc.connection = connection; mltc.c = c; mltc.num_metrics = 0; /* We need to construct a copy of the entire JSON metric metadata string, in one long malloc()'d buffer. We size it generously to avoid having to realloc the bad boy and cause copies. */ mhdb_init (& mltc.mhdb, 300000); /* 1000 pmns entries * 300 bytes each */ mhdb_printf(& mltc.mhdb, "{ \"metrics\":[\n"); val = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "prefix"); if (val == NULL) val = ""; (void) pmTraversePMNS_r (val, & metric_list_traverse, & mltc); /* cannot fail */ /* XXX: also handle pmids=... */ /* XXX: also handle names=... */ mhdb_printf(&mltc.mhdb, "] }"); resp = mhdb_fini_response (& mltc.mhdb); if (resp == NULL) { pmweb_notify (LOG_ERR, connection, "mhdb_response failed\n"); rc = -ENOMEM; goto out; } rc = MHD_add_response_header (resp, "Content-Type", "application/json"); if (rc != MHD_YES) { pmweb_notify (LOG_ERR, connection, "MHD_add_response_header failed\n"); rc = -ENOMEM; goto out1; } rc = MHD_queue_response (connection, MHD_HTTP_OK, resp); if (rc != MHD_YES) { pmweb_notify (LOG_ERR, connection, "MHD_queue_response failed\n"); rc = -ENOMEM; goto out1; } MHD_destroy_response (resp); return MHD_YES; out1: MHD_destroy_response (resp); out: return pmwebapi_notify_error (connection, rc); } /* ------------------------------------------------------------------------ */ /* Print "value":, possibly nested for PM_TYPE_EVENT. Upon failure to decode, print less and return non-0. */ static int pmwebapi_format_value (struct mhdb* output, pmDesc* desc, pmValueSet* pvs, int vsidx) { pmValue* value = & pvs->vlist[vsidx]; pmAtomValue a; int rc; /* unpack, as per pmevent.c:myeventdump */ if (desc->type == PM_TYPE_EVENT) { pmResult **res; int numres, i; numres = pmUnpackEventRecords (pvs, vsidx, &res); if (numres < 0) return numres; mhdb_printf (output, "\"events\":["); for (i=0; i0) mhdb_printf (output, ","); mhdb_printf (output, "{ \"timestamp\": { \"s\":%lu, \"us\":%lu } ", res[i]->timestamp.tv_sec, res[i]->timestamp.tv_usec); mhdb_printf (output, ", \"fields\":["); for (j=0; jnumpmid; j++) { pmValueSet *fieldvsp = res[i]->vset[j]; pmDesc fielddesc; char *fieldname; if (j>0) mhdb_printf (output, ","); mhdb_printf (output, "{"); /* recurse */ rc = pmLookupDesc (fieldvsp->pmid, &fielddesc); if (rc == 0) rc = pmwebapi_format_value (output, &fielddesc, fieldvsp, 0); if (rc == 0) /* printer value: ... etc. ? */ mhdb_printf (output, ", "); /* XXX: handle value: for event.flags / event.missed */ rc = pmNameID (fieldvsp->pmid, & fieldname); if (rc == 0) { mhdb_printf (output, "\"name\":\"%s\"", fieldname); free (fieldname); } else { mhdb_printf (output, "\"name\":\"%s\"", pmIDStr (fieldvsp->pmid)); } mhdb_printf (output, "}"); } mhdb_printf (output, "]"); mhdb_printf (output, "}\n"); } mhdb_printf (output, "]"); pmFreeEventResult(res); return 0; } rc = pmExtractValue (pvs->valfmt, value, desc->type, &a, desc->type); if (rc != 0) return rc; switch (desc->type) { case PM_TYPE_32: mhdb_printf (output, "\"value\":%i", a.l); break; case PM_TYPE_U32: mhdb_printf (output, "\"value\":%u", a.ul); break; case PM_TYPE_64: mhdb_printf (output, "\"value\":%" PRIi64, a.ll); break; case PM_TYPE_U64: mhdb_printf (output, "\"value\":%" PRIu64, a.ull); break; case PM_TYPE_FLOAT: mhdb_printf (output, "\"value\":%g", (double)a.f); break; case PM_TYPE_DOUBLE: mhdb_printf (output, "\"value\":%g", a.d); break; case PM_TYPE_STRING: mhdb_print_key_value (output, "value", a.cp, ""); free (a.cp); break; case PM_TYPE_AGGREGATE: case PM_TYPE_AGGREGATE_STATIC: { /* base64-encode binary data */ const char* p_bytes = & value->value.pval->vbuf[0]; /* from pmevent.c:mydump() */ unsigned p_size = value->value.pval->vlen - PM_VAL_HDR_SIZE; unsigned i; const char base64_encoding_table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; if (value->value.pval->vlen < PM_VAL_HDR_SIZE) /* less than zero size? */ return -EINVAL; mhdb_printf (output, "\"value\":\""); for (i=0; i> 3*6) & 63]); mhdb_printf (output, "%c", base64_encoding_table[(triple >> 2*6) & 63]); mhdb_printf (output, "%c", base64_encoding_table[(triple >> 1*6) & 63]); mhdb_printf (output, "%c", base64_encoding_table[(triple >> 0*6) & 63]); } switch (p_size % 3) { case 0: /*mhdb_printf (output, "");*/ break; case 1: mhdb_printf (output, "=="); break; case 2: mhdb_printf (output, "="); break; } mhdb_printf (output, "\""); if (desc->type != PM_TYPE_AGGREGATE_STATIC) /* XXX: correct? */ free (a.vbp); break; } default: /* ... just a complete unknown ... */ return -EINVAL; } return 0; } static int pmwebapi_respond_metric_fetch (struct MHD_Connection *connection, struct webcontext *c) { const char* val_pmids; const char* val_names; struct MHD_Response* resp; int rc = 0; int max_num_metrics; int num_metrics; int printed_metrics; /* exclude skipped ones */ pmID *metrics; struct mhdb output; pmResult *results; int i; (void) c; val_pmids = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "pmids"); if (val_pmids == NULL) val_pmids = ""; val_names = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "names"); if (val_names == NULL) val_names = ""; /* Pessimistically overestimate maximum number of pmID elements we'll need, to allocate the metrics[] array just once, and not have to range-check. */ max_num_metrics = strlen(val_pmids)+strlen(val_names); /* The real minimum is actually closer to strlen()/2, to account for commas. */ num_metrics = 0; metrics = calloc ((size_t) max_num_metrics, sizeof(pmID)); if (metrics == NULL) { pmweb_notify (LOG_ERR, connection, "calloc pmIDs[%d] oom\n", max_num_metrics); rc = -ENOMEM; goto out; } /* Loop over names= names in val_names, collect them in metrics[]. */ while (*val_names != '\0') { char *name; char *name_end = strchr (val_names, ','); char *names[1]; pmID found_pmid; int num; /* Ignore plain "," XXX: elsewhere too? */ if (*val_names == ',') { val_names ++; continue; } /* Copy just this name piece. */ if (name_end) { name = strndup (val_names, (name_end - val_names)); val_names = name_end + 1; /* skip past , */ } else { name = strdup (val_names); val_names += strlen (val_names); /* skip onto \0 */ } names[0] = name; num = pmLookupName (1, names, & found_pmid); free(name); if (num == 1) { assert (num_metrics < max_num_metrics); metrics[num_metrics++] = found_pmid; } } /* Loop over pmids= numbers in val_pmids, append them to metrics[]. */ while (*val_pmids) { char *numend; unsigned long pmid = strtoul (val_pmids, & numend, 10); /* matches pmid printing above */ if (numend == val_pmids) break; /* invalid contents */ assert (num_metrics < max_num_metrics); metrics[num_metrics++] = pmid; if (*numend == '\0') break; /* end of string */ if (*numend == ',') val_pmids = numend+1; /* advance to next string */ } /* Time to fetch the metric values. */ /* num_metrics=0 ==> PM_ERR_TOOSMALL */ rc = pmFetch (num_metrics, metrics, & results); free (metrics); /* don't need any more */ if (rc < 0) { pmweb_notify (LOG_ERR, connection, "pmFetch failed\n"); goto out; } /* NB: we don't care about the possibility of PMCD_*_AGENT bits being set, so rc > 0. */ /* We need to construct a copy of the entire JSON metric value string, in one long malloc()'d buffer. We size it generously to avoid having to realloc the bad boy and cause copies. */ mhdb_init (& output, num_metrics * 200); /* WAG: per-metric size */ mhdb_printf(& output, "{ \"timestamp\": { \"s\":%lu, \"us\":%lu },\n", results->timestamp.tv_sec, results->timestamp.tv_usec); mhdb_printf(& output, "\"values\": [\n"); assert (results->numpmid == num_metrics); printed_metrics = 0; for (i=0; inumpmid; i++) { int j; pmValueSet *pvs = results->vset[i]; char *metric_name; pmDesc desc; if (pvs->numval <= 0) continue; /* error code; skip metric */ rc = pmLookupDesc (pvs->pmid, &desc); /* need to find desc.type only */ if (rc < 0) continue; /* quietly skip it */ if (printed_metrics >= 1) mhdb_printf (& output, ",\n"); mhdb_printf (& output, "{ "); mhdb_printf (& output, "\"pmid\":%lu, ", (unsigned long) pvs->pmid); rc = pmNameID (pvs->pmid, &metric_name); if (rc == 0) { mhdb_print_key_value (& output, "name", metric_name, ","); free (metric_name); } mhdb_printf (& output, "\"instances\": [\n"); for (j=0; jnumval; j++) { pmValue* val = & pvs->vlist[j]; int printed_value; mhdb_printf (& output, "{"); printed_value = ! pmwebapi_format_value (& output, & desc, pvs, j); if (desc.indom != PM_INDOM_NULL) mhdb_printf (& output, "%s \"instance\":%d", printed_value ? ", " : "", /* comma separation */ val->inst); mhdb_printf (& output, "}"); if (j+1 < pvs->numval) mhdb_printf (& output, ","); /* comma separation */ } mhdb_printf(& output, "] }"); /* iteration over instances */ printed_metrics ++; /* comma separation at beginning of loop */ } mhdb_printf(& output, "] }"); /* iteration over metrics */ pmFreeResult (results); /* not needed any more */ resp = mhdb_fini_response (& output); if (resp == NULL) { pmweb_notify (LOG_ERR, connection, "mhdb_response failed\n"); rc = -ENOMEM; goto out; } rc = MHD_add_response_header (resp, "Content-Type", "application/json"); if (rc != MHD_YES) { pmweb_notify (LOG_ERR, connection, "MHD_add_response_header failed\n"); rc = -ENOMEM; goto out1; } rc = MHD_queue_response (connection, MHD_HTTP_OK, resp); if (rc != MHD_YES) { pmweb_notify (LOG_ERR, connection, "MHD_queue_response failed\n"); rc = -ENOMEM; goto out1; } MHD_destroy_response (resp); return MHD_YES; out1: MHD_destroy_response (resp); out: return pmwebapi_notify_error (connection, rc); } /* ------------------------------------------------------------------------ */ static int pmwebapi_respond_instance_list (struct MHD_Connection *connection, struct webcontext *c) { const char* val_indom; const char* val_name; const char* val_instance; const char* val_iname; struct MHD_Response* resp; int rc = 0; int max_num_instances; int num_instances; int printed_instances; int *instances; struct mhdb output; pmID metric_id; pmDesc metric_desc; pmInDom inDom; int i; (void) c; val_indom = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "indom"); if (val_indom == NULL) val_indom = ""; val_name = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "name"); if (val_name == NULL) val_name = ""; val_instance = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "instance"); if (val_instance == NULL) val_instance = ""; val_iname = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "iname"); if (val_iname == NULL) val_iname = ""; /* Obtain the instance domain. */ if (0 == strcmp(val_indom, "")) { rc = pmLookupName (1, (char **)& val_name, & metric_id); if (rc != 1) { pmweb_notify (LOG_ERR, connection, "failed to lookup metric '%s'\n", val_name); goto out; } assert (metric_id != PM_ID_NULL); rc = pmLookupDesc (metric_id, & metric_desc); if (rc != 0) { pmweb_notify (LOG_ERR, connection, "failed to lookup metric '%s'\n", val_name); goto out; } inDom = metric_desc.indom; } else { char *numend; inDom = strtoul (val_indom, & numend, 10); if (numend == val_indom) { pmweb_notify (LOG_ERR, connection, "failed to parse indom '%s'\n", val_indom); rc = -EINVAL; goto out; } } /* Pessimistically overestimate maximum number of instance IDs needed. */ max_num_instances = strlen(val_indom) + strlen(val_name); num_instances = 0; instances = calloc ((size_t) max_num_instances, sizeof(int)); if (instances == NULL) { pmweb_notify (LOG_ERR, connection, "calloc instances[%d] oom\n", max_num_instances); rc = -ENOMEM; goto out; } /* In the case where neither val_instance nor val_iname are specified, pmGetInDom will allocate different arrays on our behalf, so we don't have to worry about accounting for how many instances are returned in that case. */ /* Loop over instance= numbers in val_instance, collect them in instances[]. */ while (*val_instance != '\0') { char *numend; int iid = (int) strtoul (val_instance, & numend, 10); if (numend == val_instance) break; /* invalid contents */ assert (num_instances < max_num_instances); instances[num_instances++] = iid; if (*numend == '\0') break; /* end of string */ if (*numend == ',') val_instance = numend+1; /* advance to next string */ } /* Loop over iname= names in val_iname, collect them in instances[]. */ while (*val_iname != '\0') { char *iname; char *iname_end = strchr (val_iname, ','); int iid; /* Ignore plain "," XXX: elsewhere too? */ if (*val_iname == ',') { val_iname ++; continue; } if (iname_end) { iname = strndup (val_iname, (iname_end - val_iname)); val_iname = iname_end + 1; /* skip past , */ } else { iname = strdup (val_iname); val_iname += strlen (val_iname); /* skip onto \0 */ } iid = pmLookupInDom(inDom, iname); if (iid > 0) { assert (num_instances < max_num_instances); instances[num_instances++] = iid; } } /* Time to fetch the instance info. */ int *instlist; char **namelist = NULL; if (num_instances == 0) { free (instances); num_instances = pmGetInDom(inDom, & instlist, & namelist); if (num_instances < 1) { pmweb_notify (LOG_ERR, connection, "pmGetInDom failed\n"); rc = num_instances; goto out; } } else { instlist = instances; } /* Build the response string all in one giant buffer: */ mhdb_init (& output, num_instances * 200); mhdb_printf (& output, "{ \"indom\": %lu,\n", (unsigned long) inDom); mhdb_printf (& output, "\"instances\": [\n"); printed_instances = 0; for (i=0; i= 1) mhdb_printf (& output, ",\n"); mhdb_printf (& output, "{ \"instance\":%d,\n", instlist[i]); mhdb_print_key_value (& output, "name", instance_name, "\n"); mhdb_printf (& output, "}"); if (namelist == NULL) free (instance_name); printed_instances ++; /* comma separation at beginning of loop */ } mhdb_printf(& output, "] }"); /* iteration over instances */ /* Free no-longer-needed things: */ free (instlist); if (namelist != NULL) free (namelist); resp = mhdb_fini_response (& output); if (resp == NULL) { pmweb_notify (LOG_ERR, connection, "mhdb_response failed\n"); rc = -ENOMEM; goto out; } rc = MHD_add_response_header (resp, "Content-Type", "application/json"); if (rc != MHD_YES) { pmweb_notify (LOG_ERR, connection, "MHD_add_response_header failed\n"); rc = -ENOMEM; goto out1; } rc = MHD_queue_response (connection, MHD_HTTP_OK, resp); if (rc != MHD_YES) { pmweb_notify (LOG_ERR, connection, "MHD_queue_response failed\n"); rc = -ENOMEM; goto out1; } MHD_destroy_response (resp); return MHD_YES; out1: MHD_destroy_response (resp); out: return pmwebapi_notify_error (connection, rc); } /* ------------------------------------------------------------------------ */ int pmwebapi_respond (void *cls, struct MHD_Connection *connection, const char* url, const char* method, const char* upload_data, size_t *upload_data_size) { /* XXX: emit CORS header, e.g. https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS */ /* NB: url is already edited to remove the /pmapi/ prefix. */ long webapi_ctx; __pmHashNode *chn; struct webcontext *c; char *context_command; int rc = 0; (void) cls; (void) upload_data; (void) upload_data_size; /* Decode the calls to the web API. */ /* -------------------------------------------------------------------- */ /* context creation */ /* if-multithreaded: write-lock contexts */ if (0 == strcmp (url, "context") && new_contexts_p && /* permitted */ (0 == strcmp (method, "POST") || 0 == strcmp (method, "GET"))) return pmwebapi_respond_new_context (connection); /* -------------------------------------------------------------------- */ /* All other calls use $CTX/command, so we parse $CTX generally and map it to the webcontext* */ if (! (0 == strcmp (method, "POST") || 0 == strcmp (method, "GET"))) { pmweb_notify (LOG_WARNING, connection, "unknown method %s\n", method); rc = -EINVAL; goto out; } errno = 0; webapi_ctx = strtol (url, & context_command, 10); /* matches %d above */ if (errno != 0 || webapi_ctx <= 0 /* range check, plus string-nonemptyness check */ || webapi_ctx > INT_MAX /* matches random() loop above */ || *context_command != '/') { /* parsed up to the next slash */ pmweb_notify (LOG_WARNING, connection, "unrecognized %s url %s \n", method, url); rc = -EINVAL; goto out; } context_command ++; /* skip the / */ /* if-multithreaded: read-lock contexts */ chn = __pmHashSearch ((int)webapi_ctx, & contexts); if (chn == NULL) { pmweb_notify (LOG_WARNING, connection, "unknown web context #%ld\n", webapi_ctx); rc = PM_ERR_NOCONTEXT; goto out; } c = (struct webcontext *) chn->data; assert (c != NULL); /* Process HTTP Basic userid/password, if supplied. Both returned strings need to be free(3)'d later. */ if (c->userid != NULL) { /* Did this context requires userid/password auth? */ char *userid = NULL; char *password = NULL; userid = MHD_basic_auth_get_username_password (connection, &password); /* 401 */ if (userid == NULL || password == NULL) { static char auth_req_msg[] = "authentication required"; struct MHD_Response *resp; char auth_realm[40]; free (userid); free (password); resp = MHD_create_response_from_buffer (strlen(auth_req_msg), auth_req_msg, MHD_RESPMEM_PERSISTENT); if (! resp) { rc = -ENOMEM; goto out; } /* We need the user to resubmit this with http authentication info, with a custom HTTP authenticaion realm for this context. */ snprintf (auth_realm, sizeof(auth_realm), "%s/%ld", uriprefix, webapi_ctx); rc = MHD_queue_basic_auth_fail_response (connection, auth_realm, resp); MHD_destroy_response (resp); if (rc != MHD_YES) { rc = -ENOMEM; goto out; } return MHD_YES; } /* 403 */ if (strcmp (userid, c->userid) || (c->password && strcmp (password, c->password))) { static char auth_failed_msg[] = "authentication failed"; struct MHD_Response *resp; free (userid); free (password); resp = MHD_create_response_from_buffer (strlen(auth_failed_msg), auth_failed_msg, MHD_RESPMEM_PERSISTENT); if (! resp) { rc = -ENOMEM; goto out; } /* We need the user to resubmit this with http authentication info. */ rc = MHD_queue_response (connection, MHD_HTTP_FORBIDDEN, resp); MHD_destroy_response (resp); if (rc != MHD_YES) { rc = -ENOMEM; goto out; } return MHD_YES; } /* FALLTHROUGH: authentication required & succeeded. */ free (userid); free (password); } /* Update last-use of this connection. */ if (c->expires != 0) { time (& c->expires); c->expires += c->mypolltimeout; } /* Switch to this context for subsequent operations. */ /* if-multithreaded: watch out. */ rc = pmUseContext (c->context); if (rc) goto out; /* -------------------------------------------------------------------- */ /* metric enumeration: /context/$ID/_metric */ if (0 == strcmp (context_command, "_metric") && (0 == strcmp (method, "POST") || 0 == strcmp (method, "GET"))) return pmwebapi_respond_metric_list (connection, c); /* -------------------------------------------------------------------- */ /* metric instance metadata: /context/$ID/_indom */ if (0 == strcmp (context_command, "_indom") && (0 == strcmp (method, "POST") || 0 == strcmp (method, "GET"))) return pmwebapi_respond_instance_list (connection, c); /* -------------------------------------------------------------------- */ /* metric fetch: /context/$ID/_fetch */ if (0 == strcmp (context_command, "_fetch") && (0 == strcmp (method, "POST") || 0 == strcmp (method, "GET"))) return pmwebapi_respond_metric_fetch (connection, c); pmweb_notify (LOG_WARNING, connection, "unrecognized %s context command %s \n", method, context_command); out: return pmwebapi_notify_error (connection, rc); } pcp-3.8.12ubuntu1/src/pmwebapi/pmwebd.options0000664000000000000000000000154112272262501016071 0ustar # command-line options and environment variables for pmwebd # uncomment/edit lines as required # note: environment variables are *not* expanded - use full path # expose resources for non PMAPI requests, e.g. # -R $(PCP_VAR_DIR)/pmwebd/resources # expose archives from local pmloggers, e.g. # -A $(PCP_LOG_DIR)/pmlogger # default is pmwebd's private log directory: $(PCP_LOG_DIR)/pmwebd # run in the foreground # -f # make log go someplace else # -l /some/place/else # assume identity of some user other than "pcp" # -U nobody # emergency messages before logfile created # -x /tmp/desperate.log # port for incoming connections from PCP monitoring clients # -p 44323 # setting of environment variables for pmwebd # timeouts for interactions with pmcd on behalf of clients # PMCD_CONNECT_TIMEOUT=10 # PMCD_RECONNECT_TIMEOUT=10,20,30 # PMCD_REQUEST_TIMEOUT=10 pcp-3.8.12ubuntu1/src/pmwebapi/main.c0000664000000000000000000004625112272262501014275 0ustar /* * JSON web bridge for PMAPI. * * Copyright (c) 2011-2013 Red Hat Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmwebapi.h" /* ------------------------------------------------------------------------ */ const char uriprefix[] = "/pmapi"; char *resourcedir; /* set by -R option */ char *archivesdir = "."; /* set by -A option */ unsigned verbosity; /* set by -v option */ unsigned maxtimeout = 300; /* set by -t option */ unsigned perm_context = 1; /* set by -c option, changed by -h/-a/-L */ unsigned new_contexts_p = 1; /* set by -N option */ unsigned exit_p; /* counted by SIG* handler */ static char *logfile = "pmwebd.log"; static char *fatalfile = "/dev/tty"; /* fatal messages at startup go here */ static char *username; static int mhd_log_args (void *connection, enum MHD_ValueKind kind, const char *key, const char *value) { (void) kind; pmweb_notify (LOG_DEBUG, connection, "%s%s%s", key, (value ? "=" : ""), (value ? value : "")); return MHD_YES; } /* Respond to a new incoming HTTP request. It may be one of three general categories: (a) creation of a new PMAPI context: do it (b) operation on an existing context: do it (c) access to some non-API URI: serve it from $resourcedir/ if configured. */ static int mhd_respond (void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls) { static int dummy; struct MHD_Response* resp = NULL; int rc; static const char error_page[] = "PMWEBD error"; /* could also be an actual error page... */ /* MHD calls us at least twice per request. Skip the first one, since it only gives us headers, and not any POST content. */ if (& dummy != *con_cls) { *con_cls = &dummy; return MHD_YES; } *con_cls = NULL; if (verbosity > 1) pmweb_notify (LOG_INFO, connection, "%s %s %s", version, method, url); if (verbosity > 2) /* Print arguments too. */ (void) MHD_get_connection_values (connection, MHD_GET_ARGUMENT_KIND, &mhd_log_args, connection); /* pmwebapi? */ if (0 == strncmp(url, uriprefix, strlen(uriprefix))) return pmwebapi_respond (cls, connection, & url[strlen(uriprefix)+1], /* strip prefix */ method, upload_data, upload_data_size); /* pmresapi? */ else if (0 == strcmp(method, "GET") && resourcedir != NULL) return pmwebres_respond (cls, connection, url); /* junk? */ (void) MHD_add_response_header (resp, "Content-Type", "text/plain"); resp = MHD_create_response_from_buffer (strlen(error_page), (char*)error_page, MHD_RESPMEM_PERSISTENT); if (resp == NULL) { pmweb_notify (LOG_ERR, connection, "MHD_create_response_from_callback failed\n"); return MHD_NO; } rc = MHD_queue_response (connection, MHD_HTTP_BAD_REQUEST, resp); MHD_destroy_response (resp); if (rc != MHD_YES) { pmweb_notify (LOG_ERR, connection, "MHD_queue_response failed\n"); return MHD_NO; } return MHD_YES; } /* ------------------------------------------------------------------------ */ /* NB: see also ../../man/man1/pmwebd.1 */ #define OPTIONS "fl:p:46K:R:t:c:h:a:LA:NU:vx:?" #define STRINGIFY2(x) #x #define STRINGIFY(x) STRINGIFY2(x) static char usage[] = "Usage: %s [options]\n\n" "Network options:\n" " -p N listen on given TCP port, default " STRINGIFY(PMWEBD_PORT) "\n" " -4 listen on IPv4 only\n" " -6 listen on IPv6 only\n" " -t timeout max time (seconds) for pmapi polling, default 300\n" " -R resdir serve non-API files from given directory, no default\n" "Context options:\n" " -c number set next permanent-binding context number\n" " -h hostname permanent-bind next context to PMCD on host\n" " -a archive permanent-bind next context to archive\n" " -L permanent-bind next context to local PMDAs\n" " -N disable remote new-context requests\n" " -K spec optional additional PMDA spec for local connection\n" " -A archdir permit remote new-archive-context under archdir, CWD default\n" "Other options:\n" " -f run in the foreground\n" " -l logfile redirect diagnostics and trace output\n" " -v increase verbosity\n" " -U username assume identity of username (only when run as root)\n" " -x file fatal messages at startup sent to file [default /dev/tty]\n" " -? help\n"; static void handle_signals (int sig) { (void) sig; exit_p ++; } static void pmweb_dont_start(void) { FILE *tty; FILE *log; __pmNotifyErr(LOG_ERR, "pmwebd not started due to errors!\n"); if ((tty = fopen(fatalfile, "w")) != NULL) { fflush(stderr); fprintf(tty, "NOTE: pmwebd not started due to errors! "); if ((log = fopen(logfile, "r")) != NULL) { int c; fprintf(tty, "Log file \"%s\" contains ...\n", logfile); while ((c = fgetc(log)) != EOF) fputc(c, tty); fclose(log); } else fprintf(tty, "Log file \"%s\" has vanished!\n", logfile); fclose(tty); } exit(1); } /* * Local variant of __pmServerDumpRequestPorts - remove this * when an NSS-based pmweb daemon is built. */ static void server_dump_request_ports(FILE *f, int ipv4, int ipv6, int port) { if (ipv4) fprintf (f, "Started daemon on IPv4 TCP port %d\n", port); if (ipv6) fprintf (f, "Started daemon on IPv6 TCP port %d\n", port); } static void server_dump_configuration(FILE *f) { char *cwd; char path[MAXPATHLEN]; char cwdpath[MAXPATHLEN]; int sep = __pmPathSeparator(); int len; cwd = getcwd(cwdpath, sizeof(cwdpath)); if (resourcedir) { len = (__pmAbsolutePath(resourcedir) || !cwd) ? snprintf(path, sizeof(path), "%s", resourcedir) : snprintf(path, sizeof(path), "%s%c%s", cwd, sep, resourcedir); while (len-- > 1) { if (path[len] != '.' && path[len] != sep) break; path[len] = '\0'; } fprintf (f, "Serving non-pmwebapi URLs under directory %s\n", path); } if (new_contexts_p) { len = (__pmAbsolutePath(archivesdir) || !cwd) ? snprintf(path, sizeof(path), "%s", archivesdir) : snprintf(path, sizeof(path), "%s%c%s", cwd, sep, archivesdir); while (len-- > 1) { if (path[len] != '.' && path[len] != sep) break; path[len] = '\0'; } /* XXX: network outbound ACL */ fprintf (f, "Serving PCP archives under directory %s\n", path); } else { fprintf (f, "Remote context creation requests disabled\n"); } } static void pmweb_init_random_seed(void) { struct timeval tv; gettimeofday (&tv, NULL); srandom ((unsigned int) getpid() ^ (unsigned int) tv.tv_sec ^ (unsigned int) tv.tv_usec); } static void pmweb_shutdown (struct MHD_Daemon *d4, struct MHD_Daemon *d6) { /* Shut down cleanly, out of a misplaced sense of propriety. */ if (d4) MHD_stop_daemon (d4); if (d6) MHD_stop_daemon (d6); /* Let's politely clean up all the active contexts. */ /* The OS could do all that for us anyway, but let's make valgrind happy. */ pmwebapi_deallocate_all (); __pmNotifyErr (LOG_INFO, "pmwebd Shutdown\n"); fflush(stderr); } int main(int argc, char *argv[]) { struct MHD_Daemon *d4 = NULL; int mhd_ipv4 = 1; struct MHD_Daemon *d6 = NULL; int mhd_ipv6 = 1; int c; int sts; int run_daemon = 1; char *errmsg = NULL; unsigned errflag = 0; unsigned short port = PMWEBD_PORT; umask(022); __pmSetProgname(argv[0]); __pmGetUsername(&username); while ((c = getopt(argc, argv, "D:" OPTIONS)) != EOF) switch (c) { case 'p': { long pn; char *endptr; errno = 0; pn = strtol(optarg, &endptr, 0); if (errno != 0 || *endptr != '\0' || pn < 0 || pn > 65535) { fprintf(stderr, "%s: invalid -p port number %s\n", pmProgname, optarg); errflag ++; } else port = (unsigned short) pn; } break; case 't': { long tn; char *endptr; errno = 0; tn = strtol(optarg, &endptr, 0); /* NB: strtoul would accept negative values. */ if (errno != 0 || *endptr != '\0' || tn < 0 || tn > (long)UINT_MAX) { fprintf(stderr, "%s: invalid -t timeout %s\n", pmProgname, optarg); errflag ++; } else maxtimeout = (unsigned) tn; } break; case 'K': if ((errmsg = __pmSpecLocalPMDA(optarg)) != NULL) { fprintf(stderr, "%s: __pmSpecLocalPMDA failed\n%s\n", pmProgname, errmsg); errflag++; } break; case 'R': resourcedir = optarg; break; case 'A': archivesdir = optarg; break; case '6': mhd_ipv6 = 1; mhd_ipv4 = 0; break; case '4': mhd_ipv4 = 1; mhd_ipv6 = 0; break; case 'v': verbosity ++; break; case 'c': assert (optarg); { long pc; char *endptr; errno = 0; pc = strtol(optarg, &endptr, 0); if (errno != 0 || *endptr != '\0' || pc <= 0 || pc >= INT_MAX) { fprintf(stderr, "%s: invalid -c context number %s\n", pmProgname, optarg); errflag ++; } else perm_context = (unsigned) pc; } break; case 'h': assert (optarg); { int pcp_context = pmNewContext (PM_CONTEXT_HOST, optarg); int rc; if (pcp_context < 0) { __pmNotifyErr (LOG_ERR, "new context failed\n"); exit(EXIT_FAILURE); } rc = pmwebapi_bind_permanent (perm_context++, pcp_context); if (rc < 0) { __pmNotifyErr (LOG_ERR, "new context failed\n"); exit(EXIT_FAILURE); } __pmNotifyErr (LOG_INFO, "context (web%d=pm%d) created, host %s, permanent\n", perm_context-1, pcp_context, optarg); } break; case 'a': assert (optarg); { int pcp_context = pmNewContext (PM_CONTEXT_ARCHIVE, optarg); int rc; if (pcp_context < 0) { __pmNotifyErr (LOG_ERR, "new context failed\n"); exit(EXIT_FAILURE); } rc = pmwebapi_bind_permanent (perm_context++, pcp_context); if (rc < 0) { __pmNotifyErr (LOG_ERR, "new context failed\n"); exit(EXIT_FAILURE); } __pmNotifyErr (LOG_INFO, "context (web%d=pm%d) created, archive %s, permanent\n", perm_context-1, pcp_context, optarg); } break; case 'L': { int pcp_context = pmNewContext (PM_CONTEXT_LOCAL, NULL); int rc; if (pcp_context < 0) { __pmNotifyErr (LOG_ERR, "new context failed\n"); exit(EXIT_FAILURE); } rc = pmwebapi_bind_permanent (perm_context++, pcp_context); if (rc < 0) { __pmNotifyErr (LOG_ERR, "new context failed\n"); exit(EXIT_FAILURE); } __pmNotifyErr (LOG_INFO, "context (web%d=pm%d) created, local, permanent\n", perm_context-1, pcp_context); } break; case 'N': new_contexts_p = 0; break; case 'D': /* debug flag */ sts = __pmParseDebug(optarg); if (sts < 0) { fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", pmProgname, optarg); errflag++; } pmDebug |= sts; break; case 'f': /* foreground, i.e. do _not_ run as a daemon */ run_daemon = 0; break; case 'l': /* log file name */ logfile = optarg; break; case 'U': /* run as user username */ username = optarg; break; case 'x': fatalfile = optarg; break; default: case '?': fprintf(stderr, usage, pmProgname); exit(EXIT_FAILURE); } if (errflag) exit(EXIT_FAILURE); if (run_daemon) { fflush(stderr); pmweb_start_daemon(argc, argv); } /* Start microhttp daemon. Use the application-driven threading model, so we don't complicate things with threads. In the future, if this daemon becomes safe to run multithreaded (now that libpcp is), consider MHD_USE_THREAD_PER_CONNECTION; need to add ample locking over pmwebd context structures etc. */ if (mhd_ipv4) d4 = MHD_start_daemon(0, port, NULL, NULL, /* default accept policy */ &mhd_respond, NULL, /* handler callback */ MHD_OPTION_CONNECTION_TIMEOUT, maxtimeout, MHD_OPTION_END); if (mhd_ipv6) d6 = MHD_start_daemon(MHD_USE_IPv6, port, NULL, NULL, /* default accept policy */ &mhd_respond, NULL, /* handler callback */ MHD_OPTION_CONNECTION_TIMEOUT, maxtimeout, MHD_OPTION_END); if (d4 == NULL && d6 == NULL) { __pmNotifyErr(LOG_ERR, "error starting microhttpd daemons\n"); pmweb_dont_start(); } __pmOpenLog(pmProgname, logfile, stderr, &sts); /* close old stdout, and force stdout into same stream as stderr */ fflush(stdout); close(fileno(stdout)); if (dup(fileno(stderr)) == -1) { fprintf(stderr, "Warning: dup() failed: %s\n", pmErrStr(-oserror())); } fprintf(stderr, "pmwebd: PID = %" FMT_PID ", PMAPI URL = %s\n", getpid(), uriprefix); server_dump_request_ports(stderr, d4 != NULL, d6 != NULL, port); server_dump_configuration(stderr); fflush(stderr); /* Set up signal handlers. */ __pmSetSignalHandler(SIGHUP, SIG_IGN); __pmSetSignalHandler(SIGINT, handle_signals); __pmSetSignalHandler(SIGTERM, handle_signals); __pmSetSignalHandler(SIGQUIT, handle_signals); /* Not this one; might get it from pmcd momentary disconnection. */ /* __pmSetSignalHandler(SIGPIPE, handle_signals); */ /* lose root privileges if we have them */ __pmSetProcessIdentity(username); /* Setup randomness for calls to random() */ pmweb_init_random_seed(); /* Block indefinitely. */ while (! exit_p) { struct timeval tv; fd_set rs; fd_set ws; fd_set es; int max = 0; /* Based upon MHD fileserver_example_external_select.c */ FD_ZERO (& rs); FD_ZERO (& ws); FD_ZERO (& es); if (d4 && MHD_YES != MHD_get_fdset (d4, &rs, &ws, &es, &max)) break; /* fatal internal error */ if (d6 && MHD_YES != MHD_get_fdset (d6, &rs, &ws, &es, &max)) break; /* fatal internal error */ /* Find the next expiry. We don't need to bound it by MHD_get_timeout, since we don't use a small MHD_OPTION_CONNECTION_TIMEOUT. */ tv.tv_sec = pmwebapi_gc (); tv.tv_usec = 0; (void) select (max+1, &rs, &ws, &es, &tv); if (d4) MHD_run (d4); if (d6) MHD_run (d6); } pmweb_shutdown (d4, d6); return 0; } /* Generate a __pmNotifyErr with the given arguments, but also adding some per-connection metadata info. */ void pmweb_notify (int priority, struct MHD_Connection* connection, const char *fmt, ...) { va_list arg; char message_buf [2048]; /* size similar to that used in __pmNotifyErr itself. */ char *message_tail; size_t message_len; struct sockaddr *so; char hostname[128]; char servname[128]; int rc = -1; /* Look up client address data. */ so = (struct sockaddr *) MHD_get_connection_info (connection,MHD_CONNECTION_INFO_CLIENT_ADDRESS)->client_addr; if (so && so->sa_family == AF_INET) rc = getnameinfo (so, sizeof(struct sockaddr_in), hostname, sizeof(hostname), servname, sizeof(servname), NI_NUMERICHOST|NI_NUMERICSERV); else if (so && so->sa_family == AF_INET6) rc = getnameinfo (so, sizeof(struct sockaddr_in6), hostname, sizeof(hostname), servname, sizeof(servname), NI_NUMERICHOST|NI_NUMERICSERV); if (rc != 0) hostname[0] = servname[0] = '\0'; /* Add the [hostname:port] as a prefix */ rc = snprintf (message_buf, sizeof(message_buf), "[%s:%s] ", hostname, servname); if (rc > 0 && rc < (int)sizeof(message_buf)) { message_tail = message_buf + rc; /* Keep it only if successful. */ message_len = sizeof(message_buf)-rc; } else { message_tail = message_buf; message_len = sizeof(message_buf); } /* Add the remaining incoming text. */ va_start (arg, fmt); rc = vsnprintf (message_tail, message_len, fmt, arg); va_end (arg); (void) rc; /* If this fails, we can't do much really. */ /* Delegate, but avoid format-string vulnerabilities. Drop the trailing \n, if there is one, since __pmNotifyErr will add one for us (since it is missing from the %s format string). */ if (rc >= 0 && rc < (int)message_len) if (message_tail[rc-1] == '\n') message_tail[rc-1] = '\0'; __pmNotifyErr (priority, "%s", message_buf); } pcp-3.8.12ubuntu1/src/pmwebapi/util.c0000664000000000000000000000522012272262501014315 0ustar /* * Copyright (c) 2002 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2009 Aconex. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include "pmwebapi.h" #ifdef IS_MINGW void pmweb_start_daemon(int argc, char **argv) { PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; LPTSTR cmdline = NULL; int i, sz = 3; /* -f\0 */ for (i = 0; i < argc; i++) sz += strlen(argv[i]) + 1; if ((cmdline = malloc(sz)) == NULL) { __pmNotifyErr(LOG_ERR, "pmweb_start_daemon: no memory"); exit(1); } for (sz = i = 0; i < argc; i++) sz += sprintf(cmdline, "%s ", argv[i]); sprintf(cmdline + sz, "-f"); ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); if (0 == CreateProcess( NULL, cmdline, NULL, NULL, /* process and thread attributes */ FALSE, /* inherit handles */ CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW | DETACHED_PROCESS, NULL, /* environment (from parent) */ NULL, /* current directory */ &siStartInfo, /* STARTUPINFO pointer */ &piProcInfo)) { /* receives PROCESS_INFORMATION */ __pmNotifyErr(LOG_ERR, "pmweb_start_daemon: CreateProcess"); /* but keep going */ } else { /* parent, let her exit, but avoid ugly "Log finished" messages */ fclose(stderr); exit(0); } } #else /* Based on Stevens (Unix Network Programming, p.83) */ void pmweb_start_daemon(int argc, char **argv) { int childpid; (void)argc; (void)argv; #if defined(HAVE_TERMIO_SIGNALS) signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTSTP, SIG_IGN); #endif if ((childpid = fork()) < 0) __pmNotifyErr(LOG_ERR, "pmweb_start_daemon: fork"); /* but keep going */ else if (childpid > 0) { /* parent, let her exit, but avoid ugly "Log finished" messages */ fclose(stderr); exit(0); } /* not a process group leader, lose controlling tty */ if (setsid() == -1) __pmNotifyErr(LOG_WARNING, "pmweb_start_daemon: setsid"); /* but keep going */ close(0); /* don't close other fd's -- we know that only good ones are open! */ /* don't chdir("/") -- we still need to open pmcd.log */ } #endif pcp-3.8.12ubuntu1/src/pmwebapi/GNUmakefile0000664000000000000000000000267312272262501015257 0ustar # # Copyright (c) 2011-2013 Red Hat Inc. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../.. include $(TOPDIR)/src/include/builddefs CMDTARGET = pmwebd$(EXECSUFFIX) HFILES = pmwebapi.h CFILES = main.c util.c pmwebapi.c pmresapi.c LSRCFILES = rc_pmwebd pmwebd.options LLDLIBS = $(PCPLIB) -lmicrohttpd LDIRT = pmwebd.log LCFLAGS += -Wextra LCFLAGS += $(PIECFLAGS) LLDFLAGS += $(PIELDFLAGS) SUBDIRS = jsdemos default: build-me include $(BUILDRULES) ifeq "$(HAVE_LIBMICROHTTPD)" "1" build-me: $(CMDTARGET) install: default $(INSTALL) -m 755 -d `dirname $(PCP_PMWEBDOPTIONS_PATH)` $(INSTALL) -m 644 pmwebd.options $(PCP_PMWEBDOPTIONS_PATH) $(INSTALL) -m 755 rc_pmwebd $(PCP_RC_DIR)/pmwebd $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BINADM_DIR)/$(CMDTARGET) $(INSTALL) -m 775 -o $(PCP_USER) -g $(PCP_GROUP) -d $(PCP_LOG_DIR)/pmwebd else build-me: install: endif default_pcp :: default default_pcp :: $(SUBDIRS) $(SUBDIRS_MAKERULE) install_pcp :: install install_pcp :: $(SUBDIRS) $(SUBDIRS_MAKERULE) pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/0000775000000000000000000000000012272262620014643 5ustar pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/jquery-1.7.2.js0000664000000000000000000075572112272262501017202 0ustar /*! * jQuery JavaScript Library v1.7.2 * http://jquery.com/ * * Copyright 2011, John Resig * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * Includes Sizzle.js * http://sizzlejs.com/ * Copyright 2011, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * * Date: Wed Mar 21 12:46:34 2012 -0700 */ (function( window, undefined ) { // Use the correct document accordingly with window argument (sandbox) var document = window.document, navigator = window.navigator, location = window.location; var jQuery = (function() { // Define a local copy of jQuery var jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' return new jQuery.fn.init( selector, context, rootjQuery ); }, // Map over jQuery in case of overwrite _jQuery = window.jQuery, // Map over the $ in case of overwrite _$ = window.$, // A central reference to the root jQuery(document) rootjQuery, // A simple way to check for HTML strings or ID strings // Prioritize #id over to avoid XSS via location.hash (#9521) quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, // Check if a string has a non-whitespace character in it rnotwhite = /\S/, // Used for trimming whitespace trimLeft = /^\s+/, trimRight = /\s+$/, // Match a standalone tag rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, // JSON RegExp rvalidchars = /^[\],:{}\s]*$/, rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, // Useragent RegExp rwebkit = /(webkit)[ \/]([\w.]+)/, ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/, rmsie = /(msie) ([\w.]+)/, rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/, // Matches dashed string for camelizing rdashAlpha = /-([a-z]|[0-9])/ig, rmsPrefix = /^-ms-/, // Used by jQuery.camelCase as callback to replace() fcamelCase = function( all, letter ) { return ( letter + "" ).toUpperCase(); }, // Keep a UserAgent string for use with jQuery.browser userAgent = navigator.userAgent, // For matching the engine and version of the browser browserMatch, // The deferred used on DOM ready readyList, // The ready event handler DOMContentLoaded, // Save a reference to some core methods toString = Object.prototype.toString, hasOwn = Object.prototype.hasOwnProperty, push = Array.prototype.push, slice = Array.prototype.slice, trim = String.prototype.trim, indexOf = Array.prototype.indexOf, // [[Class]] -> type pairs class2type = {}; jQuery.fn = jQuery.prototype = { constructor: jQuery, init: function( selector, context, rootjQuery ) { var match, elem, ret, doc; // Handle $(""), $(null), or $(undefined) if ( !selector ) { return this; } // Handle $(DOMElement) if ( selector.nodeType ) { this.context = this[0] = selector; this.length = 1; return this; } // The body element only exists once, optimize finding it if ( selector === "body" && !context && document.body ) { this.context = document; this[0] = document.body; this.selector = selector; this.length = 1; return this; } // Handle HTML strings if ( typeof selector === "string" ) { // Are we dealing with HTML string or an ID? if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [ null, selector, null ]; } else { match = quickExpr.exec( selector ); } // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) { context = context instanceof jQuery ? context[0] : context; doc = ( context ? context.ownerDocument || context : document ); // If a single string is passed in and it's a single tag // just do a createElement and skip the rest ret = rsingleTag.exec( selector ); if ( ret ) { if ( jQuery.isPlainObject( context ) ) { selector = [ document.createElement( ret[1] ) ]; jQuery.fn.attr.call( selector, context, true ); } else { selector = [ doc.createElement( ret[1] ) ]; } } else { ret = jQuery.buildFragment( [ match[1] ], [ doc ] ); selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes; } return jQuery.merge( this, selector ); // HANDLE: $("#id") } else { elem = document.getElementById( match[2] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id !== match[2] ) { return rootjQuery.find( selector ); } // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; } // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return ( context || rootjQuery ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); } // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector ); } if ( selector.selector !== undefined ) { this.selector = selector.selector; this.context = selector.context; } return jQuery.makeArray( selector, this ); }, // Start with an empty selector selector: "", // The current version of jQuery being used jquery: "1.7.2", // The default length of a jQuery object is 0 length: 0, // The number of elements contained in the matched element set size: function() { return this.length; }, toArray: function() { return slice.call( this, 0 ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { return num == null ? // Return a 'clean' array this.toArray() : // Return just the object ( num < 0 ? this[ this.length + num ] : this[ num ] ); }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems, name, selector ) { // Build a new jQuery matched element set var ret = this.constructor(); if ( jQuery.isArray( elems ) ) { push.apply( ret, elems ); } else { jQuery.merge( ret, elems ); } // Add the old object onto the stack (as a reference) ret.prevObject = this; ret.context = this.context; if ( name === "find" ) { ret.selector = this.selector + ( this.selector ? " " : "" ) + selector; } else if ( name ) { ret.selector = this.selector + "." + name + "(" + selector + ")"; } // Return the newly-formed element set return ret; }, // Execute a callback for every element in the matched set. // (You can seed the arguments with an array of args, but this is // only used internally.) each: function( callback, args ) { return jQuery.each( this, callback, args ); }, ready: function( fn ) { // Attach the listeners jQuery.bindReady(); // Add the callback readyList.add( fn ); return this; }, eq: function( i ) { i = +i; return i === -1 ? this.slice( i ) : this.slice( i, i + 1 ); }, first: function() { return this.eq( 0 ); }, last: function() { return this.eq( -1 ); }, slice: function() { return this.pushStack( slice.apply( this, arguments ), "slice", slice.call(arguments).join(",") ); }, map: function( callback ) { return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); }, end: function() { return this.prevObject || this.constructor(null); }, // For internal use only. // Behaves like an Array's method, not like a jQuery method. push: push, sort: [].sort, splice: [].splice }; // Give the init function the jQuery prototype for later instantiation jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; // skip the boolean and the target i = 2; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // extend jQuery itself if only one argument is passed if ( length === i ) { target = this; --i; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { if ( copyIsArray ) { copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object return target; }; jQuery.extend({ noConflict: function( deep ) { if ( window.$ === jQuery ) { window.$ = _$; } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } return jQuery; }, // Is the DOM ready to be used? Set to true once it occurs. isReady: false, // A counter to track how many items to wait for before // the ready event fires. See #6781 readyWait: 1, // Hold (or release) the ready event holdReady: function( hold ) { if ( hold ) { jQuery.readyWait++; } else { jQuery.ready( true ); } }, // Handle when the DOM is ready ready: function( wait ) { // Either a released hold or an DOMready/load event and not yet ready if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready, 1 ); } // Remember that the DOM is ready jQuery.isReady = true; // If a normal DOM Ready event fired, decrement, and wait if need be if ( wait !== true && --jQuery.readyWait > 0 ) { return; } // If there are functions bound, to execute readyList.fireWith( document, [ jQuery ] ); // Trigger any bound ready events if ( jQuery.fn.trigger ) { jQuery( document ).trigger( "ready" ).off( "ready" ); } } }, bindReady: function() { if ( readyList ) { return; } readyList = jQuery.Callbacks( "once memory" ); // Catch cases where $(document).ready() is called after the // browser event has already occurred. if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready return setTimeout( jQuery.ready, 1 ); } // Mozilla, Opera and webkit nightlies currently support this event if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); // A fallback to window.onload, that will always work window.addEventListener( "load", jQuery.ready, false ); // If IE event model is used } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes document.attachEvent( "onreadystatechange", DOMContentLoaded ); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); // If IE and not a frame // continually check to see if the document is ready var toplevel = false; try { toplevel = window.frameElement == null; } catch(e) {} if ( document.documentElement.doScroll && toplevel ) { doScrollCheck(); } } }, // See test/unit/core.js for details concerning isFunction. // Since version 1.3, DOM methods and functions like alert // aren't supported. They return false on IE (#2968). isFunction: function( obj ) { return jQuery.type(obj) === "function"; }, isArray: Array.isArray || function( obj ) { return jQuery.type(obj) === "array"; }, isWindow: function( obj ) { return obj != null && obj == obj.window; }, isNumeric: function( obj ) { return !isNaN( parseFloat(obj) ) && isFinite( obj ); }, type: function( obj ) { return obj == null ? String( obj ) : class2type[ toString.call(obj) ] || "object"; }, isPlainObject: function( obj ) { // Must be an Object. // Because of IE, we also have to check the presence of the constructor property. // Make sure that DOM nodes and window objects don't pass through, as well if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { return false; } try { // Not own constructor property must be Object if ( obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { return false; } } catch ( e ) { // IE8,9 Will throw exceptions on certain host objects #9897 return false; } // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. var key; for ( key in obj ) {} return key === undefined || hasOwn.call( obj, key ); }, isEmptyObject: function( obj ) { for ( var name in obj ) { return false; } return true; }, error: function( msg ) { throw new Error( msg ); }, parseJSON: function( data ) { if ( typeof data !== "string" || !data ) { return null; } // Make sure leading/trailing whitespace is removed (IE can't handle it) data = jQuery.trim( data ); // Attempt to parse using the native JSON parser first if ( window.JSON && window.JSON.parse ) { return window.JSON.parse( data ); } // Make sure the incoming data is actual JSON // Logic borrowed from http://json.org/json2.js if ( rvalidchars.test( data.replace( rvalidescape, "@" ) .replace( rvalidtokens, "]" ) .replace( rvalidbraces, "")) ) { return ( new Function( "return " + data ) )(); } jQuery.error( "Invalid JSON: " + data ); }, // Cross-browser xml parsing parseXML: function( data ) { if ( typeof data !== "string" || !data ) { return null; } var xml, tmp; try { if ( window.DOMParser ) { // Standard tmp = new DOMParser(); xml = tmp.parseFromString( data , "text/xml" ); } else { // IE xml = new ActiveXObject( "Microsoft.XMLDOM" ); xml.async = "false"; xml.loadXML( data ); } } catch( e ) { xml = undefined; } if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { jQuery.error( "Invalid XML: " + data ); } return xml; }, noop: function() {}, // Evaluates a script in a global context // Workarounds based on findings by Jim Driscoll // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context globalEval: function( data ) { if ( data && rnotwhite.test( data ) ) { // We use execScript on Internet Explorer // We use an anonymous function so that context is window // rather than jQuery in Firefox ( window.execScript || function( data ) { window[ "eval" ].call( window, data ); } )( data ); } }, // Convert dashed to camelCase; used by the css and data modules // Microsoft forgot to hump their vendor prefix (#9572) camelCase: function( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); }, // args is for internal usage only each: function( object, callback, args ) { var name, i = 0, length = object.length, isObj = length === undefined || jQuery.isFunction( object ); if ( args ) { if ( isObj ) { for ( name in object ) { if ( callback.apply( object[ name ], args ) === false ) { break; } } } else { for ( ; i < length; ) { if ( callback.apply( object[ i++ ], args ) === false ) { break; } } } // A special, fast, case for the most common use of each } else { if ( isObj ) { for ( name in object ) { if ( callback.call( object[ name ], name, object[ name ] ) === false ) { break; } } } else { for ( ; i < length; ) { if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { break; } } } } return object; }, // Use native String.trim function wherever possible trim: trim ? function( text ) { return text == null ? "" : trim.call( text ); } : // Otherwise use our own trimming functionality function( text ) { return text == null ? "" : text.toString().replace( trimLeft, "" ).replace( trimRight, "" ); }, // results is for internal usage only makeArray: function( array, results ) { var ret = results || []; if ( array != null ) { // The window, strings (and functions) also have 'length' // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 var type = jQuery.type( array ); if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { push.call( ret, array ); } else { jQuery.merge( ret, array ); } } return ret; }, inArray: function( elem, array, i ) { var len; if ( array ) { if ( indexOf ) { return indexOf.call( array, elem, i ); } len = array.length; i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; for ( ; i < len; i++ ) { // Skip accessing in sparse arrays if ( i in array && array[ i ] === elem ) { return i; } } } return -1; }, merge: function( first, second ) { var i = first.length, j = 0; if ( typeof second.length === "number" ) { for ( var l = second.length; j < l; j++ ) { first[ i++ ] = second[ j ]; } } else { while ( second[j] !== undefined ) { first[ i++ ] = second[ j++ ]; } } first.length = i; return first; }, grep: function( elems, callback, inv ) { var ret = [], retVal; inv = !!inv; // Go through the array, only saving the items // that pass the validator function for ( var i = 0, length = elems.length; i < length; i++ ) { retVal = !!callback( elems[ i ], i ); if ( inv !== retVal ) { ret.push( elems[ i ] ); } } return ret; }, // arg is for internal usage only map: function( elems, callback, arg ) { var value, key, ret = [], i = 0, length = elems.length, // jquery objects are treated as arrays isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ; // Go through the array, translating each of the items to their if ( isArray ) { for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret[ ret.length ] = value; } } // Go through every key on the object, } else { for ( key in elems ) { value = callback( elems[ key ], key, arg ); if ( value != null ) { ret[ ret.length ] = value; } } } // Flatten any nested arrays return ret.concat.apply( [], ret ); }, // A global GUID counter for objects guid: 1, // Bind a function to a context, optionally partially applying any // arguments. proxy: function( fn, context ) { if ( typeof context === "string" ) { var tmp = fn[ context ]; context = fn; fn = tmp; } // Quick check to determine if target is callable, in the spec // this throws a TypeError, but we will just return undefined. if ( !jQuery.isFunction( fn ) ) { return undefined; } // Simulated bind var args = slice.call( arguments, 2 ), proxy = function() { return fn.apply( context, args.concat( slice.call( arguments ) ) ); }; // Set the guid of unique handler to the same of original handler, so it can be removed proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; return proxy; }, // Mutifunctional method to get and set values to a collection // The value/s can optionally be executed if it's a function access: function( elems, fn, key, value, chainable, emptyGet, pass ) { var exec, bulk = key == null, i = 0, length = elems.length; // Sets many values if ( key && typeof key === "object" ) { for ( i in key ) { jQuery.access( elems, fn, i, key[i], 1, emptyGet, value ); } chainable = 1; // Sets one value } else if ( value !== undefined ) { // Optionally, function values get executed if exec is true exec = pass === undefined && jQuery.isFunction( value ); if ( bulk ) { // Bulk operations only iterate when executing function values if ( exec ) { exec = fn; fn = function( elem, key, value ) { return exec.call( jQuery( elem ), value ); }; // Otherwise they run against the entire set } else { fn.call( elems, value ); fn = null; } } if ( fn ) { for (; i < length; i++ ) { fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); } } chainable = 1; } return chainable ? elems : // Gets bulk ? fn.call( elems ) : length ? fn( elems[0], key ) : emptyGet; }, now: function() { return ( new Date() ).getTime(); }, // Use of jQuery.browser is frowned upon. // More details: http://docs.jquery.com/Utilities/jQuery.browser uaMatch: function( ua ) { ua = ua.toLowerCase(); var match = rwebkit.exec( ua ) || ropera.exec( ua ) || rmsie.exec( ua ) || ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) || []; return { browser: match[1] || "", version: match[2] || "0" }; }, sub: function() { function jQuerySub( selector, context ) { return new jQuerySub.fn.init( selector, context ); } jQuery.extend( true, jQuerySub, this ); jQuerySub.superclass = this; jQuerySub.fn = jQuerySub.prototype = this(); jQuerySub.fn.constructor = jQuerySub; jQuerySub.sub = this.sub; jQuerySub.fn.init = function init( selector, context ) { if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { context = jQuerySub( context ); } return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); }; jQuerySub.fn.init.prototype = jQuerySub.fn; var rootjQuerySub = jQuerySub(document); return jQuerySub; }, browser: {} }); // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); }); browserMatch = jQuery.uaMatch( userAgent ); if ( browserMatch.browser ) { jQuery.browser[ browserMatch.browser ] = true; jQuery.browser.version = browserMatch.version; } // Deprecated, use jQuery.browser.webkit instead if ( jQuery.browser.webkit ) { jQuery.browser.safari = true; } // IE doesn't match non-breaking spaces with \s if ( rnotwhite.test( "\xA0" ) ) { trimLeft = /^[\s\xA0]+/; trimRight = /[\s\xA0]+$/; } // All jQuery objects should point back to these rootjQuery = jQuery(document); // Cleanup functions for the document ready method if ( document.addEventListener ) { DOMContentLoaded = function() { document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); jQuery.ready(); }; } else if ( document.attachEvent ) { DOMContentLoaded = function() { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( document.readyState === "complete" ) { document.detachEvent( "onreadystatechange", DOMContentLoaded ); jQuery.ready(); } }; } // The DOM ready check for Internet Explorer function doScrollCheck() { if ( jQuery.isReady ) { return; } try { // If IE is used, use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ document.documentElement.doScroll("left"); } catch(e) { setTimeout( doScrollCheck, 1 ); return; } // and execute any waiting functions jQuery.ready(); } return jQuery; })(); // String to Object flags format cache var flagsCache = {}; // Convert String-formatted flags into Object-formatted ones and store in cache function createFlags( flags ) { var object = flagsCache[ flags ] = {}, i, length; flags = flags.split( /\s+/ ); for ( i = 0, length = flags.length; i < length; i++ ) { object[ flags[i] ] = true; } return object; } /* * Create a callback list using the following parameters: * * flags: an optional list of space-separated flags that will change how * the callback list behaves * * By default a callback list will act like an event callback list and can be * "fired" multiple times. * * Possible flags: * * once: will ensure the callback list can only be fired once (like a Deferred) * * memory: will keep track of previous values and will call any callback added * after the list has been fired right away with the latest "memorized" * values (like a Deferred) * * unique: will ensure a callback can only be added once (no duplicate in the list) * * stopOnFalse: interrupt callings when a callback returns false * */ jQuery.Callbacks = function( flags ) { // Convert flags from String-formatted to Object-formatted // (we check in cache first) flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; var // Actual callback list list = [], // Stack of fire calls for repeatable lists stack = [], // Last fire value (for non-forgettable lists) memory, // Flag to know if list was already fired fired, // Flag to know if list is currently firing firing, // First callback to fire (used internally by add and fireWith) firingStart, // End of the loop when firing firingLength, // Index of currently firing callback (modified by remove if needed) firingIndex, // Add one or several callbacks to the list add = function( args ) { var i, length, elem, type, actual; for ( i = 0, length = args.length; i < length; i++ ) { elem = args[ i ]; type = jQuery.type( elem ); if ( type === "array" ) { // Inspect recursively add( elem ); } else if ( type === "function" ) { // Add if not in unique mode and callback is not in if ( !flags.unique || !self.has( elem ) ) { list.push( elem ); } } } }, // Fire callbacks fire = function( context, args ) { args = args || []; memory = !flags.memory || [ context, args ]; fired = true; firing = true; firingIndex = firingStart || 0; firingStart = 0; firingLength = list.length; for ( ; list && firingIndex < firingLength; firingIndex++ ) { if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) { memory = true; // Mark as halted break; } } firing = false; if ( list ) { if ( !flags.once ) { if ( stack && stack.length ) { memory = stack.shift(); self.fireWith( memory[ 0 ], memory[ 1 ] ); } } else if ( memory === true ) { self.disable(); } else { list = []; } } }, // Actual Callbacks object self = { // Add a callback or a collection of callbacks to the list add: function() { if ( list ) { var length = list.length; add( arguments ); // Do we need to add the callbacks to the // current firing batch? if ( firing ) { firingLength = list.length; // With memory, if we're not firing then // we should call right away, unless previous // firing was halted (stopOnFalse) } else if ( memory && memory !== true ) { firingStart = length; fire( memory[ 0 ], memory[ 1 ] ); } } return this; }, // Remove a callback from the list remove: function() { if ( list ) { var args = arguments, argIndex = 0, argLength = args.length; for ( ; argIndex < argLength ; argIndex++ ) { for ( var i = 0; i < list.length; i++ ) { if ( args[ argIndex ] === list[ i ] ) { // Handle firingIndex and firingLength if ( firing ) { if ( i <= firingLength ) { firingLength--; if ( i <= firingIndex ) { firingIndex--; } } } // Remove the element list.splice( i--, 1 ); // If we have some unicity property then // we only need to do this once if ( flags.unique ) { break; } } } } } return this; }, // Control if a given callback is in the list has: function( fn ) { if ( list ) { var i = 0, length = list.length; for ( ; i < length; i++ ) { if ( fn === list[ i ] ) { return true; } } } return false; }, // Remove all callbacks from the list empty: function() { list = []; return this; }, // Have the list do nothing anymore disable: function() { list = stack = memory = undefined; return this; }, // Is it disabled? disabled: function() { return !list; }, // Lock the list in its current state lock: function() { stack = undefined; if ( !memory || memory === true ) { self.disable(); } return this; }, // Is it locked? locked: function() { return !stack; }, // Call all callbacks with the given context and arguments fireWith: function( context, args ) { if ( stack ) { if ( firing ) { if ( !flags.once ) { stack.push( [ context, args ] ); } } else if ( !( flags.once && memory ) ) { fire( context, args ); } } return this; }, // Call all the callbacks with the given arguments fire: function() { self.fireWith( this, arguments ); return this; }, // To know if the callbacks have already been called at least once fired: function() { return !!fired; } }; return self; }; var // Static reference to slice sliceDeferred = [].slice; jQuery.extend({ Deferred: function( func ) { var doneList = jQuery.Callbacks( "once memory" ), failList = jQuery.Callbacks( "once memory" ), progressList = jQuery.Callbacks( "memory" ), state = "pending", lists = { resolve: doneList, reject: failList, notify: progressList }, promise = { done: doneList.add, fail: failList.add, progress: progressList.add, state: function() { return state; }, // Deprecated isResolved: doneList.fired, isRejected: failList.fired, then: function( doneCallbacks, failCallbacks, progressCallbacks ) { deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks ); return this; }, always: function() { deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments ); return this; }, pipe: function( fnDone, fnFail, fnProgress ) { return jQuery.Deferred(function( newDefer ) { jQuery.each( { done: [ fnDone, "resolve" ], fail: [ fnFail, "reject" ], progress: [ fnProgress, "notify" ] }, function( handler, data ) { var fn = data[ 0 ], action = data[ 1 ], returned; if ( jQuery.isFunction( fn ) ) { deferred[ handler ](function() { returned = fn.apply( this, arguments ); if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify ); } else { newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] ); } }); } else { deferred[ handler ]( newDefer[ action ] ); } }); }).promise(); }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { if ( obj == null ) { obj = promise; } else { for ( var key in promise ) { obj[ key ] = promise[ key ]; } } return obj; } }, deferred = promise.promise({}), key; for ( key in lists ) { deferred[ key ] = lists[ key ].fire; deferred[ key + "With" ] = lists[ key ].fireWith; } // Handle state deferred.done( function() { state = "resolved"; }, failList.disable, progressList.lock ).fail( function() { state = "rejected"; }, doneList.disable, progressList.lock ); // Call given func if any if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; }, // Deferred helper when: function( firstParam ) { var args = sliceDeferred.call( arguments, 0 ), i = 0, length = args.length, pValues = new Array( length ), count = length, pCount = length, deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ? firstParam : jQuery.Deferred(), promise = deferred.promise(); function resolveFunc( i ) { return function( value ) { args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; if ( !( --count ) ) { deferred.resolveWith( deferred, args ); } }; } function progressFunc( i ) { return function( value ) { pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value; deferred.notifyWith( promise, pValues ); }; } if ( length > 1 ) { for ( ; i < length; i++ ) { if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) { args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) ); } else { --count; } } if ( !count ) { deferred.resolveWith( deferred, args ); } } else if ( deferred !== firstParam ) { deferred.resolveWith( deferred, length ? [ firstParam ] : [] ); } return promise; } }); jQuery.support = (function() { var support, all, a, select, opt, input, fragment, tds, events, eventName, i, isSupported, div = document.createElement( "div" ), documentElement = document.documentElement; // Preliminary tests div.setAttribute("className", "t"); div.innerHTML = "
a"; all = div.getElementsByTagName( "*" ); a = div.getElementsByTagName( "a" )[ 0 ]; // Can't get basic test support if ( !all || !all.length || !a ) { return {}; } // First batch of supports tests select = document.createElement( "select" ); opt = select.appendChild( document.createElement("option") ); input = div.getElementsByTagName( "input" )[ 0 ]; support = { // IE strips leading whitespace when .innerHTML is used leadingWhitespace: ( div.firstChild.nodeType === 3 ), // Make sure that tbody elements aren't automatically inserted // IE will insert them into empty tables tbody: !div.getElementsByTagName("tbody").length, // Make sure that link elements get serialized correctly by innerHTML // This requires a wrapper element in IE htmlSerialize: !!div.getElementsByTagName("link").length, // Get the style information from getAttribute // (IE uses .cssText instead) style: /top/.test( a.getAttribute("style") ), // Make sure that URLs aren't manipulated // (IE normalizes it by default) hrefNormalized: ( a.getAttribute("href") === "/a" ), // Make sure that element opacity exists // (IE uses filter instead) // Use a regex to work around a WebKit issue. See #5145 opacity: /^0.55/.test( a.style.opacity ), // Verify style float existence // (IE uses styleFloat instead of cssFloat) cssFloat: !!a.style.cssFloat, // Make sure that if no value is specified for a checkbox // that it defaults to "on". // (WebKit defaults to "" instead) checkOn: ( input.value === "on" ), // Make sure that a selected-by-default option has a working selected property. // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) getSetAttribute: div.className !== "t", // Tests for enctype support on a form(#6743) enctype: !!document.createElement("form").enctype, // Makes sure cloning an html5 element does not cause problems // Where outerHTML is undefined, this still works html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", // Will be defined later submitBubbles: true, changeBubbles: true, focusinBubbles: false, deleteExpando: true, noCloneEvent: true, inlineBlockNeedsLayout: false, shrinkWrapBlocks: false, reliableMarginRight: true, pixelMargin: true }; // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat"); // Make sure checked status is properly cloned input.checked = true; support.noCloneChecked = input.cloneNode( true ).checked; // Make sure that the options inside disabled selects aren't marked as disabled // (WebKit marks them as disabled) select.disabled = true; support.optDisabled = !opt.disabled; // Test to see if it's possible to delete an expando from an element // Fails in Internet Explorer try { delete div.test; } catch( e ) { support.deleteExpando = false; } if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { div.attachEvent( "onclick", function() { // Cloning a node shouldn't copy over any // bound event handlers (IE does this) support.noCloneEvent = false; }); div.cloneNode( true ).fireEvent( "onclick" ); } // Check if a radio maintains its value // after being appended to the DOM input = document.createElement("input"); input.value = "t"; input.setAttribute("type", "radio"); support.radioValue = input.value === "t"; input.setAttribute("checked", "checked"); // #11217 - WebKit loses check when the name is after the checked attribute input.setAttribute( "name", "t" ); div.appendChild( input ); fragment = document.createDocumentFragment(); fragment.appendChild( div.lastChild ); // WebKit doesn't clone checked state correctly in fragments support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; // Check if a disconnected checkbox will retain its checked // value of true after appended to the DOM (IE6/7) support.appendChecked = input.checked; fragment.removeChild( input ); fragment.appendChild( div ); // Technique from Juriy Zaytsev // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/ // We only care about the case where non-standard event systems // are used, namely in IE. Short-circuiting here helps us to // avoid an eval call (in setAttribute) which can cause CSP // to go haywire. See: https://developer.mozilla.org/en/Security/CSP if ( div.attachEvent ) { for ( i in { submit: 1, change: 1, focusin: 1 }) { eventName = "on" + i; isSupported = ( eventName in div ); if ( !isSupported ) { div.setAttribute( eventName, "return;" ); isSupported = ( typeof div[ eventName ] === "function" ); } support[ i + "Bubbles" ] = isSupported; } } fragment.removeChild( div ); // Null elements to avoid leaks in IE fragment = select = opt = div = input = null; // Run tests that need a body at doc ready jQuery(function() { var container, outer, inner, table, td, offsetSupport, marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight, paddingMarginBorderVisibility, paddingMarginBorder, body = document.getElementsByTagName("body")[0]; if ( !body ) { // Return for frameset docs that don't have a body return; } conMarginTop = 1; paddingMarginBorder = "padding:0;margin:0;border:"; positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;"; paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;"; style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;"; html = "
" + "" + "
"; container = document.createElement("div"); container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px"; body.insertBefore( container, body.firstChild ); // Construct the test element div = document.createElement("div"); container.appendChild( div ); // Check if table cells still have offsetWidth/Height when they are set // to display:none and there are still other visible table cells in a // table row; if so, offsetWidth/Height are not reliable for use when // determining if an element has been hidden directly using // display:none (it is still safe to use offsets if a parent element is // hidden; don safety goggles and see bug #4512 for more information). // (only IE 8 fails this test) div.innerHTML = "
t
"; tds = div.getElementsByTagName( "td" ); isSupported = ( tds[ 0 ].offsetHeight === 0 ); tds[ 0 ].style.display = ""; tds[ 1 ].style.display = "none"; // Check if empty table cells still have offsetWidth/Height // (IE <= 8 fail this test) support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); // Check if div with explicit width and no margin-right incorrectly // gets computed margin-right based on width of container. For more // info see bug #3333 // Fails in WebKit before Feb 2011 nightlies // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right if ( window.getComputedStyle ) { div.innerHTML = ""; marginDiv = document.createElement( "div" ); marginDiv.style.width = "0"; marginDiv.style.marginRight = "0"; div.style.width = "2px"; div.appendChild( marginDiv ); support.reliableMarginRight = ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0; } if ( typeof div.style.zoom !== "undefined" ) { // Check if natively block-level elements act like inline-block // elements when setting their display to 'inline' and giving // them layout // (IE < 8 does this) div.innerHTML = ""; div.style.width = div.style.padding = "1px"; div.style.border = 0; div.style.overflow = "hidden"; div.style.display = "inline"; div.style.zoom = 1; support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); // Check if elements with layout shrink-wrap their children // (IE 6 does this) div.style.display = "block"; div.style.overflow = "visible"; div.innerHTML = "
"; support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); } div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility; div.innerHTML = html; outer = div.firstChild; inner = outer.firstChild; td = outer.nextSibling.firstChild.firstChild; offsetSupport = { doesNotAddBorder: ( inner.offsetTop !== 5 ), doesAddBorderForTableAndCells: ( td.offsetTop === 5 ) }; inner.style.position = "fixed"; inner.style.top = "20px"; // safari subtracts parent border width here which is 5px offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 ); inner.style.position = inner.style.top = ""; outer.style.overflow = "hidden"; outer.style.position = "relative"; offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 ); offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop ); if ( window.getComputedStyle ) { div.style.marginTop = "1%"; support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%"; } if ( typeof container.style.zoom !== "undefined" ) { container.style.zoom = 1; } body.removeChild( container ); marginDiv = div = container = null; jQuery.extend( support, offsetSupport ); }); return support; })(); var rbrace = /^(?:\{.*\}|\[.*\])$/, rmultiDash = /([A-Z])/g; jQuery.extend({ cache: {}, // Please use with caution uuid: 0, // Unique for each copy of jQuery on the page // Non-digits removed to match rinlinejQuery expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ), // The following elements throw uncatchable exceptions if you // attempt to add expando properties to them. noData: { "embed": true, // Ban all objects except for Flash (which handle expandos) "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", "applet": true }, hasData: function( elem ) { elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; return !!elem && !isEmptyDataObject( elem ); }, data: function( elem, name, data, pvt /* Internal Use Only */ ) { if ( !jQuery.acceptData( elem ) ) { return; } var privateCache, thisCache, ret, internalKey = jQuery.expando, getByName = typeof name === "string", // We have to handle DOM nodes and JS objects differently because IE6-7 // can't GC object references properly across the DOM-JS boundary isNode = elem.nodeType, // Only DOM nodes need the global jQuery cache; JS object data is // attached directly to the object so GC can occur automatically cache = isNode ? jQuery.cache : elem, // Only defining an ID for JS objects if its cache already exists allows // the code to shortcut on the same path as a DOM node with no cache id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey, isEvents = name === "events"; // Avoid doing any more work than we need to when trying to get data on an // object that has no data at all if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) { return; } if ( !id ) { // Only DOM nodes need a new unique ID for each element since their data // ends up in the global cache if ( isNode ) { elem[ internalKey ] = id = ++jQuery.uuid; } else { id = internalKey; } } if ( !cache[ id ] ) { cache[ id ] = {}; // Avoids exposing jQuery metadata on plain JS objects when the object // is serialized using JSON.stringify if ( !isNode ) { cache[ id ].toJSON = jQuery.noop; } } // An object can be passed to jQuery.data instead of a key/value pair; this gets // shallow copied over onto the existing cache if ( typeof name === "object" || typeof name === "function" ) { if ( pvt ) { cache[ id ] = jQuery.extend( cache[ id ], name ); } else { cache[ id ].data = jQuery.extend( cache[ id ].data, name ); } } privateCache = thisCache = cache[ id ]; // jQuery data() is stored in a separate object inside the object's internal data // cache in order to avoid key collisions between internal data and user-defined // data. if ( !pvt ) { if ( !thisCache.data ) { thisCache.data = {}; } thisCache = thisCache.data; } if ( data !== undefined ) { thisCache[ jQuery.camelCase( name ) ] = data; } // Users should not attempt to inspect the internal events object using jQuery.data, // it is undocumented and subject to change. But does anyone listen? No. if ( isEvents && !thisCache[ name ] ) { return privateCache.events; } // Check for both converted-to-camel and non-converted data property names // If a data property was specified if ( getByName ) { // First Try to find as-is property data ret = thisCache[ name ]; // Test for null|undefined property data if ( ret == null ) { // Try to find the camelCased property ret = thisCache[ jQuery.camelCase( name ) ]; } } else { ret = thisCache; } return ret; }, removeData: function( elem, name, pvt /* Internal Use Only */ ) { if ( !jQuery.acceptData( elem ) ) { return; } var thisCache, i, l, // Reference to internal data cache key internalKey = jQuery.expando, isNode = elem.nodeType, // See jQuery.data for more information cache = isNode ? jQuery.cache : elem, // See jQuery.data for more information id = isNode ? elem[ internalKey ] : internalKey; // If there is already no cache entry for this object, there is no // purpose in continuing if ( !cache[ id ] ) { return; } if ( name ) { thisCache = pvt ? cache[ id ] : cache[ id ].data; if ( thisCache ) { // Support array or space separated string names for data keys if ( !jQuery.isArray( name ) ) { // try the string as a key before any manipulation if ( name in thisCache ) { name = [ name ]; } else { // split the camel cased version by spaces unless a key with the spaces exists name = jQuery.camelCase( name ); if ( name in thisCache ) { name = [ name ]; } else { name = name.split( " " ); } } } for ( i = 0, l = name.length; i < l; i++ ) { delete thisCache[ name[i] ]; } // If there is no data left in the cache, we want to continue // and let the cache object itself get destroyed if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { return; } } } // See jQuery.data for more information if ( !pvt ) { delete cache[ id ].data; // Don't destroy the parent cache unless the internal data object // had been the only thing left in it if ( !isEmptyDataObject(cache[ id ]) ) { return; } } // Browsers that fail expando deletion also refuse to delete expandos on // the window, but it will allow it on all other JS objects; other browsers // don't care // Ensure that `cache` is not a window object #10080 if ( jQuery.support.deleteExpando || !cache.setInterval ) { delete cache[ id ]; } else { cache[ id ] = null; } // We destroyed the cache and need to eliminate the expando on the node to avoid // false lookups in the cache for entries that no longer exist if ( isNode ) { // IE does not allow us to delete expando properties from nodes, // nor does it have a removeAttribute function on Document nodes; // we must handle all of these cases if ( jQuery.support.deleteExpando ) { delete elem[ internalKey ]; } else if ( elem.removeAttribute ) { elem.removeAttribute( internalKey ); } else { elem[ internalKey ] = null; } } }, // For internal use only. _data: function( elem, name, data ) { return jQuery.data( elem, name, data, true ); }, // A method for determining if a DOM node can handle the data expando acceptData: function( elem ) { if ( elem.nodeName ) { var match = jQuery.noData[ elem.nodeName.toLowerCase() ]; if ( match ) { return !(match === true || elem.getAttribute("classid") !== match); } } return true; } }); jQuery.fn.extend({ data: function( key, value ) { var parts, part, attr, name, l, elem = this[0], i = 0, data = null; // Gets all values if ( key === undefined ) { if ( this.length ) { data = jQuery.data( elem ); if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { attr = elem.attributes; for ( l = attr.length; i < l; i++ ) { name = attr[i].name; if ( name.indexOf( "data-" ) === 0 ) { name = jQuery.camelCase( name.substring(5) ); dataAttr( elem, name, data[ name ] ); } } jQuery._data( elem, "parsedAttrs", true ); } } return data; } // Sets multiple values if ( typeof key === "object" ) { return this.each(function() { jQuery.data( this, key ); }); } parts = key.split( ".", 2 ); parts[1] = parts[1] ? "." + parts[1] : ""; part = parts[1] + "!"; return jQuery.access( this, function( value ) { if ( value === undefined ) { data = this.triggerHandler( "getData" + part, [ parts[0] ] ); // Try to fetch any internally stored data first if ( data === undefined && elem ) { data = jQuery.data( elem, key ); data = dataAttr( elem, key, data ); } return data === undefined && parts[1] ? this.data( parts[0] ) : data; } parts[1] = value; this.each(function() { var self = jQuery( this ); self.triggerHandler( "setData" + part, parts ); jQuery.data( this, key, value ); self.triggerHandler( "changeData" + part, parts ); }); }, null, value, arguments.length > 1, null, false ); }, removeData: function( key ) { return this.each(function() { jQuery.removeData( this, key ); }); } }); function dataAttr( elem, key, data ) { // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { data = data === "true" ? true : data === "false" ? false : data === "null" ? null : jQuery.isNumeric( data ) ? +data : rbrace.test( data ) ? jQuery.parseJSON( data ) : data; } catch( e ) {} // Make sure we set the data so it isn't changed later jQuery.data( elem, key, data ); } else { data = undefined; } } return data; } // checks a cache object for emptiness function isEmptyDataObject( obj ) { for ( var name in obj ) { // if the public data object is empty, the private is still empty if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { continue; } if ( name !== "toJSON" ) { return false; } } return true; } function handleQueueMarkDefer( elem, type, src ) { var deferDataKey = type + "defer", queueDataKey = type + "queue", markDataKey = type + "mark", defer = jQuery._data( elem, deferDataKey ); if ( defer && ( src === "queue" || !jQuery._data(elem, queueDataKey) ) && ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) { // Give room for hard-coded callbacks to fire first // and eventually mark/queue something else on the element setTimeout( function() { if ( !jQuery._data( elem, queueDataKey ) && !jQuery._data( elem, markDataKey ) ) { jQuery.removeData( elem, deferDataKey, true ); defer.fire(); } }, 0 ); } } jQuery.extend({ _mark: function( elem, type ) { if ( elem ) { type = ( type || "fx" ) + "mark"; jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 ); } }, _unmark: function( force, elem, type ) { if ( force !== true ) { type = elem; elem = force; force = false; } if ( elem ) { type = type || "fx"; var key = type + "mark", count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 ); if ( count ) { jQuery._data( elem, key, count ); } else { jQuery.removeData( elem, key, true ); handleQueueMarkDefer( elem, type, "mark" ); } } }, queue: function( elem, type, data ) { var q; if ( elem ) { type = ( type || "fx" ) + "queue"; q = jQuery._data( elem, type ); // Speed up dequeue by getting out quickly if this is just a lookup if ( data ) { if ( !q || jQuery.isArray(data) ) { q = jQuery._data( elem, type, jQuery.makeArray(data) ); } else { q.push( data ); } } return q || []; } }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), fn = queue.shift(), hooks = {}; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { fn = queue.shift(); } if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { queue.unshift( "inprogress" ); } jQuery._data( elem, type + ".run", hooks ); fn.call( elem, function() { jQuery.dequeue( elem, type ); }, hooks ); } if ( !queue.length ) { jQuery.removeData( elem, type + "queue " + type + ".run", true ); handleQueueMarkDefer( elem, type, "queue" ); } } }); jQuery.fn.extend({ queue: function( type, data ) { var setter = 2; if ( typeof type !== "string" ) { data = type; type = "fx"; setter--; } if ( arguments.length < setter ) { return jQuery.queue( this[0], type ); } return data === undefined ? this : this.each(function() { var queue = jQuery.queue( this, type, data ); if ( type === "fx" && queue[0] !== "inprogress" ) { jQuery.dequeue( this, type ); } }); }, dequeue: function( type ) { return this.each(function() { jQuery.dequeue( this, type ); }); }, // Based off of the plugin by Clint Helfers, with permission. // http://blindsignals.com/index.php/2009/07/jquery-delay/ delay: function( time, type ) { time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; type = type || "fx"; return this.queue( type, function( next, hooks ) { var timeout = setTimeout( next, time ); hooks.stop = function() { clearTimeout( timeout ); }; }); }, clearQueue: function( type ) { return this.queue( type || "fx", [] ); }, // Get a promise resolved when queues of a certain type // are emptied (fx is the type by default) promise: function( type, object ) { if ( typeof type !== "string" ) { object = type; type = undefined; } type = type || "fx"; var defer = jQuery.Deferred(), elements = this, i = elements.length, count = 1, deferDataKey = type + "defer", queueDataKey = type + "queue", markDataKey = type + "mark", tmp; function resolve() { if ( !( --count ) ) { defer.resolveWith( elements, [ elements ] ); } } while( i-- ) { if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) || jQuery.data( elements[ i ], markDataKey, undefined, true ) ) && jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) { count++; tmp.add( resolve ); } } resolve(); return defer.promise( object ); } }); var rclass = /[\n\t\r]/g, rspace = /\s+/, rreturn = /\r/g, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, getSetAttribute = jQuery.support.getSetAttribute, nodeHook, boolHook, fixSpecified; jQuery.fn.extend({ attr: function( name, value ) { return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); }, removeAttr: function( name ) { return this.each(function() { jQuery.removeAttr( this, name ); }); }, prop: function( name, value ) { return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); }, removeProp: function( name ) { name = jQuery.propFix[ name ] || name; return this.each(function() { // try/catch handles cases where IE balks (such as removing a property on window) try { this[ name ] = undefined; delete this[ name ]; } catch( e ) {} }); }, addClass: function( value ) { var classNames, i, l, elem, setClass, c, cl; if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { jQuery( this ).addClass( value.call(this, j, this.className) ); }); } if ( value && typeof value === "string" ) { classNames = value.split( rspace ); for ( i = 0, l = this.length; i < l; i++ ) { elem = this[ i ]; if ( elem.nodeType === 1 ) { if ( !elem.className && classNames.length === 1 ) { elem.className = value; } else { setClass = " " + elem.className + " "; for ( c = 0, cl = classNames.length; c < cl; c++ ) { if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) { setClass += classNames[ c ] + " "; } } elem.className = jQuery.trim( setClass ); } } } } return this; }, removeClass: function( value ) { var classNames, i, l, elem, className, c, cl; if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { jQuery( this ).removeClass( value.call(this, j, this.className) ); }); } if ( (value && typeof value === "string") || value === undefined ) { classNames = ( value || "" ).split( rspace ); for ( i = 0, l = this.length; i < l; i++ ) { elem = this[ i ]; if ( elem.nodeType === 1 && elem.className ) { if ( value ) { className = (" " + elem.className + " ").replace( rclass, " " ); for ( c = 0, cl = classNames.length; c < cl; c++ ) { className = className.replace(" " + classNames[ c ] + " ", " "); } elem.className = jQuery.trim( className ); } else { elem.className = ""; } } } } return this; }, toggleClass: function( value, stateVal ) { var type = typeof value, isBool = typeof stateVal === "boolean"; if ( jQuery.isFunction( value ) ) { return this.each(function( i ) { jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); }); } return this.each(function() { if ( type === "string" ) { // toggle individual class names var className, i = 0, self = jQuery( this ), state = stateVal, classNames = value.split( rspace ); while ( (className = classNames[ i++ ]) ) { // check each className given, space seperated list state = isBool ? state : !self.hasClass( className ); self[ state ? "addClass" : "removeClass" ]( className ); } } else if ( type === "undefined" || type === "boolean" ) { if ( this.className ) { // store className if set jQuery._data( this, "__className__", this.className ); } // toggle whole className this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; } }); }, hasClass: function( selector ) { var className = " " + selector + " ", i = 0, l = this.length; for ( ; i < l; i++ ) { if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { return true; } } return false; }, val: function( value ) { var hooks, ret, isFunction, elem = this[0]; if ( !arguments.length ) { if ( elem ) { hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { return ret; } ret = elem.value; return typeof ret === "string" ? // handle most common string cases ret.replace(rreturn, "") : // handle cases where value is null/undef or number ret == null ? "" : ret; } return; } isFunction = jQuery.isFunction( value ); return this.each(function( i ) { var self = jQuery(this), val; if ( this.nodeType !== 1 ) { return; } if ( isFunction ) { val = value.call( this, i, self.val() ); } else { val = value; } // Treat null/undefined as ""; convert numbers to string if ( val == null ) { val = ""; } else if ( typeof val === "number" ) { val += ""; } else if ( jQuery.isArray( val ) ) { val = jQuery.map(val, function ( value ) { return value == null ? "" : value + ""; }); } hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; // If set returns undefined, fall back to normal setting if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { this.value = val; } }); } }); jQuery.extend({ valHooks: { option: { get: function( elem ) { // attributes.value is undefined in Blackberry 4.7 but // uses .value. See #6932 var val = elem.attributes.value; return !val || val.specified ? elem.value : elem.text; } }, select: { get: function( elem ) { var value, i, max, option, index = elem.selectedIndex, values = [], options = elem.options, one = elem.type === "select-one"; // Nothing was selected if ( index < 0 ) { return null; } // Loop through all the selected options i = one ? index : 0; max = one ? index + 1 : options.length; for ( ; i < max; i++ ) { option = options[ i ]; // Don't return options that are disabled or in a disabled optgroup if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) { // Get the specific value for the option value = jQuery( option ).val(); // We don't need an array for one selects if ( one ) { return value; } // Multi-Selects return an array values.push( value ); } } // Fixes Bug #2551 -- select.val() broken in IE after form.reset() if ( one && !values.length && options.length ) { return jQuery( options[ index ] ).val(); } return values; }, set: function( elem, value ) { var values = jQuery.makeArray( value ); jQuery(elem).find("option").each(function() { this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; }); if ( !values.length ) { elem.selectedIndex = -1; } return values; } } }, attrFn: { val: true, css: true, html: true, text: true, data: true, width: true, height: true, offset: true }, attr: function( elem, name, value, pass ) { var ret, hooks, notxml, nType = elem.nodeType; // don't get/set attributes on text, comment and attribute nodes if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return; } if ( pass && name in jQuery.attrFn ) { return jQuery( elem )[ name ]( value ); } // Fallback to prop when attributes are not supported if ( typeof elem.getAttribute === "undefined" ) { return jQuery.prop( elem, name, value ); } notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); // All attributes are lowercase // Grab necessary hook if one is defined if ( notxml ) { name = name.toLowerCase(); hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); } if ( value !== undefined ) { if ( value === null ) { jQuery.removeAttr( elem, name ); return; } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { elem.setAttribute( name, "" + value ); return value; } } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined return ret === null ? undefined : ret; } }, removeAttr: function( elem, value ) { var propName, attrNames, name, l, isBool, i = 0; if ( value && elem.nodeType === 1 ) { attrNames = value.toLowerCase().split( rspace ); l = attrNames.length; for ( ; i < l; i++ ) { name = attrNames[ i ]; if ( name ) { propName = jQuery.propFix[ name ] || name; isBool = rboolean.test( name ); // See #9699 for explanation of this approach (setting first, then removal) // Do not do this for boolean attributes (see #10870) if ( !isBool ) { jQuery.attr( elem, name, "" ); } elem.removeAttribute( getSetAttribute ? name : propName ); // Set corresponding property to false for boolean attributes if ( isBool && propName in elem ) { elem[ propName ] = false; } } } } }, attrHooks: { type: { set: function( elem, value ) { // We can't allow the type property to be changed (since it causes problems in IE) if ( rtype.test( elem.nodeName ) && elem.parentNode ) { jQuery.error( "type property can't be changed" ); } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { // Setting the type on a radio button after the value resets the value in IE6-9 // Reset value to it's default in case type is set after value // This is for element creation var val = elem.value; elem.setAttribute( "type", value ); if ( val ) { elem.value = val; } return value; } } }, // Use the value property for back compat // Use the nodeHook for button elements in IE6/7 (#1954) value: { get: function( elem, name ) { if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { return nodeHook.get( elem, name ); } return name in elem ? elem.value : null; }, set: function( elem, value, name ) { if ( nodeHook && jQuery.nodeName( elem, "button" ) ) { return nodeHook.set( elem, value, name ); } // Does not return so that setAttribute is also used elem.value = value; } } }, propFix: { tabindex: "tabIndex", readonly: "readOnly", "for": "htmlFor", "class": "className", maxlength: "maxLength", cellspacing: "cellSpacing", cellpadding: "cellPadding", rowspan: "rowSpan", colspan: "colSpan", usemap: "useMap", frameborder: "frameBorder", contenteditable: "contentEditable" }, prop: function( elem, name, value ) { var ret, hooks, notxml, nType = elem.nodeType; // don't get/set properties on text, comment and attribute nodes if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return; } notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); if ( notxml ) { // Fix name and attach hooks name = jQuery.propFix[ name ] || name; hooks = jQuery.propHooks[ name ]; } if ( value !== undefined ) { if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { return ( elem[ name ] = value ); } } else { if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { return elem[ name ]; } } }, propHooks: { tabIndex: { get: function( elem ) { // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ var attributeNode = elem.getAttributeNode("tabindex"); return attributeNode && attributeNode.specified ? parseInt( attributeNode.value, 10 ) : rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? 0 : undefined; } } } }); // Add the tabIndex propHook to attrHooks for back-compat (different case is intentional) jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex; // Hook for boolean attributes boolHook = { get: function( elem, name ) { // Align boolean attributes with corresponding properties // Fall back to attribute presence where some booleans are not supported var attrNode, property = jQuery.prop( elem, name ); return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ? name.toLowerCase() : undefined; }, set: function( elem, value, name ) { var propName; if ( value === false ) { // Remove boolean attributes when set to false jQuery.removeAttr( elem, name ); } else { // value is true since we know at this point it's type boolean and not false // Set boolean attributes to the same name and set the DOM property propName = jQuery.propFix[ name ] || name; if ( propName in elem ) { // Only set the IDL specifically if it already exists on the element elem[ propName ] = true; } elem.setAttribute( name, name.toLowerCase() ); } return name; } }; // IE6/7 do not support getting/setting some attributes with get/setAttribute if ( !getSetAttribute ) { fixSpecified = { name: true, id: true, coords: true }; // Use this for any attribute in IE6/7 // This fixes almost every IE6/7 issue nodeHook = jQuery.valHooks.button = { get: function( elem, name ) { var ret; ret = elem.getAttributeNode( name ); return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ? ret.nodeValue : undefined; }, set: function( elem, value, name ) { // Set the existing or create a new attribute node var ret = elem.getAttributeNode( name ); if ( !ret ) { ret = document.createAttribute( name ); elem.setAttributeNode( ret ); } return ( ret.nodeValue = value + "" ); } }; // Apply the nodeHook to tabindex jQuery.attrHooks.tabindex.set = nodeHook.set; // Set width and height to auto instead of 0 on empty string( Bug #8150 ) // This is for removals jQuery.each([ "width", "height" ], function( i, name ) { jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { set: function( elem, value ) { if ( value === "" ) { elem.setAttribute( name, "auto" ); return value; } } }); }); // Set contenteditable to false on removals(#10429) // Setting to empty string throws an error as an invalid value jQuery.attrHooks.contenteditable = { get: nodeHook.get, set: function( elem, value, name ) { if ( value === "" ) { value = "false"; } nodeHook.set( elem, value, name ); } }; } // Some attributes require a special call on IE if ( !jQuery.support.hrefNormalized ) { jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { get: function( elem ) { var ret = elem.getAttribute( name, 2 ); return ret === null ? undefined : ret; } }); }); } if ( !jQuery.support.style ) { jQuery.attrHooks.style = { get: function( elem ) { // Return undefined in the case of empty string // Normalize to lowercase since IE uppercases css property names return elem.style.cssText.toLowerCase() || undefined; }, set: function( elem, value ) { return ( elem.style.cssText = "" + value ); } }; } // Safari mis-reports the default selected property of an option // Accessing the parent's selectedIndex property fixes it if ( !jQuery.support.optSelected ) { jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { get: function( elem ) { var parent = elem.parentNode; if ( parent ) { parent.selectedIndex; // Make sure that it also works with optgroups, see #5701 if ( parent.parentNode ) { parent.parentNode.selectedIndex; } } return null; } }); } // IE6/7 call enctype encoding if ( !jQuery.support.enctype ) { jQuery.propFix.enctype = "encoding"; } // Radios and checkboxes getter/setter if ( !jQuery.support.checkOn ) { jQuery.each([ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = { get: function( elem ) { // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified return elem.getAttribute("value") === null ? "on" : elem.value; } }; }); } jQuery.each([ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { set: function( elem, value ) { if ( jQuery.isArray( value ) ) { return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); } } }); }); var rformElems = /^(?:textarea|input|select)$/i, rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/, rhoverHack = /(?:^|\s)hover(\.\S+)?\b/, rkeyEvent = /^key/, rmouseEvent = /^(?:mouse|contextmenu)|click/, rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/, quickParse = function( selector ) { var quick = rquickIs.exec( selector ); if ( quick ) { // 0 1 2 3 // [ _, tag, id, class ] quick[1] = ( quick[1] || "" ).toLowerCase(); quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" ); } return quick; }, quickIs = function( elem, m ) { var attrs = elem.attributes || {}; return ( (!m[1] || elem.nodeName.toLowerCase() === m[1]) && (!m[2] || (attrs.id || {}).value === m[2]) && (!m[3] || m[3].test( (attrs[ "class" ] || {}).value )) ); }, hoverHack = function( events ) { return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" ); }; /* * Helper functions for managing events -- not part of the public interface. * Props to Dean Edwards' addEvent library for many of the ideas. */ jQuery.event = { add: function( elem, types, handler, data, selector ) { var elemData, eventHandle, events, t, tns, type, namespaces, handleObj, handleObjIn, quick, handlers, special; // Don't attach events to noData or text/comment nodes (allow plain objects tho) if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) { return; } // Caller can pass in an object of custom data in lieu of the handler if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; selector = handleObjIn.selector; } // Make sure that the handler has a unique ID, used to find/remove it later if ( !handler.guid ) { handler.guid = jQuery.guid++; } // Init the element's event structure and main handler, if this is the first events = elemData.events; if ( !events ) { elemData.events = events = {}; } eventHandle = elemData.handle; if ( !eventHandle ) { elemData.handle = eventHandle = function( e ) { // Discard the second event of a jQuery.event.trigger() and // when an event is called after a page has unloaded return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ? jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : undefined; }; // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events eventHandle.elem = elem; } // Handle multiple events separated by a space // jQuery(...).bind("mouseover mouseout", fn); types = jQuery.trim( hoverHack(types) ).split( " " ); for ( t = 0; t < types.length; t++ ) { tns = rtypenamespace.exec( types[t] ) || []; type = tns[1]; namespaces = ( tns[2] || "" ).split( "." ).sort(); // If event changes its type, use the special event handlers for the changed type special = jQuery.event.special[ type ] || {}; // If selector defined, determine special event api type, otherwise given type type = ( selector ? special.delegateType : special.bindType ) || type; // Update special based on newly reset type special = jQuery.event.special[ type ] || {}; // handleObj is passed to all event handlers handleObj = jQuery.extend({ type: type, origType: tns[1], data: data, handler: handler, guid: handler.guid, selector: selector, quick: selector && quickParse( selector ), namespace: namespaces.join(".") }, handleObjIn ); // Init the event handler queue if we're the first handlers = events[ type ]; if ( !handlers ) { handlers = events[ type ] = []; handlers.delegateCount = 0; // Only use addEventListener/attachEvent if the special events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { // Bind the global event handler to the element if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, eventHandle ); } } } if ( special.add ) { special.add.call( elem, handleObj ); if ( !handleObj.handler.guid ) { handleObj.handler.guid = handler.guid; } } // Add to the element's handler list, delegates in front if ( selector ) { handlers.splice( handlers.delegateCount++, 0, handleObj ); } else { handlers.push( handleObj ); } // Keep track of which events have ever been used, for event optimization jQuery.event.global[ type ] = true; } // Nullify elem to prevent memory leaks in IE elem = null; }, global: {}, // Detach an event or set of events from an element remove: function( elem, types, handler, selector, mappedTypes ) { var elemData = jQuery.hasData( elem ) && jQuery._data( elem ), t, tns, type, origType, namespaces, origCount, j, events, special, handle, eventType, handleObj; if ( !elemData || !(events = elemData.events) ) { return; } // Once for each type.namespace in types; type may be omitted types = jQuery.trim( hoverHack( types || "" ) ).split(" "); for ( t = 0; t < types.length; t++ ) { tns = rtypenamespace.exec( types[t] ) || []; type = origType = tns[1]; namespaces = tns[2]; // Unbind all events (on this namespace, if provided) for the element if ( !type ) { for ( type in events ) { jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); } continue; } special = jQuery.event.special[ type ] || {}; type = ( selector? special.delegateType : special.bindType ) || type; eventType = events[ type ] || []; origCount = eventType.length; namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null; // Remove matching events for ( j = 0; j < eventType.length; j++ ) { handleObj = eventType[ j ]; if ( ( mappedTypes || origType === handleObj.origType ) && ( !handler || handler.guid === handleObj.guid ) && ( !namespaces || namespaces.test( handleObj.namespace ) ) && ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { eventType.splice( j--, 1 ); if ( handleObj.selector ) { eventType.delegateCount--; } if ( special.remove ) { special.remove.call( elem, handleObj ); } } } // Remove generic event handler if we removed something and no more handlers exist // (avoids potential for endless recursion during removal of special event handlers) if ( eventType.length === 0 && origCount !== eventType.length ) { if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } delete events[ type ]; } } // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { handle = elemData.handle; if ( handle ) { handle.elem = null; } // removeData also checks for emptiness and clears the expando if empty // so use it instead of delete jQuery.removeData( elem, [ "events", "handle" ], true ); } }, // Events that are safe to short-circuit if no handlers are attached. // Native DOM events should not be added, they may have inline handlers. customEvent: { "getData": true, "setData": true, "changeData": true }, trigger: function( event, data, elem, onlyHandlers ) { // Don't do events on text and comment nodes if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) { return; } // Event object or event type var type = event.type || event, namespaces = [], cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType; // focus/blur morphs to focusin/out; ensure we're not firing them right now if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { return; } if ( type.indexOf( "!" ) >= 0 ) { // Exclusive events trigger only for the exact event (no namespaces) type = type.slice(0, -1); exclusive = true; } if ( type.indexOf( "." ) >= 0 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split("."); type = namespaces.shift(); namespaces.sort(); } if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) { // No jQuery handlers for this event type, and it can't have inline handlers return; } // Caller can pass in an Event, Object, or just an event type string event = typeof event === "object" ? // jQuery.Event object event[ jQuery.expando ] ? event : // Object literal new jQuery.Event( type, event ) : // Just the event type (string) new jQuery.Event( type ); event.type = type; event.isTrigger = true; event.exclusive = exclusive; event.namespace = namespaces.join( "." ); event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null; ontype = type.indexOf( ":" ) < 0 ? "on" + type : ""; // Handle a global trigger if ( !elem ) { // TODO: Stop taunting the data cache; remove global events and always attach to document cache = jQuery.cache; for ( i in cache ) { if ( cache[ i ].events && cache[ i ].events[ type ] ) { jQuery.event.trigger( event, data, cache[ i ].handle.elem, true ); } } return; } // Clean up the event in case it is being reused event.result = undefined; if ( !event.target ) { event.target = elem; } // Clone any incoming data and prepend the event, creating the handler arg list data = data != null ? jQuery.makeArray( data ) : []; data.unshift( event ); // Allow special events to draw outside the lines special = jQuery.event.special[ type ] || {}; if ( special.trigger && special.trigger.apply( elem, data ) === false ) { return; } // Determine event propagation path in advance, per W3C events spec (#9951) // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) eventPath = [[ elem, special.bindType || type ]]; if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { bubbleType = special.delegateType || type; cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode; old = null; for ( ; cur; cur = cur.parentNode ) { eventPath.push([ cur, bubbleType ]); old = cur; } // Only add window if we got to document (e.g., not plain obj or detached DOM) if ( old && old === elem.ownerDocument ) { eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]); } } // Fire handlers on the event path for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) { cur = eventPath[i][0]; event.type = eventPath[i][1]; handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); if ( handle ) { handle.apply( cur, data ); } // Note that this is a bare JS function and not a jQuery handler handle = ontype && cur[ ontype ]; if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) { event.preventDefault(); } } event.type = type; // If nobody prevented the default action, do it now if ( !onlyHandlers && !event.isDefaultPrevented() ) { if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { // Call a native DOM method on the target with the same name name as the event. // Can't use an .isFunction() check here because IE6/7 fails that test. // Don't do default actions on window, that's where global variables be (#6170) // IE<9 dies on focus/blur to hidden element (#1486) if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) { // Don't re-trigger an onFOO event when we call its FOO() method old = elem[ ontype ]; if ( old ) { elem[ ontype ] = null; } // Prevent re-triggering of the same event, since we already bubbled it above jQuery.event.triggered = type; elem[ type ](); jQuery.event.triggered = undefined; if ( old ) { elem[ ontype ] = old; } } } } return event.result; }, dispatch: function( event ) { // Make a writable jQuery.Event from the native event object event = jQuery.event.fix( event || window.event ); var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []), delegateCount = handlers.delegateCount, args = [].slice.call( arguments, 0 ), run_all = !event.exclusive && !event.namespace, special = jQuery.event.special[ event.type ] || {}, handlerQueue = [], i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related; // Use the fix-ed jQuery.Event rather than the (read-only) native event args[0] = event; event.delegateTarget = this; // Call the preDispatch hook for the mapped type, and let it bail if desired if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { return; } // Determine handlers that should run if there are delegated events // Avoid non-left-click bubbling in Firefox (#3861) if ( delegateCount && !(event.button && event.type === "click") ) { // Pregenerate a single jQuery object for reuse with .is() jqcur = jQuery(this); jqcur.context = this.ownerDocument || this; for ( cur = event.target; cur != this; cur = cur.parentNode || this ) { // Don't process events on disabled elements (#6911, #8165) if ( cur.disabled !== true ) { selMatch = {}; matches = []; jqcur[0] = cur; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; sel = handleObj.selector; if ( selMatch[ sel ] === undefined ) { selMatch[ sel ] = ( handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel ) ); } if ( selMatch[ sel ] ) { matches.push( handleObj ); } } if ( matches.length ) { handlerQueue.push({ elem: cur, matches: matches }); } } } } // Add the remaining (directly-bound) handlers if ( handlers.length > delegateCount ) { handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) }); } // Run delegates first; they may want to stop propagation beneath us for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) { matched = handlerQueue[ i ]; event.currentTarget = matched.elem; for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) { handleObj = matched.matches[ j ]; // Triggered event must either 1) be non-exclusive and have no namespace, or // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) { event.data = handleObj.data; event.handleObj = handleObj; ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) .apply( matched.elem, args ); if ( ret !== undefined ) { event.result = ret; if ( ret === false ) { event.preventDefault(); event.stopPropagation(); } } } } } // Call the postDispatch hook for the mapped type if ( special.postDispatch ) { special.postDispatch.call( this, event ); } return event.result; }, // Includes some event props shared by KeyEvent and MouseEvent // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 *** props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), fixHooks: {}, keyHooks: { props: "char charCode key keyCode".split(" "), filter: function( event, original ) { // Add which for key events if ( event.which == null ) { event.which = original.charCode != null ? original.charCode : original.keyCode; } return event; } }, mouseHooks: { props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), filter: function( event, original ) { var eventDoc, doc, body, button = original.button, fromElement = original.fromElement; // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && original.clientX != null ) { eventDoc = event.target.ownerDocument || document; doc = eventDoc.documentElement; body = eventDoc.body; event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); } // Add relatedTarget, if necessary if ( !event.relatedTarget && fromElement ) { event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; } // Add which for click: 1 === left; 2 === middle; 3 === right // Note: button is not normalized, so don't use it if ( !event.which && button !== undefined ) { event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); } return event; } }, fix: function( event ) { if ( event[ jQuery.expando ] ) { return event; } // Create a writable copy of the event object and normalize some properties var i, prop, originalEvent = event, fixHook = jQuery.event.fixHooks[ event.type ] || {}, copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; event = jQuery.Event( originalEvent ); for ( i = copy.length; i; ) { prop = copy[ --i ]; event[ prop ] = originalEvent[ prop ]; } // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2) if ( !event.target ) { event.target = originalEvent.srcElement || document; } // Target should not be a text node (#504, Safari) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; } // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8) if ( event.metaKey === undefined ) { event.metaKey = event.ctrlKey; } return fixHook.filter? fixHook.filter( event, originalEvent ) : event; }, special: { ready: { // Make sure the ready event is setup setup: jQuery.bindReady }, load: { // Prevent triggered image.load events from bubbling to window.load noBubble: true }, focus: { delegateType: "focusin" }, blur: { delegateType: "focusout" }, beforeunload: { setup: function( data, namespaces, eventHandle ) { // We only want to do this special case on windows if ( jQuery.isWindow( this ) ) { this.onbeforeunload = eventHandle; } }, teardown: function( namespaces, eventHandle ) { if ( this.onbeforeunload === eventHandle ) { this.onbeforeunload = null; } } } }, simulate: function( type, elem, event, bubble ) { // Piggyback on a donor event to simulate a different one. // Fake originalEvent to avoid donor's stopPropagation, but if the // simulated event prevents default then we do the same on the donor. var e = jQuery.extend( new jQuery.Event(), event, { type: type, isSimulated: true, originalEvent: {} } ); if ( bubble ) { jQuery.event.trigger( e, null, elem ); } else { jQuery.event.dispatch.call( elem, e ); } if ( e.isDefaultPrevented() ) { event.preventDefault(); } } }; // Some plugins are using, but it's undocumented/deprecated and will be removed. // The 1.7 special event interface should provide all the hooks needed now. jQuery.event.handle = jQuery.event.dispatch; jQuery.removeEvent = document.removeEventListener ? function( elem, type, handle ) { if ( elem.removeEventListener ) { elem.removeEventListener( type, handle, false ); } } : function( elem, type, handle ) { if ( elem.detachEvent ) { elem.detachEvent( "on" + type, handle ); } }; jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword if ( !(this instanceof jQuery.Event) ) { return new jQuery.Event( src, props ); } // Event object if ( src && src.type ) { this.originalEvent = src; this.type = src.type; // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; // Event type } else { this.type = src; } // Put explicitly provided properties onto the event object if ( props ) { jQuery.extend( this, props ); } // Create a timestamp if incoming event doesn't have one this.timeStamp = src && src.timeStamp || jQuery.now(); // Mark it as fixed this[ jQuery.expando ] = true; }; function returnFalse() { return false; } function returnTrue() { return true; } // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html jQuery.Event.prototype = { preventDefault: function() { this.isDefaultPrevented = returnTrue; var e = this.originalEvent; if ( !e ) { return; } // if preventDefault exists run it on the original event if ( e.preventDefault ) { e.preventDefault(); // otherwise set the returnValue property of the original event to false (IE) } else { e.returnValue = false; } }, stopPropagation: function() { this.isPropagationStopped = returnTrue; var e = this.originalEvent; if ( !e ) { return; } // if stopPropagation exists run it on the original event if ( e.stopPropagation ) { e.stopPropagation(); } // otherwise set the cancelBubble property of the original event to true (IE) e.cancelBubble = true; }, stopImmediatePropagation: function() { this.isImmediatePropagationStopped = returnTrue; this.stopPropagation(); }, isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse }; // Create mouseenter/leave events using mouseover/out and event-time checks jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { delegateType: fix, bindType: fix, handle: function( event ) { var target = this, related = event.relatedTarget, handleObj = event.handleObj, selector = handleObj.selector, ret; // For mousenter/leave call the handler if related is outside the target. // NB: No relatedTarget if the mouse left/entered the browser window if ( !related || (related !== target && !jQuery.contains( target, related )) ) { event.type = handleObj.origType; ret = handleObj.handler.apply( this, arguments ); event.type = fix; } return ret; } }; }); // IE submit delegation if ( !jQuery.support.submitBubbles ) { jQuery.event.special.submit = { setup: function() { // Only need this for delegated form submit events if ( jQuery.nodeName( this, "form" ) ) { return false; } // Lazy-add a submit handler when a descendant form may potentially be submitted jQuery.event.add( this, "click._submit keypress._submit", function( e ) { // Node name check avoids a VML-related crash in IE (#9807) var elem = e.target, form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; if ( form && !form._submit_attached ) { jQuery.event.add( form, "submit._submit", function( event ) { event._submit_bubble = true; }); form._submit_attached = true; } }); // return undefined since we don't need an event listener }, postDispatch: function( event ) { // If form was submitted by the user, bubble the event up the tree if ( event._submit_bubble ) { delete event._submit_bubble; if ( this.parentNode && !event.isTrigger ) { jQuery.event.simulate( "submit", this.parentNode, event, true ); } } }, teardown: function() { // Only need this for delegated form submit events if ( jQuery.nodeName( this, "form" ) ) { return false; } // Remove delegated handlers; cleanData eventually reaps submit handlers attached above jQuery.event.remove( this, "._submit" ); } }; } // IE change delegation and checkbox/radio fix if ( !jQuery.support.changeBubbles ) { jQuery.event.special.change = { setup: function() { if ( rformElems.test( this.nodeName ) ) { // IE doesn't fire change on a check/radio until blur; trigger it on click // after a propertychange. Eat the blur-change in special.change.handle. // This still fires onchange a second time for check/radio after blur. if ( this.type === "checkbox" || this.type === "radio" ) { jQuery.event.add( this, "propertychange._change", function( event ) { if ( event.originalEvent.propertyName === "checked" ) { this._just_changed = true; } }); jQuery.event.add( this, "click._change", function( event ) { if ( this._just_changed && !event.isTrigger ) { this._just_changed = false; jQuery.event.simulate( "change", this, event, true ); } }); } return false; } // Delegated event; lazy-add a change handler on descendant inputs jQuery.event.add( this, "beforeactivate._change", function( e ) { var elem = e.target; if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) { jQuery.event.add( elem, "change._change", function( event ) { if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { jQuery.event.simulate( "change", this.parentNode, event, true ); } }); elem._change_attached = true; } }); }, handle: function( event ) { var elem = event.target; // Swallow native change events from checkbox/radio, we already triggered them above if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { return event.handleObj.handler.apply( this, arguments ); } }, teardown: function() { jQuery.event.remove( this, "._change" ); return rformElems.test( this.nodeName ); } }; } // Create "bubbling" focus and blur events if ( !jQuery.support.focusinBubbles ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { // Attach a single capturing handler while someone wants focusin/focusout var attaches = 0, handler = function( event ) { jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); }; jQuery.event.special[ fix ] = { setup: function() { if ( attaches++ === 0 ) { document.addEventListener( orig, handler, true ); } }, teardown: function() { if ( --attaches === 0 ) { document.removeEventListener( orig, handler, true ); } } }; }); } jQuery.fn.extend({ on: function( types, selector, data, fn, /*INTERNAL*/ one ) { var origFn, type; // Types can be a map of types/handlers if ( typeof types === "object" ) { // ( types-Object, selector, data ) if ( typeof selector !== "string" ) { // && selector != null // ( types-Object, data ) data = data || selector; selector = undefined; } for ( type in types ) { this.on( type, selector, data, types[ type ], one ); } return this; } if ( data == null && fn == null ) { // ( types, fn ) fn = selector; data = selector = undefined; } else if ( fn == null ) { if ( typeof selector === "string" ) { // ( types, selector, fn ) fn = data; data = undefined; } else { // ( types, data, fn ) fn = data; data = selector; selector = undefined; } } if ( fn === false ) { fn = returnFalse; } else if ( !fn ) { return this; } if ( one === 1 ) { origFn = fn; fn = function( event ) { // Can use an empty set, since event contains the info jQuery().off( event ); return origFn.apply( this, arguments ); }; // Use same guid so caller can remove using origFn fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); } return this.each( function() { jQuery.event.add( this, types, fn, data, selector ); }); }, one: function( types, selector, data, fn ) { return this.on( types, selector, data, fn, 1 ); }, off: function( types, selector, fn ) { if ( types && types.preventDefault && types.handleObj ) { // ( event ) dispatched jQuery.Event var handleObj = types.handleObj; jQuery( types.delegateTarget ).off( handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler ); return this; } if ( typeof types === "object" ) { // ( types-object [, selector] ) for ( var type in types ) { this.off( type, selector, types[ type ] ); } return this; } if ( selector === false || typeof selector === "function" ) { // ( types [, fn] ) fn = selector; selector = undefined; } if ( fn === false ) { fn = returnFalse; } return this.each(function() { jQuery.event.remove( this, types, fn, selector ); }); }, bind: function( types, data, fn ) { return this.on( types, null, data, fn ); }, unbind: function( types, fn ) { return this.off( types, null, fn ); }, live: function( types, data, fn ) { jQuery( this.context ).on( types, this.selector, data, fn ); return this; }, die: function( types, fn ) { jQuery( this.context ).off( types, this.selector || "**", fn ); return this; }, delegate: function( selector, types, data, fn ) { return this.on( types, selector, data, fn ); }, undelegate: function( selector, types, fn ) { // ( namespace ) or ( selector, types [, fn] ) return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn ); }, trigger: function( type, data ) { return this.each(function() { jQuery.event.trigger( type, data, this ); }); }, triggerHandler: function( type, data ) { if ( this[0] ) { return jQuery.event.trigger( type, data, this[0], true ); } }, toggle: function( fn ) { // Save reference to arguments for access in closure var args = arguments, guid = fn.guid || jQuery.guid++, i = 0, toggler = function( event ) { // Figure out which function to execute var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i; jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 ); // Make sure that clicks stop event.preventDefault(); // and execute the function return args[ lastToggle ].apply( this, arguments ) || false; }; // link all the functions, so any of them can unbind this click handler toggler.guid = guid; while ( i < args.length ) { args[ i++ ].guid = guid; } return this.click( toggler ); }, hover: function( fnOver, fnOut ) { return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); } }); jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { // Handle event binding jQuery.fn[ name ] = function( data, fn ) { if ( fn == null ) { fn = data; data = null; } return arguments.length > 0 ? this.on( name, null, data, fn ) : this.trigger( name ); }; if ( jQuery.attrFn ) { jQuery.attrFn[ name ] = true; } if ( rkeyEvent.test( name ) ) { jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks; } if ( rmouseEvent.test( name ) ) { jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks; } }); /*! * Sizzle CSS Selector Engine * Copyright 2011, The Dojo Foundation * Released under the MIT, BSD, and GPL Licenses. * More information: http://sizzlejs.com/ */ (function(){ var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, expando = "sizcache" + (Math.random() + '').replace('.', ''), done = 0, toString = Object.prototype.toString, hasDuplicate = false, baseHasDuplicate = true, rBackslash = /\\/g, rReturn = /\r\n/g, rNonWord = /\W/; // Here we check if the JavaScript engine is using some sort of // optimization where it does not always call our comparision // function. If that is the case, discard the hasDuplicate value. // Thus far that includes Google Chrome. [0, 0].sort(function() { baseHasDuplicate = false; return 0; }); var Sizzle = function( selector, context, results, seed ) { results = results || []; context = context || document; var origContext = context; if ( context.nodeType !== 1 && context.nodeType !== 9 ) { return []; } if ( !selector || typeof selector !== "string" ) { return results; } var m, set, checkSet, extra, ret, cur, pop, i, prune = true, contextXML = Sizzle.isXML( context ), parts = [], soFar = selector; // Reset the position of the chunker regexp (start from head) do { chunker.exec( "" ); m = chunker.exec( soFar ); if ( m ) { soFar = m[3]; parts.push( m[1] ); if ( m[2] ) { extra = m[3]; break; } } } while ( m ); if ( parts.length > 1 && origPOS.exec( selector ) ) { if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { set = posProcess( parts[0] + parts[1], context, seed ); } else { set = Expr.relative[ parts[0] ] ? [ context ] : Sizzle( parts.shift(), context ); while ( parts.length ) { selector = parts.shift(); if ( Expr.relative[ selector ] ) { selector += parts.shift(); } set = posProcess( selector, set, seed ); } } } else { // Take a shortcut and set the context if the root selector is an ID // (but not if it'll be faster if the inner selector is an ID) if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { ret = Sizzle.find( parts.shift(), context, contextXML ); context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; } if ( context ) { ret = seed ? { expr: parts.pop(), set: makeArray(seed) } : Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; if ( parts.length > 0 ) { checkSet = makeArray( set ); } else { prune = false; } while ( parts.length ) { cur = parts.pop(); pop = cur; if ( !Expr.relative[ cur ] ) { cur = ""; } else { pop = parts.pop(); } if ( pop == null ) { pop = context; } Expr.relative[ cur ]( checkSet, pop, contextXML ); } } else { checkSet = parts = []; } } if ( !checkSet ) { checkSet = set; } if ( !checkSet ) { Sizzle.error( cur || selector ); } if ( toString.call(checkSet) === "[object Array]" ) { if ( !prune ) { results.push.apply( results, checkSet ); } else if ( context && context.nodeType === 1 ) { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { results.push( set[i] ); } } } else { for ( i = 0; checkSet[i] != null; i++ ) { if ( checkSet[i] && checkSet[i].nodeType === 1 ) { results.push( set[i] ); } } } } else { makeArray( checkSet, results ); } if ( extra ) { Sizzle( extra, origContext, results, seed ); Sizzle.uniqueSort( results ); } return results; }; Sizzle.uniqueSort = function( results ) { if ( sortOrder ) { hasDuplicate = baseHasDuplicate; results.sort( sortOrder ); if ( hasDuplicate ) { for ( var i = 1; i < results.length; i++ ) { if ( results[i] === results[ i - 1 ] ) { results.splice( i--, 1 ); } } } } return results; }; Sizzle.matches = function( expr, set ) { return Sizzle( expr, null, null, set ); }; Sizzle.matchesSelector = function( node, expr ) { return Sizzle( expr, null, null, [node] ).length > 0; }; Sizzle.find = function( expr, context, isXML ) { var set, i, len, match, type, left; if ( !expr ) { return []; } for ( i = 0, len = Expr.order.length; i < len; i++ ) { type = Expr.order[i]; if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { left = match[1]; match.splice( 1, 1 ); if ( left.substr( left.length - 1 ) !== "\\" ) { match[1] = (match[1] || "").replace( rBackslash, "" ); set = Expr.find[ type ]( match, context, isXML ); if ( set != null ) { expr = expr.replace( Expr.match[ type ], "" ); break; } } } } if ( !set ) { set = typeof context.getElementsByTagName !== "undefined" ? context.getElementsByTagName( "*" ) : []; } return { set: set, expr: expr }; }; Sizzle.filter = function( expr, set, inplace, not ) { var match, anyFound, type, found, item, filter, left, i, pass, old = expr, result = [], curLoop = set, isXMLFilter = set && set[0] && Sizzle.isXML( set[0] ); while ( expr && set.length ) { for ( type in Expr.filter ) { if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { filter = Expr.filter[ type ]; left = match[1]; anyFound = false; match.splice(1,1); if ( left.substr( left.length - 1 ) === "\\" ) { continue; } if ( curLoop === result ) { result = []; } if ( Expr.preFilter[ type ] ) { match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); if ( !match ) { anyFound = found = true; } else if ( match === true ) { continue; } } if ( match ) { for ( i = 0; (item = curLoop[i]) != null; i++ ) { if ( item ) { found = filter( item, match, i, curLoop ); pass = not ^ found; if ( inplace && found != null ) { if ( pass ) { anyFound = true; } else { curLoop[i] = false; } } else if ( pass ) { result.push( item ); anyFound = true; } } } } if ( found !== undefined ) { if ( !inplace ) { curLoop = result; } expr = expr.replace( Expr.match[ type ], "" ); if ( !anyFound ) { return []; } break; } } } // Improper expression if ( expr === old ) { if ( anyFound == null ) { Sizzle.error( expr ); } else { break; } } old = expr; } return curLoop; }; Sizzle.error = function( msg ) { throw new Error( "Syntax error, unrecognized expression: " + msg ); }; /** * Utility function for retreiving the text value of an array of DOM nodes * @param {Array|Element} elem */ var getText = Sizzle.getText = function( elem ) { var i, node, nodeType = elem.nodeType, ret = ""; if ( nodeType ) { if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { // Use textContent || innerText for elements if ( typeof elem.textContent === 'string' ) { return elem.textContent; } else if ( typeof elem.innerText === 'string' ) { // Replace IE's carriage returns return elem.innerText.replace( rReturn, '' ); } else { // Traverse it's children for ( elem = elem.firstChild; elem; elem = elem.nextSibling) { ret += getText( elem ); } } } else if ( nodeType === 3 || nodeType === 4 ) { return elem.nodeValue; } } else { // If no nodeType, this is expected to be an array for ( i = 0; (node = elem[i]); i++ ) { // Do not traverse comment nodes if ( node.nodeType !== 8 ) { ret += getText( node ); } } } return ret; }; var Expr = Sizzle.selectors = { order: [ "ID", "NAME", "TAG" ], match: { ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/, TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/, POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ }, leftMatch: {}, attrMap: { "class": "className", "for": "htmlFor" }, attrHandle: { href: function( elem ) { return elem.getAttribute( "href" ); }, type: function( elem ) { return elem.getAttribute( "type" ); } }, relative: { "+": function(checkSet, part){ var isPartStr = typeof part === "string", isTag = isPartStr && !rNonWord.test( part ), isPartStrNotTag = isPartStr && !isTag; if ( isTag ) { part = part.toLowerCase(); } for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { if ( (elem = checkSet[i]) ) { while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? elem || false : elem === part; } } if ( isPartStrNotTag ) { Sizzle.filter( part, checkSet, true ); } }, ">": function( checkSet, part ) { var elem, isPartStr = typeof part === "string", i = 0, l = checkSet.length; if ( isPartStr && !rNonWord.test( part ) ) { part = part.toLowerCase(); for ( ; i < l; i++ ) { elem = checkSet[i]; if ( elem ) { var parent = elem.parentNode; checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; } } } else { for ( ; i < l; i++ ) { elem = checkSet[i]; if ( elem ) { checkSet[i] = isPartStr ? elem.parentNode : elem.parentNode === part; } } if ( isPartStr ) { Sizzle.filter( part, checkSet, true ); } } }, "": function(checkSet, part, isXML){ var nodeCheck, doneName = done++, checkFn = dirCheck; if ( typeof part === "string" && !rNonWord.test( part ) ) { part = part.toLowerCase(); nodeCheck = part; checkFn = dirNodeCheck; } checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML ); }, "~": function( checkSet, part, isXML ) { var nodeCheck, doneName = done++, checkFn = dirCheck; if ( typeof part === "string" && !rNonWord.test( part ) ) { part = part.toLowerCase(); nodeCheck = part; checkFn = dirNodeCheck; } checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML ); } }, find: { ID: function( match, context, isXML ) { if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 return m && m.parentNode ? [m] : []; } }, NAME: function( match, context ) { if ( typeof context.getElementsByName !== "undefined" ) { var ret = [], results = context.getElementsByName( match[1] ); for ( var i = 0, l = results.length; i < l; i++ ) { if ( results[i].getAttribute("name") === match[1] ) { ret.push( results[i] ); } } return ret.length === 0 ? null : ret; } }, TAG: function( match, context ) { if ( typeof context.getElementsByTagName !== "undefined" ) { return context.getElementsByTagName( match[1] ); } } }, preFilter: { CLASS: function( match, curLoop, inplace, result, not, isXML ) { match = " " + match[1].replace( rBackslash, "" ) + " "; if ( isXML ) { return match; } for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { if ( elem ) { if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) { if ( !inplace ) { result.push( elem ); } } else if ( inplace ) { curLoop[i] = false; } } } return false; }, ID: function( match ) { return match[1].replace( rBackslash, "" ); }, TAG: function( match, curLoop ) { return match[1].replace( rBackslash, "" ).toLowerCase(); }, CHILD: function( match ) { if ( match[1] === "nth" ) { if ( !match[2] ) { Sizzle.error( match[0] ); } match[2] = match[2].replace(/^\+|\s*/g, ''); // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec( match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); // calculate the numbers (first)n+(last) including if they are negative match[2] = (test[1] + (test[2] || 1)) - 0; match[3] = test[3] - 0; } else if ( match[2] ) { Sizzle.error( match[0] ); } // TODO: Move to normal caching system match[0] = done++; return match; }, ATTR: function( match, curLoop, inplace, result, not, isXML ) { var name = match[1] = match[1].replace( rBackslash, "" ); if ( !isXML && Expr.attrMap[name] ) { match[1] = Expr.attrMap[name]; } // Handle if an un-quoted value was used match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" ); if ( match[2] === "~=" ) { match[4] = " " + match[4] + " "; } return match; }, PSEUDO: function( match, curLoop, inplace, result, not ) { if ( match[1] === "not" ) { // If we're dealing with a complex expression, or a simple one if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { match[3] = Sizzle(match[3], null, null, curLoop); } else { var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); if ( !inplace ) { result.push.apply( result, ret ); } return false; } } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { return true; } return match; }, POS: function( match ) { match.unshift( true ); return match; } }, filters: { enabled: function( elem ) { return elem.disabled === false && elem.type !== "hidden"; }, disabled: function( elem ) { return elem.disabled === true; }, checked: function( elem ) { return elem.checked === true; }, selected: function( elem ) { // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { elem.parentNode.selectedIndex; } return elem.selected === true; }, parent: function( elem ) { return !!elem.firstChild; }, empty: function( elem ) { return !elem.firstChild; }, has: function( elem, i, match ) { return !!Sizzle( match[3], elem ).length; }, header: function( elem ) { return (/h\d/i).test( elem.nodeName ); }, text: function( elem ) { var attr = elem.getAttribute( "type" ), type = elem.type; // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) // use getAttribute instead to test this case return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null ); }, radio: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type; }, checkbox: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type; }, file: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "file" === elem.type; }, password: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "password" === elem.type; }, submit: function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && "submit" === elem.type; }, image: function( elem ) { return elem.nodeName.toLowerCase() === "input" && "image" === elem.type; }, reset: function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && "reset" === elem.type; }, button: function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && "button" === elem.type || name === "button"; }, input: function( elem ) { return (/input|select|textarea|button/i).test( elem.nodeName ); }, focus: function( elem ) { return elem === elem.ownerDocument.activeElement; } }, setFilters: { first: function( elem, i ) { return i === 0; }, last: function( elem, i, match, array ) { return i === array.length - 1; }, even: function( elem, i ) { return i % 2 === 0; }, odd: function( elem, i ) { return i % 2 === 1; }, lt: function( elem, i, match ) { return i < match[3] - 0; }, gt: function( elem, i, match ) { return i > match[3] - 0; }, nth: function( elem, i, match ) { return match[3] - 0 === i; }, eq: function( elem, i, match ) { return match[3] - 0 === i; } }, filter: { PSEUDO: function( elem, match, i, array ) { var name = match[1], filter = Expr.filters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } else if ( name === "contains" ) { return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; } else if ( name === "not" ) { var not = match[3]; for ( var j = 0, l = not.length; j < l; j++ ) { if ( not[j] === elem ) { return false; } } return true; } else { Sizzle.error( name ); } }, CHILD: function( elem, match ) { var first, last, doneName, parent, cache, count, diff, type = match[1], node = elem; switch ( type ) { case "only": case "first": while ( (node = node.previousSibling) ) { if ( node.nodeType === 1 ) { return false; } } if ( type === "first" ) { return true; } node = elem; /* falls through */ case "last": while ( (node = node.nextSibling) ) { if ( node.nodeType === 1 ) { return false; } } return true; case "nth": first = match[2]; last = match[3]; if ( first === 1 && last === 0 ) { return true; } doneName = match[0]; parent = elem.parentNode; if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) { count = 0; for ( node = parent.firstChild; node; node = node.nextSibling ) { if ( node.nodeType === 1 ) { node.nodeIndex = ++count; } } parent[ expando ] = doneName; } diff = elem.nodeIndex - last; if ( first === 0 ) { return diff === 0; } else { return ( diff % first === 0 && diff / first >= 0 ); } } }, ID: function( elem, match ) { return elem.nodeType === 1 && elem.getAttribute("id") === match; }, TAG: function( elem, match ) { return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match; }, CLASS: function( elem, match ) { return (" " + (elem.className || elem.getAttribute("class")) + " ") .indexOf( match ) > -1; }, ATTR: function( elem, match ) { var name = match[1], result = Sizzle.attr ? Sizzle.attr( elem, name ) : Expr.attrHandle[ name ] ? Expr.attrHandle[ name ]( elem ) : elem[ name ] != null ? elem[ name ] : elem.getAttribute( name ), value = result + "", type = match[2], check = match[4]; return result == null ? type === "!=" : !type && Sizzle.attr ? result != null : type === "=" ? value === check : type === "*=" ? value.indexOf(check) >= 0 : type === "~=" ? (" " + value + " ").indexOf(check) >= 0 : !check ? value && result !== false : type === "!=" ? value !== check : type === "^=" ? value.indexOf(check) === 0 : type === "$=" ? value.substr(value.length - check.length) === check : type === "|=" ? value === check || value.substr(0, check.length + 1) === check + "-" : false; }, POS: function( elem, match, i, array ) { var name = match[2], filter = Expr.setFilters[ name ]; if ( filter ) { return filter( elem, i, match, array ); } } } }; var origPOS = Expr.match.POS, fescape = function(all, num){ return "\\" + (num - 0 + 1); }; for ( var type in Expr.match ) { Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); } // Expose origPOS // "global" as in regardless of relation to brackets/parens Expr.match.globalPOS = origPOS; var makeArray = function( array, results ) { array = Array.prototype.slice.call( array, 0 ); if ( results ) { results.push.apply( results, array ); return results; } return array; }; // Perform a simple check to determine if the browser is capable of // converting a NodeList to an array using builtin methods. // Also verifies that the returned array holds DOM nodes // (which is not the case in the Blackberry browser) try { Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; // Provide a fallback method if it does not work } catch( e ) { makeArray = function( array, results ) { var i = 0, ret = results || []; if ( toString.call(array) === "[object Array]" ) { Array.prototype.push.apply( ret, array ); } else { if ( typeof array.length === "number" ) { for ( var l = array.length; i < l; i++ ) { ret.push( array[i] ); } } else { for ( ; array[i]; i++ ) { ret.push( array[i] ); } } } return ret; }; } var sortOrder, siblingCheck; if ( document.documentElement.compareDocumentPosition ) { sortOrder = function( a, b ) { if ( a === b ) { hasDuplicate = true; return 0; } if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { return a.compareDocumentPosition ? -1 : 1; } return a.compareDocumentPosition(b) & 4 ? -1 : 1; }; } else { sortOrder = function( a, b ) { // The nodes are identical, we can exit early if ( a === b ) { hasDuplicate = true; return 0; // Fallback to using sourceIndex (in IE) if it's available on both nodes } else if ( a.sourceIndex && b.sourceIndex ) { return a.sourceIndex - b.sourceIndex; } var al, bl, ap = [], bp = [], aup = a.parentNode, bup = b.parentNode, cur = aup; // If the nodes are siblings (or identical) we can do a quick check if ( aup === bup ) { return siblingCheck( a, b ); // If no parents were found then the nodes are disconnected } else if ( !aup ) { return -1; } else if ( !bup ) { return 1; } // Otherwise they're somewhere else in the tree so we need // to build up a full list of the parentNodes for comparison while ( cur ) { ap.unshift( cur ); cur = cur.parentNode; } cur = bup; while ( cur ) { bp.unshift( cur ); cur = cur.parentNode; } al = ap.length; bl = bp.length; // Start walking down the tree looking for a discrepancy for ( var i = 0; i < al && i < bl; i++ ) { if ( ap[i] !== bp[i] ) { return siblingCheck( ap[i], bp[i] ); } } // We ended someplace up the tree so do a sibling check return i === al ? siblingCheck( a, bp[i], -1 ) : siblingCheck( ap[i], b, 1 ); }; siblingCheck = function( a, b, ret ) { if ( a === b ) { return ret; } var cur = a.nextSibling; while ( cur ) { if ( cur === b ) { return -1; } cur = cur.nextSibling; } return 1; }; } // Check to see if the browser returns elements by name when // querying by getElementById (and provide a workaround) (function(){ // We're going to inject a fake input element with a specified name var form = document.createElement("div"), id = "script" + (new Date()).getTime(), root = document.documentElement; form.innerHTML = ""; // Inject it into the root element, check its status, and remove it quickly root.insertBefore( form, root.firstChild ); // The workaround has to do additional checks after a getElementById // Which slows things down for other browsers (hence the branching) if ( document.getElementById( id ) ) { Expr.find.ID = function( match, context, isXML ) { if ( typeof context.getElementById !== "undefined" && !isXML ) { var m = context.getElementById(match[1]); return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; } }; Expr.filter.ID = function( elem, match ) { var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); return elem.nodeType === 1 && node && node.nodeValue === match; }; } root.removeChild( form ); // release memory in IE root = form = null; })(); (function(){ // Check to see if the browser returns only elements // when doing getElementsByTagName("*") // Create a fake element var div = document.createElement("div"); div.appendChild( document.createComment("") ); // Make sure no comments are found if ( div.getElementsByTagName("*").length > 0 ) { Expr.find.TAG = function( match, context ) { var results = context.getElementsByTagName( match[1] ); // Filter out possible comments if ( match[1] === "*" ) { var tmp = []; for ( var i = 0; results[i]; i++ ) { if ( results[i].nodeType === 1 ) { tmp.push( results[i] ); } } results = tmp; } return results; }; } // Check to see if an attribute returns normalized href attributes div.innerHTML = ""; if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && div.firstChild.getAttribute("href") !== "#" ) { Expr.attrHandle.href = function( elem ) { return elem.getAttribute( "href", 2 ); }; } // release memory in IE div = null; })(); if ( document.querySelectorAll ) { (function(){ var oldSizzle = Sizzle, div = document.createElement("div"), id = "__sizzle__"; div.innerHTML = "

"; // Safari can't handle uppercase or unicode characters when // in quirks mode. if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { return; } Sizzle = function( query, context, extra, seed ) { context = context || document; // Only use querySelectorAll on non-XML documents // (ID selectors don't work in non-HTML documents) if ( !seed && !Sizzle.isXML(context) ) { // See if we find a selector to speed up var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query ); if ( match && (context.nodeType === 1 || context.nodeType === 9) ) { // Speed-up: Sizzle("TAG") if ( match[1] ) { return makeArray( context.getElementsByTagName( query ), extra ); // Speed-up: Sizzle(".CLASS") } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) { return makeArray( context.getElementsByClassName( match[2] ), extra ); } } if ( context.nodeType === 9 ) { // Speed-up: Sizzle("body") // The body element only exists once, optimize finding it if ( query === "body" && context.body ) { return makeArray( [ context.body ], extra ); // Speed-up: Sizzle("#ID") } else if ( match && match[3] ) { var elem = context.getElementById( match[3] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id === match[3] ) { return makeArray( [ elem ], extra ); } } else { return makeArray( [], extra ); } } try { return makeArray( context.querySelectorAll(query), extra ); } catch(qsaError) {} // qSA works strangely on Element-rooted queries // We can work around this by specifying an extra ID on the root // and working up from there (Thanks to Andrew Dupont for the technique) // IE 8 doesn't work on object elements } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { var oldContext = context, old = context.getAttribute( "id" ), nid = old || id, hasParent = context.parentNode, relativeHierarchySelector = /^\s*[+~]/.test( query ); if ( !old ) { context.setAttribute( "id", nid ); } else { nid = nid.replace( /'/g, "\\$&" ); } if ( relativeHierarchySelector && hasParent ) { context = context.parentNode; } try { if ( !relativeHierarchySelector || hasParent ) { return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra ); } } catch(pseudoError) { } finally { if ( !old ) { oldContext.removeAttribute( "id" ); } } } } return oldSizzle(query, context, extra, seed); }; for ( var prop in oldSizzle ) { Sizzle[ prop ] = oldSizzle[ prop ]; } // release memory in IE div = null; })(); } (function(){ var html = document.documentElement, matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector; if ( matches ) { // Check to see if it's possible to do matchesSelector // on a disconnected node (IE 9 fails this) var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ), pseudoWorks = false; try { // This should fail with an exception // Gecko does not error, returns false instead matches.call( document.documentElement, "[test!='']:sizzle" ); } catch( pseudoError ) { pseudoWorks = true; } Sizzle.matchesSelector = function( node, expr ) { // Make sure that attribute selectors are quoted expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']"); if ( !Sizzle.isXML( node ) ) { try { if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) { var ret = matches.call( node, expr ); // IE 9's matchesSelector returns false on disconnected nodes if ( ret || !disconnectedMatch || // As well, disconnected nodes are said to be in a document // fragment in IE 9, so check for that node.document && node.document.nodeType !== 11 ) { return ret; } } } catch(e) {} } return Sizzle(expr, null, null, [node]).length > 0; }; } })(); (function(){ var div = document.createElement("div"); div.innerHTML = "
"; // Opera can't find a second classname (in 9.6) // Also, make sure that getElementsByClassName actually exists if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { return; } // Safari caches class attributes, doesn't catch changes (in 3.2) div.lastChild.className = "e"; if ( div.getElementsByClassName("e").length === 1 ) { return; } Expr.order.splice(1, 0, "CLASS"); Expr.find.CLASS = function( match, context, isXML ) { if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { return context.getElementsByClassName(match[1]); } }; // release memory in IE div = null; })(); function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { var match = false; elem = elem[dir]; while ( elem ) { if ( elem[ expando ] === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 && !isXML ){ elem[ expando ] = doneName; elem.sizset = i; } if ( elem.nodeName.toLowerCase() === cur ) { match = elem; break; } elem = elem[dir]; } checkSet[i] = match; } } } function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { for ( var i = 0, l = checkSet.length; i < l; i++ ) { var elem = checkSet[i]; if ( elem ) { var match = false; elem = elem[dir]; while ( elem ) { if ( elem[ expando ] === doneName ) { match = checkSet[elem.sizset]; break; } if ( elem.nodeType === 1 ) { if ( !isXML ) { elem[ expando ] = doneName; elem.sizset = i; } if ( typeof cur !== "string" ) { if ( elem === cur ) { match = true; break; } } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { match = elem; break; } } elem = elem[dir]; } checkSet[i] = match; } } } if ( document.documentElement.contains ) { Sizzle.contains = function( a, b ) { return a !== b && (a.contains ? a.contains(b) : true); }; } else if ( document.documentElement.compareDocumentPosition ) { Sizzle.contains = function( a, b ) { return !!(a.compareDocumentPosition(b) & 16); }; } else { Sizzle.contains = function() { return false; }; } Sizzle.isXML = function( elem ) { // documentElement is verified for cases where it doesn't yet exist // (such as loading iframes in IE - #4833) var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }; var posProcess = function( selector, context, seed ) { var match, tmpSet = [], later = "", root = context.nodeType ? [context] : context; // Position selectors must be done after the filter // And so must :not(positional) so we move all PSEUDOs to the end while ( (match = Expr.match.PSEUDO.exec( selector )) ) { later += match[0]; selector = selector.replace( Expr.match.PSEUDO, "" ); } selector = Expr.relative[selector] ? selector + "*" : selector; for ( var i = 0, l = root.length; i < l; i++ ) { Sizzle( selector, root[i], tmpSet, seed ); } return Sizzle.filter( later, tmpSet ); }; // EXPOSE // Override sizzle attribute retrieval Sizzle.attr = jQuery.attr; Sizzle.selectors.attrMap = {}; jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; jQuery.expr[":"] = jQuery.expr.filters; jQuery.unique = Sizzle.uniqueSort; jQuery.text = Sizzle.getText; jQuery.isXMLDoc = Sizzle.isXML; jQuery.contains = Sizzle.contains; })(); var runtil = /Until$/, rparentsprev = /^(?:parents|prevUntil|prevAll)/, // Note: This RegExp should be improved, or likely pulled from Sizzle rmultiselector = /,/, isSimple = /^.[^:#\[\.,]*$/, slice = Array.prototype.slice, POS = jQuery.expr.match.globalPOS, // methods guaranteed to produce a unique set when starting from a unique set guaranteedUnique = { children: true, contents: true, next: true, prev: true }; jQuery.fn.extend({ find: function( selector ) { var self = this, i, l; if ( typeof selector !== "string" ) { return jQuery( selector ).filter(function() { for ( i = 0, l = self.length; i < l; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } } }); } var ret = this.pushStack( "", "find", selector ), length, n, r; for ( i = 0, l = this.length; i < l; i++ ) { length = ret.length; jQuery.find( selector, this[i], ret ); if ( i > 0 ) { // Make sure that the results are unique for ( n = length; n < ret.length; n++ ) { for ( r = 0; r < length; r++ ) { if ( ret[r] === ret[n] ) { ret.splice(n--, 1); break; } } } } } return ret; }, has: function( target ) { var targets = jQuery( target ); return this.filter(function() { for ( var i = 0, l = targets.length; i < l; i++ ) { if ( jQuery.contains( this, targets[i] ) ) { return true; } } }); }, not: function( selector ) { return this.pushStack( winnow(this, selector, false), "not", selector); }, filter: function( selector ) { return this.pushStack( winnow(this, selector, true), "filter", selector ); }, is: function( selector ) { return !!selector && ( typeof selector === "string" ? // If this is a positional selector, check membership in the returned set // so $("p:first").is("p:last") won't return true for a doc with two "p". POS.test( selector ) ? jQuery( selector, this.context ).index( this[0] ) >= 0 : jQuery.filter( selector, this ).length > 0 : this.filter( selector ).length > 0 ); }, closest: function( selectors, context ) { var ret = [], i, l, cur = this[0]; // Array (deprecated as of jQuery 1.7) if ( jQuery.isArray( selectors ) ) { var level = 1; while ( cur && cur.ownerDocument && cur !== context ) { for ( i = 0; i < selectors.length; i++ ) { if ( jQuery( cur ).is( selectors[ i ] ) ) { ret.push({ selector: selectors[ i ], elem: cur, level: level }); } } cur = cur.parentNode; level++; } return ret; } // String var pos = POS.test( selectors ) || typeof selectors !== "string" ? jQuery( selectors, context || this.context ) : 0; for ( i = 0, l = this.length; i < l; i++ ) { cur = this[i]; while ( cur ) { if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { ret.push( cur ); break; } else { cur = cur.parentNode; if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { break; } } } } ret = ret.length > 1 ? jQuery.unique( ret ) : ret; return this.pushStack( ret, "closest", selectors ); }, // Determine the position of an element within // the matched set of elements index: function( elem ) { // No argument, return index in parent if ( !elem ) { return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1; } // index in selector if ( typeof elem === "string" ) { return jQuery.inArray( this[0], jQuery( elem ) ); } // Locate the position of the desired element return jQuery.inArray( // If it receives a jQuery object, the first element is used elem.jquery ? elem[0] : elem, this ); }, add: function( selector, context ) { var set = typeof selector === "string" ? jQuery( selector, context ) : jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), all = jQuery.merge( this.get(), set ); return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? all : jQuery.unique( all ) ); }, andSelf: function() { return this.add( this.prevObject ); } }); // A painfully simple check to see if an element is disconnected // from a document (should be improved, where feasible). function isDisconnected( node ) { return !node || !node.parentNode || node.parentNode.nodeType === 11; } jQuery.each({ parent: function( elem ) { var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; }, parents: function( elem ) { return jQuery.dir( elem, "parentNode" ); }, parentsUntil: function( elem, i, until ) { return jQuery.dir( elem, "parentNode", until ); }, next: function( elem ) { return jQuery.nth( elem, 2, "nextSibling" ); }, prev: function( elem ) { return jQuery.nth( elem, 2, "previousSibling" ); }, nextAll: function( elem ) { return jQuery.dir( elem, "nextSibling" ); }, prevAll: function( elem ) { return jQuery.dir( elem, "previousSibling" ); }, nextUntil: function( elem, i, until ) { return jQuery.dir( elem, "nextSibling", until ); }, prevUntil: function( elem, i, until ) { return jQuery.dir( elem, "previousSibling", until ); }, siblings: function( elem ) { return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); }, children: function( elem ) { return jQuery.sibling( elem.firstChild ); }, contents: function( elem ) { return jQuery.nodeName( elem, "iframe" ) ? elem.contentDocument || elem.contentWindow.document : jQuery.makeArray( elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { var ret = jQuery.map( this, fn, until ); if ( !runtil.test( name ) ) { selector = until; } if ( selector && typeof selector === "string" ) { ret = jQuery.filter( selector, ret ); } ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { ret = ret.reverse(); } return this.pushStack( ret, name, slice.call( arguments ).join(",") ); }; }); jQuery.extend({ filter: function( expr, elems, not ) { if ( not ) { expr = ":not(" + expr + ")"; } return elems.length === 1 ? jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : jQuery.find.matches(expr, elems); }, dir: function( elem, dir, until ) { var matched = [], cur = elem[ dir ]; while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { if ( cur.nodeType === 1 ) { matched.push( cur ); } cur = cur[dir]; } return matched; }, nth: function( cur, result, dir, elem ) { result = result || 1; var num = 0; for ( ; cur; cur = cur[dir] ) { if ( cur.nodeType === 1 && ++num === result ) { break; } } return cur; }, sibling: function( n, elem ) { var r = []; for ( ; n; n = n.nextSibling ) { if ( n.nodeType === 1 && n !== elem ) { r.push( n ); } } return r; } }); // Implement the identical functionality for filter and not function winnow( elements, qualifier, keep ) { // Can't pass null or undefined to indexOf in Firefox 4 // Set to 0 to skip string check qualifier = qualifier || 0; if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep(elements, function( elem, i ) { var retVal = !!qualifier.call( elem, i, elem ); return retVal === keep; }); } else if ( qualifier.nodeType ) { return jQuery.grep(elements, function( elem, i ) { return ( elem === qualifier ) === keep; }); } else if ( typeof qualifier === "string" ) { var filtered = jQuery.grep(elements, function( elem ) { return elem.nodeType === 1; }); if ( isSimple.test( qualifier ) ) { return jQuery.filter(qualifier, filtered, !keep); } else { qualifier = jQuery.filter( qualifier, filtered ); } } return jQuery.grep(elements, function( elem, i ) { return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; }); } function createSafeFragment( document ) { var list = nodeNames.split( "|" ), safeFrag = document.createDocumentFragment(); if ( safeFrag.createElement ) { while ( list.length ) { safeFrag.createElement( list.pop() ); } } return safeFrag; } var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, rleadingWhitespace = /^\s+/, rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, rtagName = /<([\w:]+)/, rtbody = /]", "i"), // checked="checked" or checked rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, rscriptType = /\/(java|ecma)script/i, rcleanScript = /^\s*", "" ], legend: [ 1, "
", "
" ], thead: [ 1, "", "
" ], tr: [ 2, "", "
" ], td: [ 3, "", "
" ], col: [ 2, "", "
" ], area: [ 1, "", "" ], _default: [ 0, "", "" ] }, safeFragment = createSafeFragment( document ); wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; // IE can't serialize and pcp blinkenlights demo

pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/blinkenlights/blinken_off.png0000664000000000000000000001426412272262501022467 0ustar ‰PNG  IHDRddpâ•TsBIT|dˆ pHYs¯¯^‘tEXtSoftwarewww.inkscape.org›î<1IDATxœÝ{p[×}ç?çâ @ß/Q¢(J&åø!§J3Ží8~E±-ëÑ&iÒtgg;ã™vf;IÆÛÍf›™Î®g6ã̶™¶Óºí´¤ûp3²E–D®G®üˆëZ‘DE%Q$Aˆ ‚ ^÷âÞýã.ñº(¦ß™3¸¸÷œƒó=¿ß9çw~ç¡ë:[ÇŽ #«atõÚ ´¾‚+@X.¸†qàâêuüèÑ£K›™»[cÇŽ àÀ¡Õ°·ÎI\ÆVûGÝR°%9vì˜x8 z7)ép8¼~ôèÑÌ&¥[·—_~¹x C pKíÜ.$€W1$çä‘#G¢·#›NÈË/¿ì¾|ÛOB9$€ï/9r$±™ o!ÇwÏtmJ¢ÇMà>¬lF‚›BÈØØØççá†'ÖLß8tèÐ?6:¡†266öiàÛ½¦ xxîСCo6*†òƒü x£Ñþ·ˆ“À³Ï<óÌl½#®;!'NœØÑì«kÄ% ( ªª¢(†zw:ȲŒÓéltÒ³ÀჾWÏHëJȉ'¾ ü-ÐT¯8Eaii‰T*µVøy"Êå]±FL>455êMVøÝƒþïzEXB~øÃ à¿ߨpd@:&‹±´´D2™¬G”kðz½‚Á MMu«7Ïß|úé§7\˜&ääÉ“>à{¼š‘H$ÖHÈd6gÀìv»×Èñù6<$¾òÔSOmhܲ!BNž<9ü¸«Ö8’É$333,//לg*€âñÔGKK ýýýx½ÞªÏ !ÊýtxæÉ'Ÿ¼Vk>j&ä•W^ùu ;Pg-ïg2fffˆF«[(ŠBÇä$¾H„¦åešâqÓURU4Y&ÝÒBÚï7]D††Ð\®ªiµ¶¶Ò×ׇÛí®åoÌŸ|òÉwjy¹&BN:5ˆÑ'·M†¢(„B!æççË6Ê®•ºùKz.^¤óÊŠy ìðûq´µáhkCnkC×4rÑ(¹…ÔÅE´„YsäœN懇 Œ¾ã²ÍÍeÓBÐÙÙIOOO­€yàŸûÜç®Ù}Ñ6!§NòoSƒš …B„B!4M+ù»;‘`Û¿þ+=ãã´NM!távã¹ç¼û÷ãÝ¿Ÿ¦‘mmY®˜–®(¨ ¤ÏŸ'ùÞ{$ߟôG¡«*ºD·o'<:Ê̽÷’)Ó~ȲLww7===vÿ*êëþØjSlòꫯ àel6àš¦199I4-©Ù,»Îœaèg?CÎf‘;:~ñ‹ø>óø “<@Îå*™¿@ Ààà ’$ÙMr 8ràÀË…l‹×^{í`³k›Íf¹|ùrÉî«Ð4¶ð{þé ܉žûöÑö;¿ƒÿÀº‘PZ*ÅÒ‰D¿÷=Ò.ñù¸üè£Lüãè% Þãñ°k×.\Ú¡uxþ³Ÿýìµú°eB^{íµ/ÿ`''‰D‚‰‰‰µ‘taíëgä'§ñE"´<ö¿ÿ{4Ýy§èë†ÔÏÎüŸü +gϲÒÙÉ¥Ç'<:Zôœ,Ë ÕÒEþí'žxÂÒàÑ!?úÑö?ÅÆ<‰píÚµ¢†Û¡(ì;>FïÅqä®.ºÿÛ7iyâq«Ñ6KÇŽqó~›\4ÆÜÞ½|ôGŠÔ˜‚mÛ¶ÑÞÞn'ê4ðÐO!Ä‹Õ »¢„üä'?ù4ðFµHòH$\ºt©HM |ôwz Ùã¡ÿ»Šç¾}å#iÀt@­ƒß•7Jè¹?$§ªœúI¦ï½Çô»$I Ó\aLS?öØceçS*rúôéw°8¹”Íf9þ<êê¨9‘Ÿ¾Åî·ÿG0Hßwÿ÷wTŽ¨Þ„l0¾äûïúúsh©Wz€‰Ïúëå~,KÈéÓ§?¼TÁn³†\.ÇÅ‹I¥R&U5ðÑ9î~åU¤æf¶ýå_ଋ˜¼¬™[ï¥qžÙÿôèŠÂ/>ÍÌ:Iñx<ìÞ½ÛÎ8å <òHÉéà’„¼þúëN ‡2KsàÄb1Ó½¶™>ùÿ)—£óÿ3-?Z1ކL%×1Î¥—¾Ïâ_ý5šÃÁ{_ùÑmÀ­®¼ßïgçÎV£›ö>òÈ#EŽ%)B<+„¶ÒXÍÍͱ´´dºç]Nðkc'qèà{øa|Ÿù´a²(=«€¢Ö9( ªeCÙü” þ#‡hº÷$]gß±ãx–—MÚ`yy™ùùy« ü°âÙ’e¿¾f¾ñÆ>à \uEáܹsär¹µÌ9…OýŸ—ðßœÇÑÞNïwÿ’oµÑ[_aËVà Öì9n¨‘¡?ø*ÚÊ ËÝ]¼ûï¾B®À¢ I£££ÈUìl«¸ ìzøá‡M¶®Ròu,úMå ……5eß«?ÆYI¢õ?ü{$w(9C,×È\íA)|ß¾$T Ž`à—~ !9ðÏ/p׉SÀ­!€®ë„Ãa+EÇj}ýM!o¾ùf«âkVÄ.›Í‰D$i-ôM^£÷ÊU„ä@nïÀ³ï^ôœŠ®–Q¹¡‚š©ŠÔT®îÁ{ÿýH‰îËt_¾b*ÐÅÅE²Ù¬UÕõµ7ß|³µð}“l !žÂ¢{çÌÌŒé»Ð4FÞ>‹Xíi4?ô€¡:TÕ² Ù¸¦i|—Y8e¼Ÿü$+?ý{Þz›Èî]è’´¦)Âá0;vì°’‚ÃUê{ùë•%³úÊÊ ±X̤ª¶_¸„/ÉBà}àSèªÚ˜®l)TeÓ~FÊEé}è’gÞÀ‹±í˜¹÷îµßãñ8©TÊÒt0F™òÖ[o¹…¬Ä033c"á¨ÜñîÏפõ{‡ß®¨å¢¨/6¹ËììëÃÙ׋:g´Ão¿ÃÜ£¦~nnŽ¡¡!+)xë­·Ü>ø` B<‚u•H$XYY12üáG4¥Ó°Jˆ³·ÇŽÀj7ÂÔb!q¹»õftp§2 ¾ÿ!“÷ß2j¬¬¬L&­˜U|kcNYe¶’ÙõªÊL1ôá/ Uµ )ØŠ®æ ÞjÞª9Ú /Z$ØÑÞ¶¦v~ð!³÷ÝM¶@M-//[;9Ì*!À™3g„â •žÁúAà¶_^AÎå’´­Áu½§œõ`µÇ£l¤GV)Nké;‚AÓ–s9z/^Z+a!ñxܹÀÁ3gÎX•!Ä'°°Œ,•J‘Íf×è¹~ÃTS¿‘ñF¢FUU~,j/>)0i€®É)¦~í¾µïªª’Éd¬xHöbqßÉ«,K½«¥¥%“Í•JÓz3‚X—1C*ꢨ6k…—ÝtVµB!‚s7q§Ód ö–——ñXsà;Dž!„%Bâñ¸©ýèž2&nXgÎÅ–ptvX‰²2tg^Ù`\Z4¶®"ê óÚ f÷Þ±VN‰D‚®.K†CÀ7ä³gÏ„U—+ŠRd^ïžš)–ŽÕÌ6TeÙ.¿ò/ÔjeÖ–âk½ÊBt^›"tçÈÚ÷t:ªªVîöž={6 c,ĝХ%óz{‡š£s6\$¶Z|r¥áÖ£tqTêYŠÖl‘a~V‹ÇKþ÷öéŽ\½€€D"A[[›•DFd!„%BÒé´©ýè˜ áд’µ$·EÏÕ*![‘Œbh±xIí k:í3sDÖîÙðæ‘…ÅH% ªªI]µÄ—Kf@‹,¢EcH~…mH½Ûö’„XKD½9žX))!¾¥8‹¿NOTÁh‘Ê*÷âzBšRé²P._Á½ï—D µ¶¦Š¾AéP&&Kj†<Ü©´©¬Ö—]ŒÈBˆn+O®w^hJeVûá¥ÿœrm ×ÇF‹úêe±)ÝÛÏÛë™,êôlYíДL›¾ç¬«ïnYÑbåIMÓLmHS:SQBPs¨×§‘·”&½bÿ¶~°•Dé‡Õ«× .bCeµÈBˆªÆ–¼tFêIU!P.\ÂÑÑŽhª°ø¥&ʼ”¿Ý iÓVVÈN\­*õM©L‘J.—³2µë“1ö›ªeÝb!M¥¤Ø…žÓÈž»€û¾{)Yˆ 1›×ýAãiM'ûÑy„®W”w:S$ªª–%¤àYë’7&83Y¤2[/˜Úb õú ä®Áõ…7X2ÀPU•zV…pè:®¬‚â¾å½ àõü—5…·gÏž ÆùUÑÙÙiMM–™݉p8Œ`Ku•W_µ„º¨µ**l}˜¾kÝ)¯•‡$I´¶¶V/H¯®–=P¼ès øÍj1x<ZZZHl4ì¡ÿZïrjÃ5®:¬Y]-E³Á¼¦Z¼DvmC*¯×kg“æ±Â/ë 9‰µ†”$“É[s$Bp}ïNö¾w©Ì·­ V·Lß³ÛhøW¿ !hkk³Úv$06ö_ƒ‰áááèÄÄÄw€oU‹ÉétL«„¢},l[¤cýè½}þ â– ‰Yìï ÖßizÅçó­b-ò]»v™6..2Ô !^þ#vshoo'‘H˜f'öíÆ›ÊÒ_V­ Wa¥`S­ÙÌg2àãêþQS¡K’D0´*7ŠòVÊ9`rrò÷€?³k4eqqÑtÏÊrÏ™ó83åN úÕV_ŠÛÉù‡÷‘õºM…ðWt07á÷‡††þ|ýÍr„ØÚž)³²²bºç&øØ;ã­Q…ß`µVŽ#I0þ©‘h¿UðB<–WM{wîÜYTcËn`võêÕÏ/Y‰]Ó4B¡ÐšI%®éÃç®ÞºQŸv´ÔB™W®Ý·›Èv³6w:tuuYUU_عs§õ ÌÖ¿vÍòªª2;;[äé=py–mWBõóRÜ ”ÉRhO?3£ÛM÷$I¢»»‡Ãòl㻃ƒƒe·ø«6ûþ7Á”e™®®.Âá°©‘ŸÞÓO¶¹‰¡óS T_ÐHbuIpý®!"ÛÍ=*!vœÀ(Ó²¨ºoïõë׈ý‰„ÉDŸGK,Áž™Ä™-XgR£ ïÆa=&Õådâã»I´ÍZ[[íîHzrÇŽOWz *!SSS¶7RŽÅb%w1p¥³ìù`ÒÍo±±I)$ý^&>>LÖS¼ãhKK ,WÀ,°ûöí7R¶´ÕøÔÔ”í­ÆWVVŠºÃRNcèÜmak“ZµaãäE»ƒLÞ=ˆæ0Oû !j‘Œ4ðÐÀÀÀÆ·ÏãÆ¶7ãÏd2D"‘’ç…´ÞŒ3p9DÓJÞ®v›Fçënv3½»—hWqíw8´··×rúÎo Ôo3þ<¦§§mW¡ª*‘H¤hÑÏjâtÌF韛ۖª¨?yŠKffW7‘þ6ôÝW§ÓYKðü¶mÛê\Àôô´ Ì.•úຮ³°°`šC)„”Ó蹡÷zÄÖ‡CGsH„vt2·££H=åáñxhoo·3ÎÈc 8Òßßo¹my433Só‘Gñxœx<^v-‡3«Ò1·D0’ ei¥qZLÀrÀK¬£…HOÅU~©™ßï·c)Ä9àþþþþÆy”Çììì 5 –ËåˆÇãEFÉõ•­ ‚‘h²ŠäTÿšCb©Õ !ÚîCu–È !ðù|øý~;¾BÌŸèëë»f÷ÅšÍ …B:6OUUb±˜¥“<%MÇMâIfqfU\Õt•Vœš$P\2Y·lº¦¼.â­^4©ºÊñz½ƒÁZÚŠ<惽½½›wl^¡Ph ,™Íf‰Åb&H»W]DU¹¦Ú @SSÁ`°–3¦ qx¦··÷Z­løèÕ¹¹¹º½šÉdH&“k‡oòî±^¯w#Iæ1|¥§§çö½šG8ÔñpbEQÖÈ©÷¹¸n·{„:žý<ðÍîîî f]ï‡Ãu?¾;—Ë‘L&Q…\.g •Žïv8¦àt:ñz½µ6Òå~·»»{kß]ˆ›7onÚ÷…ä&6³Àá®®®­{À}óóó}‡‰Y¶ÿŠá$ðlgggECa-h!yÌÏÏø6'¹~ð.ð\gggÙC½6І’G$ù²zämZF `ppŸÏW÷Z!DµSg€§üñ«Íæ£iB~ô£}ÓÔÝÌý¹\Ž©©)ë{(TCa2™¨:OR["©%HêæwJ_B5Td!Ó&ð;‚ø ߎr›]ÛpJ®ºiµ··300€Ûínæ±æ€?þøÛÍÜÜ!'OžÜ‚Ù&o˜ EQˆD"ÌÍÍU5Ê=Å¥ì.åÎs-w Űv”ž ím´û:hoë@7tbéE¢©SQR9«æp 'Ãîíl÷ìf›g>©­jÚBº»»éëëk¶0ÜûÕ¯~õj£76LÈÉ“'ýÀÿ¥ 5‰DˆD"èº^ñ|ZOr.ó!Ùq¦ó“¸e7w}šÏ ïå3Ã{ÙÑ·›v_²C®™–¢)D“ ŒGÎòþµwùàÚ{œúUW]›ÙîÝèïnÚ¤ÊöC–ez{{éëëkôQÁT__Ü¿C6¥!B^|ñEZÓ!i‡¨àµ­Ö9šŸŸçÊ•+eÇ#êu~”üG ‡Îïù~nÛ—k¦{«ñòÙüÎñßÀ‡áÍ€ssÙ5›7on´¦œxä‘Gž¬uAMB~üã?¼f7µd2É'Ÿ|R¦¦Îç?äõôI¼n/päÏøÔÐgªÊXá£Iktzâ5~ûù_GSUöždÔs·å¼$Ilß¾¶¶ê}š xð‘G©:žR“S§N½ÍÁ¥|>ÏÙ³gQUÕrüÝÜü¿ÜiBÞ0ÿý🱣gWM9Í^Uyk$øƒëïñýç¿MFÉp¯ï~¾à{Èr^–evîÜÙHëë‡~øóÕNV%äÔ©SO?¬á·)BÓ4Ο?O&“±¨²qå#^ËœÀçjãŸþs6·o©)§!2l^Ú ‚ÏG>æ7ŽýGTMáaÿSŒº­5Åëõ²cÇŽFú)¿°oß¾ŠÃÁ yõÕW˜e¶ÆÀ'&&ˆÅb–c7µ¼ù;t4þó¾ïòàÎGkÊhª2jüZŽ}øCþò§Žß _Þ¬ØÒ`0ÈÖ­[튛F÷íÛW8QÑÿ „ø&6ɈD"ÄãqKÍH NåÇ@2øò¶‡øòöQõêA·“ݨ†'î<Äû“os6ò/¥òtà—ðKÁâù¥¥%æææèé±P³3ç­>QVC^{í5?p ¡:Š¢pæÌ4M+¢¢p<÷·,è³tø:ùýƒJ›ËìHm\ ˜Q῵#ššç»cÿ‰t>E—£—Ãþ‡S¬x$IbÏž=Èrm?Û2f‘|Ðâ몤ô¾Í¸©‚£°´v¼¡¾È"óH’Ä×÷þÙƒ¦«¨º‚f¨ÖÞúª+¨ºZü´RvÈæçïù7H’DÔ˜ã'Ù〩¶„†ÁÌÌŒ¢c¹Œ¿½ú ¥†¼þúëíÀ$6" s¹ü±åؤ>Á)e €°·gü)’Z®>ªa#j`VÉðëÏ‹œjŽj~Ås„-òÎây!»ví²;ž’6?ðÀÅA!KÝB<ÍðΩ©)Ëo÷õÓŖƶݎf親ZN¥IvÈ|nóøéÕ7xW}“aç$¤¢¦˜™™axxØN~ÌN÷_寺À–[=•J‹Å,ªê¢~Ž%CÁÏm¹U×ZPHöî_ZX-ë_ØzoOþ ¹ aÔyOñ|"‘ “ÉØÆ,órBÞ|óM·b¿ SSS2TΈ·‘fíéØIÀ¬Ù²j%6º•Ö¤?8Àlò&h?e§óNdV üÍ›7Ù¶m›¤ö¿ùæ›îûî»/%„!öaC]%“IR©”µÈÏÈIÙâ8BO°uÕëz™‘–× ÃžÌž@/óéYÀ Ošµ÷¸Gþbñ|*•"NÛq«ø1çÆœ«Ê:d'¿«UU–4çùI¬4ØÂ¾v4]³#® lª©:5c=-W{[§©–ópNQq^±BÀÒҒݱ“C”rúôi!„8`çÎÕÀk\Àše”-ä #AZ†²Òm¾¸«ÝÙHm yÃH’̲ÐиdœçNñ9Àlm% ».ú§OŸþ_úÒ— yùæ{±1,“ÉÏç‹ LKWˆ<ƒžºaÖê¸Æ÷·Å¯¿Þ  z‚e¾«\æ.±·ø[UUr¹œÉ~L'îÛ•e«uÇ-™È‘!ê˜E2¬SuMo¼†T.’–| Q•jG­”5C+#d›äD+{KKKx½¶øR Da‹D"aQWi! Vp<£Óh*~΂ éPÚ4â«Ï-â(!¤ aš+Œˆ;Šå”L&íú·ß“ßzë­¢îÔcEQÊÜëǵŠ.çxnŒz…ò¸µ½ûúi'rñŠÏ>Ŷ‹;‹¿³Ù,ªªÚ ¸}ë­·B2æDüºˆÇ­óí5TæäéŠ!3Kùš±šÖu¬ñ–¦ÉH*‰åV–õø,7ÐÑKœŽÉd’ŽŽ;bwËB[„d³YË1#ÝÄôЄIJ‹E£nÂ~qµ²×x£Ø~âñ\¬b ÑÑ™1¦4¶5Í¿[B” U€ªªu•rÄWéЕ‡‰fg‰e£ÜAEËø¨#¨²J´—ú|j–´š¬:B˜2b–†NéðDì)SYÕn\MHΑ)ºJÌ×Úzß•Øîì©ÌP ·ÖˆÛOûJìbÍáÚ¬‘Aè%®¥UeW»e!D¯+W/ä™åL•“p#y•ÝÝw" ‡ñç®Ü‚°¼ž#’ºQ›Ý6«i¶8½²ÂV¤š®ë–LäÙBÊ¡*7’“ Êã™ÊPƒŒ–ÒÔÒ'ã—ÂJH©äœ°ÖTV@BÔu¶jG©P“×A%\Œž¥ÃÛ…ÛÑää—*åW¯XËkAkhM+)®&&VTuñy#SVƒ4M³3´ë—1×›ª‰B°tBòr¦b Ë’ 4Æ>⮞ÏV<_×fØz©ŠÂìÉl†¡snáC aX©•'ƒP­™WUµ*!%/ºýR7PD!8¨^m ˆå£L%¯Ñï*;×z³±J`•šIv2q¹fËÊ*ß@‘ò¸ŒÍ`Smùe;º­@FáZ!Dyµ­–9&—.ãsù 8WšÁëó&¯’YéÑšPƒ±\´®!_ !¬.¥Òò«s ½f7ÒétZ2ãƒ,œè¾{äbìc¶‡÷p…ö¬ÚƒQåÿUhD ‹™(Wâ+úìªÁ7KZN§Ó!IY±DB\®ò©^^ÚÈHMɾ”g80BÐÝ^ù‚&yZ/#ÍÎ3•¼†ä°6^ê½O^Ý_V^6'.ÉBˆº¥Z¨!¥}/~rRã«,\O^a•°»Â;PáªúìëlÄ2³Ì¤§m׌Ò\ø°RXêÃ’2æêu!˲¥sè¥Dã“ ˆ¤o°¤$èõõ#KÍÌ%4@´t±ˆ¼–c&=MZM53É€6ÍJˆMuË5ÄV¨Ëå²ô8}´U6ì6 %­%¹–¼D‡§›«Š «ˆÆìƒ]se`ËEYÌÍcFÓd€©=Jï·Y;fd!Ä86F ].—Åké5Ú,ÎE¨¯^*!š›#¥.vuà•mÅ1-‹´YÒuÕ AZMÏEÉkyÛ­¡ZX­²¨!ã2æ"Ãu±šå6-d³M^ÿ„bä™ËÝDVœøåmN?¢Vç«­4ÍÐH©IRŠ9vcÀšj|é #Ü,!ç 5¤.¼^¯eªSéÇ)œh 4} ¨öŒ: -Æ’Ç+ûp;<¸$·Å#`,Ûf y-OVËÓ2EYµzÞÖz‡á S]™+„hdÝ”qÛ„„B!Kd·™Ne€yÏT»ìcõóeõÌò*?²‘%'.ÉC’‘–ÿjA7tttT]AÑó(zÞ2ŠÙH¿¢^^KÏtçÍ) %¢ýþòfpŒËwÜqGüìٳ稳¤·,Ëx½^²ÙlñXwnˆ¨/b'!¨ö˜ÅÈ¡h9 Cõ¦Ó_ „dF؆®W¶/ujÂÚaæ¨O¶x4Ün·Ý>ȹÑÑÑx!êd k¬ƒA‹aïÊrÑñ>å>$›Ï`¹¡YCj` oŽÞü–Ošéö(›,µ¡ºc°¹¸LÈwëÝ YXX(þvã¥]é&îž·—çª'ÖÖªi*Ù–Þ`æ?¬ôà6¼ V<¸ ¨«B0×¾ŠP'zÑívãr¹,Ñ‹ÝÙ!’ÞhsÏRŒuy‡±òNK’D?‡­hÍY`dddÄ2b[q5 Ë—/ÿ ð?íH]\\$ZŽåÎ ¿êhl ÷õ'©5)Èš›OO?Œ[õYjA("´`þ­mÛ¶Õ_|àòåË -Ï433C*•²Kz£\þ)†XµhrƒeÒ:’š ƒ\aHܹŸ@vei?!^¯—®®.»b&€Ñ­[·–M䯺€Ù•+Wž~hGº®ëD"‘¢K¥€…ðu®öÿ¬¾€u'©u´ŽÌ~–ž¥-–cN§“žžžFFaëÖ­ö0+àêÕ«¶—øSU•ééé²HïéžO¸ÙuÑnFWÐD®wÈö`t7›¢V§¸$IôööÚµïlÙ²¥êõFß¿ƒÍE0eY¦§§‡™™‹‘œÛGiãúÀÇåê«•°é,^Þ€haHl½›îİE”‚®®®F‚À,ÓiÕ1t×®]«¸Ll5$“I‹‹¾€”o‘Ë›ÞC•óîZ+Zc*]îÔÜlŸº¦<ެ½½½ÑIO 7¿L,Àäädà )Çb1Kÿ¤€¼3ÕÍï‘ñ$ÖßX·àr_6ÄÈÔ½¸”rŸT  *_`¹¦½›7o^ÛBÊ“““ /5žJ¥ÊšÃ`öS&‡>$¼YvîVëÕ'úžºI·Ú†‚ŸªÁš‘îß´iÓÚ—/àúõë /ÆŸË嘟Ÿ¯¸_H"8C¤ÿrîåærÃZg}ÈpçüôßÜE(Q>ÓÏápÐÙÙÙÌî;_ß´iSëã/àÆ oW¡ª*óóóe“~ a°Øqƒ™¾ T¹Nd ç} «nzgvÐBå§ÓÙŒxfhh¨õÛUܸq£ê†.µÚà†a°°°`C)….iÌ÷\e¾ç ºTh6·Î6Ô’$éºg·Ò5·µL=àõzéììl&¢q 8<88hûaÞòhjjªé-‰‰D¢êŒ[Õ™'Þa)4KÚ£%j©¢7"ï!@V+/.„  6â)Åà‹ƒƒƒë·åQÓÓÓ[hrS0MÓH$$“ÉšS¡59O2<ÏRxŽt0ZRsšƒ¤;ð%:ĺñǺpT!L"ü~?Á`°‘_)æ€{®6zcÓÛæE"‘5m›§ª*±XÌÖNž†¤“ FÉ{Ò¨®ª3·òíÌaHf£Aè²â6?ù•oWÖG[¢¡×”óù|„ÃáflEsÀþþæ†Ö´±d$ÙÂ7–ÌçóÄb1KDd£Ðd³ÁàP›ß·Êãñ‡›Ùcªg€§úûû¯6+`Í[¯Þ¼y³%[¯ær9Òétqâ@!<Öçó­e#ÉÆ€oôõõݺ­W ˜™™iéæÄŠ¢Éiõ¾¸n·»HB wŽ~ø­ÞÞÞ5fK·ïž™™iùöÝš¦‘N§QMÓ,ŸZÛw;ËÇétâóùš5ÒÕ~¹··÷öÚ¾»³³³¶Á})9€…€ À4p¨§§çöÝྀ¹¹¹à4à%þg†À7»»»k: ›ÁºRÀÜÜÜÀbsëŸÞ¾ÓÝÝ]uS¯µb] )`~~þiLÃgkŒþ6Äð½®®®ŠÃ®­Ä†°°°àÄ æþ>67Œ¹ 0 ü.ðƒÎÎÎ ÙY`Ã)`aaÁ¹³Ì¯bs¯’[€¤âYà:::ÖÔ¯hNHÑh´ÓèösëÉI/bvðNttt,Ö¹~]pË)Åââ¢sˆCÀl¬Cß"D0ýqÇ€WÛÛÛ[Û m·!¥X\\˜­²ƒËŸQ°'kç0kÁðN8¾­ à¶#d5b±Xs)ÛÝÀžåï^Ì¥ ý%ß`ª¥’ï`sµŠq`<×:¾ÅøÿN‡epË ÝIEND®B`‚pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/blinkenlights/GNUmakefile0000664000000000000000000000160212272262501021547 0ustar # # Copyright (c) 2013 Red Hat. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../../.. include $(TOPDIR)/src/include/builddefs IMAGES = blinken_error.png blinken_off.png blinken_on.png JSFILES = blinkenlights.js CSSFILES = blinkenlights.css HTMLFILES = index.html LSRCFILES = $(IMAGES) $(JSFILES) $(CSSFILES) $(HTMLFILES) default: include $(BUILDRULES) install: default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/blinkenlights/blinkenlights.css0000664000000000000000000000132012272262501023041 0ustar #interval-slider-label { margin: 0px; } #interval-slider { width: 300px; margin: 0px; display: inline-block; } #blinkenlights { font-family: monospace; font-size: 130%; } #blinkenlights li { list-style: none; line-height: 25px; background-repeat: no-repeat; background-size: 25px 25px; padding-left: 32px; margin-top: 5px; } /* public domain images courtesy of - http://www.clker.com/clipart-led-off.html - http://www.clker.com/clipart-6514.html XXX and related images from the same site */ #blinkenlights li.on { background-image: url(blinken_on.png); } #blinkenlights li.off { background-image: url(blinken_off.png); } #blinkenlights li.error { background-image: url(blinken_error.png); } pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/blinkenlights/blinken_error.png0000664000000000000000000001730712272262501023047 0ustar ‰PNG  IHDRddpâ•TbKGDÿÿÿ ½§“ pHYs¦¦~uÉ vpAgdd‡&^æ²IDATxÚåip\×uçç¾×¯@£±Hbã¾h3-YòP–)Y%“¶6R¡Rå„¶eË–ËI&5IMU¾Ä®”Êž/S•x¦&UìL&ÞRù ÉÚ©ÍcjµµQ2Esw€ØF£Ñèå½wçÃë÷Э@¤åSõ î÷î»÷üïrî9çž#\aôØcù  h6[õ@'Ð 4QÀÌü36’ÀМÎÇSÀE`pöíÛw¹›\Dr¹+ð裢µ¥T ØÜ| ¸hêñ¿Ðúj< â@pxx8¡µNúþûï¿Ü¬¸|€<öØc444Çë€ë]ZëÏáR· uÓ"2 œ~¼jkk½xñâe9ËÈ/~ñ ð¦£MZ뻽À'ð¦ŸËIIà·À"ò ÞôæÜwß}ËZ‰e$D¸ø2p/ÞttEL›¤ñ¦µ§€Ÿï¹åfÉ™ñÄO€·èÞ|Kk½X1k…DÐZ/KãK2Gdxø!0öÞ½{—öKUð“O>‰R ×u7k­ÿ Ø4-ik–Ž€Ÿ‹È#"rRkÍž={–äEä‰'ž@Djñ¦¦¿Æ[?t øÞT6T˜ŠòÔSOáº.J©ëïwj­­ŠTT®˜¥& <|϶íC†aT”еòé§Ÿˆh­÷ ¬[tå @ÐZãº.Žãà8¶mãº.®ëkŽˆ ”B)…iš†a(¥¦•U:+"ÿ ø9¾çž{*ÂÇEòÔSOùm¾|¨ZT¥Dp]Û¶I§ÓLLL011A6›%—Ëá8NÄTæŠHŒa„B!,Ë¢ªªŠªª*"‘¦i¢”ª0À¿ßúE„»ï¾{Q. gžyÆÿxð÷ZëÝ )Óï½Zk2™ Éd’±±1R©¹\nÚ(˜M=¡Pˆêêjjkk‰F£„ÃáÅN‡xø¯ÀQ­5‹- ®É³Ï>‹ã8(¥>ü/à“ó~yž¶m“L&‰Ç㌑ÍfÑZÏͨÂßüÏ…=~ŽÞï—mYµµµÔ××F1M3ø}ô¾ˆü¥Öú á®»îZ_ȳÏ>ëÜüo`ü_,B.—ctt”¡¡!ÆÇÇqgfD¼KkpÈå ›…\mÛÞw†˜&„B`YÞ_Ø|vFk­1 ƒššV¬XA]]¡Ph¡ œþܶíC¡wÞyçÒòÜsÏùïþ è˜oŽãÇ`||×u‹(`bC_º¿=8‰:•‚Lí8àºÞsJ!†á0R] uuÈŠHs3ÒÒ H$JM>SŒRŠššššš¨¯¯G)µP.!"Ïh­ç ʼ9pà€Ï¼Ýx»×²ÁðwàÉd’ÞÞ^FGGg`|ÝÝþè#ÜóçуƒH6‹ ŽF ÇbD ×Öb„Ãá°t&ƒN“I$HŒI$È&“ض¶,ÔÊ•¨µk‘‘ÖV$õÑ(ª«RŠX,FKK 555 Ñ\‘oi­_¾øÅ/Vøoþ/°q>`är9úûûéïï'›Í¡8º¯}ô(î±c00€eYÔutÐ|Í5¬Ü¶ÆM›¨]³†H]¡šŒPQ É÷díºh×ÅÉfÉŽ“ŽÇëîfèäI£ÿÈ]]älij¸újÔÕW{£Ç0ŠFÖšP(Dss3MMM˜¦9_P>¾¼."|á _¨ Ï?ÿ¼ÿñ*à§xêò²)•JÑÕÕÅèèhñb-®‹îîÆ}÷]ÜcÇÙ6+6ofíí·Ó¾c+6m"ÒØˆQ¸àjöþ™­ï¥@kœ\ŽÔà C'Orá78÷«_1rú4¶ea\uÆ7"­­0Z#L.þ±XŒ5kÖP]]=Ÿf¾Ê¥,@^xိõ¿åA§‘‘ºººH§ÓüòÖÝßû›ßàüö·DB!:o½•m{÷²ú†¨jlô¦Š‘w±$"ˆRh×e|`€îwÞáøãsñÍ7ɸ.æöí;v ZZŠÀÖZ‰Dhmm¥®®.˜Â¦ 3ÕSDž¾ôíÞ½{ñ€äÁˆÿøÏ储µ¦¿¿ŸK—.aÛöä •B§Ó¸ï¿ýÚkX™ wïæÚýûiùÄ'E"¡8ÙTŠKï¾ËáŸþ”³âTWÚ¹ãúë= _­5¦i²zõjV®\9Ÿ½‹þQDþHïÚµkြøâ‹þÇoàí5ÊÚ»®KOO===ÅŒU ÝßýÒKècÇhýä'¹áÛߦsçNB‘®/¾.'å7ŒÙñqμü2ïýó?Ó{ô(æÕWÚ½in.™•R´´´ÐÒÒ2)løKàÿÌʬ€¼ôÒKþ°¼^ký(eꦴÖtwwÓÛÛë=Ÿo4Zãž8Aîùç±R)®Û¿Ÿëzˆhs3®ëι‘[N`F»ºx÷‘GøÝ£âÄbX_ü"ƶm“b8ÞèjiiaÕªUe«`Dä,p?pHk=+(Æl|õ«_EDbÀDd‡¯#šëèéé¡··7¨¸/ó;o½Eîé§©‹F¹íá‡Ùþµ¯ŽFÑSö³ \QÞÏXšÖh×%‹ÑqË-D[Zè}ã Òï¿„Ãmm’RDH¥RˆH —Á› EDˆHæ'?ùÉÌÀÍôåË/¿ìü3àâ™^KR__]]]^Ï¢s9ìW_%wð M6pÛßý­7ÝHK‹bìRŒ*­)íÜ+¯ðÊ÷¾GüÒ%·ߎuÛmÞî¿`úZ³f MMeÛÝrÀ¸ãŽ;¦Ý`ÎôTÑÍZë¿¢ 0D„ááa.]º4)}ˆ@.‡ýòËä^{•›6qû÷¿O˵×bg2 bÒ´ï*ŽÅd™"BÇg>Ãç~˜ÿ÷Ýï2úÒKÍÞµËSËä5ͽ½½X–E}}}9¯ü89Ó Ó¦¬_þò—ˆˆü­ˆÜUj(*¥H¥Rœ?ž\.7ù›ëb¿ò ¹ƒ©kmåö‡¦ùÚkqs¹`WÎåº.Úq‚ ×Åuœy•QÖ5µLÇÁµmj[[©ïì¤û­·˜8v 1MÌuë¼ i^ü˜˜ bYeÙâVŽˆ¼üÀèÿøÇE?u»'Ÿ|’ÚÚZ€ÿ„gÜo.UºmÛœ9s†x<^$ Úo¾Iö¹ç°"nýÎwX¿k—ÇÐùwÛ‚ÚÊ’-þsM¢Çœ7ÿáp\—ª»ïƺ喢úÄb1:;;1 £œ×õ{€ß8ŽÃç?ÿùà‡¢)+‹„´ÖQ$‰@¥°÷;r/½¹WùËt|ö³8Ã…2I˜eA^,•Y„»w3xü8Gœô /  ]{m ncppU«V•óÆfà!à=Ó4s…?Ì´†|JDî-U¢ˆ066ÆÀÀ@‘šÂíï'ûüó¸©ÍW_Í–={¼á¿ž½ ££\Á@”âªûï§çÐ!FÎ#ýÜsÍÍ»ú¡¡¡ÀðUF¹÷ŠÈ¿h­]øe°³9xð "¢Dd¿ˆ¬,µv¸®K__ß云ßgž·§ò¸êþˆH}=N6‹›Ë•}9þgÛž¼²Yœüo»æQ/'“!ÚÒ–{ïE)…séé “ xbÛ6ƒƒƒ»Äµد”R FH¾—oʲ?Æãq‰Ä¤œ-Bî½÷°AM[·²jûvœLfþâéRŒ„ ¼GDhûô§9ùì³ Ÿ>MöðaB7Ù¹ÓSHægD"ACCC9EÞü“ˆó¿0^yåÿÿ»(ÃÆaÛ6ˆ+Jáôö’}õUÈ[ý:wîĬªÂÉfçǸ¥Ú[TˆÂ±í;v0|ú48郱¶lÁXµ*…‡‡‡‰Åbå¨ì;òÀꘔ‰ÆÇÇÉf³„óNsÐ< ÞöÅÞ›€†¹ÆÇǃ}"è±1²GŽݧ”B™æŒ#¤¢gY´ÔÖÆ|E©"uPæÃ‰~îs¨X ÑÛ¶I¥RD"‘"Ê:~p“ÖúmSDÞËmÔŒ…¢¹ pò¶B¦û›»"@.£ªÒS¢(…;Ãúh÷ô»pÈu×yÎZ“J¥hÌûÏÏÜñ?¥”R¦ˆ¬À;í:'år9&&&ŠŒQ¹'ÐS*¦‡\*U4B*-zÎÁùÊ9ÃwJ)¯Sg€\ŽÌ±cT]w]`.˜˜˜À¶mB¡’VŒk€&Þ9ð¶¹î2™ ¶m{ë‡:•"wöì´{]Ç!+@c»ˆB§¥éx|Æß²§O£S)TÞeȶm²Ù,–eÍ­QiÚMÙ„w y®›I§Ó“Æ'¥p†‡qfdJ²·×Û¡Ït\€Ë¤±]P‘³×=ÙׇfºÉÕîïǨ­Eò2“Éøf¹¨ØdŠÈV<7Ÿ9+æûUù ºÝÓƒ;>>ãýc==äR)”i.ËÚ±,#ÃÙ"Øé4ɾ¾sÇDZ{z¯_tÈL~ƒ\Bü[M¼p%ì»Gzzfd¶ÉÞ^RT75ÓV¥EÏYW‰"§”[¸æ‰R^ûgvHК\w7R`vÎår3÷T3ñZoŠHg© ú§™@\§¿Öû³É$#gΩ¯ŸŸ.k!Ì[BG‡¢ÿ'¹ÈðéÓØ™ÌŒ€h¼i × t[þ‰¯2Ô(¦ˆ”´ :Ž Œ:“Á‰Çgo0pì7bF"K˸Š9ûº!"dÆÆ>ujÖçpFF —CªªÝV¡'ÎÔlâù Íþ‚¼1ªÐ›ÄÍfg]?üJ÷÷3têMÛ¶-z”,Û†²Ô{D:y’‰áá9]>ñqÏp•—´|@ÊP¡4˜"RR¡X„®d³èš\×uéûðC¢--Xå™4ËcÊÑ4oz¯wðabd„½Ý¬e¥ÓèlÖ›²ò¼ó)¥h4EdNß•¢Í÷D´mïšë9`bhˆ¾Ã‡Y}à >X¹lbóô2×¶é;|˜ôØXIosçOЙ<ÚP‚,“Yœå¦RàÈàŸé(s:uŠp,FÃúõ‹7å.¡£ÃTVM}ËÐÉ“ÄÏ+×õ\%‚.L ù8 ™f)Ô¦úî2å¥Èµmzư,j¦œ»˜³M~à êqYƺ»8zt^ka¡¯A!KµÁ/ZÛœbHWÙô:ĪíÛ©^¹²<Æ^ê!ÙÛK߇ÎÏ7 ø´©Ñ$fc•)"YæÂSøó {ÇçAÙñqz>ø€¦mÛ¨)áœ|ÙÕ-ùìíeðÄ ìy:ù‰iz<Ê;€ø€xEÏ JÖÄ‹¤6«¤%" ¾¤ "TdNmËŒ”§ïða6l võêÙGÙet“üžèî&~în áe&R‘F$0ßóQÆ”•4Ed˜ÓÿÑäâ/~F$‚Ψ\+EN6ËЉdâqê::‚#0syË¥nñÕ©£.\ÐþIfm-FUUpXÉÄûwNŽ˜xAS¶M¯ó¤¨kš&¦i‘T8ŒÙظp~¸.c==¤ j׬¡º±Ñ;ð?³Ãû¿œ®Orm›Ôà c½½Ø‹zg¨±•Ÿ²üH¦i–³†ô›"r~¦_ ö£ê FËÂ*Ï©xNÊ3òÑG¤êê¨ijª­E婈D5W@dÆÆHõ÷“I&+Ò!«W£ ö„B¡`Êš»ºú¼)"gJ½À0 Âápàþ#Jno4¸‹ã™&“I$°jjˆ44`E£¡ÐÌAeÊ-·à¹™Ž/;Ù,Ùd’tS7^Þí:8M\ËìíR³u+f4xÃûí ¤„Õ\TÀˆ)užÁ4Mªªª&¿3 j¯»UÞ¹ºÊa”ïùN6‹þ“›˜ 71Ncg2Þù’¼ g9ɰ,ê¶oGÄyôC –q^ä0¤DÄÅ L?')¥ˆF£“gµêM›ˆ´µ-öõ ' DÚÛ©Ù¼a2¤`uuõœ z ï*¥\•ÿçm) ºº˲@BõõÔÝtÓ+ürQç?M¸±1$ Ï*³ð/µÆÛ0y¤í¤ˆœ(5¬,Ë "(”aаc¡El?.d56Òø™ÏñËïÀ@©éꄈœÌóUPJŃ¥^êGZ3 âVuvRwãÐÓ–Æ5kדú¿h4ZdGšã:˜ÇµuëVÿE$YδåC%‚ …húüç ÕÕÍ»!²êëiùÂP–…Êó*‰ÉëéJHWIàE­5[·n¥pµy_D>(5m†A]]Ýäâ®55›7³bçÎ?ÈQ¢•·ÞJí–-H^ÔUJQ[[¨KJ\ˆÈûf‚áÇ‹Þ0'‰µµµTWWO‚ Ñr÷ÝT­YóŠªZ[Y½g* ø‰DŠøSâz2Ï{ ÈæÍ›ýŸ‘ ¥¦-Ó4ƒ0ªÜÙÉêûîóÜGÿ@H™&mûö]»¶htø'pË  À³àaMYh­OˆÈÓ¥PˆF£Á¢å_MwÜAãÍ7ÿAŒ ¬¼åZví Ä\_²ª©©J.ääy}¢p Ù´iJ)/Úÿ`© †ACC!¨¡h”ί}šuë>Ö h º~=ë|Pmm‘6£h}ûÄKãnÜ8q·h„ø;FyªœQRUUL]J)¨éìdíƒòÙ|,ÉŠÅXÿÍozb®oÖÎOUeœ'ôé)™¦!™¶§‘œˆüHDúËY”êë닆(Z³bÇ:x`Av÷+T$º¯¦›oFòþξ6¼¶`´”¸úó<ÎM]kŠÙ°Á‹©¯µ~ø÷rF‰a466:¿·¬¹÷^:þäOÒG¹~oHB!ÖîßOÛÞ½¨‘Ö(W¦˜‹ˆü;ð@ggñáƒi#dýúõ(¥y„YÂÐ̃‡ill,2S¦IÇ—¾Dû¾} P$¢óÿ˜µú§ž5“Éy]]Ý|¦ª“À#"â¬_?ýhάjH¥ÔIùù)¬$êÑh4ÅÆF$ºdíW¾‚ŠD~/z UU¬à6|ó›»o¥uuuAò2ø”Ëóôäl»÷Y÷ôçΈ?‘½¥l ’·ˆŽŽ1Þƒï‡î'ŸäÌ¿þ+ÙDâ÷F;¬«®Ž ßøí{÷zÎ|ˆÅbÁºQ&=¡µ~H¬Í뽦ñq¶'/\¸à3õz`^”GGGIDwÈÿÀà¯ÍG?ü!c§O_ñ h ¶a›¾ýmVÞ|s‘ Ö×VÄJH’…@i­ƒ@Ê"BGÇÌQ°æäËùóç}Òy…×Z“H$H$ÓŽ2ŒŸ;Çéýˆ¾W_ŵí+·o¹õV6>ôѵk‹æ|0æ92ŠBÏ”áxxáÂÈã‘yãO&“Ó·(…LréÀÎÿÇ0ÞÝ}Å€¢šÖV:¿ô%Zï¼³¦¦ ¯Q¨V/³ØÔZÿ ž ÊeîÅ‹Ás‚ø7æ™®bbb‚x<^œ!!ïœ<{– =FïË/“‰Ç/0×׳êŽ;èØ·èºuÓÎØûú»ªªò3æ§¹ ]E{{{égÊ)øâÅ‹~XPB—l6ËèèhQÈÇ ±mÇŽÑõôÓô¿þ:é¡¡ò+¶òYY±‚æ[n¡íž{ˆmÛ†2Íi>½‘H„úúúrÂcL¥¢„.mmm%(»Ý]]]>ⷈȼRwÆnllŒd29-›LòÌz¤ÿµ×Hž;D¤«8>F8LtíZš?ûYVÝvÑõë§áûäúa_ ,Hy¤µ. Œy·µ»»Û?#²à¤`Ùl–D"„ê(º'ßèÌð0£G2øÎ;Ä?üñ‹±ÇƦ{™©³‹1kk©io§þÚkYyãÔ]uá¼/ÀÔáÛ4 uSeÇ÷õÚyø^ÂIZ[[Ëæñ¼;_ww·ï ¿à´y~Ø¢d2„˜Òª 5‘=6Fª§‡äéÓ$ÏžeüâE2dGGq&&Š¢‰R¨P£ª «®ŽpS5ííD×­#ºaÕ«WcÖÖ§cg ØfYÑh400-€.¡µ~FDX³fͼ^Ð/]º„eYd³Ù]"² Ä’àMc©T*ˆ¼6ãYn_o–W\úA‰ ïòsbžËiU•w…ÞzþÙ™Rdø|šR~T%è4ðç¦i¾˜Ëåæ Æ‚‚tF"²èÔ«®ëIˆÓét9b–‡&³öþäpñߢŸŠÏ…†˜[ÃápÄ|=óÓÔûx{7V¯^½ ¾.j½ìŒ&wð÷À‚’4 Û¶Éd2¤Ói²Ù¬—2ß»8…L|Α,Ë"‰‡7ÏE¸%'Ê È?3üdž @i‘ФïöÉqr¹\¶{jênŸÙE *ðƒ*Láí;=û‡g*DE黵֋*(î÷yñ£"À~¼d0óJp_*"ª?Jü¤ö…Éí Õ3>…W¡ý¦‚tVk$¸oiiYly^*YÃ/s€ã\|¸“G®\ñ ^BÏ÷,ðð=Ó49Ž3ŸT¥ÛUéÚöOÆÑª¾," lZ*î,3~ü ÓZÓÜ\VÞ›²iÉ4ƒƒƒˆ®ënÆËö¶_Dš`ézïLK> h­Ž—]í$PÑQQÔ†¥jOƒƒƒà¸¹o÷º/1Öï áysþx°W®\¹¤/\6k˜ˆÜ|¸/<í•¢}÷Iã/{ ø™Öú= ·Ô@ø´ìÌò´¹Þºr·ˆì>A‰Ì Ë@Ià·xfÖgðÖ §Ì £ËÖ;GFF8uê7n¬ÃSçï>‡˜¾nê¦ñN¾žÀËÝñ"p¨««k´½½½Ü”E§+bºÈ'ˆ &"[ð’| /üv^ökõÕxâjo::‚w®òm­õ èÆ+à$ØH!ù9Jð¦µF¼P蛀­x1†;Å‹¤Ú€7ÍYLFųñŸF´ÖýÀyà poº N}}ýRJf ¢ÿ‚æ8oMHa%tEXtdate:create2011-08-25T10:30:26-07:00¤Ï%tEXtdate:modify2011-08-25T10:30:26-07:00Õ^½stEXtSoftwarewww.inkscape.org›î< tEXtTitleled offÛéo†IEND®B`‚pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/blinkenlights/blinkenlights.js0000664000000000000000000001263512272262501022700 0ustar var pm_host = location.hostname; var pm_root = "http://" + pm_host + ":44323/pmapi"; var pm_context = -1; // ---------------------------------------------------------------------- function Predicate(name,index,operator,threshold) { this.name = name; this.index = index; this.operator = operator; this.threshold = threshold; this.inames = {}; } Predicate.prototype.to_string = function() { return this.name + "[" + this.index + "] " + this.operator + " " + this.threshold; }; Predicate.prototype.get_iname = function(iid) { if (!(iid in this.inames)) { var pm_url = pm_root + "/" + pm_context + "/_indom?name=" + this.name + "&instance=" + iid; var predicate = this; $.getJSON(pm_url, function(data, status) { // TODOXXX error check: should return 1 instance predicate.inames[iid] = data.instances[0].name; }); return "..."; // will be reloaded next cycle } return this.inames[iid]; } Predicate.prototype.test = function(elt,data_dict,index) { if (this.index == "*" && typeof(index) == "undefined") { var predicate = this; $.each(data_dict[this.name].instances, function(i,_instance) { predicate.test(elt,data_dict,i); }); return; } if (typeof(index) == "undefined") index = this.index; var metric = data_dict[this.name].instances[index].value; var iid = data_dict[this.name].instances[index].instance; var result = 0, error = ""; if (this.operator == "<") result = metric < this.threshold; else if (this.operator == ">") result = metric > this.threshold; else if (this.operator == "<=") result = metric <= this.threshold; else if (this.operator == ">=") result = metric >= this.threshold; else if (this.operator == "==") result = metric == this.threshold; else { error = "unknown operator '" + this.operator + "'"; result = -1; } // TODOXXX avoid $("#blinkenlights").empty() by using existing li's?? var bclass = result < 0 ? "error" : result ? "on" : "off"; var source = "" + metric + " -- " + this.name + " ( " + this.get_iname(iid) + " : " + iid + " ) " + this.operator + " " + this.threshold; var content = "" + source + "" + (result < 0 ? " -- error: " + error : ""); elt.append("
  • " + content + "
  • "); }; var predicates = []; function parsePredicate(src) { var matches = /^([^[ ]+)\s*(\[\d+\]|\[\*\]|\[\]|)\s*(<=|>=|==|<|>)\s*(\S*)$/.exec(src); if (matches == null) return null; var name = matches[1]; var index = matches[2]; index = index == "" ? "*" : index.substring(1,index.length-1); var operator = matches[3]; var threshold = parseFloat(matches[4]); // TODOXXX what about other types?; accepts 40foobar if (isNaN(threshold)) return null; console.log ("create predicate " + name + " : " + index + " : " + operator + " : " + threshold) return new Predicate(name,index,operator,threshold); } // ---------------------------------------------------------------------- var updateInterval = 10000; // milliseconds var updateIntervalID = 1; function setUpdateInterval(i) { if (updateIntervalID >= 0) { clearInterval(updateIntervalID); } if (i > updateInterval) { pm_context = -1; } // will likely need a new context updateInterval = i; updateIntervalID = setInterval(updateBlinkenlights, updateInterval); } // default mode var pm_context_type = "hostspec"; var pm_context_spec = "localhost"; function setPMContextType(k) { pm_context_type = k; pm_context = -1; updateBlinkenlights(); } function setPMContextSpec(i) { pm_context_spec = i; pm_context = -1; updateBlinkenlights(); } function updateBlinkenlights() { var pm_url; if (pm_context < 0) { pm_url = pm_root + "/context?" + pm_context_type + "=" + encodeURIComponent(pm_context_spec) + "&polltimeout=" + Math.floor(5*updateInterval/1000); $.getJSON(pm_url, function(data, status) { pm_context = data.context; setTimeout(updateBlinkenlights, 100); // retry soon }).error(function() { pm_context = -1; }); return; // will retry one cycle later } if(predicates.length == 0) { $("#blinkenlights").html("No predicates requested..."); return; } // ajax request for JSON data pm_url = pm_root + "/" + pm_context + "/_fetch?names="; $.each(predicates, function(i, predicate) { if (i > 0) pm_url += ","; pm_url += predicate.name; }); $.getJSON(pm_url, function(data, status) { // update data_dict var data_dict = {}; $.each(data.values, function(i, value) { data_dict[value.name] = value; }); // update status field theDate = new Date(0); theDate.setUTCSeconds(data.timestamp.s); theDate.setUTCMilliseconds(data.timestamp.us/1000); $("#status").html("Timestamp: " + theDate.toString()); // update the view $("#blinkenlights").empty(); $.each(predicates, function(i, predicate) { predicate.test($("#blinkenlights"), data_dict); }); }).error(function() { $("#blinkenlights").html("error accessing server, retrying..."); pm_context = -1; }); } function loadBlinkenlights() { $("#header").html("pcp blinkenlights demo"); $("#content").html("
    • loading...
    "); // start timer for updateBlinkenlights updateBlinkenlights(); setUpdateInterval(updateInterval); } $(document).ready(function() { loadBlinkenlights(); // TODOXXX add support for editing mode }); pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/jsbrowser/0000775000000000000000000000000012272262620016663 5ustar pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/jsbrowser/index.html0000664000000000000000000000161412272262501020660 0ustar pcp metric browser

    pcp metric browser: host-local connection

    pcp metric browser: remote connection

    pcp metric browser: archive file

    pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/jsbrowser/GNUmakefile0000664000000000000000000000137512272262501020741 0ustar # # Copyright (c) 2013 Red Hat. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../../.. include $(TOPDIR)/src/include/builddefs JSFILES = jsbrowser.js HTMLFILES = index.html LSRCFILES = $(JSFILES) $(HTMLFILES) default default_pcp: include $(BUILDRULES) install install_pcp: pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/jsbrowser/jsbrowser.js0000664000000000000000000000020012272262501021227 0ustar /*! */ var context = -1; /* pmwebapi context, if connected */ /* Initial load. */ $(document).ready(function() { }); pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/GNUmakefile0000664000000000000000000000211212272262501016707 0ustar # # Copyright (c) 2013 Red Hat. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # TOPDIR = ../../.. include $(TOPDIR)/src/include/builddefs JSFILES = jquery-1.7.2.js jquery-ui-1.10.2.js jquery-ui-themes-1.10.2.tar.gz SUBDIRS = blinkenlights jsbrowser LSRCFILES = $(JSFILES) favicon.ico LDIRDIRT = jquery-ui-themes-1.10.2 LDIRT = .unpacked default: $(SUBDIRS) jquery-ui-themes $(SUBDIRS_MAKERULE) include $(BUILDRULES) jquery-ui-themes: .unpacked .unpacked: jquery-ui-themes-1.10.2.tar.gz $(ZIP) -d < $^ | $(TAR) -xf - touch .unpacked install: $(SUBDIRS) $(SUBDIRS_MAKERULE) default_pcp: default install_pcp: install pcp-3.8.12ubuntu1/src/pmwebapi/jsdemos/jquery-ui-1.10.2.js0000664000000000000000000152363212272262501017662 0ustar /*! jQuery UI - v1.10.2 - 2013-03-14 * http://jqueryui.com * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js * Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */ (function( $, undefined ) { var uuid = 0, runiqueId = /^ui-id-\d+$/; // $.ui might exist from components with no dependencies, e.g., $.ui.position $.ui = $.ui || {}; $.extend( $.ui, { version: "1.10.2", keyCode: { BACKSPACE: 8, COMMA: 188, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, LEFT: 37, NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108, NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SPACE: 32, TAB: 9, UP: 38 } }); // plugins $.fn.extend({ focus: (function( orig ) { return function( delay, fn ) { return typeof delay === "number" ? this.each(function() { var elem = this; setTimeout(function() { $( elem ).focus(); if ( fn ) { fn.call( elem ); } }, delay ); }) : orig.apply( this, arguments ); }; })( $.fn.focus ), scrollParent: function() { var scrollParent; if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { scrollParent = this.parents().filter(function() { return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); }).eq(0); } else { scrollParent = this.parents().filter(function() { return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); }).eq(0); } return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; }, zIndex: function( zIndex ) { if ( zIndex !== undefined ) { return this.css( "zIndex", zIndex ); } if ( this.length ) { var elem = $( this[ 0 ] ), position, value; while ( elem.length && elem[ 0 ] !== document ) { // Ignore z-index if position is set to a value where z-index is ignored by the browser // This makes behavior of this function consistent across browsers // WebKit always returns auto if the element is positioned position = elem.css( "position" ); if ( position === "absolute" || position === "relative" || position === "fixed" ) { // IE returns 0 when zIndex is not specified // other browsers return a string // we ignore the case of nested elements with an explicit value of 0 //
    value = parseInt( elem.css( "zIndex" ), 10 ); if ( !isNaN( value ) && value !== 0 ) { return value; } } elem = elem.parent(); } } return 0; }, uniqueId: function() { return this.each(function() { if ( !this.id ) { this.id = "ui-id-" + (++uuid); } }); }, removeUniqueId: function() { return this.each(function() { if ( runiqueId.test( this.id ) ) { $( this ).removeAttr( "id" ); } }); } }); // selectors function focusable( element, isTabIndexNotNaN ) { var map, mapName, img, nodeName = element.nodeName.toLowerCase(); if ( "area" === nodeName ) { map = element.parentNode; mapName = map.name; if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { return false; } img = $( "img[usemap=#" + mapName + "]" )[0]; return !!img && visible( img ); } return ( /input|select|textarea|button|object/.test( nodeName ) ? !element.disabled : "a" === nodeName ? element.href || isTabIndexNotNaN : isTabIndexNotNaN) && // the element and all of its ancestors must be visible visible( element ); } function visible( element ) { return $.expr.filters.visible( element ) && !$( element ).parents().addBack().filter(function() { return $.css( this, "visibility" ) === "hidden"; }).length; } $.extend( $.expr[ ":" ], { data: $.expr.createPseudo ? $.expr.createPseudo(function( dataName ) { return function( elem ) { return !!$.data( elem, dataName ); }; }) : // support: jQuery <1.8 function( elem, i, match ) { return !!$.data( elem, match[ 3 ] ); }, focusable: function( element ) { return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); }, tabbable: function( element ) { var tabIndex = $.attr( element, "tabindex" ), isTabIndexNaN = isNaN( tabIndex ); return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); } }); // support: jQuery <1.8 if ( !$( "" ).outerWidth( 1 ).jquery ) { $.each( [ "Width", "Height" ], function( i, name ) { var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], type = name.toLowerCase(), orig = { innerWidth: $.fn.innerWidth, innerHeight: $.fn.innerHeight, outerWidth: $.fn.outerWidth, outerHeight: $.fn.outerHeight }; function reduce( elem, size, border, margin ) { $.each( side, function() { size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; if ( border ) { size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; } if ( margin ) { size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; } }); return size; } $.fn[ "inner" + name ] = function( size ) { if ( size === undefined ) { return orig[ "inner" + name ].call( this ); } return this.each(function() { $( this ).css( type, reduce( this, size ) + "px" ); }); }; $.fn[ "outer" + name] = function( size, margin ) { if ( typeof size !== "number" ) { return orig[ "outer" + name ].call( this, size ); } return this.each(function() { $( this).css( type, reduce( this, size, true, margin ) + "px" ); }); }; }); } // support: jQuery <1.8 if ( !$.fn.addBack ) { $.fn.addBack = function( selector ) { return this.add( selector == null ? this.prevObject : this.prevObject.filter( selector ) ); }; } // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { $.fn.removeData = (function( removeData ) { return function( key ) { if ( arguments.length ) { return removeData.call( this, $.camelCase( key ) ); } else { return removeData.call( this ); } }; })( $.fn.removeData ); } // deprecated $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); $.support.selectstart = "onselectstart" in document.createElement( "div" ); $.fn.extend({ disableSelection: function() { return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + ".ui-disableSelection", function( event ) { event.preventDefault(); }); }, enableSelection: function() { return this.unbind( ".ui-disableSelection" ); } }); $.extend( $.ui, { // $.ui.plugin is deprecated. Use the proxy pattern instead. plugin: { add: function( module, option, set ) { var i, proto = $.ui[ module ].prototype; for ( i in set ) { proto.plugins[ i ] = proto.plugins[ i ] || []; proto.plugins[ i ].push( [ option, set[ i ] ] ); } }, call: function( instance, name, args ) { var i, set = instance.plugins[ name ]; if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { return; } for ( i = 0; i < set.length; i++ ) { if ( instance.options[ set[ i ][ 0 ] ] ) { set[ i ][ 1 ].apply( instance.element, args ); } } } }, // only used by resizable hasScroll: function( el, a ) { //If overflow is hidden, the element might have extra content, but the user wants to hide it if ( $( el ).css( "overflow" ) === "hidden") { return false; } var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", has = false; if ( el[ scroll ] > 0 ) { return true; } // TODO: determine which cases actually cause this to happen // if the element doesn't have the scroll set, see if it's possible to // set the scroll el[ scroll ] = 1; has = ( el[ scroll ] > 0 ); el[ scroll ] = 0; return has; } }); })( jQuery ); (function( $, undefined ) { var uuid = 0, slice = Array.prototype.slice, _cleanData = $.cleanData; $.cleanData = function( elems ) { for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { try { $( elem ).triggerHandler( "remove" ); // http://bugs.jquery.com/ticket/8235 } catch( e ) {} } _cleanData( elems ); }; $.widget = function( name, base, prototype ) { var fullName, existingConstructor, constructor, basePrototype, // proxiedPrototype allows the provided prototype to remain unmodified // so that it can be used as a mixin for multiple widgets (#8876) proxiedPrototype = {}, namespace = name.split( "." )[ 0 ]; name = name.split( "." )[ 1 ]; fullName = namespace + "-" + name; if ( !prototype ) { prototype = base; base = $.Widget; } // create selector for plugin $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { return !!$.data( elem, fullName ); }; $[ namespace ] = $[ namespace ] || {}; existingConstructor = $[ namespace ][ name ]; constructor = $[ namespace ][ name ] = function( options, element ) { // allow instantiation without "new" keyword if ( !this._createWidget ) { return new constructor( options, element ); } // allow instantiation without initializing for simple inheritance // must use "new" keyword (the code above always passes args) if ( arguments.length ) { this._createWidget( options, element ); } }; // extend with the existing constructor to carry over any static properties $.extend( constructor, existingConstructor, { version: prototype.version, // copy the object used to create the prototype in case we need to // redefine the widget later _proto: $.extend( {}, prototype ), // track widgets that inherit from this widget in case this widget is // redefined after a widget inherits from it _childConstructors: [] }); basePrototype = new base(); // we need to make the options hash a property directly on the new instance // otherwise we'll modify the options hash on the prototype that we're // inheriting from basePrototype.options = $.widget.extend( {}, basePrototype.options ); $.each( prototype, function( prop, value ) { if ( !$.isFunction( value ) ) { proxiedPrototype[ prop ] = value; return; } proxiedPrototype[ prop ] = (function() { var _super = function() { return base.prototype[ prop ].apply( this, arguments ); }, _superApply = function( args ) { return base.prototype[ prop ].apply( this, args ); }; return function() { var __super = this._super, __superApply = this._superApply, returnValue; this._super = _super; this._superApply = _superApply; returnValue = value.apply( this, arguments ); this._super = __super; this._superApply = __superApply; return returnValue; }; })(); }); constructor.prototype = $.widget.extend( basePrototype, { // TODO: remove support for widgetEventPrefix // always use the name + a colon as the prefix, e.g., draggable:start // don't prefix for widgets that aren't DOM-based widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name }, proxiedPrototype, { constructor: constructor, namespace: namespace, widgetName: name, widgetFullName: fullName }); // If this widget is being redefined then we need to find all widgets that // are inheriting from it and redefine all of them so that they inherit from // the new version of this widget. We're essentially trying to replace one // level in the prototype chain. if ( existingConstructor ) { $.each( existingConstructor._childConstructors, function( i, child ) { var childPrototype = child.prototype; // redefine the child widget using the same prototype that was // originally used, but inherit from the new version of the base $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); }); // remove the list of existing child constructors from the old constructor // so the old child constructors can be garbage collected delete existingConstructor._childConstructors; } else { base._childConstructors.push( constructor ); } $.widget.bridge( name, constructor ); }; $.widget.extend = function( target ) { var input = slice.call( arguments, 1 ), inputIndex = 0, inputLength = input.length, key, value; for ( ; inputIndex < inputLength; inputIndex++ ) { for ( key in input[ inputIndex ] ) { value = input[ inputIndex ][ key ]; if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { // Clone objects if ( $.isPlainObject( value ) ) { target[ key ] = $.isPlainObject( target[ key ] ) ? $.widget.extend( {}, target[ key ], value ) : // Don't extend strings, arrays, etc. with objects $.widget.extend( {}, value ); // Copy everything else by reference } else { target[ key ] = value; } } } } return target; }; $.widget.bridge = function( name, object ) { var fullName = object.prototype.widgetFullName || name; $.fn[ name ] = function( options ) { var isMethodCall = typeof options === "string", args = slice.call( arguments, 1 ), returnValue = this; // allow multiple hashes to be passed on init options = !isMethodCall && args.length ? $.widget.extend.apply( null, [ options ].concat(args) ) : options; if ( isMethodCall ) { this.each(function() { var methodValue, instance = $.data( this, fullName ); if ( !instance ) { return $.error( "cannot call methods on " + name + " prior to initialization; " + "attempted to call method '" + options + "'" ); } if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { return $.error( "no such method '" + options + "' for " + name + " widget instance" ); } methodValue = instance[ options ].apply( instance, args ); if ( methodValue !== instance && methodValue !== undefined ) { returnValue = methodValue && methodValue.jquery ? returnValue.pushStack( methodValue.get() ) : methodValue; return false; } }); } else { this.each(function() { var instance = $.data( this, fullName ); if ( instance ) { instance.option( options || {} )._init(); } else { $.data( this, fullName, new object( options, this ) ); } }); } return returnValue; }; }; $.Widget = function( /* options, element */ ) {}; $.Widget._childConstructors = []; $.Widget.prototype = { widgetName: "widget", widgetEventPrefix: "", defaultElement: "
    ", options: { disabled: false, // callbacks create: null }, _createWidget: function( options, element ) { element = $( element || this.defaultElement || this )[ 0 ]; this.element = $( element ); this.uuid = uuid++; this.eventNamespace = "." + this.widgetName + this.uuid; this.options = $.widget.extend( {}, this.options, this._getCreateOptions(), options ); this.bindings = $(); this.hoverable = $(); this.focusable = $(); if ( element !== this ) { $.data( element, this.widgetFullName, this ); this._on( true, this.element, { remove: function( event ) { if ( event.target === element ) { this.destroy(); } } }); this.document = $( element.style ? // element within the document element.ownerDocument : // element is window or document element.document || element ); this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); } this._create(); this._trigger( "create", null, this._getCreateEventData() ); this._init(); }, _getCreateOptions: $.noop, _getCreateEventData: $.noop, _create: $.noop, _init: $.noop, destroy: function() { this._destroy(); // we can probably remove the unbind calls in 2.0 // all event bindings should go through this._on() this.element .unbind( this.eventNamespace ) // 1.9 BC for #7810 // TODO remove dual storage .removeData( this.widgetName ) .removeData( this.widgetFullName ) // support: jquery <1.6.3 // http://bugs.jquery.com/ticket/9413 .removeData( $.camelCase( this.widgetFullName ) ); this.widget() .unbind( this.eventNamespace ) .removeAttr( "aria-disabled" ) .removeClass( this.widgetFullName + "-disabled " + "ui-state-disabled" ); // clean up events and states this.bindings.unbind( this.eventNamespace ); this.hoverable.removeClass( "ui-state-hover" ); this.focusable.removeClass( "ui-state-focus" ); }, _destroy: $.noop, widget: function() { return this.element; }, option: function( key, value ) { var options = key, parts, curOption, i; if ( arguments.length === 0 ) { // don't return a reference to the internal hash return $.widget.extend( {}, this.options ); } if ( typeof key === "string" ) { // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } options = {}; parts = key.split( "." ); key = parts.shift(); if ( parts.length ) { curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); for ( i = 0; i < parts.length - 1; i++ ) { curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; curOption = curOption[ parts[ i ] ]; } key = parts.pop(); if ( value === undefined ) { return curOption[ key ] === undefined ? null : curOption[ key ]; } curOption[ key ] = value; } else { if ( value === undefined ) { return this.options[ key ] === undefined ? null : this.options[ key ]; } options[ key ] = value; } } this._setOptions( options ); return this; }, _setOptions: function( options ) { var key; for ( key in options ) { this._setOption( key, options[ key ] ); } return this; }, _setOption: function( key, value ) { this.options[ key ] = value; if ( key === "disabled" ) { this.widget() .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) .attr( "aria-disabled", value ); this.hoverable.removeClass( "ui-state-hover" ); this.focusable.removeClass( "ui-state-focus" ); } return this; }, enable: function() { return this._setOption( "disabled", false ); }, disable: function() { return this._setOption( "disabled", true ); }, _on: function( suppressDisabledCheck, element, handlers ) { var delegateElement, instance = this; // no suppressDisabledCheck flag, shuffle arguments if ( typeof suppressDisabledCheck !== "boolean" ) { handlers = element; element = suppressDisabledCheck; suppressDisabledCheck = false; } // no element argument, shuffle and use this.element if ( !handlers ) { handlers = element; element = this.element; delegateElement = this.widget(); } else { // accept selectors, DOM elements element = delegateElement = $( element ); this.bindings = this.bindings.add( element ); } $.each( handlers, function( event, handler ) { function handlerProxy() { // allow widgets to customize the disabled handling // - disabled as an array instead of boolean // - disabled class as method for disabling individual parts if ( !suppressDisabledCheck && ( instance.options.disabled === true || $( this ).hasClass( "ui-state-disabled" ) ) ) { return; } return ( typeof handler === "string" ? instance[ handler ] : handler ) .apply( instance, arguments ); } // copy the guid so direct unbinding works if ( typeof handler !== "string" ) { handlerProxy.guid = handler.guid = handler.guid || handlerProxy.guid || $.guid++; } var match = event.match( /^(\w+)\s*(.*)$/ ), eventName = match[1] + instance.eventNamespace, selector = match[2]; if ( selector ) { delegateElement.delegate( selector, eventName, handlerProxy ); } else { element.bind( eventName, handlerProxy ); } }); }, _off: function( element, eventName ) { eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; element.unbind( eventName ).undelegate( eventName ); }, _delay: function( handler, delay ) { function handlerProxy() { return ( typeof handler === "string" ? instance[ handler ] : handler ) .apply( instance, arguments ); } var instance = this; return setTimeout( handlerProxy, delay || 0 ); }, _hoverable: function( element ) { this.hoverable = this.hoverable.add( element ); this._on( element, { mouseenter: function( event ) { $( event.currentTarget ).addClass( "ui-state-hover" ); }, mouseleave: function( event ) { $( event.currentTarget ).removeClass( "ui-state-hover" ); } }); }, _focusable: function( element ) { this.focusable = this.focusable.add( element ); this._on( element, { focusin: function( event ) { $( event.currentTarget ).addClass( "ui-state-focus" ); }, focusout: function( event ) { $( event.currentTarget ).removeClass( "ui-state-focus" ); } }); }, _trigger: function( type, event, data ) { var prop, orig, callback = this.options[ type ]; data = data || {}; event = $.Event( event ); event.type = ( type === this.widgetEventPrefix ? type : this.widgetEventPrefix + type ).toLowerCase(); // the original event may come from any element // so we need to reset the target on the new event event.target = this.element[ 0 ]; // copy original event properties over to the new event orig = event.originalEvent; if ( orig ) { for ( prop in orig ) { if ( !( prop in event ) ) { event[ prop ] = orig[ prop ]; } } } this.element.trigger( event, data ); return !( $.isFunction( callback ) && callback.apply( this.element[0], [ event ].concat( data ) ) === false || event.isDefaultPrevented() ); } }; $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { if ( typeof options === "string" ) { options = { effect: options }; } var hasOptions, effectName = !options ? method : options === true || typeof options === "number" ? defaultEffect : options.effect || defaultEffect; options = options || {}; if ( typeof options === "number" ) { options = { duration: options }; } hasOptions = !$.isEmptyObject( options ); options.complete = callback; if ( options.delay ) { element.delay( options.delay ); } if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { element[ method ]( options ); } else if ( effectName !== method && element[ effectName ] ) { element[ effectName ]( options.duration, options.easing, callback ); } else { element.queue(function( next ) { $( this )[ method ](); if ( callback ) { callback.call( element[ 0 ] ); } next(); }); } }; }); })( jQuery ); (function( $, undefined ) { var mouseHandled = false; $( document ).mouseup( function() { mouseHandled = false; }); $.widget("ui.mouse", { version: "1.10.2", options: { cancel: "input,textarea,button,select,option", distance: 1, delay: 0 }, _mouseInit: function() { var that = this; this.element .bind("mousedown."+this.widgetName, function(event) { return that._mouseDown(event); }) .bind("click."+this.widgetName, function(event) { if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { $.removeData(event.target, that.widgetName + ".preventClickEvent"); event.stopImmediatePropagation(); return false; } }); this.started = false; }, // TODO: make sure destroying one instance of mouse doesn't mess with // other instances of mouse _mouseDestroy: function() { this.element.unbind("."+this.widgetName); if ( this._mouseMoveDelegate ) { $(document) .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); } }, _mouseDown: function(event) { // don't let more than one widget handle mouseStart if( mouseHandled ) { return; } // we may have missed mouseup (out of window) (this._mouseStarted && this._mouseUp(event)); this._mouseDownEvent = event; var that = this, btnIsLeft = (event.which === 1), // event.target.nodeName works around a bug in IE 8 with // disabled inputs (#7620) elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { return true; } this.mouseDelayMet = !this.options.delay; if (!this.mouseDelayMet) { this._mouseDelayTimer = setTimeout(function() { that.mouseDelayMet = true; }, this.options.delay); } if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { this._mouseStarted = (this._mouseStart(event) !== false); if (!this._mouseStarted) { event.preventDefault(); return true; } } // Click event may never have fired (Gecko & Opera) if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { $.removeData(event.target, this.widgetName + ".preventClickEvent"); } // these delegates are required to keep context this._mouseMoveDelegate = function(event) { return that._mouseMove(event); }; this._mouseUpDelegate = function(event) { return that._mouseUp(event); }; $(document) .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) .bind("mouseup."+this.widgetName, this._mouseUpDelegate); event.preventDefault(); mouseHandled = true; return true; }, _mouseMove: function(event) { // IE mouseup check - mouseup happened when mouse was out of window if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { return this._mouseUp(event); } if (this._mouseStarted) { this._mouseDrag(event); return event.preventDefault(); } if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { this._mouseStarted = (this._mouseStart(this._mouseDownEvent, event) !== false); (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); } return !this._mouseStarted; }, _mouseUp: function(event) { $(document) .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); if (this._mouseStarted) { this._mouseStarted = false; if (event.target === this._mouseDownEvent.target) { $.data(event.target, this.widgetName + ".preventClickEvent", true); } this._mouseStop(event); } return false; }, _mouseDistanceMet: function(event) { return (Math.max( Math.abs(this._mouseDownEvent.pageX - event.pageX), Math.abs(this._mouseDownEvent.pageY - event.pageY) ) >= this.options.distance ); }, _mouseDelayMet: function(/* event */) { return this.mouseDelayMet; }, // These are placeholder methods, to be overriden by extending plugin _mouseStart: function(/* event */) {}, _mouseDrag: function(/* event */) {}, _mouseStop: function(/* event */) {}, _mouseCapture: function(/* event */) { return true; } }); })(jQuery); (function( $, undefined ) { $.widget("ui.draggable", $.ui.mouse, { version: "1.10.2", widgetEventPrefix: "drag", options: { addClasses: true, appendTo: "parent", axis: false, connectToSortable: false, containment: false, cursor: "auto", cursorAt: false, grid: false, handle: false, helper: "original", iframeFix: false, opacity: false, refreshPositions: false, revert: false, revertDuration: 500, scope: "default", scroll: true, scrollSensitivity: 20, scrollSpeed: 20, snap: false, snapMode: "both", snapTolerance: 20, stack: false, zIndex: false, // callbacks drag: null, start: null, stop: null }, _create: function() { if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) { this.element[0].style.position = "relative"; } if (this.options.addClasses){ this.element.addClass("ui-draggable"); } if (this.options.disabled){ this.element.addClass("ui-draggable-disabled"); } this._mouseInit(); }, _destroy: function() { this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); this._mouseDestroy(); }, _mouseCapture: function(event) { var o = this.options; // among others, prevent a drag on a resizable-handle if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { return false; } //Quit if we're not on a valid handle this.handle = this._getHandle(event); if (!this.handle) { return false; } $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { $("
    ") .css({ width: this.offsetWidth+"px", height: this.offsetHeight+"px", position: "absolute", opacity: "0.001", zIndex: 1000 }) .css($(this).offset()) .appendTo("body"); }); return true; }, _mouseStart: function(event) { var o = this.options; //Create and append the visible helper this.helper = this._createHelper(event); this.helper.addClass("ui-draggable-dragging"); //Cache the helper size this._cacheHelperProportions(); //If ddmanager is used for droppables, set the global draggable if($.ui.ddmanager) { $.ui.ddmanager.current = this; } /* * - Position generation - * This block generates everything position related - it's the core of draggables. */ //Cache the margins of the original element this._cacheMargins(); //Store the helper's css position this.cssPosition = this.helper.css("position"); this.scrollParent = this.helper.scrollParent(); //The element's absolute position on the page minus margins this.offset = this.positionAbs = this.element.offset(); this.offset = { top: this.offset.top - this.margins.top, left: this.offset.left - this.margins.left }; $.extend(this.offset, { click: { //Where the click happened, relative to the element left: event.pageX - this.offset.left, top: event.pageY - this.offset.top }, parent: this._getParentOffset(), relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper }); //Generate the original position this.originalPosition = this.position = this._generatePosition(event); this.originalPageX = event.pageX; this.originalPageY = event.pageY; //Adjust the mouse offset relative to the helper if "cursorAt" is supplied (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); //Set a containment if given in the options if(o.containment) { this._setContainment(); } //Trigger event + callbacks if(this._trigger("start", event) === false) { this._clear(); return false; } //Recache the helper size this._cacheHelperProportions(); //Prepare the droppable offsets if ($.ui.ddmanager && !o.dropBehaviour) { $.ui.ddmanager.prepareOffsets(this, event); } this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) if ( $.ui.ddmanager ) { $.ui.ddmanager.dragStart(this, event); } return true; }, _mouseDrag: function(event, noPropagation) { //Compute the helpers position this.position = this._generatePosition(event); this.positionAbs = this._convertPositionTo("absolute"); //Call plugins and callbacks and use the resulting position if something is returned if (!noPropagation) { var ui = this._uiHash(); if(this._trigger("drag", event, ui) === false) { this._mouseUp({}); return false; } this.position = ui.position; } if(!this.options.axis || this.options.axis !== "y") { this.helper[0].style.left = this.position.left+"px"; } if(!this.options.axis || this.options.axis !== "x") { this.helper[0].style.top = this.position.top+"px"; } if($.ui.ddmanager) { $.ui.ddmanager.drag(this, event); } return false; }, _mouseStop: function(event) { //If we are using droppables, inform the manager about the drop var element, that = this, elementInDom = false, dropped = false; if ($.ui.ddmanager && !this.options.dropBehaviour) { dropped = $.ui.ddmanager.drop(this, event); } //if a drop comes from outside (a sortable) if(this.dropped) { dropped = this.dropped; this.dropped = false; } //if the original element is no longer in the DOM don't bother to continue (see #8269) element = this.element[0]; while ( element && (element = element.parentNode) ) { if (element === document ) { elementInDom = true; } } if ( !elementInDom && this.options.helper === "original" ) { return false; } if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { if(that._trigger("stop", event) !== false) { that._clear(); } }); } else { if(this._trigger("stop", event) !== false) { this._clear(); } } return false; }, _mouseUp: function(event) { //Remove frame helpers $("div.ui-draggable-iframeFix").each(function() { this.parentNode.removeChild(this); }); //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) if( $.ui.ddmanager ) { $.ui.ddmanager.dragStop(this, event); } return $.ui.mouse.prototype._mouseUp.call(this, event); }, cancel: function() { if(this.helper.is(".ui-draggable-dragging")) { this._mouseUp({}); } else { this._clear(); } return this; }, _getHandle: function(event) { return this.options.handle ? !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : true; }, _createHelper: function(event) { var o = this.options, helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element); if(!helper.parents("body").length) { helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); } if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { helper.css("position", "absolute"); } return helper; }, _adjustOffsetFromHelper: function(obj) { if (typeof obj === "string") { obj = obj.split(" "); } if ($.isArray(obj)) { obj = {left: +obj[0], top: +obj[1] || 0}; } if ("left" in obj) { this.offset.click.left = obj.left + this.margins.left; } if ("right" in obj) { this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; } if ("top" in obj) { this.offset.click.top = obj.top + this.margins.top; } if ("bottom" in obj) { this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; } }, _getParentOffset: function() { //Get the offsetParent and cache its position this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset(); // This is a special case where we need to modify a offset calculated on start, since the following happened: // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { po.left += this.scrollParent.scrollLeft(); po.top += this.scrollParent.scrollTop(); } //This needs to be actually done for all browsers, since pageX/pageY includes this information //Ugly IE fix if((this.offsetParent[0] === document.body) || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { po = { top: 0, left: 0 }; } return { top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) }; }, _getRelativeOffset: function() { if(this.cssPosition === "relative") { var p = this.element.position(); return { top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() }; } else { return { top: 0, left: 0 }; } }, _cacheMargins: function() { this.margins = { left: (parseInt(this.element.css("marginLeft"),10) || 0), top: (parseInt(this.element.css("marginTop"),10) || 0), right: (parseInt(this.element.css("marginRight"),10) || 0), bottom: (parseInt(this.element.css("marginBottom"),10) || 0) }; }, _cacheHelperProportions: function() { this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; }, _setContainment: function() { var over, c, ce, o = this.options; if(o.containment === "parent") { o.containment = this.helper[0].parentNode; } if(o.containment === "document" || o.containment === "window") { this.containment = [ o.containment === "document" ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left, o.containment === "document" ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top, (o.containment === "document" ? 0 : $(window).scrollLeft()) + $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, (o.containment === "document" ? 0 : $(window).scrollTop()) + ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top ]; } if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor !== Array) { c = $(o.containment); ce = c[0]; if(!ce) { return; } over = ($(ce).css("overflow") !== "hidden"); this.containment = [ (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0), (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0), (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderRightWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right, (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderBottomWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom ]; this.relative_container = c; } else if(o.containment.constructor === Array) { this.containment = o.containment; } }, _convertPositionTo: function(d, pos) { if(!pos) { pos = this.position; } var mod = d === "absolute" ? 1 : -1, scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); return { top: ( pos.top + // The absolute mouse position this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) ), left: ( pos.left + // The absolute mouse position this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) ) }; }, _generatePosition: function(event) { var containment, co, top, left, o = this.options, scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName), pageX = event.pageX, pageY = event.pageY; /* * - Position constraining - * Constrain the position to a mix of grid, containment. */ if(this.originalPosition) { //If we are not dragging yet, we won't check for options if(this.containment) { if (this.relative_container){ co = this.relative_container.offset(); containment = [ this.containment[0] + co.left, this.containment[1] + co.top, this.containment[2] + co.left, this.containment[3] + co.top ]; } else { containment = this.containment; } if(event.pageX - this.offset.click.left < containment[0]) { pageX = containment[0] + this.offset.click.left; } if(event.pageY - this.offset.click.top < containment[1]) { pageY = containment[1] + this.offset.click.top; } if(event.pageX - this.offset.click.left > containment[2]) { pageX = containment[2] + this.offset.click.left; } if(event.pageY - this.offset.click.top > containment[3]) { pageY = containment[3] + this.offset.click.top; } } if(o.grid) { //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; } } return { top: ( pageY - // The absolute mouse position this.offset.click.top - // Click offset (relative to the element) this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent this.offset.parent.top + // The offsetParent's offset without borders (offset + border) ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) ), left: ( pageX - // The absolute mouse position this.offset.click.left - // Click offset (relative to the element) this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent this.offset.parent.left + // The offsetParent's offset without borders (offset + border) ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) ) }; }, _clear: function() { this.helper.removeClass("ui-draggable-dragging"); if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { this.helper.remove(); } this.helper = null; this.cancelHelperRemoval = false; }, // From now on bulk stuff - mainly helpers _trigger: function(type, event, ui) { ui = ui || this._uiHash(); $.ui.plugin.call(this, type, [event, ui]); //The absolute position has to be recalculated after plugins if(type === "drag") { this.positionAbs = this._convertPositionTo("absolute"); } return $.Widget.prototype._trigger.call(this, type, event, ui); }, plugins: {}, _uiHash: function() { return { helper: this.helper, position: this.position, originalPosition: this.originalPosition, offset: this.positionAbs }; } }); $.ui.plugin.add("draggable", "connectToSortable", { start: function(event, ui) { var inst = $(this).data("ui-draggable"), o = inst.options, uiSortable = $.extend({}, ui, { item: inst.element }); inst.sortables = []; $(o.connectToSortable).each(function() { var sortable = $.data(this, "ui-sortable"); if (sortable && !sortable.options.disabled) { inst.sortables.push({ instance: sortable, shouldRevert: sortable.options.revert }); sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). sortable._trigger("activate", event, uiSortable); } }); }, stop: function(event, ui) { //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper var inst = $(this).data("ui-draggable"), uiSortable = $.extend({}, ui, { item: inst.element }); $.each(inst.sortables, function() { if(this.instance.isOver) { this.instance.isOver = 0; inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid" if(this.shouldRevert) { this.instance.options.revert = this.shouldRevert; } //Trigger the stop of the sortable this.instance._mouseStop(event); this.instance.options.helper = this.instance.options._helper; //If the helper has been the original item, restore properties in the sortable if(inst.options.helper === "original") { this.instance.currentItem.css({ top: "auto", left: "auto" }); } } else { this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance this.instance._trigger("deactivate", event, uiSortable); } }); }, drag: function(event, ui) { var inst = $(this).data("ui-draggable"), that = this; $.each(inst.sortables, function() { var innermostIntersecting = false, thisSortable = this; //Copy over some variables to allow calling the sortable's native _intersectsWith this.instance.positionAbs = inst.positionAbs; this.instance.helperProportions = inst.helperProportions; this.instance.offset.click = inst.offset.click; if(this.instance._intersectsWith(this.instance.containerCache)) { innermostIntersecting = true; $.each(inst.sortables, function () { this.instance.positionAbs = inst.positionAbs; this.instance.helperProportions = inst.helperProportions; this.instance.offset.click = inst.offset.click; if (this !== thisSortable && this.instance._intersectsWith(this.instance.containerCache) && $.contains(thisSortable.instance.element[0], this.instance.element[0]) ) { innermostIntersecting = false; } return innermostIntersecting; }); } if(innermostIntersecting) { //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once if(!this.instance.isOver) { this.instance.isOver = 1; //Now we fake the start of dragging for the sortable instance, //by cloning the list group item, appending it to the sortable and using it as inst.currentItem //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true); this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it this.instance.options.helper = function() { return ui.helper[0]; }; event.target = this.instance.currentItem[0]; this.instance._mouseCapture(event, true); this.instance._mouseStart(event, true, true); //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes this.instance.offset.click.top = inst.offset.click.top; this.instance.offset.click.left = inst.offset.click.left; this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; inst._trigger("toSortable", event); inst.dropped = this.instance.element; //draggable revert needs that //hack so receive/update callbacks work (mostly) inst.currentItem = inst.element; this.instance.fromOutside = inst; } //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable if(this.instance.currentItem) { this.instance._mouseDrag(event); } } else { //If it doesn't intersect with the sortable, and it intersected before, //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval if(this.instance.isOver) { this.instance.isOver = 0; this.instance.cancelHelperRemoval = true; //Prevent reverting on this forced stop this.instance.options.revert = false; // The out event needs to be triggered independently this.instance._trigger("out", event, this.instance._uiHash(this.instance)); this.instance._mouseStop(event, true); this.instance.options.helper = this.instance.options._helper; //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size this.instance.currentItem.remove(); if(this.instance.placeholder) { this.instance.placeholder.remove(); } inst._trigger("fromSortable", event); inst.dropped = false; //draggable revert needs that } } }); } }); $.ui.plugin.add("draggable", "cursor", { start: function() { var t = $("body"), o = $(this).data("ui-draggable").options; if (t.css("cursor")) { o._cursor = t.css("cursor"); } t.css("cursor", o.cursor); }, stop: function() { var o = $(this).data("ui-draggable").options; if (o._cursor) { $("body").css("cursor", o._cursor); } } }); $.ui.plugin.add("draggable", "opacity", { start: function(event, ui) { var t = $(ui.helper), o = $(this).data("ui-draggable").options; if(t.css("opacity")) { o._opacity = t.css("opacity"); } t.css("opacity", o.opacity); }, stop: function(event, ui) { var o = $(this).data("ui-draggable").options; if(o._opacity) { $(ui.helper).css("opacity", o._opacity); } } }); $.ui.plugin.add("draggable", "scroll", { start: function() { var i = $(this).data("ui-draggable"); if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { i.overflowOffset = i.scrollParent.offset(); } }, drag: function( event ) { var i = $(this).data("ui-draggable"), o = i.options, scrolled = false; if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { if(!o.axis || o.axis !== "x") { if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) { i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; } } if(!o.axis || o.axis !== "y") { if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) { i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; } } } else { if(!o.axis || o.axis !== "x") { if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); } } if(!o.axis || o.axis !== "y") { if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); } } } if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { $.ui.ddmanager.prepareOffsets(i, event); } } }); $.ui.plugin.add("draggable", "snap", { start: function() { var i = $(this).data("ui-draggable"), o = i.options; i.snapElements = []; $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { var $t = $(this), $o = $t.offset(); if(this !== i.element[0]) { i.snapElements.push({ item: this, width: $t.outerWidth(), height: $t.outerHeight(), top: $o.top, left: $o.left }); } }); }, drag: function(event, ui) { var ts, bs, ls, rs, l, r, t, b, i, first, inst = $(this).data("ui-draggable"), o = inst.options, d = o.snapTolerance, x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; for (i = inst.snapElements.length - 1; i >= 0; i--){ l = inst.snapElements[i].left; r = l + inst.snapElements[i].width; t = inst.snapElements[i].top; b = t + inst.snapElements[i].height; //Yes, I know, this is insane ;) if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) { if(inst.snapElements[i].snapping) { (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); } inst.snapElements[i].snapping = false; continue; } if(o.snapMode !== "inner") { ts = Math.abs(t - y2) <= d; bs = Math.abs(b - y1) <= d; ls = Math.abs(l - x2) <= d; rs = Math.abs(r - x1) <= d; if(ts) { ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; } if(bs) { ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; } if(ls) { ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; } if(rs) { ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; } } first = (ts || bs || ls || rs); if(o.snapMode !== "outer") { ts = Math.abs(t - y1) <= d; bs = Math.abs(b - y2) <= d; ls = Math.abs(l - x1) <= d; rs = Math.abs(r - x2) <= d; if(ts) { ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; } if(bs) { ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; } if(ls) { ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; } if(rs) { ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; } } if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); } inst.snapElements[i].snapping = (ts || bs || ls || rs || first); } } }); $.ui.plugin.add("draggable", "stack", { start: function() { var min, o = this.data("ui-draggable").options, group = $.makeArray($(o.stack)).sort(function(a,b) { return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); }); if (!group.length) { return; } min = parseInt($(group[0]).css("zIndex"), 10) || 0; $(group).each(function(i) { $(this).css("zIndex", min + i); }); this.css("zIndex", (min + group.length)); } }); $.ui.plugin.add("draggable", "zIndex", { start: function(event, ui) { var t = $(ui.helper), o = $(this).data("ui-draggable").options; if(t.css("zIndex")) { o._zIndex = t.css("zIndex"); } t.css("zIndex", o.zIndex); }, stop: function(event, ui) { var o = $(this).data("ui-draggable").options; if(o._zIndex) { $(ui.helper).css("zIndex", o._zIndex); } } }); })(jQuery); (function( $, undefined ) { function isOverAxis( x, reference, size ) { return ( x > reference ) && ( x < ( reference + size ) ); } $.widget("ui.droppable", { version: "1.10.2", widgetEventPrefix: "drop", options: { accept: "*", activeClass: false, addClasses: true, greedy: false, hoverClass: false, scope: "default", tolerance: "intersect", // callbacks activate: null, deactivate: null, drop: null, out: null, over: null }, _create: function() { var o = this.options, accept = o.accept; this.isover = false; this.isout = true; this.accept = $.isFunction(accept) ? accept : function(d) { return d.is(accept); }; //Store the droppable's proportions this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; // Add the reference and positions to the manager $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || []; $.ui.ddmanager.droppables[o.scope].push(this); (o.addClasses && this.element.addClass("ui-droppable")); }, _destroy: function() { var i = 0, drop = $.ui.ddmanager.droppables[this.options.scope]; for ( ; i < drop.length; i++ ) { if ( drop[i] === this ) { drop.splice(i, 1); } } this.element.removeClass("ui-droppable ui-droppable-disabled"); }, _setOption: function(key, value) { if(key === "accept") { this.accept = $.isFunction(value) ? value : function(d) { return d.is(value); }; } $.Widget.prototype._setOption.apply(this, arguments); }, _activate: function(event) { var draggable = $.ui.ddmanager.current; if(this.options.activeClass) { this.element.addClass(this.options.activeClass); } if(draggable){ this._trigger("activate", event, this.ui(draggable)); } }, _deactivate: function(event) { var draggable = $.ui.ddmanager.current; if(this.options.activeClass) { this.element.removeClass(this.options.activeClass); } if(draggable){ this._trigger("deactivate", event, this.ui(draggable)); } }, _over: function(event) { var draggable = $.ui.ddmanager.current; // Bail if draggable and droppable are same element if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { return; } if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { if(this.options.hoverClass) { this.element.addClass(this.options.hoverClass); } this._trigger("over", event, this.ui(draggable)); } }, _out: function(event) { var draggable = $.ui.ddmanager.current; // Bail if draggable and droppable are same element if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { return; } if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { if(this.options.hoverClass) { this.element.removeClass(this.options.hoverClass); } this._trigger("out", event, this.ui(draggable)); } }, _drop: function(event,custom) { var draggable = custom || $.ui.ddmanager.current, childrenIntersection = false; // Bail if draggable and droppable are same element if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { return false; } this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() { var inst = $.data(this, "ui-droppable"); if( inst.options.greedy && !inst.options.disabled && inst.options.scope === draggable.options.scope && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) ) { childrenIntersection = true; return false; } }); if(childrenIntersection) { return false; } if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { if(this.options.activeClass) { this.element.removeClass(this.options.activeClass); } if(this.options.hoverClass) { this.element.removeClass(this.options.hoverClass); } this._trigger("drop", event, this.ui(draggable)); return this.element; } return false; }, ui: function(c) { return { draggable: (c.currentItem || c.element), helper: c.helper, position: c.position, offset: c.positionAbs }; } }); $.ui.intersect = function(draggable, droppable, toleranceMode) { if (!droppable.offset) { return false; } var draggableLeft, draggableTop, x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height, l = droppable.offset.left, r = l + droppable.proportions.width, t = droppable.offset.top, b = t + droppable.proportions.height; switch (toleranceMode) { case "fit": return (l <= x1 && x2 <= r && t <= y1 && y2 <= b); case "intersect": return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half x2 - (draggable.helperProportions.width / 2) < r && // Left Half t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half y2 - (draggable.helperProportions.height / 2) < b ); // Top Half case "pointer": draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left); draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top); return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width ); case "touch": return ( (y1 >= t && y1 <= b) || // Top edge touching (y2 >= t && y2 <= b) || // Bottom edge touching (y1 < t && y2 > b) // Surrounded vertically ) && ( (x1 >= l && x1 <= r) || // Left edge touching (x2 >= l && x2 <= r) || // Right edge touching (x1 < l && x2 > r) // Surrounded horizontally ); default: return false; } }; /* This manager tracks offsets of draggables and droppables */ $.ui.ddmanager = { current: null, droppables: { "default": [] }, prepareOffsets: function(t, event) { var i, j, m = $.ui.ddmanager.droppables[t.options.scope] || [], type = event ? event.type : null, // workaround for #2317 list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack(); droppablesLoop: for (i = 0; i < m.length; i++) { //No disabled and non-accepted if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) { continue; } // Filter out elements in the current dragged item for (j=0; j < list.length; j++) { if(list[j] === m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } } m[i].visible = m[i].element.css("display") !== "none"; if(!m[i].visible) { continue; } //Activate the droppable if used directly from draggables if(type === "mousedown") { m[i]._activate.call(m[i], event); } m[i].offset = m[i].element.offset(); m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; } }, drop: function(draggable, event) { var dropped = false; // Create a copy of the droppables in case the list changes during the drop (#9116) $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() { if(!this.options) { return; } if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) { dropped = this._drop.call(this, event) || dropped; } if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { this.isout = true; this.isover = false; this._deactivate.call(this, event); } }); return dropped; }, dragStart: function( draggable, event ) { //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { if( !draggable.options.refreshPositions ) { $.ui.ddmanager.prepareOffsets( draggable, event ); } }); }, drag: function(draggable, event) { //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. if(draggable.options.refreshPositions) { $.ui.ddmanager.prepareOffsets(draggable, event); } //Run through all droppables and check their positions based on specific tolerance options $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { if(this.options.disabled || this.greedyChild || !this.visible) { return; } var parentInstance, scope, parent, intersects = $.ui.intersect(draggable, this, this.options.tolerance), c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null); if(!c) { return; } if (this.options.greedy) { // find droppable parents with same scope scope = this.options.scope; parent = this.element.parents(":data(ui-droppable)").filter(function () { return $.data(this, "ui-droppable").options.scope === scope; }); if (parent.length) { parentInstance = $.data(parent[0], "ui-droppable"); parentInstance.greedyChild = (c === "isover"); } } // we just moved into a greedy child if (parentInstance && c === "isover") { parentInstance.isover = false; parentInstance.isout = true; parentInstance._out.call(parentInstance, event); } this[c] = true; this[c === "isout" ? "isover" : "isout"] = false; this[c === "isover" ? "_over" : "_out"].call(this, event); // we just moved out of a greedy child if (parentInstance && c === "isout") { parentInstance.isout = false; parentInstance.isover = true; parentInstance._over.call(parentInstance, event); } }); }, dragStop: function( draggable, event ) { draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) if( !draggable.options.refreshPositions ) { $.ui.ddmanager.prepareOffsets( draggable, event ); } } }; })(jQuery); (function( $, undefined ) { function num(v) { return parseInt(v, 10) || 0; } function isNumber(value) { return !isNaN(parseInt(value, 10)); } $.widget("ui.resizable", $.ui.mouse, { version: "1.10.2", widgetEventPrefix: "resize", options: { alsoResize: false, animate: false, animateDuration: "slow", animateEasing: "swing", aspectRatio: false, autoHide: false, containment: false, ghost: false, grid: false, handles: "e,s,se", helper: false, maxHeight: null, maxWidth: null, minHeight: 10, minWidth: 10, // See #7960 zIndex: 90, // callbacks resize: null, start: null, stop: null }, _create: function() { var n, i, handle, axis, hname, that = this, o = this.options; this.element.addClass("ui-resizable"); $.extend(this, { _aspectRatio: !!(o.aspectRatio), aspectRatio: o.aspectRatio, originalElement: this.element, _proportionallyResizeElements: [], _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null }); //Wrap the element if it cannot hold child nodes if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { //Create a wrapper element and set the wrapper to the new current internal element this.element.wrap( $("
    ").css({ position: this.element.css("position"), width: this.element.outerWidth(), height: this.element.outerHeight(), top: this.element.css("top"), left: this.element.css("left") }) ); //Overwrite the original this.element this.element = this.element.parent().data( "ui-resizable", this.element.data("ui-resizable") ); this.elementIsWrapper = true; //Move margins to the wrapper this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); //Prevent Safari textarea resize this.originalResizeStyle = this.originalElement.css("resize"); this.originalElement.css("resize", "none"); //Push the actual element to our proportionallyResize internal array this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" })); // avoid IE jump (hard set the margin) this.originalElement.css({ margin: this.originalElement.css("margin") }); // fix handlers offset this._proportionallyResize(); } this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" }); if(this.handles.constructor === String) { if ( this.handles === "all") { this.handles = "n,e,s,w,se,sw,ne,nw"; } n = this.handles.split(","); this.handles = {}; for(i = 0; i < n.length; i++) { handle = $.trim(n[i]); hname = "ui-resizable-"+handle; axis = $("
    "); // Apply zIndex to all handles - see #7960 axis.css({ zIndex: o.zIndex }); //TODO : What's going on here? if ("se" === handle) { axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se"); } //Insert into internal handles object and append to element this.handles[handle] = ".ui-resizable-"+handle; this.element.append(axis); } } this._renderAxis = function(target) { var i, axis, padPos, padWrapper; target = target || this.element; for(i in this.handles) { if(this.handles[i].constructor === String) { this.handles[i] = $(this.handles[i], this.element).show(); } //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { axis = $(this.handles[i], this.element); //Checking the correct pad and border padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); //The padding type i have to apply... padPos = [ "padding", /ne|nw|n/.test(i) ? "Top" : /se|sw|s/.test(i) ? "Bottom" : /^e$/.test(i) ? "Right" : "Left" ].join(""); target.css(padPos, padWrapper); this._proportionallyResize(); } //TODO: What's that good for? There's not anything to be executed left if(!$(this.handles[i]).length) { continue; } } }; //TODO: make renderAxis a prototype function this._renderAxis(this.element); this._handles = $(".ui-resizable-handle", this.element) .disableSelection(); //Matching axis name this._handles.mouseover(function() { if (!that.resizing) { if (this.className) { axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); } //Axis, default = se that.axis = axis && axis[1] ? axis[1] : "se"; } }); //If we want to auto hide the elements if (o.autoHide) { this._handles.hide(); $(this.element) .addClass("ui-resizable-autohide") .mouseenter(function() { if (o.disabled) { return; } $(this).removeClass("ui-resizable-autohide"); that._handles.show(); }) .mouseleave(function(){ if (o.disabled) { return; } if (!that.resizing) { $(this).addClass("ui-resizable-autohide"); that._handles.hide(); } }); } //Initialize the mouse interaction this._mouseInit(); }, _destroy: function() { this._mouseDestroy(); var wrapper, _destroy = function(exp) { $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove(); }; //TODO: Unwrap at same DOM position if (this.elementIsWrapper) { _destroy(this.element); wrapper = this.element; this.originalElement.css({ position: wrapper.css("position"), width: wrapper.outerWidth(), height: wrapper.outerHeight(), top: wrapper.css("top"), left: wrapper.css("left") }).insertAfter( wrapper ); wrapper.remove(); } this.originalElement.css("resize", this.originalResizeStyle); _destroy(this.originalElement); return this; }, _mouseCapture: function(event) { var i, handle, capture = false; for (i in this.handles) { handle = $(this.handles[i])[0]; if (handle === event.target || $.contains(handle, event.target)) { capture = true; } } return !this.options.disabled && capture; }, _mouseStart: function(event) { var curleft, curtop, cursor, o = this.options, iniPos = this.element.position(), el = this.element; this.resizing = true; // bugfix for http://dev.jquery.com/ticket/1749 if ( (/absolute/).test( el.css("position") ) ) { el.css({ position: "absolute", top: el.css("top"), left: el.css("left") }); } else if (el.is(".ui-draggable")) { el.css({ position: "absolute", top: iniPos.top, left: iniPos.left }); } this._renderProxy(); curleft = num(this.helper.css("left")); curtop = num(this.helper.css("top")); if (o.containment) { curleft += $(o.containment).scrollLeft() || 0; curtop += $(o.containment).scrollTop() || 0; } //Store needed variables this.offset = this.helper.offset(); this.position = { left: curleft, top: curtop }; this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; this.originalPosition = { left: curleft, top: curtop }; this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; this.originalMousePosition = { left: event.pageX, top: event.pageY }; //Aspect Ratio this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); cursor = $(".ui-resizable-" + this.axis).css("cursor"); $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor); el.addClass("ui-resizable-resizing"); this._propagate("start", event); return true; }, _mouseDrag: function(event) { //Increase performance, avoid regex var data, el = this.helper, props = {}, smp = this.originalMousePosition, a = this.axis, prevTop = this.position.top, prevLeft = this.position.left, prevWidth = this.size.width, prevHeight = this.size.height, dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0, trigger = this._change[a]; if (!trigger) { return false; } // Calculate the attrs that will be change data = trigger.apply(this, [event, dx, dy]); // Put this in the mouseDrag handler since the user can start pressing shift while resizing this._updateVirtualBoundaries(event.shiftKey); if (this._aspectRatio || event.shiftKey) { data = this._updateRatio(data, event); } data = this._respectSize(data, event); this._updateCache(data); // plugins callbacks need to be called first this._propagate("resize", event); if (this.position.top !== prevTop) { props.top = this.position.top + "px"; } if (this.position.left !== prevLeft) { props.left = this.position.left + "px"; } if (this.size.width !== prevWidth) { props.width = this.size.width + "px"; } if (this.size.height !== prevHeight) { props.height = this.size.height + "px"; } el.css(props); if (!this._helper && this._proportionallyResizeElements.length) { this._proportionallyResize(); } // Call the user callback if the element was resized if ( ! $.isEmptyObject(props) ) { this._trigger("resize", event, this.ui()); } return false; }, _mouseStop: function(event) { this.resizing = false; var pr, ista, soffseth, soffsetw, s, left, top, o = this.options, that = this; if(this._helper) { pr = this._proportionallyResizeElements; ista = pr.length && (/textarea/i).test(pr[0].nodeName); soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height; soffsetw = ista ? 0 : that.sizeDiff.width; s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) }; left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null; top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; if (!o.animate) { this.element.css($.extend(s, { top: top, left: left })); } that.helper.height(that.size.height); that.helper.width(that.size.width); if (this._helper && !o.animate) { this._proportionallyResize(); } } $("body").css("cursor", "auto"); this.element.removeClass("ui-resizable-resizing"); this._propagate("stop", event); if (this._helper) { this.helper.remove(); } return false; }, _updateVirtualBoundaries: function(forceAspectRatio) { var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, o = this.options; b = { minWidth: isNumber(o.minWidth) ? o.minWidth : 0, maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, minHeight: isNumber(o.minHeight) ? o.minHeight : 0, maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity }; if(this._aspectRatio || forceAspectRatio) { // We want to create an enclosing box whose aspect ration is the requested one // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension pMinWidth = b.minHeight * this.aspectRatio; pMinHeight = b.minWidth / this.aspectRatio; pMaxWidth = b.maxHeight * this.aspectRatio; pMaxHeight = b.maxWidth / this.aspectRatio; if(pMinWidth > b.minWidth) { b.minWidth = pMinWidth; } if(pMinHeight > b.minHeight) { b.minHeight = pMinHeight; } if(pMaxWidth < b.maxWidth) { b.maxWidth = pMaxWidth; } if(pMaxHeight < b.maxHeight) { b.maxHeight = pMaxHeight; } } this._vBoundaries = b; }, _updateCache: function(data) { this.offset = this.helper.offset(); if (isNumber(data.left)) { this.position.left = data.left; } if (isNumber(data.top)) { this.position.top = data.top; } if (isNumber(data.height)) { this.size.height = data.height; } if (isNumber(data.width)) { this.size.width = data.width; } }, _updateRatio: function( data ) { var cpos = this.position, csize = this.size, a = this.axis; if (isNumber(data.height)) { data.width = (data.height * this.aspectRatio); } else if (isNumber(data.width)) { data.height = (data.width / this.aspectRatio); } if (a === "sw") { data.left = cpos.left + (csize.width - data.width); data.top = null; } if (a === "nw") { data.top = cpos.top + (csize.height - data.height); data.left = cpos.left + (csize.width - data.width); } return data; }, _respectSize: function( data ) { var o = this._vBoundaries, a = this.axis, ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height), dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height, cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); if (isminw) { data.width = o.minWidth; } if (isminh) { data.height = o.minHeight; } if (ismaxw) { data.width = o.maxWidth; } if (ismaxh) { data.height = o.maxHeight; } if (isminw && cw) { data.left = dw - o.minWidth; } if (ismaxw && cw) { data.left = dw - o.maxWidth; } if (isminh && ch) { data.top = dh - o.minHeight; } if (ismaxh && ch) { data.top = dh - o.maxHeight; } // fixing jump error on top/left - bug #2330 if (!data.width && !data.height && !data.left && data.top) { data.top = null; } else if (!data.width && !data.height && !data.top && data.left) { data.left = null; } return data; }, _proportionallyResize: function() { if (!this._proportionallyResizeElements.length) { return; } var i, j, borders, paddings, prel, element = this.helper || this.element; for ( i=0; i < this._proportionallyResizeElements.length; i++) { prel = this._proportionallyResizeElements[i]; if (!this.borderDif) { this.borderDif = []; borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")]; paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")]; for ( j = 0; j < borders.length; j++ ) { this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 ); } } prel.css({ height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 }); } }, _renderProxy: function() { var el = this.element, o = this.options; this.elementOffset = el.offset(); if(this._helper) { this.helper = this.helper || $("
    "); this.helper.addClass(this._helper).css({ width: this.element.outerWidth() - 1, height: this.element.outerHeight() - 1, position: "absolute", left: this.elementOffset.left +"px", top: this.elementOffset.top +"px", zIndex: ++o.zIndex //TODO: Don't modify option }); this.helper .appendTo("body") .disableSelection(); } else { this.helper = this.element; } }, _change: { e: function(event, dx) { return { width: this.originalSize.width + dx }; }, w: function(event, dx) { var cs = this.originalSize, sp = this.originalPosition; return { left: sp.left + dx, width: cs.width - dx }; }, n: function(event, dx, dy) { var cs = this.originalSize, sp = this.originalPosition; return { top: sp.top + dy, height: cs.height - dy }; }, s: function(event, dx, dy) { return { height: this.originalSize.height + dy }; }, se: function(event, dx, dy) { return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); }, sw: function(event, dx, dy) { return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); }, ne: function(event, dx, dy) { return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); }, nw: function(event, dx, dy) { return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); } }, _propagate: function(n, event) { $.ui.plugin.call(this, n, [event, this.ui()]); (n !== "resize" && this._trigger(n, event, this.ui())); }, plugins: {}, ui: function() { return { originalElement: this.originalElement, element: this.element, helper: this.helper, position: this.position, size: this.size, originalSize: this.originalSize, originalPosition: this.originalPosition }; } }); /* * Resizable Extensions */ $.ui.plugin.add("resizable", "animate", { stop: function( event ) { var that = $(this).data("ui-resizable"), o = that.options, pr = that._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName), soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height, soffsetw = ista ? 0 : that.sizeDiff.width, style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null, top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; that.element.animate( $.extend(style, top && left ? { top: top, left: left } : {}), { duration: o.animateDuration, easing: o.animateEasing, step: function() { var data = { width: parseInt(that.element.css("width"), 10), height: parseInt(that.element.css("height"), 10), top: parseInt(that.element.css("top"), 10), left: parseInt(that.element.css("left"), 10) }; if (pr && pr.length) { $(pr[0]).css({ width: data.width, height: data.height }); } // propagating resize, and updating values for each animation step that._updateCache(data); that._propagate("resize", event); } } ); } }); $.ui.plugin.add("resizable", "containment", { start: function() { var element, p, co, ch, cw, width, height, that = $(this).data("ui-resizable"), o = that.options, el = that.element, oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; if (!ce) { return; } that.containerElement = $(ce); if (/document/.test(oc) || oc === document) { that.containerOffset = { left: 0, top: 0 }; that.containerPosition = { left: 0, top: 0 }; that.parentData = { element: $(document), left: 0, top: 0, width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight }; } // i'm a node, so compute top, left, right, bottom else { element = $(ce); p = []; $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); that.containerOffset = element.offset(); that.containerPosition = element.position(); that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; co = that.containerOffset; ch = that.containerSize.height; cw = that.containerSize.width; width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ); height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); that.parentData = { element: ce, left: co.left, top: co.top, width: width, height: height }; } }, resize: function( event ) { var woset, hoset, isParent, isOffsetRelative, that = $(this).data("ui-resizable"), o = that.options, co = that.containerOffset, cp = that.position, pRatio = that._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = that.containerElement; if (ce[0] !== document && (/static/).test(ce.css("position"))) { cop = co; } if (cp.left < (that._helper ? co.left : 0)) { that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left)); if (pRatio) { that.size.height = that.size.width / that.aspectRatio; } that.position.left = o.helper ? co.left : 0; } if (cp.top < (that._helper ? co.top : 0)) { that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top); if (pRatio) { that.size.width = that.size.height * that.aspectRatio; } that.position.top = that._helper ? co.top : 0; } that.offset.left = that.parentData.left+that.position.left; that.offset.top = that.parentData.top+that.position.top; woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ); hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height ); isParent = that.containerElement.get(0) === that.element.parent().get(0); isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position")); if(isParent && isOffsetRelative) { woset -= that.parentData.left; } if (woset + that.size.width >= that.parentData.width) { that.size.width = that.parentData.width - woset; if (pRatio) { that.size.height = that.size.width / that.aspectRatio; } } if (hoset + that.size.height >= that.parentData.height) { that.size.height = that.parentData.height - hoset; if (pRatio) { that.size.width = that.size.height * that.aspectRatio; } } }, stop: function(){ var that = $(this).data("ui-resizable"), o = that.options, co = that.containerOffset, cop = that.containerPosition, ce = that.containerElement, helper = $(that.helper), ho = helper.offset(), w = helper.outerWidth() - that.sizeDiff.width, h = helper.outerHeight() - that.sizeDiff.height; if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) { $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); } if (that._helper && !o.animate && (/static/).test(ce.css("position"))) { $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); } } }); $.ui.plugin.add("resizable", "alsoResize", { start: function () { var that = $(this).data("ui-resizable"), o = that.options, _store = function (exp) { $(exp).each(function() { var el = $(this); el.data("ui-resizable-alsoresize", { width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10) }); }); }; if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) { if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } else { $.each(o.alsoResize, function (exp) { _store(exp); }); } }else{ _store(o.alsoResize); } }, resize: function (event, ui) { var that = $(this).data("ui-resizable"), o = that.options, os = that.originalSize, op = that.originalPosition, delta = { height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0, top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0 }, _alsoResize = function (exp, c) { $(exp).each(function() { var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {}, css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"]; $.each(css, function (i, prop) { var sum = (start[prop]||0) + (delta[prop]||0); if (sum && sum >= 0) { style[prop] = sum || null; } }); el.css(style); }); }; if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) { $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); }else{ _alsoResize(o.alsoResize); } }, stop: function () { $(this).removeData("resizable-alsoresize"); } }); $.ui.plugin.add("resizable", "ghost", { start: function() { var that = $(this).data("ui-resizable"), o = that.options, cs = that.size; that.ghost = that.originalElement.clone(); that.ghost .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) .addClass("ui-resizable-ghost") .addClass(typeof o.ghost === "string" ? o.ghost : ""); that.ghost.appendTo(that.helper); }, resize: function(){ var that = $(this).data("ui-resizable"); if (that.ghost) { that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width }); } }, stop: function() { var that = $(this).data("ui-resizable"); if (that.ghost && that.helper) { that.helper.get(0).removeChild(that.ghost.get(0)); } } }); $.ui.plugin.add("resizable", "grid", { resize: function() { var that = $(this).data("ui-resizable"), o = that.options, cs = that.size, os = that.originalSize, op = that.originalPosition, a = that.axis, grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid, gridX = (grid[0]||1), gridY = (grid[1]||1), ox = Math.round((cs.width - os.width) / gridX) * gridX, oy = Math.round((cs.height - os.height) / gridY) * gridY, newWidth = os.width + ox, newHeight = os.height + oy, isMaxWidth = o.maxWidth && (o.maxWidth < newWidth), isMaxHeight = o.maxHeight && (o.maxHeight < newHeight), isMinWidth = o.minWidth && (o.minWidth > newWidth), isMinHeight = o.minHeight && (o.minHeight > newHeight); o.grid = grid; if (isMinWidth) { newWidth = newWidth + gridX; } if (isMinHeight) { newHeight = newHeight + gridY; } if (isMaxWidth) { newWidth = newWidth - gridX; } if (isMaxHeight) { newHeight = newHeight - gridY; } if (/^(se|s|e)$/.test(a)) { that.size.width = newWidth; that.size.height = newHeight; } else if (/^(ne)$/.test(a)) { that.size.width = newWidth; that.size.height = newHeight; that.position.top = op.top - oy; } else if (/^(sw)$/.test(a)) { that.size.width = newWidth; that.size.height = newHeight; that.position.left = op.left - ox; } else { that.size.width = newWidth; that.size.height = newHeight; that.position.top = op.top - oy; that.position.left = op.left - ox; } } }); })(jQuery); (function( $, undefined ) { $.widget("ui.selectable", $.ui.mouse, { version: "1.10.2", options: { appendTo: "body", autoRefresh: true, distance: 0, filter: "*", tolerance: "touch", // callbacks selected: null, selecting: null, start: null, stop: null, unselected: null, unselecting: null }, _create: function() { var selectees, that = this; this.element.addClass("ui-selectable"); this.dragged = false; // cache selectee children based on filter this.refresh = function() { selectees = $(that.options.filter, that.element[0]); selectees.addClass("ui-selectee"); selectees.each(function() { var $this = $(this), pos = $this.offset(); $.data(this, "selectable-item", { element: this, $element: $this, left: pos.left, top: pos.top, right: pos.left + $this.outerWidth(), bottom: pos.top + $this.outerHeight(), startselected: false, selected: $this.hasClass("ui-selected"), selecting: $this.hasClass("ui-selecting"), unselecting: $this.hasClass("ui-unselecting") }); }); }; this.refresh(); this.selectees = selectees.addClass("ui-selectee"); this._mouseInit(); this.helper = $("
    "); }, _destroy: function() { this.selectees .removeClass("ui-selectee") .removeData("selectable-item"); this.element .removeClass("ui-selectable ui-selectable-disabled"); this._mouseDestroy(); }, _mouseStart: function(event) { var that = this, options = this.options; this.opos = [event.pageX, event.pageY]; if (this.options.disabled) { return; } this.selectees = $(options.filter, this.element[0]); this._trigger("start", event); $(options.appendTo).append(this.helper); // position helper (lasso) this.helper.css({ "left": event.pageX, "top": event.pageY, "width": 0, "height": 0 }); if (options.autoRefresh) { this.refresh(); } this.selectees.filter(".ui-selected").each(function() { var selectee = $.data(this, "selectable-item"); selectee.startselected = true; if (!event.metaKey && !event.ctrlKey) { selectee.$element.removeClass("ui-selected"); selectee.selected = false; selectee.$element.addClass("ui-unselecting"); selectee.unselecting = true; // selectable UNSELECTING callback that._trigger("unselecting", event, { unselecting: selectee.element }); } }); $(event.target).parents().addBack().each(function() { var doSelect, selectee = $.data(this, "selectable-item"); if (selectee) { doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected"); selectee.$element .removeClass(doSelect ? "ui-unselecting" : "ui-selected") .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); selectee.unselecting = !doSelect; selectee.selecting = doSelect; selectee.selected = doSelect; // selectable (UN)SELECTING callback if (doSelect) { that._trigger("selecting", event, { selecting: selectee.element }); } else { that._trigger("unselecting", event, { unselecting: selectee.element }); } return false; } }); }, _mouseDrag: function(event) { this.dragged = true; if (this.options.disabled) { return; } var tmp, that = this, options = this.options, x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY; if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; } if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; } this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); this.selectees.each(function() { var selectee = $.data(this, "selectable-item"), hit = false; //prevent helper from being selected if appendTo: selectable if (!selectee || selectee.element === that.element[0]) { return; } if (options.tolerance === "touch") { hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); } else if (options.tolerance === "fit") { hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); } if (hit) { // SELECT if (selectee.selected) { selectee.$element.removeClass("ui-selected"); selectee.selected = false; } if (selectee.unselecting) { selectee.$element.removeClass("ui-unselecting"); selectee.unselecting = false; } if (!selectee.selecting) { selectee.$element.addClass("ui-selecting"); selectee.selecting = true; // selectable SELECTING callback that._trigger("selecting", event, { selecting: selectee.element }); } } else { // UNSELECT if (selectee.selecting) { if ((event.metaKey || event.ctrlKey) && selectee.startselected) { selectee.$element.removeClass("ui-selecting"); selectee.selecting = false; selectee.$element.addClass("ui-selected"); selectee.selected = true; } else { selectee.$element.removeClass("ui-selecting"); selectee.selecting = false; if (selectee.startselected) { selectee.$element.addClass("ui-unselecting"); selectee.unselecting = true; } // selectable UNSELECTING callback that._trigger("unselecting", event, { unselecting: selectee.element }); } } if (selectee.selected) { if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { selectee.$element.removeClass("ui-selected"); selectee.selected = false; selectee.$element.addClass("ui-unselecting"); selectee.unselecting = true; // selectable UNSELECTING callback that._trigger("unselecting", event, { unselecting: selectee.element }); } } } }); return false; }, _mouseStop: function(event) { var that = this; this.dragged = false; $(".ui-unselecting", this.element[0]).each(function() { var selectee = $.data(this, "selectable-item"); selectee.$element.removeClass("ui-unselecting"); selectee.unselecting = false; selectee.startselected = false; that._trigger("unselected", event, { unselected: selectee.element }); }); $(".ui-selecting", this.element[0]).each(function() { var selectee = $.data(this, "selectable-item"); selectee.$element.removeClass("ui-selecting").addClass("ui-selected"); selectee.selecting = false; selectee.selected = true; selectee.startselected = true; that._trigger("selected", event, { selected: selectee.element }); }); this._trigger("stop", event); this.helper.remove(); return false; } }); })(jQuery); (function( $, undefined ) { /*jshint loopfunc: true */ function isOverAxis( x, reference, size ) { return ( x > reference ) && ( x < ( reference + size ) ); } function isFloating(item) { return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); } $.widget("ui.sortable", $.ui.mouse, { version: "1.10.2", widgetEventPrefix: "sort", ready: false, options: { appendTo: "parent", axis: false, connectWith: false, containment: false, cursor: "auto", cursorAt: false, dropOnEmpty: true, forcePlaceholderSize: false, forceHelperSize: false, grid: false, handle: false, helper: "original", items: "> *", opacity: false, placeholder: false, revert: false, scroll: true, scrollSensitivity: 20, scrollSpeed: 20, scope: "default", tolerance: "intersect", zIndex: 1000, // callbacks activate: null, beforeStop: null, change: null, deactivate: null, out: null, over: null, receive: null, remove: null, sort: null, start: null, stop: null, update: null }, _create: function() { var o = this.options; this.containerCache = {}; this.element.addClass("ui-sortable"); //Get the items this.refresh(); //Let's determine if the items are being displayed horizontally this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; //Let's determine the parent's offset this.offset = this.element.offset(); //Initialize mouse events for interaction this._mouseInit(); //We're ready to go this.ready = true; }, _destroy: function() { this.element .removeClass("ui-sortable ui-sortable-disabled"); this._mouseDestroy(); for ( var i = this.items.length - 1; i >= 0; i-- ) { this.items[i].item.removeData(this.widgetName + "-item"); } return this; }, _setOption: function(key, value){ if ( key === "disabled" ) { this.options[ key ] = value; this.widget().toggleClass( "ui-sortable-disabled", !!value ); } else { // Don't call widget base _setOption for disable as it adds ui-state-disabled class $.Widget.prototype._setOption.apply(this, arguments); } }, _mouseCapture: function(event, overrideHandle) { var currentItem = null, validHandle = false, that = this; if (this.reverting) { return false; } if(this.options.disabled || this.options.type === "static") { return false; } //We have to refresh the items data once first this._refreshItems(event); //Find out if the clicked node (or one of its parents) is a actual item in this.items $(event.target).parents().each(function() { if($.data(this, that.widgetName + "-item") === that) { currentItem = $(this); return false; } }); if($.data(event.target, that.widgetName + "-item") === that) { currentItem = $(event.target); } if(!currentItem) { return false; } if(this.options.handle && !overrideHandle) { $(this.options.handle, currentItem).find("*").addBack().each(function() { if(this === event.target) { validHandle = true; } }); if(!validHandle) { return false; } } this.currentItem = currentItem; this._removeCurrentsFromItems(); return true; }, _mouseStart: function(event, overrideHandle, noActivation) { var i, body, o = this.options; this.currentContainer = this; //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture this.refreshPositions(); //Create and append the visible helper this.helper = this._createHelper(event); //Cache the helper size this._cacheHelperProportions(); /* * - Position generation - * This block generates everything position related - it's the core of draggables. */ //Cache the margins of the original element this._cacheMargins(); //Get the next scrolling parent this.scrollParent = this.helper.scrollParent(); //The element's absolute position on the page minus margins this.offset = this.currentItem.offset(); this.offset = { top: this.offset.top - this.margins.top, left: this.offset.left - this.margins.left }; $.extend(this.offset, { click: { //Where the click happened, relative to the element left: event.pageX - this.offset.left, top: event.pageY - this.offset.top }, parent: this._getParentOffset(), relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper }); // Only after we got the offset, we can change the helper's position to absolute // TODO: Still need to figure out a way to make relative sorting possible this.helper.css("position", "absolute"); this.cssPosition = this.helper.css("position"); //Generate the original position this.originalPosition = this._generatePosition(event); this.originalPageX = event.pageX; this.originalPageY = event.pageY; //Adjust the mouse offset relative to the helper if "cursorAt" is supplied (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); //Cache the former DOM position this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way if(this.helper[0] !== this.currentItem[0]) { this.currentItem.hide(); } //Create the placeholder this._createPlaceholder(); //Set a containment if given in the options if(o.containment) { this._setContainment(); } if( o.cursor && o.cursor !== "auto" ) { // cursor option body = this.document.find( "body" ); // support: IE this.storedCursor = body.css( "cursor" ); body.css( "cursor", o.cursor ); this.storedStylesheet = $( "" ).appendTo( body ); } if(o.opacity) { // opacity option if (this.helper.css("opacity")) { this._storedOpacity = this.helper.css("opacity"); } this.helper.css("opacity", o.opacity); } if(o.zIndex) { // zIndex option if (this.helper.css("zIndex")) { this._storedZIndex = this.helper.css("zIndex"); } this.helper.css("zIndex", o.zIndex); } //Prepare scrolling if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { this.overflowOffset = this.scrollParent.offset(); } //Call callbacks this._trigger("start", event, this._uiHash()); //Recache the helper size if(!this._preserveHelperProportions) { this._cacheHelperProportions(); } //Post "activate" events to possible containers if( !noActivation ) { for ( i = this.containers.length - 1; i >= 0; i-- ) { this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); } } //Prepare possible droppables if($.ui.ddmanager) { $.ui.ddmanager.current = this; } if ($.ui.ddmanager && !o.dropBehaviour) { $.ui.ddmanager.prepareOffsets(this, event); } this.dragging = true; this.helper.addClass("ui-sortable-helper"); this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position return true; }, _mouseDrag: function(event) { var i, item, itemElement, intersection, o = this.options, scrolled = false; //Compute the helpers position this.position = this._generatePosition(event); this.positionAbs = this._convertPositionTo("absolute"); if (!this.lastPositionAbs) { this.lastPositionAbs = this.positionAbs; } //Do scrolling if(this.options.scroll) { if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; } if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; } } else { if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); } if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); } } if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { $.ui.ddmanager.prepareOffsets(this, event); } } //Regenerate the absolute position used for position checks this.positionAbs = this._convertPositionTo("absolute"); //Set the helper position if(!this.options.axis || this.options.axis !== "y") { this.helper[0].style.left = this.position.left+"px"; } if(!this.options.axis || this.options.axis !== "x") { this.helper[0].style.top = this.position.top+"px"; } //Rearrange for (i = this.items.length - 1; i >= 0; i--) { //Cache variables and intersection, continue if no intersection item = this.items[i]; itemElement = item.item[0]; intersection = this._intersectsWithPointer(item); if (!intersection) { continue; } // Only put the placeholder inside the current Container, skip all // items form other containers. This works because when moving // an item from one container to another the // currentContainer is switched before the placeholder is moved. // // Without this moving items in "sub-sortables" can cause the placeholder to jitter // beetween the outer and inner container. if (item.instance !== this.currentContainer) { continue; } // cannot intersect with itself // no useless actions that have been done before // no action if the item moved is the parent of the item checked if (itemElement !== this.currentItem[0] && this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && !$.contains(this.placeholder[0], itemElement) && (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) ) { this.direction = intersection === 1 ? "down" : "up"; if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { this._rearrange(event, item); } else { break; } this._trigger("change", event, this._uiHash()); break; } } //Post events to containers this._contactContainers(event); //Interconnect with droppables if($.ui.ddmanager) { $.ui.ddmanager.drag(this, event); } //Call callbacks this._trigger("sort", event, this._uiHash()); this.lastPositionAbs = this.positionAbs; return false; }, _mouseStop: function(event, noPropagation) { if(!event) { return; } //If we are using droppables, inform the manager about the drop if ($.ui.ddmanager && !this.options.dropBehaviour) { $.ui.ddmanager.drop(this, event); } if(this.options.revert) { var that = this, cur = this.placeholder.offset(), axis = this.options.axis, animation = {}; if ( !axis || axis === "x" ) { animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); } if ( !axis || axis === "y" ) { animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); } this.reverting = true; $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { that._clear(event); }); } else { this._clear(event, noPropagation); } return false; }, cancel: function() { if(this.dragging) { this._mouseUp({ target: null }); if(this.options.helper === "original") { this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); } else { this.currentItem.show(); } //Post deactivating events to containers for (var i = this.containers.length - 1; i >= 0; i--){ this.containers[i]._trigger("deactivate", null, this._uiHash(this)); if(this.containers[i].containerCache.over) { this.containers[i]._trigger("out", null, this._uiHash(this)); this.containers[i].containerCache.over = 0; } } } if (this.placeholder) { //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! if(this.placeholder[0].parentNode) { this.placeholder[0].parentNode.removeChild(this.placeholder[0]); } if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { this.helper.remove(); } $.extend(this, { helper: null, dragging: false, reverting: false, _noFinalSort: null }); if(this.domPosition.prev) { $(this.domPosition.prev).after(this.currentItem); } else { $(this.domPosition.parent).prepend(this.currentItem); } } return this; }, serialize: function(o) { var items = this._getItemsAsjQuery(o && o.connected), str = []; o = o || {}; $(items).each(function() { var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); if (res) { str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); } }); if(!str.length && o.key) { str.push(o.key + "="); } return str.join("&"); }, toArray: function(o) { var items = this._getItemsAsjQuery(o && o.connected), ret = []; o = o || {}; items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); return ret; }, /* Be careful with the following core functions */ _intersectsWith: function(item) { var x1 = this.positionAbs.left, x2 = x1 + this.helperProportions.width, y1 = this.positionAbs.top, y2 = y1 + this.helperProportions.height, l = item.left, r = l + item.width, t = item.top, b = t + item.height, dyClick = this.offset.click.top, dxClick = this.offset.click.left, isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r; if ( this.options.tolerance === "pointer" || this.options.forcePointerForContainers || (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) ) { return isOverElement; } else { return (l < x1 + (this.helperProportions.width / 2) && // Right Half x2 - (this.helperProportions.width / 2) < r && // Left Half t < y1 + (this.helperProportions.height / 2) && // Bottom Half y2 - (this.helperProportions.height / 2) < b ); // Top Half } }, _intersectsWithPointer: function(item) { var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), isOverElement = isOverElementHeight && isOverElementWidth, verticalDirection = this._getDragVerticalDirection(), horizontalDirection = this._getDragHorizontalDirection(); if (!isOverElement) { return false; } return this.floating ? ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); }, _intersectsWithSides: function(item) { var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), verticalDirection = this._getDragVerticalDirection(), horizontalDirection = this._getDragHorizontalDirection(); if (this.floating && horizontalDirection) { return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); } else { return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); } }, _getDragVerticalDirection: function() { var delta = this.positionAbs.top - this.lastPositionAbs.top; return delta !== 0 && (delta > 0 ? "down" : "up"); }, _getDragHorizontalDirection: function() { var delta = this.positionAbs.left - this.lastPositionAbs.left; return delta !== 0 && (delta > 0 ? "right" : "left"); }, refresh: function(event) { this._refreshItems(event); this.refreshPositions(); return this; }, _connectWith: function() { var options = this.options; return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; }, _getItemsAsjQuery: function(connected) { var i, j, cur, inst, items = [], queries = [], connectWith = this._connectWith(); if(connectWith && connected) { for (i = connectWith.length - 1; i >= 0; i--){ cur = $(connectWith[i]); for ( j = cur.length - 1; j >= 0; j--){ inst = $.data(cur[j], this.widgetFullName); if(inst && inst !== this && !inst.options.disabled) { queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); } } } } queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); for (i = queries.length - 1; i >= 0; i--){ queries[i][0].each(function() { items.push(this); }); } return $(items); }, _removeCurrentsFromItems: function() { var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); this.items = $.grep(this.items, function (item) { for (var j=0; j < list.length; j++) { if(list[j] === item.item[0]) { return false; } } return true; }); }, _refreshItems: function(event) { this.items = []; this.containers = [this]; var i, j, cur, inst, targetData, _queries, item, queriesLength, items = this.items, queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], connectWith = this._connectWith(); if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down for (i = connectWith.length - 1; i >= 0; i--){ cur = $(connectWith[i]); for (j = cur.length - 1; j >= 0; j--){ inst = $.data(cur[j], this.widgetFullName); if(inst && inst !== this && !inst.options.disabled) { queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); this.containers.push(inst); } } } } for (i = queries.length - 1; i >= 0; i--) { targetData = queries[i][1]; _queries = queries[i][0]; for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { item = $(_queries[j]); item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) items.push({ item: item, instance: targetData, width: 0, height: 0, left: 0, top: 0 }); } } }, refreshPositions: function(fast) { //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change if(this.offsetParent && this.helper) { this.offset.parent = this._getParentOffset(); } var i, item, t, p; for (i = this.items.length - 1; i >= 0; i--){ item = this.items[i]; //We ignore calculating positions of all connected containers when we're not over them if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { continue; } t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; if (!fast) { item.width = t.outerWidth(); item.height = t.outerHeight(); } p = t.offset(); item.left = p.left; item.top = p.top; } if(this.options.custom && this.options.custom.refreshContainers) { this.options.custom.refreshContainers.call(this); } else { for (i = this.containers.length - 1; i >= 0; i--){ p = this.containers[i].element.offset(); this.containers[i].containerCache.left = p.left; this.containers[i].containerCache.top = p.top; this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); } } return this; }, _createPlaceholder: function(that) { that = that || this; var className, o = that.options; if(!o.placeholder || o.placeholder.constructor === String) { className = o.placeholder; o.placeholder = { element: function() { var nodeName = that.currentItem[0].nodeName.toLowerCase(), element = $( that.document[0].createElement( nodeName ) ) .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") .removeClass("ui-sortable-helper"); if ( nodeName === "tr" ) { // Use a high colspan to force the td to expand the full // width of the table (browsers are smart enough to // handle this properly) element.append( " " ); } else if ( nodeName === "img" ) { element.attr( "src", that.currentItem.attr( "src" ) ); } if ( !className ) { element.css( "visibility", "hidden" ); } return element; }, update: function(container, p) { // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified if(className && !o.forcePlaceholderSize) { return; } //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } } }; } //Create the placeholder that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); //Append it after the actual current item that.currentItem.after(that.placeholder); //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) o.placeholder.update(that, that.placeholder); }, _contactContainers: function(event) { var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, innermostContainer = null, innermostIndex = null; // get innermost container that intersects with item for (i = this.containers.length - 1; i >= 0; i--) { // never consider a container that's located within the item itself if($.contains(this.currentItem[0], this.containers[i].element[0])) { continue; } if(this._intersectsWith(this.containers[i].containerCache)) { // if we've already found a container and it's more "inner" than this, then continue if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { continue; } innermostContainer = this.containers[i]; innermostIndex = i; } else { // container doesn't intersect. trigger "out" event if necessary if(this.containers[i].containerCache.over) { this.containers[i]._trigger("out", event, this._uiHash(this)); this.containers[i].containerCache.over = 0; } } } // if no intersecting containers found, return if(!innermostContainer) { return; } // move the item into the container if it's not there already if(this.containers.length === 1) { if (!this.containers[innermostIndex].containerCache.over) { this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); this.containers[innermostIndex].containerCache.over = 1; } } else { //When entering a new container, we will find the item with the least distance and append our item near it dist = 10000; itemWithLeastDistance = null; floating = innermostContainer.floating || isFloating(this.currentItem); posProperty = floating ? "left" : "top"; sizeProperty = floating ? "width" : "height"; base = this.positionAbs[posProperty] + this.offset.click[posProperty]; for (j = this.items.length - 1; j >= 0; j--) { if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { continue; } if(this.items[j].item[0] === this.currentItem[0]) { continue; } if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { continue; } cur = this.items[j].item.offset()[posProperty]; nearBottom = false; if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ nearBottom = true; cur += this.items[j][sizeProperty]; } if(Math.abs(cur - base) < dist) { dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; this.direction = nearBottom ? "up": "down"; } } //Check if dropOnEmpty is enabled if(!itemWithLeastDistance && !this.options.dropOnEmpty) { return; } if(this.currentContainer === this.containers[innermostIndex]) { return; } itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); this._trigger("change", event, this._uiHash()); this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); this.currentContainer = this.containers[innermostIndex]; //Update the placeholder this.options.placeholder.update(this.currentContainer, this.placeholder); this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); this.containers[innermostIndex].containerCache.over = 1; } }, _createHelper: function(event) { var o = this.options, helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); //Add the helper to the DOM if that didn't happen already if(!helper.parents("body").length) { $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); } if(helper[0] === this.currentItem[0]) { this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; } if(!helper[0].style.width || o.forceHelperSize) { helper.width(this.currentItem.width()); } if(!helper[0].style.height || o.forceHelperSize) { helper.height(this.currentItem.height()); } return helper; }, _adjustOffsetFromHelper: function(obj) { if (typeof obj === "string") { obj = obj.split(" "); } if ($.isArray(obj)) { obj = {left: +obj[0], top: +obj[1] || 0}; } if ("left" in obj) { this.offset.click.left = obj.left + this.margins.left; } if ("right" in obj) { this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; } if ("top" in obj) { this.offset.click.top = obj.top + this.margins.top; } if ("bottom" in obj) { this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; } }, _getParentOffset: function() { //Get the offsetParent and cache its position this.offsetParent = this.helper.offsetParent(); var po = this.offsetParent.offset(); // This is a special case where we need to modify a offset calculated on start, since the following happened: // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { po.left += this.scrollParent.scrollLeft(); po.top += this.scrollParent.scrollTop(); } // This needs to be actually done for all browsers, since pageX/pageY includes this information // with an ugly IE fix if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { po = { top: 0, left: 0 }; } return { top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) }; }, _getRelativeOffset: function() { if(this.cssPosition === "relative") { var p = this.currentItem.position(); return { top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() }; } else { return { top: 0, left: 0 }; } }, _cacheMargins: function() { this.margins = { left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), top: (parseInt(this.currentItem.css("marginTop"),10) || 0) }; }, _cacheHelperProportions: function() { this.helperProportions = { width: this.helper.outerWidth(), height: this.helper.outerHeight() }; }, _setContainment: function() { var ce, co, over, o = this.options; if(o.containment === "parent") { o.containment = this.helper[0].parentNode; } if(o.containment === "document" || o.containment === "window") { this.containment = [ 0 - this.offset.relative.left - this.offset.parent.left, 0 - this.offset.relative.top - this.offset.parent.top, $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top ]; } if(!(/^(document|window|parent)$/).test(o.containment)) { ce = $(o.containment)[0]; co = $(o.containment).offset(); over = ($(ce).css("overflow") !== "hidden"); this.containment = [ co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top ]; } }, _convertPositionTo: function(d, pos) { if(!pos) { pos = this.position; } var mod = d === "absolute" ? 1 : -1, scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); return { top: ( pos.top + // The absolute mouse position this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) ), left: ( pos.left + // The absolute mouse position this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) ) }; }, _generatePosition: function(event) { var top, left, o = this.options, pageX = event.pageX, pageY = event.pageY, scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); // This is another very weird special case that only happens for relative elements: // 1. If the css position is relative // 2. and the scroll parent is the document or similar to the offset parent // we have to refresh the relative offset during the scroll so there are no jumps if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { this.offset.relative = this._getRelativeOffset(); } /* * - Position constraining - * Constrain the position to a mix of grid, containment. */ if(this.originalPosition) { //If we are not dragging yet, we won't check for options if(this.containment) { if(event.pageX - this.offset.click.left < this.containment[0]) { pageX = this.containment[0] + this.offset.click.left; } if(event.pageY - this.offset.click.top < this.containment[1]) { pageY = this.containment[1] + this.offset.click.top; } if(event.pageX - this.offset.click.left > this.containment[2]) { pageX = this.containment[2] + this.offset.click.left; } if(event.pageY - this.offset.click.top > this.containment[3]) { pageY = this.containment[3] + this.offset.click.top; } } if(o.grid) { top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; } } return { top: ( pageY - // The absolute mouse position this.offset.click.top - // Click offset (relative to the element) this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent this.offset.parent.top + // The offsetParent's offset without borders (offset + border) ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) ), left: ( pageX - // The absolute mouse position this.offset.click.left - // Click offset (relative to the element) this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent this.offset.parent.left + // The offsetParent's offset without borders (offset + border) ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) ) }; }, _rearrange: function(event, i, a, hardRefresh) { a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); //Various things done here to improve the performance: // 1. we create a setTimeout, that calls refreshPositions // 2. on the instance, we have a counter variable, that get's higher after every append // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same // 4. this lets only the last addition to the timeout stack through this.counter = this.counter ? ++this.counter : 1; var counter = this.counter; this._delay(function() { if(counter === this.counter) { this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove } }); }, _clear: function(event, noPropagation) { this.reverting = false; // We delay all events that have to be triggered to after the point where the placeholder has been removed and // everything else normalized again var i, delayedTriggers = []; // We first have to update the dom position of the actual currentItem // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) if(!this._noFinalSort && this.currentItem.parent().length) { this.placeholder.before(this.currentItem); } this._noFinalSort = null; if(this.helper[0] === this.currentItem[0]) { for(i in this._storedCSS) { if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { this._storedCSS[i] = ""; } } this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); } else { this.currentItem.show(); } if(this.fromOutside && !noPropagation) { delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); } if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed } // Check if the items Container has Changed and trigger appropriate // events. if (this !== this.currentContainer) { if(!noPropagation) { delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); } } //Post events to containers for (i = this.containers.length - 1; i >= 0; i--){ if(!noPropagation) { delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); } if(this.containers[i].containerCache.over) { delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); this.containers[i].containerCache.over = 0; } } //Do what was originally in plugins if ( this.storedCursor ) { this.document.find( "body" ).css( "cursor", this.storedCursor ); this.storedStylesheet.remove(); } if(this._storedOpacity) { this.helper.css("opacity", this._storedOpacity); } if(this._storedZIndex) { this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); } this.dragging = false; if(this.cancelHelperRemoval) { if(!noPropagation) { this._trigger("beforeStop", event, this._uiHash()); for (i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); } //Trigger all delayed events this._trigger("stop", event, this._uiHash()); } this.fromOutside = false; return false; } if(!noPropagation) { this._trigger("beforeStop", event, this._uiHash()); } //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! this.placeholder[0].parentNode.removeChild(this.placeholder[0]); if(this.helper[0] !== this.currentItem[0]) { this.helper.remove(); } this.helper = null; if(!noPropagation) { for (i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); } //Trigger all delayed events this._trigger("stop", event, this._uiHash()); } this.fromOutside = false; return true; }, _trigger: function() { if ($.Widget.prototype._trigger.apply(this, arguments) === false) { this.cancel(); } }, _uiHash: function(_inst) { var inst = _inst || this; return { helper: inst.helper, placeholder: inst.placeholder || $([]), position: inst.position, originalPosition: inst.originalPosition, offset: inst.positionAbs, item: inst.currentItem, sender: _inst ? _inst.element : null }; } }); })(jQuery); (function($, undefined) { var dataSpace = "ui-effects-"; $.effects = { effect: {} }; /*! * jQuery Color Animations v2.1.2 * https://github.com/jquery/jquery-color * * Copyright 2013 jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license * * Date: Wed Jan 16 08:47:09 2013 -0600 */ (function( jQuery, undefined ) { var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", // plusequals test for += 100 -= 100 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, // a set of RE's that can match strings and generate color tuples. stringParsers = [{ re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, parse: function( execResult ) { return [ execResult[ 1 ], execResult[ 2 ], execResult[ 3 ], execResult[ 4 ] ]; } }, { re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, parse: function( execResult ) { return [ execResult[ 1 ] * 2.55, execResult[ 2 ] * 2.55, execResult[ 3 ] * 2.55, execResult[ 4 ] ]; } }, { // this regex ignores A-F because it's compared against an already lowercased string re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, parse: function( execResult ) { return [ parseInt( execResult[ 1 ], 16 ), parseInt( execResult[ 2 ], 16 ), parseInt( execResult[ 3 ], 16 ) ]; } }, { // this regex ignores A-F because it's compared against an already lowercased string re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, parse: function( execResult ) { return [ parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) ]; } }, { re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, space: "hsla", parse: function( execResult ) { return [ execResult[ 1 ], execResult[ 2 ] / 100, execResult[ 3 ] / 100, execResult[ 4 ] ]; } }], // jQuery.Color( ) color = jQuery.Color = function( color, green, blue, alpha ) { return new jQuery.Color.fn.parse( color, green, blue, alpha ); }, spaces = { rgba: { props: { red: { idx: 0, type: "byte" }, green: { idx: 1, type: "byte" }, blue: { idx: 2, type: "byte" } } }, hsla: { props: { hue: { idx: 0, type: "degrees" }, saturation: { idx: 1, type: "percent" }, lightness: { idx: 2, type: "percent" } } } }, propTypes = { "byte": { floor: true, max: 255 }, "percent": { max: 1 }, "degrees": { mod: 360, floor: true } }, support = color.support = {}, // element for support tests supportElem = jQuery( "

    " )[ 0 ], // colors = jQuery.Color.names colors, // local aliases of functions called often each = jQuery.each; // determine rgba support immediately supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; // define cache name and alpha properties // for rgba and hsla spaces each( spaces, function( spaceName, space ) { space.cache = "_" + spaceName; space.props.alpha = { idx: 3, type: "percent", def: 1 }; }); function clamp( value, prop, allowEmpty ) { var type = propTypes[ prop.type ] || {}; if ( value == null ) { return (allowEmpty || !prop.def) ? null : prop.def; } // ~~ is an short way of doing floor for positive numbers value = type.floor ? ~~value : parseFloat( value ); // IE will pass in empty strings as value for alpha, // which will hit this case if ( isNaN( value ) ) { return prop.def; } if ( type.mod ) { // we add mod before modding to make sure that negatives values // get converted properly: -10 -> 350 return (value + type.mod) % type.mod; } // for now all property types without mod have min and max return 0 > value ? 0 : type.max < value ? type.max : value; } function stringParse( string ) { var inst = color(), rgba = inst._rgba = []; string = string.toLowerCase(); each( stringParsers, function( i, parser ) { var parsed, match = parser.re.exec( string ), values = match && parser.parse( match ), spaceName = parser.space || "rgba"; if ( values ) { parsed = inst[ spaceName ]( values ); // if this was an rgba parse the assignment might happen twice // oh well.... inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; rgba = inst._rgba = parsed._rgba; // exit each( stringParsers ) here because we matched return false; } }); // Found a stringParser that handled it if ( rgba.length ) { // if this came from a parsed string, force "transparent" when alpha is 0 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) if ( rgba.join() === "0,0,0,0" ) { jQuery.extend( rgba, colors.transparent ); } return inst; } // named colors return colors[ string ]; } color.fn = jQuery.extend( color.prototype, { parse: function( red, green, blue, alpha ) { if ( red === undefined ) { this._rgba = [ null, null, null, null ]; return this; } if ( red.jquery || red.nodeType ) { red = jQuery( red ).css( green ); green = undefined; } var inst = this, type = jQuery.type( red ), rgba = this._rgba = []; // more than 1 argument specified - assume ( red, green, blue, alpha ) if ( green !== undefined ) { red = [ red, green, blue, alpha ]; type = "array"; } if ( type === "string" ) { return this.parse( stringParse( red ) || colors._default ); } if ( type === "array" ) { each( spaces.rgba.props, function( key, prop ) { rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); }); return this; } if ( type === "object" ) { if ( red instanceof color ) { each( spaces, function( spaceName, space ) { if ( red[ space.cache ] ) { inst[ space.cache ] = red[ space.cache ].slice(); } }); } else { each( spaces, function( spaceName, space ) { var cache = space.cache; each( space.props, function( key, prop ) { // if the cache doesn't exist, and we know how to convert if ( !inst[ cache ] && space.to ) { // if the value was null, we don't need to copy it // if the key was alpha, we don't need to copy it either if ( key === "alpha" || red[ key ] == null ) { return; } inst[ cache ] = space.to( inst._rgba ); } // this is the only case where we allow nulls for ALL properties. // call clamp with alwaysAllowEmpty inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); }); // everything defined but alpha? if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { // use the default of 1 inst[ cache ][ 3 ] = 1; if ( space.from ) { inst._rgba = space.from( inst[ cache ] ); } } }); } return this; } }, is: function( compare ) { var is = color( compare ), same = true, inst = this; each( spaces, function( _, space ) { var localCache, isCache = is[ space.cache ]; if (isCache) { localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; each( space.props, function( _, prop ) { if ( isCache[ prop.idx ] != null ) { same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); return same; } }); } return same; }); return same; }, _space: function() { var used = [], inst = this; each( spaces, function( spaceName, space ) { if ( inst[ space.cache ] ) { used.push( spaceName ); } }); return used.pop(); }, transition: function( other, distance ) { var end = color( other ), spaceName = end._space(), space = spaces[ spaceName ], startColor = this.alpha() === 0 ? color( "transparent" ) : this, start = startColor[ space.cache ] || space.to( startColor._rgba ), result = start.slice(); end = end[ space.cache ]; each( space.props, function( key, prop ) { var index = prop.idx, startValue = start[ index ], endValue = end[ index ], type = propTypes[ prop.type ] || {}; // if null, don't override start value if ( endValue === null ) { return; } // if null - use end if ( startValue === null ) { result[ index ] = endValue; } else { if ( type.mod ) { if ( endValue - startValue > type.mod / 2 ) { startValue += type.mod; } else if ( startValue - endValue > type.mod / 2 ) { startValue -= type.mod; } } result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); } }); return this[ spaceName ]( result ); }, blend: function( opaque ) { // if we are already opaque - return ourself if ( this._rgba[ 3 ] === 1 ) { return this; } var rgb = this._rgba.slice(), a = rgb.pop(), blend = color( opaque )._rgba; return color( jQuery.map( rgb, function( v, i ) { return ( 1 - a ) * blend[ i ] + a * v; })); }, toRgbaString: function() { var prefix = "rgba(", rgba = jQuery.map( this._rgba, function( v, i ) { return v == null ? ( i > 2 ? 1 : 0 ) : v; }); if ( rgba[ 3 ] === 1 ) { rgba.pop(); prefix = "rgb("; } return prefix + rgba.join() + ")"; }, toHslaString: function() { var prefix = "hsla(", hsla = jQuery.map( this.hsla(), function( v, i ) { if ( v == null ) { v = i > 2 ? 1 : 0; } // catch 1 and 2 if ( i && i < 3 ) { v = Math.round( v * 100 ) + "%"; } return v; }); if ( hsla[ 3 ] === 1 ) { hsla.pop(); prefix = "hsl("; } return prefix + hsla.join() + ")"; }, toHexString: function( includeAlpha ) { var rgba = this._rgba.slice(), alpha = rgba.pop(); if ( includeAlpha ) { rgba.push( ~~( alpha * 255 ) ); } return "#" + jQuery.map( rgba, function( v ) { // default to 0 when nulls exist v = ( v || 0 ).toString( 16 ); return v.length === 1 ? "0" + v : v; }).join(""); }, toString: function() { return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); } }); color.fn.parse.prototype = color.fn; // hsla conversions adapted from: // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 function hue2rgb( p, q, h ) { h = ( h + 1 ) % 1; if ( h * 6 < 1 ) { return p + (q - p) * h * 6; } if ( h * 2 < 1) { return q; } if ( h * 3 < 2 ) { return p + (q - p) * ((2/3) - h) * 6; } return p; } spaces.hsla.to = function ( rgba ) { if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { return [ null, null, null, rgba[ 3 ] ]; } var r = rgba[ 0 ] / 255, g = rgba[ 1 ] / 255, b = rgba[ 2 ] / 255, a = rgba[ 3 ], max = Math.max( r, g, b ), min = Math.min( r, g, b ), diff = max - min, add = max + min, l = add * 0.5, h, s; if ( min === max ) { h = 0; } else if ( r === max ) { h = ( 60 * ( g - b ) / diff ) + 360; } else if ( g === max ) { h = ( 60 * ( b - r ) / diff ) + 120; } else { h = ( 60 * ( r - g ) / diff ) + 240; } // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) if ( diff === 0 ) { s = 0; } else if ( l <= 0.5 ) { s = diff / add; } else { s = diff / ( 2 - add ); } return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; }; spaces.hsla.from = function ( hsla ) { if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { return [ null, null, null, hsla[ 3 ] ]; } var h = hsla[ 0 ] / 360, s = hsla[ 1 ], l = hsla[ 2 ], a = hsla[ 3 ], q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, p = 2 * l - q; return [ Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), Math.round( hue2rgb( p, q, h ) * 255 ), Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), a ]; }; each( spaces, function( spaceName, space ) { var props = space.props, cache = space.cache, to = space.to, from = space.from; // makes rgba() and hsla() color.fn[ spaceName ] = function( value ) { // generate a cache for this space if it doesn't exist if ( to && !this[ cache ] ) { this[ cache ] = to( this._rgba ); } if ( value === undefined ) { return this[ cache ].slice(); } var ret, type = jQuery.type( value ), arr = ( type === "array" || type === "object" ) ? value : arguments, local = this[ cache ].slice(); each( props, function( key, prop ) { var val = arr[ type === "object" ? key : prop.idx ]; if ( val == null ) { val = local[ prop.idx ]; } local[ prop.idx ] = clamp( val, prop ); }); if ( from ) { ret = color( from( local ) ); ret[ cache ] = local; return ret; } else { return color( local ); } }; // makes red() green() blue() alpha() hue() saturation() lightness() each( props, function( key, prop ) { // alpha is included in more than one space if ( color.fn[ key ] ) { return; } color.fn[ key ] = function( value ) { var vtype = jQuery.type( value ), fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), local = this[ fn ](), cur = local[ prop.idx ], match; if ( vtype === "undefined" ) { return cur; } if ( vtype === "function" ) { value = value.call( this, cur ); vtype = jQuery.type( value ); } if ( value == null && prop.empty ) { return this; } if ( vtype === "string" ) { match = rplusequals.exec( value ); if ( match ) { value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); } } local[ prop.idx ] = value; return this[ fn ]( local ); }; }); }); // add cssHook and .fx.step function for each named hook. // accept a space separated string of properties color.hook = function( hook ) { var hooks = hook.split( " " ); each( hooks, function( i, hook ) { jQuery.cssHooks[ hook ] = { set: function( elem, value ) { var parsed, curElem, backgroundColor = ""; if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { value = color( parsed || value ); if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { curElem = hook === "backgroundColor" ? elem.parentNode : elem; while ( (backgroundColor === "" || backgroundColor === "transparent") && curElem && curElem.style ) { try { backgroundColor = jQuery.css( curElem, "backgroundColor" ); curElem = curElem.parentNode; } catch ( e ) { } } value = value.blend( backgroundColor && backgroundColor !== "transparent" ? backgroundColor : "_default" ); } value = value.toRgbaString(); } try { elem.style[ hook ] = value; } catch( e ) { // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' } } }; jQuery.fx.step[ hook ] = function( fx ) { if ( !fx.colorInit ) { fx.start = color( fx.elem, hook ); fx.end = color( fx.end ); fx.colorInit = true; } jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); }; }); }; color.hook( stepHooks ); jQuery.cssHooks.borderColor = { expand: function( value ) { var expanded = {}; each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { expanded[ "border" + part + "Color" ] = value; }); return expanded; } }; // Basic color names only. // Usage of any of the other color names requires adding yourself or including // jquery.color.svg-names.js. colors = jQuery.Color.names = { // 4.1. Basic color keywords aqua: "#00ffff", black: "#000000", blue: "#0000ff", fuchsia: "#ff00ff", gray: "#808080", green: "#008000", lime: "#00ff00", maroon: "#800000", navy: "#000080", olive: "#808000", purple: "#800080", red: "#ff0000", silver: "#c0c0c0", teal: "#008080", white: "#ffffff", yellow: "#ffff00", // 4.2.3. "transparent" color keyword transparent: [ null, null, null, 0 ], _default: "#ffffff" }; })( jQuery ); /******************************************************************************/ /****************************** CLASS ANIMATIONS ******************************/ /******************************************************************************/ (function() { var classAnimationActions = [ "add", "remove", "toggle" ], shorthandStyles = { border: 1, borderBottom: 1, borderColor: 1, borderLeft: 1, borderRight: 1, borderTop: 1, borderWidth: 1, margin: 1, padding: 1 }; $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) { $.fx.step[ prop ] = function( fx ) { if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { jQuery.style( fx.elem, prop, fx.end ); fx.setAttr = true; } }; }); function getElementStyles( elem ) { var key, len, style = elem.ownerDocument.defaultView ? elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : elem.currentStyle, styles = {}; if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { len = style.length; while ( len-- ) { key = style[ len ]; if ( typeof style[ key ] === "string" ) { styles[ $.camelCase( key ) ] = style[ key ]; } } // support: Opera, IE <9 } else { for ( key in style ) { if ( typeof style[ key ] === "string" ) { styles[ key ] = style[ key ]; } } } return styles; } function styleDifference( oldStyle, newStyle ) { var diff = {}, name, value; for ( name in newStyle ) { value = newStyle[ name ]; if ( oldStyle[ name ] !== value ) { if ( !shorthandStyles[ name ] ) { if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { diff[ name ] = value; } } } } return diff; } // support: jQuery <1.8 if ( !$.fn.addBack ) { $.fn.addBack = function( selector ) { return this.add( selector == null ? this.prevObject : this.prevObject.filter( selector ) ); }; } $.effects.animateClass = function( value, duration, easing, callback ) { var o = $.speed( duration, easing, callback ); return this.queue( function() { var animated = $( this ), baseClass = animated.attr( "class" ) || "", applyClassChange, allAnimations = o.children ? animated.find( "*" ).addBack() : animated; // map the animated objects to store the original styles. allAnimations = allAnimations.map(function() { var el = $( this ); return { el: el, start: getElementStyles( this ) }; }); // apply class change applyClassChange = function() { $.each( classAnimationActions, function(i, action) { if ( value[ action ] ) { animated[ action + "Class" ]( value[ action ] ); } }); }; applyClassChange(); // map all animated objects again - calculate new styles and diff allAnimations = allAnimations.map(function() { this.end = getElementStyles( this.el[ 0 ] ); this.diff = styleDifference( this.start, this.end ); return this; }); // apply original class animated.attr( "class", baseClass ); // map all animated objects again - this time collecting a promise allAnimations = allAnimations.map(function() { var styleInfo = this, dfd = $.Deferred(), opts = $.extend({}, o, { queue: false, complete: function() { dfd.resolve( styleInfo ); } }); this.el.animate( this.diff, opts ); return dfd.promise(); }); // once all animations have completed: $.when.apply( $, allAnimations.get() ).done(function() { // set the final class applyClassChange(); // for each animated element, // clear all css properties that were animated $.each( arguments, function() { var el = this.el; $.each( this.diff, function(key) { el.css( key, "" ); }); }); // this is guarnteed to be there if you use jQuery.speed() // it also handles dequeuing the next anim... o.complete.call( animated[ 0 ] ); }); }); }; $.fn.extend({ addClass: (function( orig ) { return function( classNames, speed, easing, callback ) { return speed ? $.effects.animateClass.call( this, { add: classNames }, speed, easing, callback ) : orig.apply( this, arguments ); }; })( $.fn.addClass ), removeClass: (function( orig ) { return function( classNames, speed, easing, callback ) { return arguments.length > 1 ? $.effects.animateClass.call( this, { remove: classNames }, speed, easing, callback ) : orig.apply( this, arguments ); }; })( $.fn.removeClass ), toggleClass: (function( orig ) { return function( classNames, force, speed, easing, callback ) { if ( typeof force === "boolean" || force === undefined ) { if ( !speed ) { // without speed parameter return orig.apply( this, arguments ); } else { return $.effects.animateClass.call( this, (force ? { add: classNames } : { remove: classNames }), speed, easing, callback ); } } else { // without force parameter return $.effects.animateClass.call( this, { toggle: classNames }, force, speed, easing ); } }; })( $.fn.toggleClass ), switchClass: function( remove, add, speed, easing, callback) { return $.effects.animateClass.call( this, { add: add, remove: remove }, speed, easing, callback ); } }); })(); /******************************************************************************/ /*********************************** EFFECTS **********************************/ /******************************************************************************/ (function() { $.extend( $.effects, { version: "1.10.2", // Saves a set of properties in a data storage save: function( element, set ) { for( var i=0; i < set.length; i++ ) { if ( set[ i ] !== null ) { element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); } } }, // Restores a set of previously saved properties from a data storage restore: function( element, set ) { var val, i; for( i=0; i < set.length; i++ ) { if ( set[ i ] !== null ) { val = element.data( dataSpace + set[ i ] ); // support: jQuery 1.6.2 // http://bugs.jquery.com/ticket/9917 // jQuery 1.6.2 incorrectly returns undefined for any falsy value. // We can't differentiate between "" and 0 here, so we just assume // empty string since it's likely to be a more common value... if ( val === undefined ) { val = ""; } element.css( set[ i ], val ); } } }, setMode: function( el, mode ) { if (mode === "toggle") { mode = el.is( ":hidden" ) ? "show" : "hide"; } return mode; }, // Translates a [top,left] array into a baseline value // this should be a little more flexible in the future to handle a string & hash getBaseline: function( origin, original ) { var y, x; switch ( origin[ 0 ] ) { case "top": y = 0; break; case "middle": y = 0.5; break; case "bottom": y = 1; break; default: y = origin[ 0 ] / original.height; } switch ( origin[ 1 ] ) { case "left": x = 0; break; case "center": x = 0.5; break; case "right": x = 1; break; default: x = origin[ 1 ] / original.width; } return { x: x, y: y }; }, // Wraps the element around a wrapper that copies position properties createWrapper: function( element ) { // if the element is already wrapped, return it if ( element.parent().is( ".ui-effects-wrapper" )) { return element.parent(); } // wrap the element var props = { width: element.outerWidth(true), height: element.outerHeight(true), "float": element.css( "float" ) }, wrapper = $( "

    " ) .addClass( "ui-effects-wrapper" ) .css({ fontSize: "100%", background: "transparent", border: "none", margin: 0, padding: 0 }), // Store the size in case width/height are defined in % - Fixes #5245 size = { width: element.width(), height: element.height() }, active = document.activeElement; // support: Firefox // Firefox incorrectly exposes anonymous content // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 try { active.id; } catch( e ) { active = document.body; } element.wrap( wrapper ); // Fixes #7595 - Elements lose focus when wrapped. if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { $( active ).focus(); } wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element // transfer positioning properties to the wrapper if ( element.css( "position" ) === "static" ) { wrapper.css({ position: "relative" }); element.css({ position: "relative" }); } else { $.extend( props, { position: element.css( "position" ), zIndex: element.css( "z-index" ) }); $.each([ "top", "left", "bottom", "right" ], function(i, pos) { props[ pos ] = element.css( pos ); if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { props[ pos ] = "auto"; } }); element.css({ position: "relative", top: 0, left: 0, right: "auto", bottom: "auto" }); } element.css(size); return wrapper.css( props ).show(); }, removeWrapper: function( element ) { var active = document.activeElement; if ( element.parent().is( ".ui-effects-wrapper" ) ) { element.parent().replaceWith( element ); // Fixes #7595 - Elements lose focus when wrapped. if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { $( active ).focus(); } } return element; }, setTransition: function( element, list, factor, value ) { value = value || {}; $.each( list, function( i, x ) { var unit = element.cssUnit( x ); if ( unit[ 0 ] > 0 ) { value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; } }); return value; } }); // return an effect options object for the given parameters: function _normalizeArguments( effect, options, speed, callback ) { // allow passing all options as the first parameter if ( $.isPlainObject( effect ) ) { options = effect; effect = effect.effect; } // convert to an object effect = { effect: effect }; // catch (effect, null, ...) if ( options == null ) { options = {}; } // catch (effect, callback) if ( $.isFunction( options ) ) { callback = options; speed = null; options = {}; } // catch (effect, speed, ?) if ( typeof options === "number" || $.fx.speeds[ options ] ) { callback = speed; speed = options; options = {}; } // catch (effect, options, callback) if ( $.isFunction( speed ) ) { callback = speed; speed = null; } // add options to effect if ( options ) { $.extend( effect, options ); } speed = speed || options.duration; effect.duration = $.fx.off ? 0 : typeof speed === "number" ? speed : speed in $.fx.speeds ? $.fx.speeds[ speed ] : $.fx.speeds._default; effect.complete = callback || options.complete; return effect; } function standardAnimationOption( option ) { // Valid standard speeds (nothing, number, named speed) if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { return true; } // Invalid strings - treat as "normal" speed if ( typeof option === "string" && !$.effects.effect[ option ] ) { return true; } // Complete callback if ( $.isFunction( option ) ) { return true; } // Options hash (but not naming an effect) if ( typeof option === "object" && !option.effect ) { return true; } // Didn't match any standard API return false; } $.fn.extend({ effect: function( /* effect, options, speed, callback */ ) { var args = _normalizeArguments.apply( this, arguments ), mode = args.mode, queue = args.queue, effectMethod = $.effects.effect[ args.effect ]; if ( $.fx.off || !effectMethod ) { // delegate to the original method (e.g., .show()) if possible if ( mode ) { return this[ mode ]( args.duration, args.complete ); } else { return this.each( function() { if ( args.complete ) { args.complete.call( this ); } }); } } function run( next ) { var elem = $( this ), complete = args.complete, mode = args.mode; function done() { if ( $.isFunction( complete ) ) { complete.call( elem[0] ); } if ( $.isFunction( next ) ) { next(); } } // If the element already has the correct final state, delegate to // the core methods so the internal tracking of "olddisplay" works. if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { elem[ mode ](); done(); } else { effectMethod.call( elem[0], args, done ); } } return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); }, show: (function( orig ) { return function( option ) { if ( standardAnimationOption( option ) ) { return orig.apply( this, arguments ); } else { var args = _normalizeArguments.apply( this, arguments ); args.mode = "show"; return this.effect.call( this, args ); } }; })( $.fn.show ), hide: (function( orig ) { return function( option ) { if ( standardAnimationOption( option ) ) { return orig.apply( this, arguments ); } else { var args = _normalizeArguments.apply( this, arguments ); args.mode = "hide"; return this.effect.call( this, args ); } }; })( $.fn.hide ), toggle: (function( orig ) { return function( option ) { if ( standardAnimationOption( option ) || typeof option === "boolean" ) { return orig.apply( this, arguments ); } else { var args = _normalizeArguments.apply( this, arguments ); args.mode = "toggle"; return this.effect.call( this, args ); } }; })( $.fn.toggle ), // helper functions cssUnit: function(key) { var style = this.css( key ), val = []; $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { if ( style.indexOf( unit ) > 0 ) { val = [ parseFloat( style ), unit ]; } }); return val; } }); })(); /******************************************************************************/ /*********************************** EASING ***********************************/ /******************************************************************************/ (function() { // based on easing equations from Robert Penner (http://www.robertpenner.com/easing) var baseEasings = {}; $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { baseEasings[ name ] = function( p ) { return Math.pow( p, i + 2 ); }; }); $.extend( baseEasings, { Sine: function ( p ) { return 1 - Math.cos( p * Math.PI / 2 ); }, Circ: function ( p ) { return 1 - Math.sqrt( 1 - p * p ); }, Elastic: function( p ) { return p === 0 || p === 1 ? p : -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 ); }, Back: function( p ) { return p * p * ( 3 * p - 2 ); }, Bounce: function ( p ) { var pow2, bounce = 4; while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); } }); $.each( baseEasings, function( name, easeIn ) { $.easing[ "easeIn" + name ] = easeIn; $.easing[ "easeOut" + name ] = function( p ) { return 1 - easeIn( 1 - p ); }; $.easing[ "easeInOut" + name ] = function( p ) { return p < 0.5 ? easeIn( p * 2 ) / 2 : 1 - easeIn( p * -2 + 2 ) / 2; }; }); })(); })(jQuery); (function( $, undefined ) { var uid = 0, hideProps = {}, showProps = {}; hideProps.height = hideProps.paddingTop = hideProps.paddingBottom = hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide"; showProps.height = showProps.paddingTop = showProps.paddingBottom = showProps.borderTopWidth = showProps.borderBottomWidth = "show"; $.widget( "ui.accordion", { version: "1.10.2", options: { active: 0, animate: {}, collapsible: false, event: "click", header: "> li > :first-child,> :not(li):even", heightStyle: "auto", icons: { activeHeader: "ui-icon-triangle-1-s", header: "ui-icon-triangle-1-e" }, // callbacks activate: null, beforeActivate: null }, _create: function() { var options = this.options; this.prevShow = this.prevHide = $(); this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) // ARIA .attr( "role", "tablist" ); // don't allow collapsible: false and active: false / null if ( !options.collapsible && (options.active === false || options.active == null) ) { options.active = 0; } this._processPanels(); // handle negative values if ( options.active < 0 ) { options.active += this.headers.length; } this._refresh(); }, _getCreateEventData: function() { return { header: this.active, panel: !this.active.length ? $() : this.active.next(), content: !this.active.length ? $() : this.active.next() }; }, _createIcons: function() { var icons = this.options.icons; if ( icons ) { $( "" ) .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) .prependTo( this.headers ); this.active.children( ".ui-accordion-header-icon" ) .removeClass( icons.header ) .addClass( icons.activeHeader ); this.headers.addClass( "ui-accordion-icons" ); } }, _destroyIcons: function() { this.headers .removeClass( "ui-accordion-icons" ) .children( ".ui-accordion-header-icon" ) .remove(); }, _destroy: function() { var contents; // clean up main element this.element .removeClass( "ui-accordion ui-widget ui-helper-reset" ) .removeAttr( "role" ); // clean up headers this.headers .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) .removeAttr( "role" ) .removeAttr( "aria-selected" ) .removeAttr( "aria-controls" ) .removeAttr( "tabIndex" ) .each(function() { if ( /^ui-accordion/.test( this.id ) ) { this.removeAttribute( "id" ); } }); this._destroyIcons(); // clean up content panels contents = this.headers.next() .css( "display", "" ) .removeAttr( "role" ) .removeAttr( "aria-expanded" ) .removeAttr( "aria-hidden" ) .removeAttr( "aria-labelledby" ) .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" ) .each(function() { if ( /^ui-accordion/.test( this.id ) ) { this.removeAttribute( "id" ); } }); if ( this.options.heightStyle !== "content" ) { contents.css( "height", "" ); } }, _setOption: function( key, value ) { if ( key === "active" ) { // _activate() will handle invalid values and update this.options this._activate( value ); return; } if ( key === "event" ) { if ( this.options.event ) { this._off( this.headers, this.options.event ); } this._setupEvents( value ); } this._super( key, value ); // setting collapsible: false while collapsed; open first panel if ( key === "collapsible" && !value && this.options.active === false ) { this._activate( 0 ); } if ( key === "icons" ) { this._destroyIcons(); if ( value ) { this._createIcons(); } } // #5332 - opacity doesn't cascade to positioned elements in IE // so we need to add the disabled class to the headers and panels if ( key === "disabled" ) { this.headers.add( this.headers.next() ) .toggleClass( "ui-state-disabled", !!value ); } }, _keydown: function( event ) { /*jshint maxcomplexity:15*/ if ( event.altKey || event.ctrlKey ) { return; } var keyCode = $.ui.keyCode, length = this.headers.length, currentIndex = this.headers.index( event.target ), toFocus = false; switch ( event.keyCode ) { case keyCode.RIGHT: case keyCode.DOWN: toFocus = this.headers[ ( currentIndex + 1 ) % length ]; break; case keyCode.LEFT: case keyCode.UP: toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; break; case keyCode.SPACE: case keyCode.ENTER: this._eventHandler( event ); break; case keyCode.HOME: toFocus = this.headers[ 0 ]; break; case keyCode.END: toFocus = this.headers[ length - 1 ]; break; } if ( toFocus ) { $( event.target ).attr( "tabIndex", -1 ); $( toFocus ).attr( "tabIndex", 0 ); toFocus.focus(); event.preventDefault(); } }, _panelKeyDown : function( event ) { if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { $( event.currentTarget ).prev().focus(); } }, refresh: function() { var options = this.options; this._processPanels(); // was collapsed or no panel if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { options.active = false; this.active = $(); // active false only when collapsible is true } if ( options.active === false ) { this._activate( 0 ); // was active, but active panel is gone } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { // all remaining panel are disabled if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { options.active = false; this.active = $(); // activate previous panel } else { this._activate( Math.max( 0, options.active - 1 ) ); } // was active, active panel still exists } else { // make sure active index is correct options.active = this.headers.index( this.active ); } this._destroyIcons(); this._refresh(); }, _processPanels: function() { this.headers = this.element.find( this.options.header ) .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); this.headers.next() .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) .filter(":not(.ui-accordion-content-active)") .hide(); }, _refresh: function() { var maxHeight, options = this.options, heightStyle = options.heightStyle, parent = this.element.parent(), accordionId = this.accordionId = "ui-accordion-" + (this.element.attr( "id" ) || ++uid); this.active = this._findActive( options.active ) .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) .removeClass( "ui-corner-all" ); this.active.next() .addClass( "ui-accordion-content-active" ) .show(); this.headers .attr( "role", "tab" ) .each(function( i ) { var header = $( this ), headerId = header.attr( "id" ), panel = header.next(), panelId = panel.attr( "id" ); if ( !headerId ) { headerId = accordionId + "-header-" + i; header.attr( "id", headerId ); } if ( !panelId ) { panelId = accordionId + "-panel-" + i; panel.attr( "id", panelId ); } header.attr( "aria-controls", panelId ); panel.attr( "aria-labelledby", headerId ); }) .next() .attr( "role", "tabpanel" ); this.headers .not( this.active ) .attr({ "aria-selected": "false", tabIndex: -1 }) .next() .attr({ "aria-expanded": "false", "aria-hidden": "true" }) .hide(); // make sure at least one header is in the tab order if ( !this.active.length ) { this.headers.eq( 0 ).attr( "tabIndex", 0 ); } else { this.active.attr({ "aria-selected": "true", tabIndex: 0 }) .next() .attr({ "aria-expanded": "true", "aria-hidden": "false" }); } this._createIcons(); this._setupEvents( options.event ); if ( heightStyle === "fill" ) { maxHeight = parent.height(); this.element.siblings( ":visible" ).each(function() { var elem = $( this ), position = elem.css( "position" ); if ( position === "absolute" || position === "fixed" ) { return; } maxHeight -= elem.outerHeight( true ); }); this.headers.each(function() { maxHeight -= $( this ).outerHeight( true ); }); this.headers.next() .each(function() { $( this ).height( Math.max( 0, maxHeight - $( this ).innerHeight() + $( this ).height() ) ); }) .css( "overflow", "auto" ); } else if ( heightStyle === "auto" ) { maxHeight = 0; this.headers.next() .each(function() { maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); }) .height( maxHeight ); } }, _activate: function( index ) { var active = this._findActive( index )[ 0 ]; // trying to activate the already active panel if ( active === this.active[ 0 ] ) { return; } // trying to collapse, simulate a click on the currently active header active = active || this.active[ 0 ]; this._eventHandler({ target: active, currentTarget: active, preventDefault: $.noop }); }, _findActive: function( selector ) { return typeof selector === "number" ? this.headers.eq( selector ) : $(); }, _setupEvents: function( event ) { var events = { keydown: "_keydown" }; if ( event ) { $.each( event.split(" "), function( index, eventName ) { events[ eventName ] = "_eventHandler"; }); } this._off( this.headers.add( this.headers.next() ) ); this._on( this.headers, events ); this._on( this.headers.next(), { keydown: "_panelKeyDown" }); this._hoverable( this.headers ); this._focusable( this.headers ); }, _eventHandler: function( event ) { var options = this.options, active = this.active, clicked = $( event.currentTarget ), clickedIsActive = clicked[ 0 ] === active[ 0 ], collapsing = clickedIsActive && options.collapsible, toShow = collapsing ? $() : clicked.next(), toHide = active.next(), eventData = { oldHeader: active, oldPanel: toHide, newHeader: collapsing ? $() : clicked, newPanel: toShow }; event.preventDefault(); if ( // click on active header, but not collapsible ( clickedIsActive && !options.collapsible ) || // allow canceling activation ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { return; } options.active = collapsing ? false : this.headers.index( clicked ); // when the call to ._toggle() comes after the class changes // it causes a very odd bug in IE 8 (see #6720) this.active = clickedIsActive ? $() : clicked; this._toggle( eventData ); // switch classes // corner classes on the previously active header stay after the animation active.removeClass( "ui-accordion-header-active ui-state-active" ); if ( options.icons ) { active.children( ".ui-accordion-header-icon" ) .removeClass( options.icons.activeHeader ) .addClass( options.icons.header ); } if ( !clickedIsActive ) { clicked .removeClass( "ui-corner-all" ) .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); if ( options.icons ) { clicked.children( ".ui-accordion-header-icon" ) .removeClass( options.icons.header ) .addClass( options.icons.activeHeader ); } clicked .next() .addClass( "ui-accordion-content-active" ); } }, _toggle: function( data ) { var toShow = data.newPanel, toHide = this.prevShow.length ? this.prevShow : data.oldPanel; // handle activating a panel during the animation for another activation this.prevShow.add( this.prevHide ).stop( true, true ); this.prevShow = toShow; this.prevHide = toHide; if ( this.options.animate ) { this._animate( toShow, toHide, data ); } else { toHide.hide(); toShow.show(); this._toggleComplete( data ); } toHide.attr({ "aria-expanded": "false", "aria-hidden": "true" }); toHide.prev().attr( "aria-selected", "false" ); // if we're switching panels, remove the old header from the tab order // if we're opening from collapsed state, remove the previous header from the tab order // if we're collapsing, then keep the collapsing header in the tab order if ( toShow.length && toHide.length ) { toHide.prev().attr( "tabIndex", -1 ); } else if ( toShow.length ) { this.headers.filter(function() { return $( this ).attr( "tabIndex" ) === 0; }) .attr( "tabIndex", -1 ); } toShow .attr({ "aria-expanded": "true", "aria-hidden": "false" }) .prev() .attr({ "aria-selected": "true", tabIndex: 0 }); }, _animate: function( toShow, toHide, data ) { var total, easing, duration, that = this, adjust = 0, down = toShow.length && ( !toHide.length || ( toShow.index() < toHide.index() ) ), animate = this.options.animate || {}, options = down && animate.down || animate, complete = function() { that._toggleComplete( data ); }; if ( typeof options === "number" ) { duration = options; } if ( typeof options === "string" ) { easing = options; } // fall back from options to animation in case of partial down settings easing = easing || options.easing || animate.easing; duration = duration || options.duration || animate.duration; if ( !toHide.length ) { return toShow.animate( showProps, duration, easing, complete ); } if ( !toShow.length ) { return toHide.animate( hideProps, duration, easing, complete ); } total = toShow.show().outerHeight(); toHide.animate( hideProps, { duration: duration, easing: easing, step: function( now, fx ) { fx.now = Math.round( now ); } }); toShow .hide() .animate( showProps, { duration: duration, easing: easing, complete: complete, step: function( now, fx ) { fx.now = Math.round( now ); if ( fx.prop !== "height" ) { adjust += fx.now; } else if ( that.options.heightStyle !== "content" ) { fx.now = Math.round( total - toHide.outerHeight() - adjust ); adjust = 0; } } }); }, _toggleComplete: function( data ) { var toHide = data.oldPanel; toHide .removeClass( "ui-accordion-content-active" ) .prev() .removeClass( "ui-corner-top" ) .addClass( "ui-corner-all" ); // Work around for rendering bug in IE (#5421) if ( toHide.length ) { toHide.parent()[0].className = toHide.parent()[0].className; } this._trigger( "activate", null, data ); } }); })( jQuery ); (function( $, undefined ) { // used to prevent race conditions with remote data sources var requestIndex = 0; $.widget( "ui.autocomplete", { version: "1.10.2", defaultElement: "", options: { appendTo: null, autoFocus: false, delay: 300, minLength: 1, position: { my: "left top", at: "left bottom", collision: "none" }, source: null, // callbacks change: null, close: null, focus: null, open: null, response: null, search: null, select: null }, pending: 0, _create: function() { // Some browsers only repeat keydown events, not keypress events, // so we use the suppressKeyPress flag to determine if we've already // handled the keydown event. #7269 // Unfortunately the code for & in keypress is the same as the up arrow, // so we use the suppressKeyPressRepeat flag to avoid handling keypress // events when we know the keydown event was used to modify the // search term. #7799 var suppressKeyPress, suppressKeyPressRepeat, suppressInput, nodeName = this.element[0].nodeName.toLowerCase(), isTextarea = nodeName === "textarea", isInput = nodeName === "input"; this.isMultiLine = // Textareas are always multi-line isTextarea ? true : // Inputs are always single-line, even if inside a contentEditable element // IE also treats inputs as contentEditable isInput ? false : // All other element types are determined by whether or not they're contentEditable this.element.prop( "isContentEditable" ); this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; this.isNewMenu = true; this.element .addClass( "ui-autocomplete-input" ) .attr( "autocomplete", "off" ); this._on( this.element, { keydown: function( event ) { /*jshint maxcomplexity:15*/ if ( this.element.prop( "readOnly" ) ) { suppressKeyPress = true; suppressInput = true; suppressKeyPressRepeat = true; return; } suppressKeyPress = false; suppressInput = false; suppressKeyPressRepeat = false; var keyCode = $.ui.keyCode; switch( event.keyCode ) { case keyCode.PAGE_UP: suppressKeyPress = true; this._move( "previousPage", event ); break; case keyCode.PAGE_DOWN: suppressKeyPress = true; this._move( "nextPage", event ); break; case keyCode.UP: suppressKeyPress = true; this._keyEvent( "previous", event ); break; case keyCode.DOWN: suppressKeyPress = true; this._keyEvent( "next", event ); break; case keyCode.ENTER: case keyCode.NUMPAD_ENTER: // when menu is open and has focus if ( this.menu.active ) { // #6055 - Opera still allows the keypress to occur // which causes forms to submit suppressKeyPress = true; event.preventDefault(); this.menu.select( event ); } break; case keyCode.TAB: if ( this.menu.active ) { this.menu.select( event ); } break; case keyCode.ESCAPE: if ( this.menu.element.is( ":visible" ) ) { this._value( this.term ); this.close( event ); // Different browsers have different default behavior for escape // Single press can mean undo or clear // Double press in IE means clear the whole form event.preventDefault(); } break; default: suppressKeyPressRepeat = true; // search timeout should be triggered before the input value is changed this._searchTimeout( event ); break; } }, keypress: function( event ) { if ( suppressKeyPress ) { suppressKeyPress = false; event.preventDefault(); return; } if ( suppressKeyPressRepeat ) { return; } // replicate some key handlers to allow them to repeat in Firefox and Opera var keyCode = $.ui.keyCode; switch( event.keyCode ) { case keyCode.PAGE_UP: this._move( "previousPage", event ); break; case keyCode.PAGE_DOWN: this._move( "nextPage", event ); break; case keyCode.UP: this._keyEvent( "previous", event ); break; case keyCode.DOWN: this._keyEvent( "next", event ); break; } }, input: function( event ) { if ( suppressInput ) { suppressInput = false; event.preventDefault(); return; } this._searchTimeout( event ); }, focus: function() { this.selectedItem = null; this.previous = this._value(); }, blur: function( event ) { if ( this.cancelBlur ) { delete this.cancelBlur; return; } clearTimeout( this.searching ); this.close( event ); this._change( event ); } }); this._initSource(); this.menu = $( "