Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
28a3d65
Changes to support pipeline collection using SimDB
colby-nyce May 15, 2026
5226b5f
Fix build failure
colby-nyce May 15, 2026
9bcfbba
Fix build failure
colby-nyce May 15, 2026
fb05e1e
Fix sporadic pipeline collector crashes
colby-nyce May 15, 2026
77320ff
Changes to support pipeline collection using SimDB
colby-nyce May 17, 2026
5c61e4f
Bump SimDB to get UI bug fixes
colby-nyce May 17, 2026
912fca5
Back out all broken v3 collector code
colby-nyce May 19, 2026
810b49a
Back out all broken v3 collector code
colby-nyce May 19, 2026
b00514b
Back out all broken v3 collector code
colby-nyce May 19, 2026
c21e22f
Add debug utility
colby-nyce May 19, 2026
3113766
Bump SimDB
colby-nyce May 19, 2026
5873806
BitBucket classes, plus remove old / unused code
colby-nyce May 21, 2026
baa26a9
Move MetaStructs.hpp to simdb/utils/TypeTraits.hpp
colby-nyce May 21, 2026
f275642
Bump SimDB
colby-nyce May 21, 2026
59015db
Disable duplicate DID fields, only use the first encountered
colby-nyce May 21, 2026
c83e7a5
Fix downstream unit tests that have no CommandLineSimulator::postProc…
colby-nyce May 21, 2026
7148fbb
Always support collecting anything with operator<< as a string (fallb…
colby-nyce May 22, 2026
d838d00
PR self-review
colby-nyce May 22, 2026
08d69f7
Support collecting struct-like types using nothing but operator<<
colby-nyce May 26, 2026
5058a58
Comment out all broken code while refactoring
colby-nyce May 28, 2026
a94dfa8
Refactor: Collectable, IterableCollector, and BitBucket
colby-nyce May 29, 2026
3332d11
Bump SimDB and remove dead code
colby-nyce May 29, 2026
0ee481c
Align argosLeafDtypeString with Collectable data type rules
colby-nyce May 29, 2026
efe621b
Fix BitBucket logic bugs
colby-nyce May 29, 2026
8213663
Implement serializeStructSchema()
colby-nyce May 29, 2026
71c5160
Ensure pipeline collection safety / DB integrity on exceptions
colby-nyce May 30, 2026
c2180f8
PR self-review
colby-nyce May 30, 2026
0235704
PR self-review
colby-nyce May 30, 2026
4faff83
Fix up DataTypeNodes table
colby-nyce May 31, 2026
0662f9d
Disable dynamic field support for now
colby-nyce May 31, 2026
a711fb9
Add postNotif api calls for uncollectable types
colby-nyce Jun 1, 2026
a2189b0
Various fixes for SimDB collection
colby-nyce Jun 5, 2026
4893440
Fix SPARTA_FLATTEN bug
colby-nyce Jun 8, 2026
aaef002
Generalize SPARTA_FLATTEN base/derived fix to multi-level nesting
colby-nyce Jun 8, 2026
50765bb
Bump SimDB (Argos bug fixes)
colby-nyce Jun 8, 2026
d9eda14
Fix warning when collecting a subclass of something with a PairDefini…
colby-nyce Jun 9, 2026
65bb783
Bump SimDB
colby-nyce Jun 9, 2026
ebf05c9
PR self-review
colby-nyce Jun 10, 2026
4f23cf5
Bump SimDB and clean up some stdout logs
colby-nyce Jun 12, 2026
c927c0b
Bug fixes and performance improvements
colby-nyce Jun 16, 2026
63c49c2
Bump SimDB
colby-nyce Jun 17, 2026
30cf2c7
Bump SimDB
colby-nyce Jun 17, 2026
7e58115
Add markdown file to let AI translate legacy collectables to PairDefi…
colby-nyce Jun 18, 2026
4eac795
Bump SimDB and delete dead code
colby-nyce Jun 24, 2026
3872cdc
Bump SimDB, and PR self-review
colby-nyce Jun 29, 2026
2124a20
Bump SimDB
colby-nyce Jun 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
537 changes: 537 additions & 0 deletions sparta/doc/PairDefinitionPortingGuide.md

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions sparta/example/CoreModel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ sparta_regress(sparta_core_example)
sparta_named_test(sparta_core_example_20000cycs sparta_core_example -r 200000)
sparta_named_test(sparta_core_example_fetch_max_ipc sparta_core_example -i 1M -p top.cpu.core0.fetch.params.fetch_max_ipc true)
sparta_named_test(sparta_core_example_pipeout sparta_core_example -i 1000 -z pipeout -K layouts/cpu_layout.alf)
sparta_named_test(sparta_core_example_pipeout_icount sparta_core_example -i 1000 --debug-on-icount 100 -z pipeout -K layouts/cpu_layout.alf)
sparta_named_test(sparta_core_example_pipeout_cycle sparta_core_example -i 1000 --debug-on 100 -z pipeout -K layouts/cpu_layout.alf)
sparta_named_test(sparta_core_example_pipeout_icount sparta_core_example -i 1000 --debug-on-icount 100 -z pipeout_icount -K layouts/cpu_layout.alf)
sparta_named_test(sparta_core_example_pipeout_cycle sparta_core_example -i 1000 --debug-on 100 -z pipeout_cycle -K layouts/cpu_layout.alf)
# Using a standard YAML causes this test to fail. Need to investigate Issue #4
# sparta_named_test(sparta_core_example_preload sparta_core_example -i 1000 -p top.cpu.core0.preloader.params.preload_file sample_preload.yaml)
sparta_named_test(sparta_core_example_multicore_yaml_opts_smoke_test sparta_core_example -i 10k --report top multicore_report_opts_basic.yaml out.txt --num-cores 2)
Expand Down Expand Up @@ -154,10 +154,10 @@ sparta_expect_failure_test(sparta_core_example_override_extensions_neg_test spar
sparta_named_test(sparta_core_example_3d_nested_extension_params sparta_core_example --no-run --extension-file nested_vecs.yaml --write-final-config final.yaml)

if(USING_SIMDB)
sparta_named_test(sparta_core_example_simdb_apps1 sparta_core_example --simdb-apps simdb-reports cherry-pick-fast-checkpointer --simdb-database test.db --no-run)
sparta_named_test(sparta_core_example_simdb_apps2 sparta_core_example --simdb-apps simdb-reports cherry-pick-fast-checkpointer --simdb-app-database simdb-reports reports.db --no-run)
sparta_named_test(sparta_core_example_simdb_apps1 sparta_core_example --simdb-apps simdb-reports cherry-pick-fast-checkpointer --simdb-database simdb_apps1.db --no-run)
sparta_named_test(sparta_core_example_simdb_apps2 sparta_core_example --simdb-apps simdb-reports cherry-pick-fast-checkpointer --simdb-app-database simdb-reports reports.db cherry-pick-fast-checkpointer chkptr.db --no-run)
sparta_named_test(sparta_core_example_simdb_apps3 sparta_core_example --simdb-apps cherry-pick-fast-checkpointer --simdb-app-count cherry-pick-fast-checkpointer 2 --simdb-database autogen --no-run)
sparta_named_test(sparta_core_example_simdb_apps4 sparta_core_example --simdb-apps cherry-pick-fast-checkpointer --simdb-app-count cherry-pick-fast-checkpointer top.cpu.core* --num-cores 2 --no-run)
sparta_named_test(sparta_core_example_simdb_apps4 sparta_core_example --simdb-apps cherry-pick-fast-checkpointer --simdb-app-count cherry-pick-fast-checkpointer top.cpu.core* --num-cores 2 --simdb-database simdb_apps4.db --no-run)

# Run all backwards compatibility tests for map_v2.1+ reports and their v2.0.* equivalents
add_test(NAME sparta_simdb_report_verif_suite COMMAND python3 ../../../scripts/simdb/run_report_verif_suite.py --sim-exe-path sparta_core_example --serial --force --fail-fast)
Expand Down
2 changes: 1 addition & 1 deletion sparta/simdb
Submodule simdb updated 72 files
+10 −0 .github/actions/regress.sh
+6 −0 include/simdb/apps/App.hpp
+30 −0 include/simdb/apps/AppManager.hpp
+843 −0 include/simdb/apps/argos/ArgosCollector.hpp
+645 −0 include/simdb/apps/argos/Checkpoint.hpp
+565 −0 include/simdb/apps/argos/CheckpointDeltas.hpp
+109 −0 include/simdb/apps/argos/CheckpointEncodings.hpp
+692 −0 include/simdb/apps/argos/Checkpointer.hpp
+49 −0 include/simdb/apps/argos/CollectedData.hpp
+0 −90 include/simdb/apps/argos/CollectionBuffer.hpp
+0 −795 include/simdb/apps/argos/CollectionPoints.hpp
+97 −0 include/simdb/apps/argos/EntryPoint.hpp
+114 −0 include/simdb/apps/argos/EnumInspector.hpp
+216 −0 include/simdb/apps/argos/PipelineDataTypes.hpp
+37 −0 include/simdb/apps/argos/PipelineStagerInterface.hpp
+0 −645 include/simdb/apps/argos/Serialize.hpp
+89 −0 include/simdb/apps/argos/StreamBuffer.hpp
+83 −0 include/simdb/apps/argos/Timestamps.hpp
+0 −74 include/simdb/apps/argos/TreeNode.hpp
+2 −0 include/simdb/pipeline/PollingThread.hpp
+41 −0 include/simdb/schema/SchemaDef.hpp
+4 −0 include/simdb/sqlite/Connection.hpp
+5 −0 include/simdb/sqlite/DatabaseManager.hpp
+198 −0 include/simdb/sqlite/Dump.hpp
+164 −25 include/simdb/sqlite/Iterator.hpp
+45 −0 include/simdb/sqlite/Query.hpp
+2 −0 include/simdb/sqlite/Table.hpp
+4 −1 include/simdb/utils/Compress.hpp
+23 −0 include/simdb/utils/StreamFormatters.hpp
+3 −0 include/simdb/utils/TickTock.hpp
+59 −25 include/simdb/utils/TinyStrings.hpp
+660 −9 include/simdb/utils/TypeTraits.hpp
+36 −2 include/simdb/utils/ValidValue.hpp
+1 −2 python/argos/argos.py
+186 −108 python/argos/viewer/gui/canvas_grid.py
+81 −67 python/argos/viewer/gui/collectable_tree.py
+53 −0 python/argos/viewer/gui/dialogs/save_view_file.py
+0 −59 python/argos/viewer/gui/dialogs/string_list_selection.py
+539 −0 python/argos/viewer/gui/dialogs/widget_data_selections.py
+0 −18 python/argos/viewer/gui/explorer.py
+151 −61 python/argos/viewer/gui/inspector.py
+55 −0 python/argos/viewer/gui/logs.py
+0 −19 python/argos/viewer/gui/tools.py
+63 −121 python/argos/viewer/gui/view_settings.py
+0 −330 python/argos/viewer/gui/watchlist.py
+11 −1 python/argos/viewer/gui/widgets/grid.py
+0 −84 python/argos/viewer/gui/widgets/ipc.py
+70 −155 python/argos/viewer/gui/widgets/iterable_struct.py
+1 −1 python/argos/viewer/gui/widgets/playback_bar.py
+37 −31 python/argos/viewer/gui/widgets/queue_utiliz.py
+0 −199 python/argos/viewer/gui/widgets/scalar_statistic.py
+0 −43 python/argos/viewer/gui/widgets/scalar_struct.py
+207 −724 python/argos/viewer/gui/widgets/scheduling_lines.py
+298 −0 python/argos/viewer/gui/widgets/summary_views.py
+5 −51 python/argos/viewer/gui/widgets/widget_creator.py
+7 −4 python/argos/viewer/gui/widgets/widget_renderer.py
+245 −0 python/argos/viewer/model/blob_handlers.py
+404 −0 python/argos/viewer/model/blob_iterator.py
+396 −0 python/argos/viewer/model/data_deserializers.py
+207 −777 python/argos/viewer/model/data_retriever.py
+36 −0 python/argos/viewer/model/dirty_reasons.py
+275 −0 python/argos/viewer/model/dtype_inspector.py
+50 −16 python/argos/viewer/model/frame.py
+225 −106 python/argos/viewer/model/simhier.py
+18 −0 python/argos/viewer/model/tiny_strings.py
+3 −3 python/argos/viewer/model/workspace.py
+1 −0 test/CMakeLists.txt
+500 −0 test/argos/BlobReplayer.hpp
+9 −0 test/argos/CMakeLists.txt
+172 −0 test/argos/compare.py
+1,448 −0 test/argos/main.cpp
+173 −0 test/sqlite/Query/main.cpp
3 changes: 1 addition & 2 deletions sparta/sparta/app/CommandLineSimulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class InformationWriter;

namespace app {

const constexpr char DefaultHeartbeat[] = "0";
const constexpr char DefaultHeartbeat[] = "10";


/*!
Expand Down Expand Up @@ -457,7 +457,6 @@ class CommandLineSimulator
*/
std::unique_ptr<sparta::trigger::Triggerable> pipeline_collection_triggerable_;
std::unique_ptr<sparta::trigger::Trigger> pipeline_trigger_;
std::unique_ptr<sparta::InformationWriter> info_out_;

/*!
* \brief Heartbeat period of pipeline collection file (before lexical cast
Expand Down
6 changes: 6 additions & 0 deletions sparta/sparta/app/Simulation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,12 @@ class Simulation
* \brief SimDB DatabaseManager/AppManager instances.
*/
std::shared_ptr<simdb::AppManagers> app_managers_;

/*!
* \brief Flag telling us whether postSimLoopTeardown() API call
* is still required.
*/
bool app_managers_require_teardown_ = true;
};

} // namespace app
Expand Down
23 changes: 23 additions & 0 deletions sparta/sparta/app/SimulationConfiguration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,12 @@ class SimulationConfiguration
*/
std::string pipeline_collection_file_prefix = NoPipelineCollectionStr;

/*!
* Set by CommandLineSimulator. Controls time/space tradeoffs for
* pipeline collection.
*/
utils::ValidValue<size_t> pipeline_collection_heartbeat;

/*!
* Additional report descriptions
*/
Expand Down Expand Up @@ -661,6 +667,22 @@ class SimulationConfiguration
return legacy_reports_enabled_;
}

/*!
* \brief Call the setVerbose() method for all SimDB apps once created.
*/
void enableVerboseMode(bool enable = true)
{
verbose_ = enable;
}

/*!
* \brief Get verbose flag.
*/
bool verboseMode() const
{
return verbose_;
}

/*!
* \brief Add a SQLite PRAGMA to execute on database creation.
* \note Applies to all app databases if different.
Expand Down Expand Up @@ -694,6 +716,7 @@ class SimulationConfiguration
std::set<std::string> reused_db_files_;
std::map<std::string, std::string> dbmgr_pragmas_;
bool legacy_reports_enabled_ = true;
bool verbose_ = false;
} simdb_config;

/*!
Expand Down
229 changes: 229 additions & 0 deletions sparta/sparta/collection/BitBucket.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
// <BitBucket.hpp> -*- C++ -*-

#pragma once

#include "sparta/utils/ValidValue.hpp"
#include "simdb/apps/argos/EntryPoint.hpp"
#include <cstring>

namespace sparta::collection {

//! \class BitBucket
//! \brief Base class for all collectable bit buckets (scalars, sparse/contig iterables).
//! We use this class so that we can gather data from e.g. Pair objects without requiring
//! that they hold onto their own collected bytes/values. When data values become available,
//! they go directly into the BitBucket and are organized into data structures that SimDB
//! expects (depends on the collected type).
class BitBucket
{
public:
explicit BitBucket(simdb::TinyStrings<>* tiny_strings, simdb::argos::EnumInspector* enum_inspector) :
tiny_strings_(tiny_strings),
enum_inspector_(enum_inspector)
{}

virtual ~BitBucket() = default;
virtual void clear() = 0;
virtual void writeField(const void* data, uint32_t bytes, uint32_t field_id) = 0;
virtual void writeTo(simdb::argos::EntryPoint* entry_point) = 0;

template <typename T>
bool writeField(const T& val, uint32_t field_id) {
// Write bools as uint8_t
if constexpr (std::is_same_v<T, bool>) {
return writeField(val ? uint8_t(1) : uint8_t(0), field_id);
}

// Write strings as uint32_t via TinyStrings
else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<std::decay_t<T>, const char*>) {
return writeField(tiny_strings_->getStringID(val), field_id);
}

// Write enums as their underlying integer type.
else if constexpr (std::is_enum_v<T>) {
enum_inspector_->inspect(val);
using underlying_t = std::underlying_type_t<T>;
const underlying_t enum_int = static_cast<underlying_t>(val);
return writeField(enum_int, field_id);
}

// Write struct/class fields that provide exactly one cast-to-POD operator
else if constexpr (simdb::type_traits::is_pod_convertible_v<T> && !std::is_enum_v<T> &&
(!std::is_trivial_v<T> || !std::is_standard_layout_v<T>)) {
using converted_t = simdb::type_traits::pod_convertible_t<T>();
static_assert(std::is_trivial_v<converted_t> && std::is_standard_layout_v<converted_t>);
auto converted_val = static_cast<converted_t>(val);
return writeField(converted_val, field_id);
}

// Write PODs (or TinyStrings uint32_t ID, or enums by their underlying type,
// or bools as uint8_t)
else if (std::is_trivial_v<T> && std::is_standard_layout_v<T>) {
writeField(&val, sizeof(T), field_id);
return true;
}

// Cannot collect this field. Let the caller decide what to do.
else {
return false;
}
}

simdb::TinyStrings<>* getTinyStrings() const {
return tiny_strings_;
}

simdb::argos::EnumInspector* getEnumInspector() const {
return enum_inspector_;
}

private:
simdb::TinyStrings<>* tiny_strings_ = nullptr;
simdb::argos::EnumInspector* enum_inspector_ = nullptr;
};

//! BitBucket implementation for Collectable objects (whether "standalone"
//! or inside an IterableCollector).
class CollectableBitBucket : public BitBucket
{
public:
using BitBucket::BitBucket;

void clear() override final {
buffer_.clear();
buffer_.reserve(bytes_per_pass_);
bytes_per_pass_ = 0;
}

void writeField(const void* data, uint32_t bytes, uint32_t) override final {
auto src = static_cast<const char*>(data);
buffer_.resize(bytes_per_pass_ + bytes);
auto dst = &buffer_[bytes_per_pass_];
memcpy(dst, src, bytes);
bytes_per_pass_ += bytes;
}

//! Called when using a standalone Collectable
void writeTo(simdb::argos::EntryPoint* entry_point) override final {
entry_point->setScalarValueBytes(std::move(buffer_));
clear();
}

//! Called when inside an IterableCollector
void writeTo(std::vector<char> & dest) {
std::swap(dest, buffer_);
clear();
}

private:
std::vector<char> buffer_;
size_t bytes_per_pass_ = 0;
};

template <bool Sparse>
class IterableCollectorBitBucket;

template <>
class IterableCollectorBitBucket<true> : public BitBucket
{
public:
IterableCollectorBitBucket(simdb::TinyStrings<>* tiny_strings, simdb::argos::EnumInspector* enum_inspector, size_t capacity)
: BitBucket(tiny_strings, enum_inspector)
, capacity_(capacity)
{
while (capacity--)
{
bin_buckets_.emplace_back(std::make_unique<CollectableBitBucket>(tiny_strings, enum_inspector));
}
}

void clear() override final {
active_bin_idx_.clearValid();
all_bin_idxs_.clear();
all_bin_idxs_.reserve(capacity_);
}

void setActiveBinIdx(uint32_t bin_idx) {
assert(bin_idx <= UINT16_MAX);
assert(bin_idx < capacity_);
active_bin_idx_ = static_cast<uint16_t>(bin_idx);
all_bin_idxs_.emplace_back(bin_idx);
}

void writeField(const void* data, uint32_t bytes, uint32_t field_id) override final {
auto& bin_bucket = bin_buckets_[active_bin_idx_.getValue()];
assert(bin_bucket);
bin_bucket->writeField(data, bytes, field_id);
}

void writeTo(simdb::argos::EntryPoint* entry_point) override final {
for (auto bin_idx : all_bin_idxs_) {
bin_buckets_[bin_idx]->writeTo(all_bin_bytes_[bin_idx]);
}

entry_point->setSparseContainerBinBytes(std::move(all_bin_bytes_));
clear();
}

private:
std::vector<std::unique_ptr<CollectableBitBucket>> bin_buckets_;
std::map<uint16_t, std::vector<char>> all_bin_bytes_;
utils::ValidValue<uint16_t> active_bin_idx_;
std::vector<uint16_t> all_bin_idxs_;
size_t capacity_ = 0;
};

template <>
class IterableCollectorBitBucket<false> : public BitBucket
{
public:
IterableCollectorBitBucket(simdb::TinyStrings<>* tiny_strings, simdb::argos::EnumInspector* enum_inspector, size_t capacity)
: BitBucket(tiny_strings, enum_inspector)
, capacity_(capacity)
{
all_bin_bytes_.reserve(capacity_);
while (capacity--)
{
bin_buckets_.emplace_back(std::make_unique<CollectableBitBucket>(tiny_strings, enum_inspector));
}
}

void clear() override final {
container_size_ = 0;
all_bin_bytes_.reserve(capacity_);
}

void setActiveBinIdx(uint32_t bin_idx) {
assert(bin_idx <= UINT16_MAX);
assert(bin_idx == container_size_);
++container_size_;
}

void writeField(const void* data, uint32_t bytes, uint32_t field_id) override final {
if (SPARTA_EXPECT_FALSE(container_size_ == 0)) {
setActiveBinIdx(0);
}
auto& bin_bucket = bin_buckets_[container_size_ - 1];
bin_bucket->writeField(data, bytes, field_id);
}

void writeTo(simdb::argos::EntryPoint* entry_point) override final {
all_bin_bytes_.resize(container_size_);
for (size_t i = 0; i < container_size_; ++i) {
auto & bin_bucket = bin_buckets_[i];
auto & bin_buffer = all_bin_bytes_[i];
bin_bucket->writeTo(bin_buffer);
}

entry_point->setContigContainerBinBytes(std::move(all_bin_bytes_));
clear();
}

private:
std::vector<std::unique_ptr<CollectableBitBucket>> bin_buckets_;
std::vector<std::vector<char>> all_bin_bytes_;
uint16_t container_size_ = 0;
size_t capacity_ = 0;
};

} // sparta::collection
Loading