mirror of
https://github.com/dlang-community/DCD.git
synced 2025-04-26 21:29:58 +03:00
add PR comments that show build statistics, speed & RAM usage (#735)
This commit is contained in:
parent
c324b60da3
commit
19e019a57b
8 changed files with 485 additions and 4 deletions
109
ci/request_time_stats.d
Normal file
109
ci/request_time_stats.d
Normal file
|
@ -0,0 +1,109 @@
|
|||
import core.time;
|
||||
import std.algorithm;
|
||||
import std.conv;
|
||||
import std.format;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
|
||||
void main()
|
||||
{
|
||||
long[] shortRequests, longRequests;
|
||||
|
||||
foreach (line; stdin.byLine)
|
||||
{
|
||||
auto index = line.countUntil("Request processed in ");
|
||||
if (index == -1)
|
||||
{
|
||||
stderr.writeln("Warning: skipping unknown line for stats: ", line);
|
||||
continue;
|
||||
}
|
||||
index += "Request processed in ".length;
|
||||
auto dur = line[index .. $].parseDuration;
|
||||
if (dur != Duration.init)
|
||||
{
|
||||
if (dur >= 10.msecs)
|
||||
longRequests ~= dur.total!"hnsecs";
|
||||
else
|
||||
shortRequests ~= dur.total!"hnsecs";
|
||||
}
|
||||
}
|
||||
|
||||
if (shortRequests.length > 0)
|
||||
{
|
||||
writeln("STAT:short requests: (", shortRequests.length, "x)");
|
||||
summarize(shortRequests);
|
||||
}
|
||||
writeln("STAT:");
|
||||
if (longRequests.length > 0)
|
||||
{
|
||||
writeln("STAT:long requests over 10ms: (", longRequests.length, "x)");
|
||||
summarize(longRequests);
|
||||
}
|
||||
}
|
||||
|
||||
void summarize(long[] hnsecs)
|
||||
{
|
||||
hnsecs.sort!"a<b";
|
||||
|
||||
auto minRequest = hnsecs[0];
|
||||
auto maxRequest = hnsecs[$ - 1];
|
||||
auto medianRequest = hnsecs[$ / 2];
|
||||
auto p10Request = hnsecs[$ * 10 / 100];
|
||||
auto p90Request = hnsecs[$ * 90 / 100];
|
||||
|
||||
writeln("STAT: min request time = ", minRequest.formatHnsecs);
|
||||
writeln("STAT: 10th percentile = ", p10Request.formatHnsecs);
|
||||
writeln("STAT: median time = ", medianRequest.formatHnsecs);
|
||||
writeln("STAT: 90th percentile = ", p90Request.formatHnsecs);
|
||||
writeln("STAT: max request time = ", maxRequest.formatHnsecs);
|
||||
}
|
||||
|
||||
string formatHnsecs(T)(T hnsecs)
|
||||
{
|
||||
return format!"%9.3fms"(cast(double)hnsecs / cast(double)1.msecs.total!"hnsecs");
|
||||
}
|
||||
|
||||
Duration parseDuration(scope const(char)[] dur)
|
||||
{
|
||||
auto origDur = dur;
|
||||
scope (failure)
|
||||
stderr.writeln("Failed to parse ", origDur);
|
||||
Duration ret;
|
||||
while (dur.length)
|
||||
{
|
||||
dur = dur.stripLeft;
|
||||
if (dur.startsWith(","))
|
||||
dur = dur[1 .. $].stripLeft;
|
||||
if (dur.startsWith("and"))
|
||||
dur = dur[3 .. $].stripLeft;
|
||||
auto num = dur.parse!int;
|
||||
dur = dur.stripLeft;
|
||||
switch (dur.startsWith(num == 1 ? "minute" : "minutes", num == 1 ? "sec" : "secs", "ms", "μs", num == 1 ? "hnsec" : "hnsecs"))
|
||||
{
|
||||
case 1:
|
||||
dur = dur[(num == 1 ? "minute" : "minutes").length .. $];
|
||||
ret += num.minutes;
|
||||
break;
|
||||
case 2:
|
||||
dur = dur[(num == 1 ? "sec" : "secs").length .. $];
|
||||
ret += num.seconds;
|
||||
break;
|
||||
case 3:
|
||||
dur = dur["ms".length .. $];
|
||||
ret += num.msecs;
|
||||
break;
|
||||
case 4:
|
||||
dur = dur["μs".length .. $];
|
||||
ret += num.usecs;
|
||||
break;
|
||||
case 5:
|
||||
dur = dur[(num == 1 ? "hnsec" : "hnsecs").length .. $];
|
||||
ret += num.hnsecs;
|
||||
break;
|
||||
default:
|
||||
stderr.writeln("Warning: unimplemented duration parsing for ", origDur, " (at ", dur, ")");
|
||||
return Duration.init;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
60
ci/summary_comment.sh
Executable file
60
ci/summary_comment.sh
Executable file
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -u
|
||||
|
||||
# Output from this script is piped to a file by CI, being run from before a
|
||||
# change has been made and after a change has been made. Then both outputs are
|
||||
# compared using summary_comment_diff.sh
|
||||
|
||||
# cd to git folder, just in case this is manually run:
|
||||
ROOT_DIR="$( cd "$(dirname "${BASH_SOURCE[0]}")/../" && pwd )"
|
||||
cd ${ROOT_DIR}
|
||||
|
||||
dub --version
|
||||
ldc2 --version
|
||||
|
||||
# fetch missing packages before timing
|
||||
dub upgrade --missing-only
|
||||
|
||||
rm -rf .dub bin
|
||||
|
||||
start=`date +%s`
|
||||
dub build --build=release --config=client --compiler=ldc2 --force 2>&1 || echo "DCD BUILD FAILED"
|
||||
dub build --build=release --config=server --compiler=ldc2 --force 2>&1 || echo "DCD BUILD FAILED"
|
||||
end=`date +%s`
|
||||
build_time=$( echo "$end - $start" | bc -l )
|
||||
|
||||
strip bin/dcd-server
|
||||
strip bin/dcd-client
|
||||
|
||||
echo "STAT:statistics (-before, +after)"
|
||||
echo "STAT:client size=$(wc -c bin/dcd-client)"
|
||||
echo "STAT:server size=$(wc -c bin/dcd-server)"
|
||||
echo "STAT:rough build time=${build_time}s"
|
||||
echo "STAT:"
|
||||
|
||||
cd tests
|
||||
./run_tests.sh --time-server
|
||||
|
||||
echo "STAT:DCD run_tests.sh $(grep -F 'Elapsed (wall clock) time' stderr.txt)"
|
||||
echo "STAT:DCD run_tests.sh $(grep -F 'Maximum resident set size (kbytes)' stderr.txt)"
|
||||
|
||||
echo "STAT:"
|
||||
grep -E 'Request processed in .*' stderr.txt | rdmd ../ci/request_time_stats.d
|
||||
echo "STAT:"
|
||||
|
||||
# now rebuild server with -profile=gc
|
||||
cd ..
|
||||
rm -rf .dub bin/dcd-server
|
||||
dub build --build=profile-gc --config=server --compiler=dmd 2>&1 || echo "DCD BUILD FAILED"
|
||||
|
||||
cd tests
|
||||
./run_tests.sh
|
||||
|
||||
echo "STAT:top 5 GC sources in server:"
|
||||
if [ ! -f "profilegc.log" ]; then
|
||||
echo 'Missing profilegc.log file!'
|
||||
echo 'Tail for stderr.txt:'
|
||||
tail -n50 stderr.txt
|
||||
fi
|
||||
head -n6 profilegc.log | sed 's/^/STAT:/g'
|
111
ci/summary_comment_diff.sh
Executable file
111
ci/summary_comment_diff.sh
Executable file
|
@ -0,0 +1,111 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -u
|
||||
|
||||
EMPTY=1
|
||||
|
||||
ADDED=$(diff --new-line-format='%L' --old-line-format='' --unchanged-line-format='' "$1" "$2")
|
||||
REMOVED=$(diff --new-line-format='' --old-line-format='%L' --unchanged-line-format='' "$1" "$2")
|
||||
TOTAL=$(cat "$2")
|
||||
|
||||
STATS_OLD=$(grep -E '^STAT:' "$1" | sed -E 's/^STAT://')
|
||||
STATS_NEW=$(grep -E '^STAT:' "$2" | sed -E 's/^STAT://')
|
||||
|
||||
STATS_DIFFED=$(diff --new-line-format='+%L' --old-line-format='-%L' --unchanged-line-format=' %L' <(echo "$STATS_OLD") <(echo "$STATS_NEW"))
|
||||
|
||||
ADDED_DEPRECATIONS=$(grep -Pi '\b(deprecation|deprecated)\b' <<< "$ADDED")
|
||||
REMOVED_DEPRECATIONS=$(grep -Pi '\b(deprecation|deprecated)\b' <<< "$REMOVED")
|
||||
ADDED_WARNINGS=$(grep -Pi '\b(warn|warning)\b' <<< "$ADDED")
|
||||
REMOVED_WARNINGS=$(grep -Pi '\b(warn|warning)\b' <<< "$REMOVED")
|
||||
|
||||
DEPRECATION_COUNT=$(grep -Pi '\b(deprecation|deprecated)\b' <<< "$TOTAL" | wc -l)
|
||||
WARNING_COUNT=$(grep -Pi '\b(warn|warning)\b' <<< "$TOTAL" | wc -l)
|
||||
|
||||
if [ -z "$ADDED_DEPRECATIONS" ]; then
|
||||
# no new deprecations
|
||||
true
|
||||
else
|
||||
echo "⚠️ This PR introduces new deprecations:"
|
||||
echo
|
||||
echo '```'
|
||||
echo "$ADDED_DEPRECATIONS"
|
||||
echo '```'
|
||||
echo
|
||||
EMPTY=0
|
||||
fi
|
||||
|
||||
if [ -z "$ADDED_WARNINGS" ]; then
|
||||
# no new deprecations
|
||||
true
|
||||
else
|
||||
echo "⚠️ This PR introduces new warnings:"
|
||||
echo
|
||||
echo '```'
|
||||
echo "$ADDED_WARNINGS"
|
||||
echo '```'
|
||||
echo
|
||||
EMPTY=0
|
||||
fi
|
||||
|
||||
if grep "DCD BUILD FAILED" <<< "$TOTAL"; then
|
||||
echo '❌ Basic `dub build` failed! Please check your changes again.'
|
||||
echo
|
||||
else
|
||||
if [ -z "$REMOVED_DEPRECATIONS" ]; then
|
||||
# no removed deprecations
|
||||
true
|
||||
else
|
||||
echo "✅ This PR fixes following deprecations:"
|
||||
echo
|
||||
echo '```'
|
||||
echo "$REMOVED_DEPRECATIONS"
|
||||
echo '```'
|
||||
echo
|
||||
EMPTY=0
|
||||
fi
|
||||
|
||||
if [ -z "$REMOVED_WARNINGS" ]; then
|
||||
# no removed warnings
|
||||
true
|
||||
else
|
||||
echo "✅ This PR fixes following warnings:"
|
||||
echo
|
||||
echo '```'
|
||||
echo "$REMOVED_WARNINGS"
|
||||
echo '```'
|
||||
echo
|
||||
EMPTY=0
|
||||
fi
|
||||
|
||||
if [ $EMPTY == 1 ]; then
|
||||
echo "✅ PR OK, no changes in deprecations or warnings"
|
||||
echo
|
||||
fi
|
||||
|
||||
echo "Total deprecations: $DEPRECATION_COUNT"
|
||||
echo
|
||||
echo "Total warnings: $WARNING_COUNT"
|
||||
echo
|
||||
fi
|
||||
|
||||
if [ -z "$STATS_DIFFED" ]; then
|
||||
# no statistics?
|
||||
true
|
||||
else
|
||||
echo "Build statistics:"
|
||||
echo
|
||||
echo '```diff'
|
||||
echo "$STATS_DIFFED"
|
||||
echo '```'
|
||||
echo
|
||||
fi
|
||||
|
||||
echo '<details>'
|
||||
echo
|
||||
echo '<summary>Full build output</summary>'
|
||||
echo
|
||||
echo '```'
|
||||
echo "$TOTAL"
|
||||
echo '```'
|
||||
echo
|
||||
echo '</details>'
|
Loading…
Add table
Add a link
Reference in a new issue