Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
7d363c1
Add (optional at compile-time) G3Frame JSON output
cozzyd Dec 17, 2021
1d88104
blindly try to fix the cmake action
cozzyd Dec 17, 2021
740ac3c
move ENABLE_JSON_OUTPUT to core/CmakeLists.txt
cozzyd Dec 18, 2021
97b9413
Add (optional at compile-time) G3Frame JSON output
cozzyd Dec 17, 2021
1fa4c82
move ENABLE_JSON_OUTPUT to core/CmakeLists.txt
cozzyd Dec 18, 2021
f85006e
First attempt at abstracting GIL locking / C++ python initialization
cozzyd Jun 3, 2022
be76b17
formatting
cozzyd Jun 3, 2022
8be8d2c
make cppexample work with python things
cozzyd Jun 3, 2022
42e7064
use python3 instead of python in shebang
cozzyd Jun 3, 2022
7724616
CmakeLists for cppexample
cozzyd Jun 3, 2022
50b4273
initial commit of spt3g-json-serve
cozzyd Jun 3, 2022
4609008
failed attempts at python thread safety
cozzyd Jun 3, 2022
3abda84
merge
cozzyd Jun 3, 2022
0de19ce
Merge branch 'master' into json_output
arahlin Jun 3, 2022
fa0a597
fix name collision with CPython symbol
cozzyd Feb 27, 2024
0cb57fa
G3PythonContext class for handling the Python GIL
arahlin Feb 28, 2024
8e949a4
more words
arahlin Feb 28, 2024
1f56430
terrible merge
cozzyd Feb 28, 2024
8fb0d62
update to newest httplib
cozzyd Feb 28, 2024
0eea5ee
Hold GIL while clearing config in G3ModuleInfo
cozzyd Feb 28, 2024
2b09b89
split interpreter initialization and GIL handling into separate classes
arahlin Feb 29, 2024
17e90d5
Hold GIL while clearing config in G3ModuleInfo
cozzyd Feb 28, 2024
d5166c0
Avoid calling into the Python interpeter in the G3ModuleConfig backend
arahlin Feb 29, 2024
2c4f205
remove spurious python context
arahlin Feb 29, 2024
f4654ff
don't bother with globals
arahlin Feb 29, 2024
f89aec8
pass tests. most pipelines are too complex to exec(repr()) anyway
arahlin Feb 29, 2024
d11b4e4
merge
cozzyd Feb 29, 2024
eefb20d
mark non-G3FrameObject arguments as repr strings and avoid python con…
arahlin Feb 29, 2024
c343a26
switch to G3PythonInterpreter
cozzyd Feb 29, 2024
80080cf
Merge branch 'gil_context' into json_output
cozzyd Feb 29, 2024
8ae8b39
cleanup
arahlin Feb 29, 2024
d7b9535
remove now-pointless to_g3frameobject function
arahlin Feb 29, 2024
9681b8f
sigint handler and make python interpreter optional
cozzyd Feb 29, 2024
eaaff1b
cleanup
arahlin Feb 29, 2024
482debd
improve whitespace in printout
cozzyd Feb 29, 2024
dd682c8
monkeypatch argument getter/setter methods for G3ModuleConfig
arahlin Feb 29, 2024
c1fc23c
rename
arahlin Feb 29, 2024
3dd3638
variable name
arahlin Feb 29, 2024
865c9f9
ocd
arahlin Feb 29, 2024
b6a1ed5
limit eval namespace, values method
arahlin Feb 29, 2024
48ba193
no print
arahlin Feb 29, 2024
fb04351
Merge remote-tracking branch 'origin/master' into modconfig_refactor
arahlin Mar 1, 2024
44ad66a
refactor to hide .config attribute from python user to avoid confusion
arahlin Mar 1, 2024
98edc00
add test
arahlin Mar 1, 2024
170fdbc
cleanup
arahlin Mar 1, 2024
24d354b
merge in latest updates to modconfig_refactor branch
cozzyd Mar 1, 2024
6b46b6d
Merge branch 'master' into json_output
cozzyd Mar 1, 2024
da75530
get rid of destructor definition resulting from crappy merge on my part
cozzyd Mar 1, 2024
fae872d
merge
cozzyd Mar 4, 2024
67843cc
remove spurious space
cozzyd Mar 4, 2024
220e605
missed part of merge
cozzyd Mar 4, 2024
b4b1b3f
somehow ended up with a few extra lines in pipelineinfo.py from earli…
cozzyd Mar 4, 2024
3de2109
cleanups
cozzyd Mar 4, 2024
84db403
style
cozzyd Mar 5, 2024
c18afae
big rework of server example, including html output for dir listing
cozzyd Mar 5, 2024
7ee4dcf
increment version, fix json output bug recently introduced
cozzyd Mar 5, 2024
7b9dc86
add some docs
cozzyd Mar 5, 2024
fc6bb3d
rst formatting
cozzyd Mar 5, 2024
e0468f6
rename to more descriptive name
cozzyd Mar 5, 2024
71d1fa4
Merge branch 'master' into json_output
arahlin Nov 20, 2024
6f41707
Fix build errors
arahlin Nov 20, 2024
0ff476a
undo unnecessary whitespace changes
arahlin Nov 20, 2024
d057779
Fix build errors
arahlin Nov 20, 2024
d9f03e6
Merge branch 'master' into json_output
arahlin Nov 20, 2024
4e4cec5
Avoid extra boost libraries
arahlin Nov 20, 2024
852f4c0
Merge branch 'master' into json_output
arahlin Mar 13, 2025
e237fe1
Use correct load method
arahlin Mar 13, 2025
7895257
Merge branch 'master' into json_output
arahlin Mar 14, 2025
add010d
specialize save member function instead of using a separate saveJSON
arahlin Mar 14, 2025
e6bf567
Merge branch 'master' into json_output
arahlin Mar 19, 2025
3e437a1
Merge branch 'master' into json_output
arahlin Mar 19, 2025
391b187
Update istream API
arahlin Mar 19, 2025
091f2e6
bug
arahlin Mar 19, 2025
cbdaeb3
bug fix for G3Timestream JSON loader
arahlin Mar 20, 2025
ab3ac21
Use a pipeline instead of loading/writing frames by hand
arahlin Mar 20, 2025
98ac445
Merge branch 'master' into json_output
arahlin Mar 20, 2025
a699c51
Finer control of serialization template specializations
arahlin Mar 20, 2025
fddc8eb
Separate template specializations for G3Timestreams
arahlin Mar 20, 2025
cf973e8
Merge branch 'master' into json_output
arahlin Apr 23, 2025
3e2cd72
Chasing changes from master branch
arahlin Apr 23, 2025
0d8261e
typo
arahlin Apr 23, 2025
3ff03cb
Merge branch 'master' into json_output
arahlin Jun 2, 2025
4ef9e9d
Missing include
arahlin Jun 2, 2025
c8dc058
Merge branch 'master' into json_output
arahlin Nov 2, 2025
3a461e7
Merge branch 'master' into json_output
arahlin Nov 2, 2025
88de55e
Merge branch 'master' into json_output
arahlin Dec 1, 2025
2c1b28d
Merge branch 'master' into json_output
arahlin Mar 19, 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
10 changes: 10 additions & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ add_spt3g_library(core SHARED
src/G3Units.cxx ${CORE_EXTRA_SRCS} src/pybindings.cxx
)


# json output option
set(ENABLE_JSON_OUTPUT "FALSE" CACHE BOOL "Enable JSON output of frames (adds to compile time and binary size)")

if (${ENABLE_JSON_OUTPUT})
target_compile_definitions(core PUBLIC -DSPT3G_ENABLE_JSON_OUTPUT)
endif()


# Link dependencies
target_link_libraries(core PUBLIC spt3g)

Expand Down Expand Up @@ -92,6 +101,7 @@ endif()
link_python_dir()

add_spt3g_program(bin/spt3g-dump)
add_spt3g_program(bin/spt3g-jsonify)
add_spt3g_program(bin/spt3g-verify)
add_spt3g_program(bin/spt3g-inspect)
add_spt3g_program(bin/gen-analysis-doc)
Expand Down
28 changes: 28 additions & 0 deletions core/bin/spt3g-jsonify
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env python3

import sys
from spt3g import core

if len(sys.argv) < 2:
print('Usage: %s file.g3 ' % sys.argv[0])
print('Dumps the given file to standard output as JSON (not quite indented properly, sorry)')
sys.exit(1)

#Crappy hand-crafted json wrapper to make this stream valid json
print('{')
print(' "filename": "%s",' % (sys.argv[1]))
print(' "frames":')
print(' [')

first = True
indent = 8*' '
print_indent = 7*' '

for f in core.G3File(sys.argv[1]):
if not first:
print (print_indent,',')
print(print_indent,indent.join(f.as_json().splitlines(True)))
first = False
print(' ]')
print('}')

4 changes: 4 additions & 0 deletions core/include/core/G3Frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ class G3Frame {
template <class A> void save(A &ar, unsigned) const;
template <class A> void load(A &ar, unsigned);

// JSON representation of a frame (if JSON output is enabled, otherwise
// outputs valid JSON telling you that JSON output isn't enabled)
std::string asJSON() const;

// Routines for handling the stored serialized copies of data.
// These are all const because they only manipulate caches and
// so change only performance rather than data contents of the frame.
Expand Down
32 changes: 30 additions & 2 deletions core/include/core/serialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#include <sstream>

#include <cereal/archives/portable_binary.hpp>
#ifdef SPT3G_ENABLE_JSON_OUTPUT
#include <cereal/archives/json.hpp>
#endif

#include <cereal/types/polymorphic.hpp>
#include <cereal/types/string.hpp>
Expand All @@ -14,14 +17,39 @@
#include <pybindings.h>
#include <G3Logging.h>

#define G3_SERIALIZABLE_CODE(x) \
#define G3_SERIALIZABLE_CODE_BINARY(x) \
template void x::serialize(cereal::PortableBinaryOutputArchive &, unsigned); \
template void x::serialize(cereal::PortableBinaryInputArchive &, unsigned); \

#define G3_SPLIT_SERIALIZABLE_CODE(x) \
#define G3_SPLIT_SERIALIZABLE_CODE_BINARY(x) \
template void x::save(cereal::PortableBinaryOutputArchive &, unsigned) const; \
template void x::load(cereal::PortableBinaryInputArchive &, unsigned); \

#ifdef SPT3G_ENABLE_JSON_OUTPUT

#define G3_SERIALIZABLE_CODE_JSON(x) \
template void x::serialize(cereal::JSONOutputArchive &, unsigned); \
template void x::serialize(cereal::JSONInputArchive &, unsigned); \

#define G3_SPLIT_SERIALIZABLE_CODE_JSON(x) \
template void x::save(cereal::JSONOutputArchive &, unsigned) const; \
template void x::load(cereal::JSONInputArchive &, unsigned); \

#define G3_SERIALIZABLE_CODE(x) \
G3_SERIALIZABLE_CODE_BINARY(x) \
G3_SERIALIZABLE_CODE_JSON(x) \

#define G3_SPLIT_SERIALIZABLE_CODE(x) \
G3_SPLIT_SERIALIZABLE_CODE_BINARY(x) \
G3_SPLIT_SERIALIZABLE_CODE_JSON(x) \

#else

#define G3_SERIALIZABLE_CODE(x) G3_SERIALIZABLE_CODE_BINARY(x)
#define G3_SPLIT_SERIALIZABLE_CODE(x) G3_SPLIT_SERIALIZABLE_CODE_BINARY(x)

#endif

// Work around crummy slow implementation of xsgetn() in libc++
class G3InputStreamBuffer : public std::basic_streambuf<char>
{
Expand Down
58 changes: 57 additions & 1 deletion core/src/G3Frame.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,61 @@ void G3Frame::save(A &ar, unsigned v) const
ar << make_nvp("crc", crc);
}

#ifdef SPT3G_ENABLE_JSON_OUTPUT
template<>
void G3Frame::save(cereal::JSONOutputArchive &ar, unsigned v) const
{
using cereal::make_nvp;
uint32_t size(map_.size());

ar << make_nvp("size", size);
std::string typestr(1,(char) type);
ar << make_nvp("type", typestr);
for (auto i = map_.begin(); i != map_.end(); i++) {
//make sure it's deserialized so we don't just write a blob
blob_decode(i->second);
ar << make_nvp("name", i->first);
ar << make_nvp("val", i->second.frameobject);
}
}

template<>
void G3Frame::load(cereal::JSONInputArchive &ar, unsigned v)
{
using cereal::make_nvp;
G3_CHECK_VERSION(v);

int size;
std::string typestr;

ar >> make_nvp("size", size);
ar >> make_nvp("type", typestr);
type = FrameType((uint32_t)typestr[0]);

map_.clear();
for (int i = 0; i < size; i++) {
std::string name;
struct blob_container blob;
ar >> make_nvp("name", name);
ar >> make_nvp("val", blob.frameobject);
map_.insert(G3MapType::value_type(name, blob));
}
}
#endif

std::string
G3Frame::asJSON() const
{
std::stringstream str;
#ifdef SPT3G_ENABLE_JSON_OUTPUT
cereal::JSONOutputArchive ar(str);
ar << cereal::make_nvp("frame", *this);
#else
str << "{error: \"spt3g_software compiled without JSON support\"}" << std::endl;
#endif
return str.str();
}

template <typename T>
void G3Frame::loads(T &is)
{
Expand Down Expand Up @@ -373,7 +428,7 @@ template void G3Frame::saves(G3BufferOutputStream &) const;
template void G3Frame::saves(std::ostream &) const;
template void G3Frame::saves(std::ostringstream &) const;

G3_SPLIT_SERIALIZABLE_CODE(G3Frame);
G3_SPLIT_SERIALIZABLE_CODE_BINARY(G3Frame);

G3FramePtr
g3frame_char_constructor(std::string max_4_chars)
Expand Down Expand Up @@ -620,6 +675,7 @@ PYBINDINGS("core", scope) {
"where those serialized copies already exist. Saves memory for "
"frames about to be written at the expense of CPU time to "
"re-decode them if they are accessed again later.")
.def("as_json", &G3Frame::asJSON, "JSON representation of frame")
.def(g3frameobject_picklesuite<G3Frame>())
.def_property_readonly("hash", &g3frame_hash,
"Return the serialized representation of the frame")
Expand Down
109 changes: 107 additions & 2 deletions core/src/G3Timestream.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,111 @@ template <class A> void G3Timestream::load(A &ar, unsigned v)
}
}

#ifdef SPT3G_ENABLE_JSON_OUTPUT
template <> void G3Timestream::save(cereal::JSONOutputArchive &ar, unsigned v) const
{
ar & cereal::make_nvp("G3FrameObject",
cereal::base_class<G3FrameObject>(this));
ar & cereal::make_nvp("units", units);
ar & cereal::make_nvp("start", start);
ar & cereal::make_nvp("stop", stop);

ar & cereal::make_nvp("data_type", data_type_);
if (buffer_) {
ar & cereal::make_nvp("data", *buffer_);
} else {
switch (data_type_) {
case TS_DOUBLE: {
std::vector<double> data((double *)data_,
(double *)data_ + len_);
ar & cereal::make_nvp("data", data);
break;
}
case TS_FLOAT: {
std::vector<float> data((float *)data_,
(float *)data_ + len_);
ar & cereal::make_nvp("data", data);
break;
}
case TS_INT32: {
std::vector<int32_t> data((int32_t *)data_,
(int32_t *)data_ + len_);
ar & cereal::make_nvp("data", data);
break;
}
case TS_INT64: {
std::vector<int64_t> data((int64_t *)data_,
(int64_t *)data_ + len_);
ar & cereal::make_nvp("data", data);
break;
}
default:
log_fatal("Unknown timestream datatype %d", data_type_);
}
}
}

template <> void G3Timestream::load(cereal::JSONInputArchive &ar, unsigned v)
{
G3_CHECK_VERSION(v);

ar & cereal::make_nvp("G3FrameObject",
cereal::base_class<G3FrameObject>(this));
ar & cereal::make_nvp("units", units);
if (v >= 2) {
ar & cereal::make_nvp("start", start);
ar & cereal::make_nvp("stop", stop);
}

if (buffer_)
delete buffer_;
buffer_ = NULL;
root_data_ref_.reset();

if (v >= 3)
ar & cereal::make_nvp("data_type", data_type_);
else
data_type_ = TS_DOUBLE;
switch (data_type_) {
case TS_DOUBLE:
buffer_ = new std::vector<double>();
ar & cereal::make_nvp("data", *buffer_);
len_ = buffer_->size();
data_ = &(*buffer_)[0];
break;
case TS_FLOAT: {
std::vector<float> *data = new std::vector<float>();
ar & cereal::make_nvp("data", *data);
root_data_ref_ = std::shared_ptr<std::vector<float> >(
data);
len_ = data->size();
data_ = &(*data)[0];
break;
}
case TS_INT32: {
std::vector<int32_t> *data = new std::vector<int32_t>();
ar & cereal::make_nvp("data", *data);
root_data_ref_ = std::shared_ptr<
std::vector<int32_t> >(data);
len_ = data->size();
data_ = &(*data)[0];
break;
}
case TS_INT64: {
std::vector<int64_t> *data = new std::vector<int64_t>();
ar & cereal::make_nvp("data", *data);
root_data_ref_ = std::shared_ptr<
std::vector<int64_t> >(data);
len_ = data->size();
data_ = &(*data)[0];
break;
}
default:
log_fatal("Unknown timestream datatype %d", data_type_);
}
}
#endif

G3Timestream::G3Timestream(const G3Timestream &r) :
units(r.units), start(r.start), stop(r.stop), use_flac_(r.use_flac_),
flac_depth_(r.flac_depth_), len_(r.len_), data_type_(r.data_type_)
Expand Down Expand Up @@ -990,7 +1095,7 @@ void G3TimestreamMap::Compactify()
}
}

G3_SPLIT_SERIALIZABLE_CODE(G3Timestream);
G3_SPLIT_SERIALIZABLE_CODE_BINARY(G3Timestream);
G3_SERIALIZABLE_CODE(G3TimestreamMap);

static void
Expand Down Expand Up @@ -1396,7 +1501,7 @@ PYBINDINGS("core", scope) {
.def("SetFLACCompression", &G3Timestream::SetFLACCompression,
"Pass True to turn on FLAC compression when serialized. "
"FLAC compression only works if the timestream is in units of "
"counts.")
"counts. FLAC compression is ignored when outputing to JSON.")
.def("SetFLACBitDepth", &G3Timestream::SetFLACBitDepth,
"Change the bit depth for FLAC compression, may be 24 or 32 "
"(default, requires version 1.4+).")
Expand Down
22 changes: 22 additions & 0 deletions serve/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

function (make_embedded_resource var_name file_name out_file)
if (${file_name} IS_NEWER_THAN ${out_file})
message(Generating ${out_file} " from " ${file_name})
file (WRITE ${out_file} "// automatically generated from ${file_name}\n")
file (READ ${file_name} filedata HEX)
string (REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," cfiledata ${filedata})
file (APPEND ${out_file} "unsigned char ${var_name}[] = { ${cfiledata} };\n")
endif()
endfunction()

make_embedded_resource(favicon favicon.ico ${CMAKE_BINARY_DIR}/serve/favicon.h)

if(NOT DEFINED ENV{CIBUILDWHEEL})
add_spt3g_executable(spt3g-json-serve-files src/spt3g-json-serve-files.cxx)

target_link_libraries(spt3g-json-serve-files core z)
target_include_directories(spt3g-json-serve-files PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
)
endif()
Loading
Loading