diff --git a/man/man3/pmregisterderived.3 b/man/man3/pmregisterderived.3 index 76cc8e12ff..5f557e58d8 100644 --- a/man/man3/pmregisterderived.3 +++ b/man/man3/pmregisterderived.3 @@ -144,13 +144,13 @@ my.summary.disk.avgsz\c The expression .I expr follows these syntactic rules: -.IP * 2n +.IP \(bu 2n Terminal elements are either names of existing metrics or numeric constants. Recursive definitions are not allowed, so only the names of regular metrics (not other derived metrics) may be used. Numeric constants are either integers constrained to the precision of 32-bit unsigned integers or double precision floating point numbers. -.IP * 2n +.IP \(bu 2n The usual binary arithmetic operators are supported, namely addition (``+''), subtraction (``-''), multiplication (``*'') and division (``/'') with the normal precedence rules where multiplication and division have @@ -163,13 +163,13 @@ is evaluated as a+(b*c)\c .ft R \&. -.IP * 2n +.IP \(bu 2n Unary negation may be used, e.g. .ft CR -3*some.metric\c .ft R \&. -.IP * 2n +.IP \(bu 2n C-style relational operators are supported, namely ``<'', ``<='', ``=='', \&``>='', ``>'' and ``!=''. Relational expressions return a value as a 32-bit unsigned number being @@ -195,7 +195,7 @@ is evaluated as (a>b)!=c\c .ft R \&. -.IP * 2n +.IP \(bu 2n C-style boolean operators are supported, namely and (``&&'') and or (``||''). Boolean expressions return a value as a 32-bit unsigned number being 0 for false and 1 for true. @@ -220,7 +220,7 @@ is evaluated as (((a>=b)||(b>c))&&(d!=e))||(f>g)\c .ft R \&. -.IP * 2n +.IP \(bu 2n Additionally, the ``!'' operator may be used to negate a boolean or relational expression, returning a value as a 32-bit unsigned number being 0 for false and 1 for true. @@ -245,7 +245,7 @@ is evaluated as !(a<(b+c))\c .ft R \&. -.IP * 2n +.IP \(bu 2n C-style ternary conditional expressions are supported. In general terms the expression .ft CR @@ -289,11 +289,13 @@ evaluation of the ``guard'', then the result is a set of values (all the same) with instance enumeration being taken from the other operand expression. For example in the expression: .ft CR -foo ? scalar : set\c +check ? foo : bar\c .ft R -\&, if \f(CRfoo\fP is true, then the result is a set of values -(all having the same value, \f(CRscalar\fP) over -the instance domain of \f(CRset\fP. +\&, if \f(CRfoo\fP is an expression with a singular value and +\f(CRbar\fP is a set-valued expression, then if \f(CRcheck\fP is true, +then the result is a set of values +(all having the same value, \f(CRfoo\fP) over +the instance domain of \f(CRbar\fP. .IP (h) 4n As a special case, either (but not both) of the expressions @@ -350,7 +352,7 @@ fumble = defined(new.metric) ? new.metric : old.metric which is valid when \f(CRnew.metric\fP is defined .B and when \f(CRnew.metric\fP is -.I not +.B not defined, although this does mean rules (b) and (c) are relaxed in this case, which further means \f(CRnovalue()\fP may have no peer operand to provide metadata. @@ -369,7 +371,7 @@ bar = !defined(a) || !defined(b) ? novalue() : a + b .RS -4n .PD .RS -2n -.IP * 2n +.IP \(bu 2n Selection of a single instance can be specified by the construct ``[\fIinstance_name\fR]'' which may be appended to a metric name or a parenthesized expression. @@ -400,7 +402,7 @@ any spurious white space. A backslash may be used as an escape prefix in the (unlikely) event that the external instance name contains a ``]''. .RE -.IP * 2n +.IP \(bu 2n Numeric constants can also be specified using the .ft CR mkconst() @@ -466,12 +468,12 @@ type and/or semantics and/or units for operands, e.g. idle = mem.util.free > mkconst(10485760, units=Kbyte) .br avg_io_size = delta(disk.dev.total) == 0 ? \e - -mkconst(1.0, semantics=instant, units="kbyte / count") : \e + mkconst(1.0, semantics=instant, units="kbyte / count") : \e delta(disk.dev.total_bytes) / delta(disk.dev.total) .ft R .in .RE -.IP * 2n +.IP \(bu 2n Expressions may be rescaled using the .ft CR rescale @@ -492,20 +494,17 @@ rescale(network.interface.total.bytes, "Mbytes/hour") The expression and the desired units must both have the same dimension, e.g Space=1, Time=\-1 and Count=0 in the example above. .RE -.IP * 2n +.IP \(bu 2n The following unary functions operate on a single performance metric and return one or more values. For all functions (except .ft CR count()\c .ft R -, -.ft CR -defined() -.ft R and .ft CR -instant()\c +defined()\c +.ft R .ft R ), the type of the operand metric must be arithmetic (integer of various sizes and signedness, float or @@ -523,10 +522,7 @@ _ count(x) T{ A singular instance being the count of the number of instances for the metric x. As a special case, if fetching the metric x returns an error, then -.ft CR -count(x) -.ft R -will be 0. +\f(CRcount(x)\fP will be 0. T} _ defined(x) T{ @@ -545,35 +541,87 @@ context has been established will not change the value of this function in the expression evaluation. T} _ -delta(x) T{ -Returns the difference in values for the metric x between +max(x) T{ +A singular instance being the maximum value across all instances for the metric x. +T} +_ +min(x) T{ +A singular instance being the minimum value across all instances for the metric x. +T} +_ +sum(x) T{ +A singular instance being the sum of the values across all instances for the metric x. +T} +.TE +.IP \(bu 2n +The following unary function returns the instantaneous value of an +expression, not the rate-converted value that is the default +for expressions with the semantics of PM_SEM_COUNTER. +.TS +box,center; +cf(R) | cf(R) +lf(CR) | lf(R)x. +Function Value +_ +instant(expr) T{ +Returns the current value of the expression, even it has +the semantics of a counter, i.e. PM_SEM_COUNTER. +The semantics of the derived metric are based on the semantics of the +expression \f(CRexpr\fR; if \f(CRexpr\fR has semantics PM_SEM_COUNTER, the semantics of +\f(CRinstant(expr)\fR is PM_SEM_INSTANT, otherwise the semantics of the derived metric +is the same as the semantics of \f(CRexpr\fR. +T} +.TE +.IP \(bu 2n +The following unary functions return values computed from +the value of an expression on consecutive samples, or +.BR pmFetch (3) +calls. +The expression (\f(CRexpr\fR below) may involve one or more metrics +but must have an arithmetic value +(integer of various sizes and signedness, float or double) for all +instances. +.RS 2n +.PP +If \f(CRexpr\fP is a set-valued expression then only those instances +that appear in +.B both +samples will appear in the result. +.TS +box,center; +cf(R) | cf(R) +lf(CR) | lf(R)x. +Function Value +_ +delta(expr) T{ +Returns the difference in values for the expression 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. -If the metric x is unsigned, then the type of the result is +If the expression is unsigned, then the type of the result is converted to ensure as much precision as possible can be retained, -so if the metric x has type PM_TYPE_U32 then the result is of type PM_TYPE_64, else -if the metric x has type PM_TYPE_U64 then the result is of type PM_TYPE_DOUBLE. +so if the expression has type PM_TYPE_U32 then the result is of type PM_TYPE_64, else +if the expression has type PM_TYPE_U64 then the result is of type PM_TYPE_DOUBLE. Otherwise the type of the result is the same as the type of the -metric x. +expression. T} _ -rate(x) T{ -Returns the difference in values for the metric x between +rate(expr) T{ +Returns the difference in values for the expression between one call to .BR pmFetch (3) and the next divided by the elapsed time between the calls to .BR pmFetch (3). The semantics of the derived metric are based on the semantics of the -metric x with the dimension in the +expression with the dimension in the .B time domain decreased by one and scaling if required in the time utilization case where the operand is in units of time, and the derived metric is unitless. There is one value in the result for each instance that appears in both the current and the previous -sample, except in the case where the metric x has +sample, except in the case where the expression has the semantics of a counter, i.e. PM_SEM_COUNTER, and current value of an instance is smaller than the previous value of the same instance then no value is @@ -586,29 +634,9 @@ such as and .BR pmchart (1). T} -_ -instant(x) T{ -Returns the current value of the metric x, even it has -the semantics of a counter, i.e. PM_SEM_COUNTER. -The semantics of the derived metric are based on the semantics of the -metric x; if x has semantics PM_SEM_COUNTER, the semantics of -instant(x) is PM_SEM_INSTANT, otherwise the semantics of the derived metric -is the same as the semantics of the metric x. -T} -_ -max(x) T{ -A singular instance being the maximum value across all instances for the metric x. -T} -_ -min(x) T{ -A singular instance being the minimum value across all instances for the metric x. -T} -_ -sum(x) T{ -A singular instance being the sum of the values across all instances for the metric x. -T} .TE -.IP * 2n +.RE +.IP \(bu 2n The \f(CRmatchinst\fR function may be used to select a subset of the instances from an instance domain for a metric or expression. The function takes two arguments: @@ -620,7 +648,7 @@ by a regular expression delimited by ``/'' characters. The regular expression follows the POSIX Extended Regular Expression syntax as described in .BR regex (3). -Backslashes may be used as escape prefixes, but double backslash is required to +A single backslash may be used to escape the regular expression delimiter ``/'', but double backslashes are required to escape any regular expression special characters, e.g. for the (extremely unlikely) case of wanting to match instance names like ``some*text/other[text]'' a regular expression of the form \f(CR/some\e\e*text\e/other\e\e[text]/\fR @@ -646,7 +674,7 @@ matchinst(!/^(lo)|(vbir)/, network.interface.in.bytes) .in .br .RE -.IP * 2n +.IP \(bu 2n The \f(CRscalar\fR function may be used convert a metric or expression defined over an instance domain into a scalar value that can be used in other expressions. @@ -672,15 +700,15 @@ or expressions that are expected to contain zero or one instances, e.g. the construct ``[\fIinstance_name\fR]'' or the \f(CRmatchinst\fR function with a pattern that matches at most one instance. .RE -.IP * 2n +.IP \(bu 2n Parenthesis may be used for explicit grouping. -.IP * 2n +.IP \(bu 2n A line ending with ``\e'' is treated as ``to be continued'' and the following line is appended after stripping the ``\e'' and the embedded newline. -.IP * 2n +.IP \(bu 2n Lines beginning with ``#'' are treated as comments and ignored. -.IP * 2n +.IP \(bu 2n White space is ignored. .SH "SEMANTIC CHECKS AND RULES" There are a number of conversions required to determine the @@ -715,25 +743,25 @@ a result that is not a counter, either or both operands of a relational expressi may be counters. .PP The mapping of the pmUnits of the metadata uses the following rules: -.IP * 2n +.IP \(bu 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 +.IP \(bu 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 +.IP \(bu 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 +.IP \(bu 2n For addition and subtraction all dimensions for each of the operands and result are identical. -.IP * 2n +.IP \(bu 2n For multiplication, the dimensions of the result are the sum of the dimensions of the operands. -.IP * 2n +.IP \(bu 2n For division, the dimensions of the result are the difference of the dimensions of the operands. .PP @@ -894,7 +922,7 @@ Metrics with counter semantics may be added or subtracted, but .TP Semantic error: derived metric : operand : Unknown metric for ternary expression When a new context was established, the metric was not in the -PMNS of the new context and is a required operand in the defintion of +PMNS of the new context and is a required operand in the definition of the derived metric . .SH "EXPRESSION EVALUATION" For the binary arithmetic operators, @@ -925,14 +953,14 @@ T{ otherwise (both are PM_TYPE_32) T} any PM_TYPE_32 .TE -.SH PMIDS AND MASKING +.SH PMIDs AND MASKING Within PCP each metric is assigned a unique Performance Metric Identifier (PMID) and internally a PMID is constructed from 3 fields: the domain number (of the associated Performance Metrics Domain Agent, or PMDA), the cluster number and the item number. Derived metrics use the reserved domain number 511 and -special PMIDs as decribed in the following table, where +special PMIDs as described in the following table, where the PMID is shown as domain.cluster.item: .TS box,center; @@ -1100,7 +1128,9 @@ Error: pmRegisterDerivedMetric("my.disk.rates", ...) syntax error The position indicator line may be followed by an additional diagnostic line describing the nature of the error, when available. .PP -In the case of an error, the caller is responsible for calling +In the case of an error, the +.B pmRegisterDerivedMetric +caller is responsible for calling .BR free (3) to release the space allocated for .IR errmsg . @@ -1127,3 +1157,6 @@ and .\" +ok+ fw {from fw.bytes} .\" +ok+ sensical {from non-sensical} .\" +ok+ abc def {both from abc.def} +.\" +ok+ bname {from operand } +.\" +ok+ dname {from operand } +.\" +ok+ Dderive {from -Dderive} diff --git a/qa/1105.out b/qa/1105.out index 7fbf6a55a6..4e4a070d2a 100644 --- a/qa/1105.out +++ b/qa/1105.out @@ -7,6 +7,7 @@ qa.ok pmcd.pmlogger.port + ^ Arithmetic expression expected to follow PLUS +bind_expr: error: global derived metric qa.hide.semantic: operand: no.such.metric.ever.will.exist: Unknown metric name traverse PMNS below qa ... qa.hide.ok @@ -15,6 +16,7 @@ qa.ok pmcd.pmlogger.port + ^ Arithmetic expression expected to follow PLUS +bind_expr: error: global derived metric qa.hide.semantic: operand: no.such.metric.ever.will.exist: Unknown metric name exact matches in PMNS ... qa.hide.ok @@ -24,6 +26,7 @@ qa.ok ^ Arithmetic expression expected to follow PLUS Error: qa.hide.syntax: Unknown metric name +bind_expr: error: global derived metric qa.hide.semantic: operand: no.such.metric.ever.will.exist: Unknown metric name Error: qa.hide.semantic: Unknown metric name mismatches in PMNS ... @@ -42,6 +45,7 @@ qa.ok pmcd.pmlogger.port + ^ Arithmetic expression expected to follow PLUS +bind_expr: error: global derived metric qa.hide.semantic: operand: no.such.metric.ever.will.exist: Unknown metric name traverse PMNS below qa -d ... qa.hide.ok @@ -50,6 +54,7 @@ qa.ok pmcd.pmlogger.port + ^ Arithmetic expression expected to follow PLUS +bind_expr: error: global derived metric qa.hide.semantic: operand: no.such.metric.ever.will.exist: Unknown metric name exact matches in PMNS -d ... qa.hide.ok @@ -59,6 +64,7 @@ qa.ok ^ Arithmetic expression expected to follow PLUS Error: qa.hide.syntax: Unknown metric name +bind_expr: error: global derived metric qa.hide.semantic: operand: no.such.metric.ever.will.exist: Unknown metric name Error: qa.hide.semantic: Unknown metric name mismatches in PMNS -d ... diff --git a/qa/1254 b/qa/1254 index a8ecdaae91..7a8bd94c9d 100755 --- a/qa/1254 +++ b/qa/1254 @@ -1,6 +1,7 @@ #!/bin/sh # PCP QA Test No. 1254 # per-context derived metrics with pmDupContext() in the mix +# - non-valgrind version, see qa/1256 for the valgrind version # # Copyright (c) 2020 Ken McDonell. All Rights Reserved. # @@ -57,11 +58,12 @@ export PCP_DERIVED_CONFIG=$tmp.conf if [ "$1" = "--valgrind" ] then - _run_valgrind src/ctx_derive -P testme.big testme.lights testme.bad + _run_valgrind --save-output src/ctx_derive -P testme.big testme.lights testme.bad else - src/ctx_derive -P testme.big testme.lights testme.bad -fi \ -| _filter + src/ctx_derive -P testme.big testme.lights testme.bad >$tmp.out 2>$tmp.err +fi +_filter <$tmp.err +_filter <$tmp.out # success, all done status=0 diff --git a/qa/1254.out b/qa/1254.out index b69abc291e..ca4dc55cda 100644 --- a/qa/1254.out +++ b/qa/1254.out @@ -1,4 +1,7 @@ QA output created by 1254 +bind_expr: error: global derived metric testme.bad: operand: sample.no.such.metric: Unknown metric name +bind_expr: error: global derived metric testme.bad: operand: sample.no.such.metric: Unknown metric name +bind_expr: error: global derived metric testme.bad: operand: sample.no.such.metric: Unknown metric name name[0] testme.one name[1] testme.two name[2] testme.sub.two diff --git a/qa/1256.out b/qa/1256.out index e5ac473d46..2a5fb858e7 100644 --- a/qa/1256.out +++ b/qa/1256.out @@ -1,6 +1,15 @@ QA output created by 1256 QA output created by 1254 --valgrind -=== std out === +=== filtered valgrind report === +Memcheck, a memory error detector +Command: src/ctx_derive -P testme.big testme.lights testme.bad +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... +bind_expr: error: global derived metric testme.bad: operand: sample.no.such.metric: Unknown metric name +bind_expr: error: global derived metric testme.bad: operand: sample.no.such.metric: Unknown metric name +bind_expr: error: global derived metric testme.bad: operand: sample.no.such.metric: Unknown metric name name[0] testme.one name[1] testme.two name[2] testme.sub.two @@ -294,11 +303,3 @@ ctx[1]: pmUseContext: Attempt to use an illegal context, skip work === State 8 === ctx[0]: pmUseContext: Attempt to use an illegal context, skip work ctx[1]: pmUseContext: Attempt to use an illegal context, skip work -=== std err === -=== filtered valgrind report === -Memcheck, a memory error detector -Command: src/ctx_derive -P testme.big testme.lights testme.bad -LEAK SUMMARY: -definitely lost: 0 bytes in 0 blocks -indirectly lost: 0 bytes in 0 blocks -ERROR SUMMARY: 0 errors from 0 contexts ... diff --git a/qa/1521 b/qa/1521 new file mode 100755 index 0000000000..eeace27b81 --- /dev/null +++ b/qa/1521 @@ -0,0 +1,134 @@ +#!/bin/sh +# PCP QA Test No. 1521 +# derived metrics ... delta(expr), rate(expr) and +# instant(expr) extensions +# +# non-valgrind variant, see qa/1522 for the valgrind variant +# +# Copyright (c) 2024 Ken McDonell. All Rights Reserved. +# + +if [ $# -eq 0 ] +then + seq=`basename $0` + echo "QA output created by $seq" +else + # use $seq from caller, unless not set + [ -n "$seq" ] || seq=`basename $0` + echo "QA output created by `basename $0` $*" +fi + +# get standard environment, filters and checks +. ./common.product +. ./common.filter +. ./common.check + +$sudo rm -rf $tmp $tmp.* $seq.full + +do_valgrind=false +if [ "$1" = "--valgrind" ] +then + _check_valgrind + do_valgrind=true +elif which valgrind >/dev/null 2>&1 +then + [ "$PCPQA_VALGRIND" = both ] || \ + _notrun "valgrind variant qa/1522 will be run" +fi + +_cleanup() +{ + cd $here + $sudo rm -rf $tmp $tmp.* +} + +status=0 # success is the default! +trap "_cleanup; exit \$status" 0 1 2 3 15 + +_filter() +{ + now=`PCP_DERIVED_CONFIG=/dev/null pmprobe -v sample.seconds | cut -d' ' -f3` + sed \ + -e "s@$tmp@TMP@g" \ + -e 's/0xffffffff/0x.../g' \ + -e 's/0x[0-9a-f][0-9a-f]*//g' \ + | $PCP_AWK_PROG ' +NF == 1 && $1 >= 0.8 && $1 <= 1.2 { print " close to 1.000"; next } +NF == 1 && $1 >= 8 && $1 <= 12 { print " close to 10.000"; next } +NF == 1 && $1 >= '$now'-20 && $1 <= '$now' { print " close to "; next } + { print }' + # end +} + +export PCP_DERIVED_CONFIG=$tmp.config + +# real QA test starts here + +echo "Syntax/semantic errors ..." +cat <<'End-of-File' >$tmp.tmp +# string-valued expr +qa.bad.b01 = delta("foo") +# unknown metric (sample mis-spelled) +qa.bad.b02 = rate(samples.string.hullo) +# cannot get pmDesc +qa.bad.b03 = delta(sample.bad.unknown) +# type == string +qa.bad.b04 = rate(sample.string.hullo) +# type == event record +qa.bad.b05 = delta(sample.event.records) +# type == aggregate +qa.bad.b06 = rate(sampledso.sysinfo) +End-of-File +sed <$tmp.tmp -e '/^#/d' \ +| while read defn +do + echo "--- $defn" + echo "$defn" >$tmp.config + if $do_valgrind + then + _run_valgrind --save-output pminfo -f qa.bad + else + pminfo -f qa.bad >$tmp.out 2>$tmp.err + fi + _filter <$tmp.err + _filter <$tmp.out +done + +pmstore sample.updown.control.reset 0 >>$seq.full 2>&1 +pmstore sample.updown.control.step 1 >>$seq.full 2>&1 +pmstore sample.updown.control.repeat 1 >>$seq.full 2>&1 +pmstore sample.updown.obs 42 >>$seq.full 2>&1 + +echo +echo "Evaluations ..." +cat <<'End-of-File' >$tmp.tmp +qa.g01 = delta(42) +qa.g02 = rate(1 * 100 + 2*10 + 3 + 4/10 + 5/100 + 6/1000) +qa.g03 = delta(sample.updown.obs) +qa.g04 = delta(sample.long.hundred * sample.updown.obs) +qa.g05 = rate(max(sample.proc.time)) +qa.g06 = delta(defined(sample.updown.obs) ? sample.updown.obs : 13) +qa.g07 = rate(defined(sample.updown.no.metric) ? 13 : sample.updown.obs) +qa.g08 = instant(1950 + 5/12 + 26/365) +qa.g09 = instant(2 * sample.seconds - sample.seconds) +End-of-File +debug=-Dderive,appl2 +sed <$tmp.tmp -e '/^#/d' \ +| while read defn +do + echo "--- $defn" + echo "$defn" >$tmp.config + metric=`echo "$defn" | sed -e 's/ .*//'` + if $do_valgrind + then + _run_valgrind --save-output pmval $debug -f4 -w9 -s 3 -t 0.1sec $metric + else + pmval $debug -f4 -w9 -s 3 -t 0.1sec $metric >$tmp.out 2>$tmp.err + fi + _filter <$tmp.err + _filter <$tmp.out + debug='' # one-trip for debugging +done + +# success, all done +exit diff --git a/qa/1521.out b/qa/1521.out new file mode 100644 index 0000000000..8eb95f1e21 --- /dev/null +++ b/qa/1521.out @@ -0,0 +1,164 @@ +QA output created by 1521 +Syntax/semantic errors ... +--- qa.bad.b01 = delta("foo") +[TMP.config:1] Error: pmRegisterDerived(qa.bad.b01, ...) syntax error + delta("foo") + ^ + expected to follow delta( +Error: qa.bad: Unknown metric name +--- qa.bad.b02 = rate(samples.string.hullo) +bind_expr: error: global derived metric qa.bad.b02: operand: samples.string.hullo: Unknown metric name +Error: qa.bad: Unknown metric name +--- qa.bad.b03 = delta(sample.bad.unknown) +bind_expr: error: global derived metric qa.bad.b03: operand (sample.bad.unknown [29.0.54]): Unknown or illegal metric identifier +Error: qa.bad: Unknown metric name +--- qa.bad.b04 = rate(sample.string.hullo) +Semantic error: derived metric qa.bad.b04: RATE(sample.string.hullo): Non-arithmetic operand for function +Error: qa.bad: Unknown metric name +--- qa.bad.b05 = delta(sample.event.records) +Semantic error: derived metric qa.bad.b05: DELTA(sample.event.records): Non-arithmetic operand for function +Error: qa.bad: Unknown metric name +--- qa.bad.b06 = rate(sampledso.sysinfo) +Semantic error: derived metric qa.bad.b06: RATE(sampledso.sysinfo): Non-arithmetic operand for function +Error: qa.bad: Unknown metric name + +Evaluations ... +--- qa.g01 = delta(42) +pmRegisterDerived: global metric[0] event.flags = anon(PM_TYPE_U32) +pmRegisterDerived: global metric[1] event.missed = anon(PM_TYPE_U32) +Derived metric initialization from $PCP_DERIVED_CONFIG +pmLoadDerivedConfig("TMP.config") +pmRegisterDerived: global metric[2] qa.g01 = delta(42) +__dmgetpmid: metric "qa.g01" -> PMID 511.0.3 +__dmgetpmid: metric "qa.g01" -> PMID 511.0.3 +__dmpostvalueset: [0] root node 511.0.3: numval=0 +expr node type=DELTA left= right=(nil) save_last=0 + PMID: PM_ID_NULL (511.0.3 from pmDesc) numval: 0 + Data Type: 64-bit int InDom: PM_INDOM_NULL 0x... + Semantics: instant Units: none +expr node type=INTEGER left=(nil) right=(nil) save_last=1 [42] primary=0 + PMID: PM_ID_NULL (PM_ID_NULL from pmDesc) numval: 1 + Data Type: 32-bit unsigned int InDom: PM_INDOM_NULL 0x... + Semantics: discrete Units: none +[0] inst=-1, val=42 +__dmpostvalueset: [0] root node 511.0.3: numval=1 vset[0]: inst=-1 ll=0 +expr node type=DELTA left= right=(nil) save_last=0 + PMID: PM_ID_NULL (511.0.3 from pmDesc) numval: 1 + Data Type: 64-bit int InDom: PM_INDOM_NULL 0x... + Semantics: instant Units: none +[0] inst=-1, val=0 +expr node type=INTEGER left=(nil) right=(nil) save_last=1 [42] primary=0 + PMID: PM_ID_NULL (PM_ID_NULL from pmDesc) numval: 1 + Data Type: 32-bit unsigned int InDom: PM_INDOM_NULL 0x... + Semantics: discrete Units: none +[0] inst=-1, val=42 (last inst=-1, val=42) +__dmpostvalueset: [0] root node 511.0.3: numval=1 vset[0]: inst=-1 ll=0 +expr node type=DELTA left= right=(nil) save_last=0 + PMID: PM_ID_NULL (511.0.3 from pmDesc) numval: 1 + Data Type: 64-bit int InDom: PM_INDOM_NULL 0x... + Semantics: instant Units: none +[0] inst=-1, val=0 +expr node type=INTEGER left=(nil) right=(nil) save_last=1 [42] primary=0 + PMID: PM_ID_NULL (PM_ID_NULL from pmDesc) numval: 1 + Data Type: 32-bit unsigned int InDom: PM_INDOM_NULL 0x... + Semantics: discrete Units: none +[0] inst=-1, val=42 (last inst=-1, val=42) +__dmclosecontext(->ctx 0) called dm-> 3 metrics + +metric: qa.g01 +host: bozo.localdomain +semantics: instantaneous value +units: none +samples: 3 +interval: 0.10 sec +No values available + 0 + 0 +--- qa.g02 = rate(1 * 100 + 2*10 + 3 + 4/10 + 5/100 + 6/1000) + +metric: qa.g02 +host: bozo.localdomain +semantics: instantaneous value +units: / sec +samples: 3 +interval: 0.10 sec +No values available + 0.0000 + 0.0000 +--- qa.g03 = delta(sample.updown.obs) + +metric: qa.g03 +host: bozo.localdomain +semantics: instantaneous value +units: none +samples: 3 +interval: 0.10 sec +No values available + close to 1.000 + close to 1.000 +--- qa.g04 = delta(sample.long.hundred * sample.updown.obs) + +metric: qa.g04 +host: bozo.localdomain +semantics: instantaneous value +units: none +samples: 3 +interval: 0.10 sec +No values available + 100 + 100 +--- qa.g05 = rate(max(sample.proc.time)) + +metric: qa.g05 +host: bozo.localdomain +semantics: instantaneous value +units: none +samples: 3 +interval: 0.10 sec +No values available + close to 1.000 + close to 1.000 +--- qa.g06 = delta(defined(sample.updown.obs) ? sample.updown.obs : 13) + +metric: qa.g06 +host: bozo.localdomain +semantics: instantaneous value +units: none +samples: 3 +interval: 0.10 sec +No values available + close to 1.000 + close to 1.000 +--- qa.g07 = rate(defined(sample.updown.no.metric) ? 13 : sample.updown.obs) + +metric: qa.g07 +host: bozo.localdomain +semantics: instantaneous value +units: / sec +samples: 3 +interval: 0.10 sec +No values available + close to 10.000 + close to 10.000 +--- qa.g08 = instant(1950 + 5/12 + 26/365) + +metric: qa.g08 +host: bozo.localdomain +semantics: discrete instantaneous value +units: none +samples: 3 +interval: 0.10 sec +1950.4879 +1950.4879 +1950.4879 +--- qa.g09 = instant(2 * sample.seconds - sample.seconds) + +metric: qa.g09 +host: bozo.localdomain +semantics: instantaneous value +units: sec +samples: 3 +interval: 0.10 sec + close to + close to + close to diff --git a/qa/1522 b/qa/1522 new file mode 100755 index 0000000000..9d085db391 --- /dev/null +++ b/qa/1522 @@ -0,0 +1,38 @@ +#!/bin/sh +# PCP QA Test No. 1522 +# derived metrics ... delta(expr), rate(expr) and +# instant(expr) extensions +# +# valgrind variant, see qa/1521 for the non-valgrind variant +# +# check-group-include: derive +# +# Copyright (c) 2024 Ken McDonell. All Rights Reserved. +# + +seq=`basename $0` +echo "QA output created by $seq" + +# get standard environment, filters and checks +. ./common.product +. ./common.filter +. ./common.check + +_check_valgrind + +_cleanup() +{ + cd $here + $sudo rm -rf $tmp $tmp.* +} + +status=0 # success is the default! +$sudo rm -rf $tmp $tmp.* $seq.full +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# real QA test starts here +export seq +./1521 --valgrind + +# success, all done +exit diff --git a/qa/1522.out b/qa/1522.out new file mode 100644 index 0000000000..3ea8e641af --- /dev/null +++ b/qa/1522.out @@ -0,0 +1,270 @@ +QA output created by 1522 +QA output created by 1521 --valgrind +Syntax/semantic errors ... +--- qa.bad.b01 = delta("foo") +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pminfo -f qa.bad +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... +[TMP.config:1] Error: pmRegisterDerived(qa.bad.b01, ...) syntax error + delta("foo") + ^ + expected to follow delta( +Error: qa.bad: Unknown metric name +--- qa.bad.b02 = rate(samples.string.hullo) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pminfo -f qa.bad +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... +bind_expr: error: global derived metric qa.bad.b02: operand: samples.string.hullo: Unknown metric name +Error: qa.bad: Unknown metric name +--- qa.bad.b03 = delta(sample.bad.unknown) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pminfo -f qa.bad +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... +bind_expr: error: global derived metric qa.bad.b03: operand (sample.bad.unknown [29.0.54]): Unknown or illegal metric identifier +Error: qa.bad: Unknown metric name +--- qa.bad.b04 = rate(sample.string.hullo) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pminfo -f qa.bad +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... +Semantic error: derived metric qa.bad.b04: RATE(sample.string.hullo): Non-arithmetic operand for function +Error: qa.bad: Unknown metric name +--- qa.bad.b05 = delta(sample.event.records) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pminfo -f qa.bad +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... +Semantic error: derived metric qa.bad.b05: DELTA(sample.event.records): Non-arithmetic operand for function +Error: qa.bad: Unknown metric name +--- qa.bad.b06 = rate(sampledso.sysinfo) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pminfo -f qa.bad +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... +Semantic error: derived metric qa.bad.b06: RATE(sampledso.sysinfo): Non-arithmetic operand for function +Error: qa.bad: Unknown metric name + +Evaluations ... +--- qa.g01 = delta(42) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmval -Dderive,appl2 -f4 -w9 -s 3 -t 0.1sec qa.g01 +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... +pmRegisterDerived: global metric[0] event.flags = anon(PM_TYPE_U32) +pmRegisterDerived: global metric[1] event.missed = anon(PM_TYPE_U32) +Derived metric initialization from $PCP_DERIVED_CONFIG +pmLoadDerivedConfig("TMP.config") +pmRegisterDerived: global metric[2] qa.g01 = delta(42) +__dmgetpmid: metric "qa.g01" -> PMID 511.0.3 +__dmgetpmid: metric "qa.g01" -> PMID 511.0.3 +__dmpostvalueset: [0] root node 511.0.3: numval=0 +expr node type=DELTA left= right=(nil) save_last=0 + PMID: PM_ID_NULL (511.0.3 from pmDesc) numval: 0 + Data Type: 64-bit int InDom: PM_INDOM_NULL 0x... + Semantics: instant Units: none +expr node type=INTEGER left=(nil) right=(nil) save_last=1 [42] primary=0 + PMID: PM_ID_NULL (PM_ID_NULL from pmDesc) numval: 1 + Data Type: 32-bit unsigned int InDom: PM_INDOM_NULL 0x... + Semantics: discrete Units: none +[0] inst=-1, val=42 +__dmpostvalueset: [0] root node 511.0.3: numval=1 vset[0]: inst=-1 ll=0 +expr node type=DELTA left= right=(nil) save_last=0 + PMID: PM_ID_NULL (511.0.3 from pmDesc) numval: 1 + Data Type: 64-bit int InDom: PM_INDOM_NULL 0x... + Semantics: instant Units: none +[0] inst=-1, val=0 +expr node type=INTEGER left=(nil) right=(nil) save_last=1 [42] primary=0 + PMID: PM_ID_NULL (PM_ID_NULL from pmDesc) numval: 1 + Data Type: 32-bit unsigned int InDom: PM_INDOM_NULL 0x... + Semantics: discrete Units: none +[0] inst=-1, val=42 (last inst=-1, val=42) +__dmpostvalueset: [0] root node 511.0.3: numval=1 vset[0]: inst=-1 ll=0 +expr node type=DELTA left= right=(nil) save_last=0 + PMID: PM_ID_NULL (511.0.3 from pmDesc) numval: 1 + Data Type: 64-bit int InDom: PM_INDOM_NULL 0x... + Semantics: instant Units: none +[0] inst=-1, val=0 +expr node type=INTEGER left=(nil) right=(nil) save_last=1 [42] primary=0 + PMID: PM_ID_NULL (PM_ID_NULL from pmDesc) numval: 1 + Data Type: 32-bit unsigned int InDom: PM_INDOM_NULL 0x... + Semantics: discrete Units: none +[0] inst=-1, val=42 (last inst=-1, val=42) +__dmclosecontext(->ctx 0) called dm-> 3 metrics + +metric: qa.g01 +host: bozo.localdomain +semantics: instantaneous value +units: none +samples: 3 +interval: 0.10 sec +No values available + 0 + 0 +--- qa.g02 = rate(1 * 100 + 2*10 + 3 + 4/10 + 5/100 + 6/1000) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmval -f4 -w9 -s 3 -t 0.1sec qa.g02 +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +metric: qa.g02 +host: bozo.localdomain +semantics: instantaneous value +units: / sec +samples: 3 +interval: 0.10 sec +No values available + 0.0000 + 0.0000 +--- qa.g03 = delta(sample.updown.obs) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmval -f4 -w9 -s 3 -t 0.1sec qa.g03 +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +metric: qa.g03 +host: bozo.localdomain +semantics: instantaneous value +units: none +samples: 3 +interval: 0.10 sec +No values available + close to 1.000 + close to 1.000 +--- qa.g04 = delta(sample.long.hundred * sample.updown.obs) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmval -f4 -w9 -s 3 -t 0.1sec qa.g04 +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +metric: qa.g04 +host: bozo.localdomain +semantics: instantaneous value +units: none +samples: 3 +interval: 0.10 sec +No values available + 100 + 100 +--- qa.g05 = rate(max(sample.proc.time)) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmval -f4 -w9 -s 3 -t 0.1sec qa.g05 +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +metric: qa.g05 +host: bozo.localdomain +semantics: instantaneous value +units: none +samples: 3 +interval: 0.10 sec +No values available + close to 1.000 + close to 1.000 +--- qa.g06 = delta(defined(sample.updown.obs) ? sample.updown.obs : 13) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmval -f4 -w9 -s 3 -t 0.1sec qa.g06 +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +metric: qa.g06 +host: bozo.localdomain +semantics: instantaneous value +units: none +samples: 3 +interval: 0.10 sec +No values available + close to 1.000 + close to 1.000 +--- qa.g07 = rate(defined(sample.updown.no.metric) ? 13 : sample.updown.obs) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmval -f4 -w9 -s 3 -t 0.1sec qa.g07 +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +metric: qa.g07 +host: bozo.localdomain +semantics: instantaneous value +units: / sec +samples: 3 +interval: 0.10 sec +No values available + close to 10.000 + close to 10.000 +--- qa.g08 = instant(1950 + 5/12 + 26/365) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmval -f4 -w9 -s 3 -t 0.1sec qa.g08 +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +metric: qa.g08 +host: bozo.localdomain +semantics: discrete instantaneous value +units: none +samples: 3 +interval: 0.10 sec +1950.4879 +1950.4879 +1950.4879 +--- qa.g09 = instant(2 * sample.seconds - sample.seconds) +=== filtered valgrind report === +Memcheck, a memory error detector +Command: pmval -f4 -w9 -s 3 -t 0.1sec qa.g09 +LEAK SUMMARY: +definitely lost: 0 bytes in 0 blocks +indirectly lost: 0 bytes in 0 blocks +ERROR SUMMARY: 0 errors from 0 contexts ... + +metric: qa.g09 +host: bozo.localdomain +semantics: instantaneous value +units: sec +samples: 3 +interval: 0.10 sec + close to + close to + close to diff --git a/qa/256 b/qa/256 index 167fd26b8c..7427336076 100755 --- a/qa/256 +++ b/qa/256 @@ -183,7 +183,10 @@ for args in "" derived derived_tree sample do echo | tee -a $seq.full echo "=== $args ===" | tee -a $seq.full - pminfo -c $tmp.config $args 2>&1 | _filter_derived + pminfo -c $tmp.config $args 2>&1 \ + | _filter_derived \ + | sed -e '/bind_expr: error: .*.: Unknown metric name/d' \ + # end done echo | tee -a $seq.full diff --git a/qa/351.out b/qa/351.out index 78af150203..65d9adf8eb 100644 --- a/qa/351.out +++ b/qa/351.out @@ -38,6 +38,7 @@ sample.long.bin_ctr inst [900 or "bin-900"] value 900 Now with the derived metrics ... +bind_expr: error: global derived metric sample.long.lots: operand: sample.million: Unknown metric name sample.long.one value 1 diff --git a/qa/923.out b/qa/923.out index fb5907dc70..58caf5b085 100644 --- a/qa/923.out +++ b/qa/923.out @@ -1,6 +1,7 @@ QA output created by 923 === std out === === std err === +bind_expr: error: global derived metric foo.bar: operand: non.existent: Unknown metric name Error: foo.bar: Unknown metric name === filtered valgrind report === Memcheck, a memory error detector diff --git a/qa/group b/qa/group index dbd4355c1a..eb554dbae3 100644 --- a/qa/group +++ b/qa/group @@ -1987,6 +1987,8 @@ x11 1518:reserved kenj 1519:reserved kenj 1520 other libpcp local pmconfig +1521 derive local +1522 derive local valgrind 1530 pmda.zfs local valgrind 1531 pmda.zfs local valgrind 1532 pmda.zfs local diff --git a/src/libpcp/src/derive_fetch.c b/src/libpcp/src/derive_fetch.c index c5d2407bb6..7bf0a7a38d 100644 --- a/src/libpcp/src/derive_fetch.c +++ b/src/libpcp/src/derive_fetch.c @@ -159,10 +159,44 @@ __dmprefetch(__pmContext *ctxp, int numpmid, const pmID *pmidlist, pmID **newlis } /* - * 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() and rate()). +* saving history for delta() or rate() ... release previous sample +* last_ivlist[] and save this sample last_ivlist[] <- ivlist[] +*/ +static void +save_ivlist(node_t *np) +{ + if (np->save_last) { + if (np->type == N_INTEGER || np->type == N_DOUBLE) { + /* + * these will never change, so fake out the "last" + * ones the first time through + */ + if (np->data.info->ivlist != NULL && + np->data.info->last_ivlist == NULL) { + np->data.info->last_numval = np->data.info->numval; + np->data.info->last_ivlist = np->data.info->ivlist; + } + } + else { + if (np->data.info->last_ivlist != NULL) { + /* + * no STRING, AGGREGATE or EVENT types for delta() or rate() + * so simple free() + */ + free(np->data.info->last_ivlist); + } + np->data.info->last_numval = np->data.info->numval; + np->data.info->last_ivlist = np->data.info->ivlist; + np->data.info->ivlist = NULL; + } + } +} + +/* + * Either call save_ivlist() to free last_ivlist[] and save one history + * sample (for delta() and rate()), or free 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. */ static void free_ivlist(node_t *np) @@ -171,22 +205,8 @@ free_ivlist(node_t *np) assert(np->data.info != NULL); - if (np->save_last) { - /* - * saving history for delta() or rate() ... release previous - * sample, and save this sample - */ - if (np->data.info->last_ivlist != NULL) { - /* - * no STRING, AGGREGATE or EVENT types for delta() or rate() - * so simple free() - */ - free(np->data.info->last_ivlist); - } - np->data.info->last_numval = np->data.info->numval; - np->data.info->last_ivlist = np->data.info->ivlist; - np->data.info->ivlist = NULL; - } + if (np->save_last) + save_ivlist(np); else { /* no history */ if (np->data.info->ivlist != NULL) { @@ -844,6 +864,7 @@ eval_expr(__pmContext *ctxp, node_t *np, struct timespec *stamp, int numpmid, case N_INTEGER: case N_DOUBLE: + save_ivlist(np); adjust_constant(ctxp, np); return np->data.info->numval; @@ -1327,6 +1348,7 @@ eval_expr(__pmContext *ctxp, node_t *np, struct timespec *stamp, int numpmid, * values are in the left expr */ assert(np->left != NULL); + save_ivlist(np); np->data.info->last_stamp = np->data.info->stamp; np->data.info->stamp = *stamp; np->data.info->numval = np->left->data.info->numval; @@ -1340,6 +1362,7 @@ eval_expr(__pmContext *ctxp, node_t *np, struct timespec *stamp, int numpmid, case N_MAX: case N_MIN: case N_SCALAR: + save_ivlist(np); if (np->data.info->ivlist == NULL) { /* initialize ivlist[] for singular instance first time through */ if ((np->data.info->ivlist = (val_t *)malloc(sizeof(val_t))) == NULL) { @@ -1549,13 +1572,13 @@ eval_expr(__pmContext *ctxp, node_t *np, struct timespec *stamp, int numpmid, if (np->data.info->pmid == PM_ID_NULL) { return 0; } + free_ivlist(np); /* * otherwise extract instance-values from pmResult and store * them in ivlist[] as pairs */ for (j = 0; j < numpmid; j++) { if (np->data.info->pmid == vset[j]->pmid) { - free_ivlist(np); np->data.info->numval = vset[j]->numval; if (np->data.info->numval <= 0) return np->data.info->numval; @@ -2220,6 +2243,11 @@ __dmpostfetch(__pmContext *ctxp, __pmResult **result) if (cp == NULL || cp->fetch_has_dm == 0) return; + if (pmDebugOptions.derive && pmDebugOptions.desperate) { + fprintf(stderr, "__dmpostfetch: from context before rewrite ...\n"); + __pmPrintResult_ctx(ctxp, stderr, rp); + } + if ((newrp = __pmAllocResult(cp->numpmid)) == NULL) { pmNoMem("__dmpostfetch: newrp", sizeof(__pmResult) + (cp->numpmid - 1) * sizeof(pmValueSet *), PM_FATAL_ERR); /* NOTREACHED */ diff --git a/src/libpcp/src/derive_parser.y.in b/src/libpcp/src/derive_parser.y.in index 14d2cbdf5b..ef4ae4dd92 100644 --- a/src/libpcp/src/derive_parser.y.in +++ b/src/libpcp/src/derive_parser.y.in @@ -390,7 +390,8 @@ free_expr(node_t *np) } free(np->data.info->ivlist); } - if (np->data.info->last_ivlist != NULL) { + if (np->data.info->last_ivlist != NULL && + np->type != N_INTEGER && np->type != N_DOUBLE) { if (np->desc.type == PM_TYPE_STRING) { int j; for (j = 0; j < np->data.info->last_numval; j++) { @@ -702,13 +703,16 @@ bind_expr(__pmContext *ctxp, int n, node_t *np, node_t *parent, int lookup_mode, new->desc.pmid = new->data.info->pmid = PM_ID_NULL; return new; } - if (pmDebugOptions.derive) { + if (async) { char errmsg[PM_MAXERRMSGLEN]; if (is_global) - fprintf(stderr, "bind_expr: error: global derived metric %s: operand: %s: %s\n", registered.mlist[n].name, new->value, pmErrStr_r(sts, errmsg, sizeof(errmsg))); + pmprintf("bind_expr: error: global derived metric %s: operand: %s: %s\n", registered.mlist[n].name, new->value, pmErrStr_r(sts, errmsg, sizeof(errmsg))); else - fprintf(stderr, "bind_expr: error: per-context derived metric %s: operand: %s: %s\n", cp->mlist[n].name, new->value, pmErrStr_r(sts, errmsg, sizeof(errmsg))); + pmprintf("bind_expr: error: per-context derived metric %s: operand: %s: %s\n", cp->mlist[n].name, new->value, pmErrStr_r(sts, errmsg, sizeof(errmsg))); + pmflush(); } + else + PM_TPD(derive_errmsg) = "Unknown operand metric"; if (is_global) free_expr(new); return NULL; @@ -742,14 +746,17 @@ bind_expr(__pmContext *ctxp, int n, node_t *np, node_t *parent, int lookup_mode, sts = pmLookupDesc_ctx(ctxp, PM_LOCKED, new->data.info->pmid, &new->desc); if (sts < 0) { - if (pmDebugOptions.derive) { + if (async) { char strbuf[20]; char errmsg[PM_MAXERRMSGLEN]; if (is_global) - fprintf(stderr, "bind_expr: error: global derived metric %s: operand (%s [%s]): %s\n", registered.mlist[n].name, new->value, pmIDStr_r(new->data.info->pmid, strbuf, sizeof(strbuf)), pmErrStr_r(sts, errmsg, sizeof(errmsg))); + pmprintf("bind_expr: error: global derived metric %s: operand (%s [%s]): %s\n", registered.mlist[n].name, new->value, pmIDStr_r(new->data.info->pmid, strbuf, sizeof(strbuf)), pmErrStr_r(sts, errmsg, sizeof(errmsg))); else - fprintf(stderr, "bind_expr: error: per-context derived metric %s: operand (%s [%s]): %s\n", cp->mlist[n].name, new->value, pmIDStr_r(new->data.info->pmid, strbuf, sizeof(strbuf)), pmErrStr_r(sts, errmsg, sizeof(errmsg))); + pmprintf("bind_expr: error: per-context derived metric %s: operand (%s [%s]): %s\n", cp->mlist[n].name, new->value, pmIDStr_r(new->data.info->pmid, strbuf, sizeof(strbuf)), pmErrStr_r(sts, errmsg, sizeof(errmsg))); + pmflush(); } + else + PM_TPD(derive_errmsg) = "Metadata for operand metric not available"; if (is_global) free_expr(new); return NULL; @@ -4377,10 +4384,9 @@ func : L_ANON L_LPAREN L_NAME L_RPAREN np->left->value = $3; $$ = np; } - | L_DELTA L_LPAREN L_NAME L_RPAREN + | L_DELTA L_LPAREN expr L_RPAREN { np = newnode(N_DELTA); - np->left = newnode(N_NAME); - np->left->value = $3; + np->left = $3; np->left->save_last = 1; $$ = np; } @@ -4402,17 +4408,15 @@ func : L_ANON L_LPAREN L_NAME L_RPAREN np->left->value = $3; $$ = np; } - | L_RATE L_LPAREN L_NAME L_RPAREN + | L_RATE L_LPAREN expr L_RPAREN { np = newnode(N_RATE); - np->left = newnode(N_NAME); - np->left->value = $3; + np->left = $3; np->left->save_last = 1; $$ = np; } - | L_INSTANT L_LPAREN L_NAME L_RPAREN + | L_INSTANT L_LPAREN expr L_RPAREN { np = newnode(N_INSTANT); - np->left = newnode(N_NAME); - np->left->value = $3; + np->left = $3; $$ = np; } | L_DEFINED L_LPAREN L_NAME L_RPAREN @@ -4458,7 +4462,7 @@ func : L_ANON L_LPAREN L_NAME L_RPAREN | L_COUNT L_LPAREN error { gramerr(name_str, follow, "count("); YYERROR; } | L_DELTA L_LPAREN error - { gramerr(name_str, follow, "delta("); YYERROR; } + { gramerr("", follow, "delta("); YYERROR; } | L_MAX L_LPAREN error { gramerr(name_str, follow, "max("); YYERROR; } | L_MIN L_LPAREN error @@ -4466,7 +4470,7 @@ func : L_ANON L_LPAREN L_NAME L_RPAREN | L_SUM L_LPAREN error { gramerr(name_str, follow, "sum("); YYERROR; } | L_RATE L_LPAREN error - { gramerr(name_str, follow, "rate("); YYERROR; } + { gramerr("", follow, "rate("); YYERROR; } | L_INSTANT L_LPAREN error { gramerr(name_str, follow, "instant("); YYERROR; } | L_RESCALE L_LPAREN error