Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add (optional at compile-time) G3Frame JSON output #69

Draft
wants to merge 65 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
65 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
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
2 changes: 1 addition & 1 deletion .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
run: |
if [ `echo ${{matrix.os}} | cut -d - -f 1` = "ubuntu" ]; then
[ `echo ${{matrix.os}} | cut -d . -f 1` = "ubuntu-20" ] && sudo apt-get install python-is-python3
sudo apt-get install libboost-all-dev libflac-dev libnetcdf-dev libfftw3-dev libgsl0-dev python python3 python3-pip
sudo apt-get install libboost-all-dev libflac-dev libnetcdf-dev libfftw3-dev libgsl0-dev python python3 python3-pip python3-setuptools
elif [ `echo ${{matrix.os}} | cut -d - -f 1` = "macOS" ]; then
brew install [email protected]
brew link --overwrite [email protected]
Expand Down
11 changes: 10 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ execute_process(COMMAND mkdir -p ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
execute_process(COMMAND mkdir -p ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
execute_process(COMMAND ln -fsn ${CMAKE_SOURCE_DIR}/cmake/init.py ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/__init__.py)

# build options
set(ENABLE_JSON_OUTPUT "FALSE" CACHE BOOL "Enable JSON output of frames (adds to compile time and binary size)")
cozzyd marked this conversation as resolved.
Show resolved Hide resolved

if (${ENABLE_JSON_OUTPUT})
# Note, newer cmake suggests using add_compile_definitions, but I think that requires 3.12
add_definitions(-DSPT3G_ENABLE_JSON_OUTPUT)
endif()


set(BUILD_PROJECTS "${BUILD_PROJECTS}" CACHE STRING "The subset of available projects to actually build")
if(NOT "${BUILD_PROJECTS}" STREQUAL "")
set(USE_PROJECT_LIST "TRUE" CACHE BOOL "Whether to build only the subset of projects sepcified by BUILD_PROJECTS")
Expand Down Expand Up @@ -268,4 +277,4 @@ configure_file(
"${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
"${CMAKE_BINARY_DIR}/cmake/cmake_uninstall_cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_BINARY_DIR}/cmake/cmake_uninstall_cmake")
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_BINARY_DIR}/cmake/cmake_uninstall_cmake")
1 change: 1 addition & 0 deletions core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,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
29 changes: 29 additions & 0 deletions core/bin/spt3g-jsonify
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env python

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('}')

5 changes: 5 additions & 0 deletions core/include/core/G3Frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ class G3Frame {
template <typename T> void save(T &os) const;
template <typename T> void load(T &is);

// JSON representation of a frame (if JSON output is enabled, otherwise
// outputs valid JSON telling you that JSON output isn't enabled)
template <typename T> void saveJSON(T &os) const;
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
21 changes: 21 additions & 0 deletions core/include/core/serialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include <boost/iostreams/filtering_stream.hpp>

#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 @@ -17,13 +20,31 @@
#include <pybindings.h>
#include <G3Logging.h>

#ifdef SPT3G_ENABLE_JSON_OUTPUT

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

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

#else

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

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

#endif

template <class T>
struct g3frameobject_picklesuite : boost::python::pickle_suite
Expand Down
35 changes: 35 additions & 0 deletions core/src/G3Frame.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,37 @@ void G3Frame::save(T &os) const
ar << make_nvp("crc", crc);
}

template<typename T>
void G3Frame::saveJSON(T & os) const
{
#ifdef SPT3G_ENABLE_JSON_OUTPUT
using cereal::make_nvp;
uint32_t version(1), size(map_.size());

cereal::JSONOutputArchive ar(os);
ar << make_nvp("version", version);
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);
}
#else
os << " {error: \"spt3g-software compiled without JSON support\"}";
#endif
}

std::string G3Frame::asJSON() const
{
std::stringstream str;
saveJSON(str);
return str.str();
}


template <typename T>
void G3Frame::load(T &is)
{
Expand Down Expand Up @@ -402,3 +433,7 @@ template void G3Frame::save(boost::iostreams::filtering_ostream &) const;
template void G3Frame::save(std::ostream &) const;
template void G3Frame::save(std::ostringstream &) const;

template void G3Frame::saveJSON(std::ostream &) const;
template void G3Frame::saveJSON(std::ostringstream &) const;
template void G3Frame::saveJSON(boost::iostreams::filtering_ostream &) const;

32 changes: 28 additions & 4 deletions core/src/G3Timestream.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,29 @@ static FLAC__StreamEncoderWriteStatus flac_encoder_write_cb(
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}


// This is only needed because cereal will generate code for loading json due
// to the nature of serialize, even though this will never actually be called.
//
// I don't know if it works or not, but since it's never called, who cares? (I
// guess in the future we can have a fromJSON method in G3Frame as well if we
// wanted to support round-tripping through JSON for some reason).
template <typename A>
static void loadBinaryFn(A * inbuf, void * buffer, size_t size)
{
inbuf->template loadBinary<1>(buffer,size);
}

#ifdef SPT3G_ENABLE_JSON_OUTPUT
template <>
void loadBinaryFn<cereal::JSONInputArchive>(cereal::JSONInputArchive * inbuf, void * buffer, size_t size)
{
inbuf->loadBinaryValue(buffer,size);
}
#endif



template<typename A>
static FLAC__StreamDecoderReadStatus flac_decoder_read_cb(
const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes,
Expand All @@ -51,11 +74,11 @@ static FLAC__StreamDecoderReadStatus flac_decoder_read_cb(
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
} else if (*bytes >= size_t(bytes_left)) {
*bytes = bytes_left;
args->inbuf->template loadBinary<1>(buffer, bytes_left);
loadBinaryFn(args->inbuf, buffer, bytes_left);
args->pos += bytes_left;
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
} else {
args->inbuf->template loadBinary<1>(buffer, *bytes);
loadBinaryFn(args->inbuf, buffer, *bytes);
args->pos += *bytes;
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
Expand Down Expand Up @@ -105,7 +128,8 @@ template <class A> void G3Timestream::save(A &ar, unsigned v) const
ar & cereal::make_nvp("flac", use_flac_);

#ifdef G3_HAS_FLAC
if (use_flac_) {
//Don't try to use FLAC when outputing to JSON, even if flac is enabled.
if (use_flac_ && typeid(A) == typeid(cereal::PortableBinaryOutputArchive)) {
std::vector<int32_t> inbuf;
std::vector<uint8_t> outbuf;
const int32_t *chanmap[1];
Expand Down Expand Up @@ -874,7 +898,7 @@ PYBINDINGS("core") {
.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_readwrite("units", &G3Timestream::units,
"Units of the data in the timestream, stored as one of the "
"members of core.G3TimestreamUnits.")
Expand Down
1 change: 1 addition & 0 deletions core/src/python.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ BOOST_PYTHON_MODULE(core)
.def("generate_blobs", &G3Frame::GenerateBlobs, bp::arg("drop_objects")=false, "Force immediate serialization of all objects. Will save some CPU time later during serialization of the frame in exchange for spending the exact same amount of CPU time right now.")
.def("drop_objects", &G3Frame::DropObjects, "Drop all decoded objects in favor of their serialized copies, 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_pickle(g3frame_picklesuite())
.def("as_json", &G3Frame::asJSON, "JSON representation of frame")
;
register_vector_of<G3FramePtr>("Frame");
register_vector_of<G3FrameObjectPtr>("FrameObject");
Expand Down