lcov + gcov-9 performance regression because of json usage - gcc

I have updated my build environment compiler from gcc 5.5.0 to gcc 9.3.0 and noticed coverage calculation performance regression.
It became 10 times slower (5 hours vs 48 hours for whole project).
My investigation shows that in gcov-9 they started to use json format instead of intermediate text format.
This slowed down intermediate gcov-files creation and parsing.
Minimal example below:
> time geninfo --gcov-tool gcov-5 test5/CPrimitiveLayerTest.cpp.gcno
Found gcov version: 5.5.0
Using intermediate gcov format
Processing test5/CPrimitiveLayerTest.cpp.gcno
Finished .info-file creation
real 0m0.351s
user 0m0.298s
sys 0m0.047s
> time geninfo --gcov-tool gcov-9 test9/CPrimitiveLayerTest.cpp.gcno
Found gcov version: 9.3.0
Using intermediate gcov format
Processing test9/CPrimitiveLayerTest.cpp.gcno
Finished .info-file creation
real 0m8.024s
user 0m7.929s
sys 0m0.084s
I didn't find the way to return to old format but maybe there are any workarounds or patches.
P.S. I know about gcov's argument --json-format, but lcov1.15 can process either json format or so-called intermediate text format. At the same time gcov9 can output either json format or so-called logfile format files

Further investigation shows that this is because of lcov 1.15 uses JSON:PP module for json parsing.
Replacing of JSON:PP to JSON:XS (fast parser) gives required speedup.
So I use next commands to reach it:
# patch geninfo to use fast json parser
> sudo sed -i 's/use JSON::PP/use JSON::XS/g' /usr/local/bin/geninfo
# install perl module
> sudo cpan install JSON:XS

Related

How to generate flamegraphs from macOS process samples?

Anyone have a clean process for converting samples on macOS to FlameGraphs?
After a bit of fiddling I thought I could perhaps use a tool such as flamegraph-sample, but it seems to give me some trouble and so I thought perhaps there may be other more up-to-date options that I'm missing insomuch that this tool gives an error:
$ sudo sample PID -file ~/tmp/sample.txt -fullPaths 1
Sampling process 198 for 1 second with 1 millisecond of run time between samples
Sampling completed, processing symbols...
Sample analysis of process 35264 written to file ~/tmp/sample.txt
$ python stackcollapse-sample.py ~/tmp/sample.txt > ~/tmp/sample_collapsed.txt
$ flamegraph.pl ~/tmp/sample_collapsed.txt > ~/tmp/sample_collapsed_flamegraph.svg
Ignored 2335 lines with invalid format
ERROR: No stack counts found

JMeter MergeResults is not handling timeStamp label correctly (millis)

Created two dummy sample projects as (dummy1.jmx and dummy2.jmx) and executed below commands with default settings (JMeter 5.3 default installation with all required plugins installed).
#> jmeter.bat -n -t dummy1.jmx -l dummy1.csv -j dummy1-jmeter.log to execute load
Generated report and timestamps look perfect both in dashboard and graphs
**#> jmeter.bat -g dummy1.csv -o dummy1 -j dummy1-report-jmeter.
#> jmeter.bat -n -t dummy2.jmx -l dummy2.csv -j dummy2-jmeter.log to execute load
Generated report and timestamps look perfect both in dashboard and graphs
#> jmeter.bat -g dummy2.csv -o dummy2 -j dummy2-report-jmeter.log
Used MergeResults plugin to merge the above CSV files to a single file and generated HTML report
#> JMeterPluginsCMD.bat --generate-csv dummy1-dummy2.csv --input-jtl merge.properties --plugin-type MergeResults
Found merged timeStamp label is not valid and also generated report shows invalid DateTime.
#> jmeter.bat -g dummy1-dummy2.csv -o merged -j merged-report-jmeter.log
Is this a bug or am I missing configuration? Even adding jmeter.save.saveservice.timestamp_format=yyyy/MM/dd HH:mm:ss.SSS to user.properties didn't help
merge.properties
inputJtl1=dummy1.csv
prefixLabel1=TEST1:
includeLabels1=.*
excludeLabelsl=
includeLabelRegex1=true
excludeLabelRegex1=
startOffset1=
endOffset1=
inputJtl2=dummy2.csv
prefixLabel2=TEST2:
includeLabels2=.*
excludeLabels2=
includeLabelRegex2=true
excludeLabelRegex2=
startOffset2=
endOffset2=
Unfortunately we cannot help without:
Seeing your merge.properties file contents
Knowing what do you expect
In the meantime I can only tell you where did this 2000-01-01 date came from:
It's declared here:
private static final long REF_START_TIME = 946681200000L;
And being added to the original SampleResult timestamp here:
res.setTimeStamp(res.getTimeStamp() - startTimeRef + REF_START_TIME);
I don't know whether it is a bug or it's designed to work like this (however the crazy logic of substraction of sampler start time from its timestamp is beyond my limited understanding), it's better to check at JMeter Plugins support forum
In the meantime you can use services like BM.Sense for comparing different test runs resutls

How do I find out a program version from a core dump? Can I write it there myself?

I have a core file, but I am uncertain which version of the program produced it. When I use the file command, I get only the binary name, not the version.
% file core.20200730-1203
core.20200730-1203: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from 'qdrouterd -c /tmp/qdrouterd.json', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: '/usr/sbin/qdrouterd', platform: 'x86_64'
I can try to give my debugger multiple binaries in turn that I guess are close in version, and see what works and what doesn't.
I believe that the solution is to put a string constant with the version into the program code. Core dumps contain the program code, because it is loaded into memory for execution, and therefore I should be able to recover it using the strings command.
Currently, the program contains the following, where QPID_DISPATCH_VERSION is a preprocessor macro.
qd_log(router->log_source, QD_LOG_INFO, "Version: %s", QPID_DISPATCH_VERSION);
I am able to get to it, with
% strings core.20200730-1203 | grep -A3 -B3 "Version: "
Activating management agent on $_management_internal
router
Router Engine Instantiated: id=router-default-0 instance=1596103149 max_routers=128
Version: 1.13.0-SNAPSHOT
Router started in Interior mode, area=0 id=router-default-0
Container Name: router-default-0
Milan
but this is probably just an accident, a log line which was still present in the memory at the moment of crash.
What is a reliable way to encode and recover the version information?

Issue in creating Vectors from text in Mahout

I'm using Mahout 0.9 (installed on HDP 2.2) for topic discovery (Latent Drichlet Allocation algorithm). I have my text file stored in directory
inputraw and executed the following commands in order
command #1:
mahout seqdirectory -i inputraw -o output-directory -c UTF-8
command #2:
mahout seq2sparse -i output-directory -o output-vector-str -wt tf -ng 3 --maxDFPercent 40 -ow -nv
command #3:
mahout rowid -i output-vector-str/tf-vectors/ -o output-vector-int
command #4:
mahout cvb -i output-vector-int/matrix -o output-topics -k 1 -mt output-tmp -x 10 -dict output-vector-str/dictionary.file-0
After executing the second command and as expected it creates a bunch of subfolders and files under the
output-vector-str (named df-count, dictionary.file-0, frequency.file-0, tf-vectors,tokenized-documents and wordcount). The size of these files all looks ok considering the size of my input file however the file under ``tf-vectors` has a very small size, in fact it's only 118 bytes).
Apparently as the
`tf-vectors` is the input to the 3rd command, the third command also generates a file of small size. Does anyone know:
what is the reason of the file under
`tf-vectors` folder to be that small? There must be something wrong.
Starting from the first command, all the generated files have a strange coding and are nor human readable. Is this something expected?
Your answers are as follows:
what is the reason of the file under tf-vectors folder to be that small?
The vectors are small considering you have given maxdf percentage to be only 40%, implying that only terms which have a doc freq(percentage freq of terms occurring throughout the docs) of less than 40% would be taken in consideration. In other words, only terms which occur in 40% of the documents or less would be taken in consideration while generating vectors.
what is the reason of the file under tf-vectors folder to be that small?
There is a command in mahout called the mahout seqdumper which would come to your rescue for dumping the files in "sequential" format to "human" readable format.
Good Luck!!

How to zgrep the last line of a gz file without tail

Here is my problem, I have a set of big gz log files, the very first info in the line is a datetime text, e.g.: 2014-03-20 05:32:00.
I need to check what set of log files holds a specific data.
For the init I simply do a:
'-query-data-'
zgrep -m 1 '^20140320-04' 20140320-0{3,4}*gz
BUT HOW to do the same with the last line without process the whole file as would be done with zcat (too heavy):
zcat foo.gz | tail -1
Additional info, those logs are created with the data time of it's initial record, so if I want to query logs at 14:00:00 I have to search, also, in files created BEFORE 14:00:00, as a file would be created at 13:50:00 and closed at 14:10:00.
The easiest solution would be to alter your log rotation to create smaller files.
The second easiest solution would be to use a compression tool that supports random access.
Projects like dictzip, BGZF, and csio each add sync flush points at various intervals within gzip-compressed data that allow you to seek to in a program aware of that extra information. While it exists in the standard, the vanilla gzip does not add such markers either by default or by option.
Files compressed by these random-access-friendly utilities are slightly larger (by perhaps 2-20%) due to the markers themselves, but fully support decompression with gzip or another utility that is unaware of these markers.
You can learn more at this question about random access in various compression formats.
There's also a "Blasted Bioinformatics" blog by Peter Cock with several posts on this topic, including:
BGZF - Blocked, Bigger & Better GZIP! – gzip with random access (like dictzip)
Random access to BZIP2? – An investigation (result: can't be done, though I do it below)
Random access to blocked XZ format (BXZF) – xz with improved random access support
Experiments with xz
xz (an LZMA compression format) actually has random access support on a per-block level, but you will only get a single block with the defaults.
File creation
xz can concatenate multiple archives together, in which case each archive would have its own block. The GNU split can do this easily:
split -b 50M --filter 'xz -c' big.log > big.log.sp.xz
This tells split to break big.log into 50MB chunks (before compression) and run each one through xz -c, which outputs the compressed chunk to standard output. We then collect that standard output into a single file named big.log.sp.xz.
To do this without GNU, you'd need a loop:
split -b 50M big.log big.log-part
for p in big.log-part*; do xz -c $p; done > big.log.sp.xz
rm big.log-part*
Parsing
You can get the list of block offsets with xz --verbose --list FILE.xz. If you want the last block, you need its compressed size (column 5) plus 36 bytes for overhead (found by comparing the size to hd big.log.sp0.xz |grep 7zXZ). Fetch that block using tail -c and pipe that through xz. Since the above question wants the last line of the file, I then pipe that through tail -n1:
SIZE=$(xz --verbose --list big.log.sp.xz |awk 'END { print $5 + 36 }')
tail -c $SIZE big.log.sp.xz |unxz -c |tail -n1
Side note
Version 5.1.1 introduced support for the --block-size flag:
xz --block-size=50M big.log
However, I have not been able to extract a specific block since it doesn't include full headers between blocks. I suspect this is nontrivial to do from the command line.
Experiments with gzip
gzip also supports concatenation. I (briefly) tried mimicking this process for gzip without any luck. gzip --verbose --list doesn't give enough information and it appears the headers are too variable to find.
This would require adding sync flush points, and since their size varies on the size of the last buffer in the previous compression, that's too hard to do on the command line (use dictzip or another of the previously discussed tools).
I did apt-get install dictzip and played with dictzip, but just a little. It doesn't work without arguments, creating a (massive!) .dz archive that neither dictunzip nor gunzip could understand.
Experiments with bzip2
bzip2 has headers we can find. This is still a bit messy, but it works.
Creation
This is just like the xz procedure above:
split -b 50M --filter 'bzip2 -c' big.log > big.log.sp.bz2
I should note that this is considerably slower than xz (48 min for bzip2 vs 17 min for xz vs 1 min for xz -0) as well as considerably larger (97M for bzip2 vs 25M for xz -0 vs 15M for xz), at least for my test log file.
Parsing
This is a little harder because we don't have the nice index. We have to guess at where to go, and we have to err on the side of scanning too much, but with a massive file, we'd still save I/O.
My guess for this test was 50000000 (out of the original 52428800, a pessimistic guess that isn't pessimistic enough for e.g. an H.264 movie.)
GUESS=50000000
LAST=$(tail -c$GUESS big.log.sp.bz2 \
|grep -abo 'BZh91AY&SY' |awk -F: 'END { print '$GUESS'-$1 }')
tail -c $LAST big.log.sp.bz2 |bunzip2 -c |tail -n1
This takes just the last 50 million bytes, finds the binary offset of the last BZIP2 header, subtracts that from the guess size, and pulls that many bytes off of the end of the file. Just that part is decompressed and thrown into tail.
Because this has to query the compressed file twice and has an extra scan (the grep call seeking the header, which examines the whole guessed space), this is a suboptimal solution. See also the below section on how slow bzip2 really is.
Perspective
Given how fast xz is, it's easily the best bet; using its fastest option (xz -0) is quite fast to compress or decompress and creates a smaller file than gzip or bzip2 on the log file I was testing with. Other tests (as well as various sources online) suggest that xz -0 is preferable to bzip2 in all scenarios.
————— No Random Access —————— ——————— Random Access ———————
FORMAT SIZE RATIO WRITE READ SIZE RATIO WRITE SEEK
————————— ————————————————————————————— —————————————————————————————
(original) 7211M 1.0000 - 0:06 7211M 1.0000 - 0:00
bzip2 96M 0.0133 48:31 3:15 97M 0.0134 47:39 0:00
gzip 79M 0.0109 0:59 0:22
dictzip 605M 0.0839 1:36 (fail)
xz -0 25M 0.0034 1:14 0:12 25M 0.0035 1:08 0:00
xz 14M 0.0019 16:32 0:11 14M 0.0020 16:44 0:00
Timing tests were not comprehensive, I did not average anything and disk caching was in use. Still, they look correct; there is a very small amount of overhead from split plus launching 145 compression instances rather than just one (this may even be a net gain if it allows an otherwise non-multithreaded utility to consume multiple threads).
Well, you can access randomly a gzipped file if you previously create an index for each file ...
I've developed a command line tool which creates indexes for gzip files which allow for very quick random access inside them:
https://github.com/circulosmeos/gztool
The tool has two options that may be of interest for you:
-S option supervise a still-growing file and creates an index for it as it is growing - this can be useful for gzipped rsyslog files as reduces to zero in the practice the time of index creation.
-t tails a gzip file: this way you can do: $ gztool -t foo.gz | tail -1
Please, note that if the index doesn't exists, this will consume the same time as a complete decompression: but as the index is reusable, next searches will be greatly reduced in time!
This tool is based on zran.c demonstration code from original zlib, so there's no out-of-the-rules magic!

Resources