Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-10-20 08:45:52

0001 #include <cassert>
0002 #include <cstdint>
0003 #include <functional>
0004 #include <iostream>
0005 #include <sstream>
0006 #include <stdexcept>
0007 #include <string>
0008 #include <vector>
0009 
0010 #include "EventTiming.hh"
0011 #include "NP.hh"
0012 
0013 namespace
0014 {
0015 int SuccessfulMemoryQuery(std::int32_t& vm_kb, std::int32_t& rss_kb)
0016 {
0017     vm_kb = 1234;
0018     rss_kb = 567;
0019     return 0;
0020 }
0021 
0022 int FailingMemoryQuery(std::int32_t&, std::int32_t&)
0023 {
0024     return 1;
0025 }
0026 
0027 std::size_t CountOccurrences(const std::string& text, const std::string& needle)
0028 {
0029     std::size_t count = 0;
0030     std::size_t offset = 0;
0031     while ((offset = text.find(needle, offset)) != std::string::npos)
0032     {
0033         ++count;
0034         offset += needle.size();
0035     }
0036     return count;
0037 }
0038 
0039 void ExpectInvalid(const std::string& text)
0040 {
0041     bool threw = false;
0042     try
0043     {
0044         (void)EventTimingSample::parse(text);
0045     }
0046     catch (const std::invalid_argument&)
0047     {
0048         threw = true;
0049     }
0050     assert(threw);
0051     assert(!EventTimingSample::looksLikeSerialized(text));
0052 }
0053 
0054 void TestCaptureMasks()
0055 {
0056     const std::vector<EventTimingCapture> optional_fields = {
0057         EventTimingCapture::Wall,
0058         EventTimingCapture::ProcessCpu,
0059         EventTimingCapture::ThreadCpu,
0060         EventTimingCapture::Memory,
0061     };
0062 
0063     for (const EventTimingCapture requested : optional_fields)
0064     {
0065         const EventTimingSample sample = requested == EventTimingCapture::Memory
0066                                              ? EventTimingSample::Capture(requested, SuccessfulMemoryQuery)
0067                                              : EventTimingSample::Capture(requested);
0068 
0069         assert(sample.has(EventTimingCapture::Monotonic));
0070         for (const EventTimingCapture field : optional_fields)
0071             assert(sample.has(field) == (field == requested));
0072     }
0073 
0074     const EventTimingSample monotonic_only =
0075         EventTimingSample::Capture(static_cast<EventTimingCapture>(0));
0076     assert(monotonic_only.has(EventTimingCapture::Monotonic));
0077     assert(!monotonic_only.has(EventTimingCapture::Wall));
0078     assert(!monotonic_only.has(EventTimingCapture::Memory));
0079 }
0080 
0081 void TestSerializationRoundTrip()
0082 {
0083     EventTimingSample sample{};
0084     sample.valid_mask = EventTimingSample::bit(EventTimingCapture::Monotonic) | EventTimingSample::bit(EventTimingCapture::Wall) | EventTimingSample::bit(EventTimingCapture::Memory);
0085     sample.wall_time_us = 1'760'000'000'000'000;
0086     sample.steady_time_ns = 42'000;
0087     sample.vm_kb = 1234;
0088     sample.rss_kb = 567;
0089 
0090     const std::string encoded = sample.serialize();
0091     assert(encoded == "1760000000000000,42000,,,1234,567");
0092     assert(EventTimingSample::looksLikeSerialized(encoded));
0093     assert(EventTimingSample::parse(encoded) == sample);
0094 
0095     const std::string description = sample.desc();
0096     assert(description.find("steady_time_ns=42000") != std::string::npos);
0097     assert(description.find("rss_kb=567") != std::string::npos);
0098 }
0099 
0100 void TestSerializationRequiresMonotonicTimestamp()
0101 {
0102     const EventTimingSample sample{};
0103     bool                    threw = false;
0104     try
0105     {
0106         (void)sample.serialize();
0107     }
0108     catch (const std::logic_error&)
0109     {
0110         threw = true;
0111     }
0112     assert(threw);
0113 }
0114 
0115 void TestMalformedSerialization()
0116 {
0117     ExpectInvalid("1,2,3,4,5");
0118     ExpectInvalid("1,2,3,4,5,6,7");
0119     ExpectInvalid("1,not-an-integer,3,4,5,6");
0120     ExpectInvalid("1,9223372036854775808,3,4,5,6");
0121     ExpectInvalid("1,2, ,4,5,6");
0122     ExpectInvalid(",,,,,");
0123 }
0124 
0125 void TestDeltas()
0126 {
0127     EventTimingSample begin{};
0128     begin.valid_mask = EventTimingSample::bit(EventTimingCapture::Monotonic) | EventTimingSample::bit(EventTimingCapture::Memory);
0129     begin.steady_time_ns = 100;
0130     begin.vm_kb = 1000;
0131     begin.rss_kb = 500;
0132 
0133     EventTimingSample end = begin;
0134     end.steady_time_ns = 350;
0135     end.vm_kb = 1012;
0136     end.rss_kb = 507;
0137 
0138     assert(EventTimingSample::elapsedNs(begin, end) == 250);
0139     assert(EventTimingSample::deltaVmKb(begin, end) == 12);
0140     assert(EventTimingSample::deltaRssKb(begin, end) == 7);
0141 
0142     EventTimingSample missing{};
0143     bool              elapsed_threw = false;
0144     bool              memory_threw = false;
0145     try
0146     {
0147         (void)EventTimingSample::elapsedNs(missing, end);
0148     }
0149     catch (const std::logic_error&)
0150     {
0151         elapsed_threw = true;
0152     }
0153     try
0154     {
0155         (void)EventTimingSample::deltaRssKb(missing, end);
0156     }
0157     catch (const std::logic_error&)
0158     {
0159         memory_threw = true;
0160     }
0161     assert(elapsed_threw);
0162     assert(memory_threw);
0163 }
0164 
0165 void TestMemoryFailureWarnsOnce()
0166 {
0167     std::ostringstream captured;
0168     std::streambuf*    original = std::cerr.rdbuf(captured.rdbuf());
0169 
0170     const EventTimingCapture mask =
0171         EventTimingCapture::Monotonic | EventTimingCapture::Memory;
0172     const EventTimingSample first = EventTimingSample::Capture(mask, FailingMemoryQuery);
0173     const EventTimingSample second = EventTimingSample::Capture(mask, FailingMemoryQuery);
0174 
0175     std::cerr.rdbuf(original);
0176     assert(!first.has(EventTimingCapture::Memory));
0177     assert(!second.has(EventTimingCapture::Memory));
0178     assert(CountOccurrences(captured.str(), "memory sample failed") == 1u);
0179 }
0180 
0181 std::string FindReportLine(const std::string& report, const std::string& key)
0182 {
0183     const std::size_t begin = report.find(key);
0184     assert(begin != std::string::npos);
0185     const std::size_t end = report.find('\n', begin);
0186     return report.substr(begin, end - begin);
0187 }
0188 
0189 void TestMetadataReportUsesEventTimingMonotonicTimestamp()
0190 {
0191     const std::string metadata =
0192         "ordinary:value\n"
0193         "first:1760000000000000,1000000000000000,,,1234,567\n"
0194         "second:1760000000000100,1000000000000300,,,1240,570\n";
0195 
0196     const std::string report = NP::DescMetaKV(metadata);
0197     assert(FindReportLine(report, "ordinary").find(" :           -1 : ") != std::string::npos);
0198     const std::string first_line = FindReportLine(report, "first");
0199     assert(first_line.find(" :            0 : ") != std::string::npos);
0200     assert(FindReportLine(report, "second").find(" :          300 : ") != std::string::npos);
0201     const std::string wall_display = U::Format(1'760'000'000'000'000);
0202     const std::string steady_display = U::Format(1'000'000'000'000'000);
0203     assert(first_line.find(wall_display) != std::string::npos);
0204     assert(first_line.find(steady_display) == std::string::npos);
0205 
0206     const std::string legacy_report = NP::DescMetaKV("legacy:1760000000000000\n");
0207     assert(FindReportLine(legacy_report, "legacy").find(" :            0 : ") != std::string::npos);
0208 }
0209 } // namespace
0210 
0211 int main()
0212 {
0213     TestCaptureMasks();
0214     TestSerializationRoundTrip();
0215     TestSerializationRequiresMonotonicTimestamp();
0216     TestMalformedSerialization();
0217     TestDeltas();
0218     TestMemoryFailureWarnsOnce();
0219     TestMetadataReportUsesEventTimingMonotonicTimestamp();
0220     return 0;
0221 }