Skip to content

Commit 2e3dcb1

Browse files
committed
Add a command-line application for fast JSON checking
1 parent 7c2897f commit 2e3dcb1

17 files changed

Lines changed: 24675 additions & 37 deletions

File tree

Makefile

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
CC=gcc#
22
CXX=g++#
33
CXXFLAGS=-std=c++11 -fPIC -O2 -pthread
4-
CXXFLAGS_APPS=-std=c++17 -fPIC -O2 -pthread -fno-new-ttp-matching#-Wall -Wextra
4+
CXXFLAGS_APPS=-std=c++17 -fPIC -pthread -O3#-Wall -Wextra
55
CXXFLAGS_TEST=-g -std=c++11 -fPIC -O0 -pthread --coverage -fno-inline -fno-inline-small-functions -fno-default-inline -fvisibility=hidden#-Wall -Wextra
66

77
LIB_FLAGS=-lcudd
8-
INCLUDE_FLAGS=-I$(ROOT_DIR) -I$(ROOT_DIR)/include -I/home/ulus/anaconda3/include/python3.6m
8+
INCLUDE_FLAGS=-I$(ROOT_DIR) -I$(ROOT_DIR)/include -I/home/dogan/anaconda3/include/python3.7m
99

1010
NAME=reelay
1111

@@ -50,7 +50,7 @@ benchmark: timescales rvbc2018
5050
timescales:
5151
mkdir -p test/build
5252
cd test/build && rm -rf timescales && git clone https://github.com/doganulus/timescales.git
53-
cd test/build/timescales && make full
53+
cd test/build/timescales && make full FLAGS="--format=json"
5454

5555
timescales-clean:
5656
rm -rf test/build/timescales
@@ -62,7 +62,9 @@ rvbc2018:
6262
rvbc2018-clean:
6363
rm -rf test/build/benchmark-challenge-2018
6464

65-
# apps: rymtl rystl ryjavu
65+
apps:
66+
mkdir -p bin
67+
$(CXX) $(CXXFLAGS_APPS) apps/$(name)/*.cpp -o bin/$(name) $(INCLUDE_FLAGS) $(LIB_FLAGS)
6668

6769
# rymtl:
6870
# mkdir -p bin
@@ -146,13 +148,18 @@ test_nested_input:
146148
cd test/build && ./test_nested_input -r compact
147149

148150
test_random:
149-
cd test/build && $(CXX) $(CXXFLAGS_TEST) main.o $(ROOT_DIR)/test/test_random.cpp -o test_random $(INCLUDE_FLAGS) -L/home/ulus/anaconda3/lib -lcudd -lpython3.6m
151+
cd test/build && $(CXX) $(CXXFLAGS_TEST) -std=c++11 main.o $(ROOT_DIR)/test/test_random.cpp -o test_random $(INCLUDE_FLAGS) -L/home/dogan/anaconda3/lib -lcudd -lpython3.7m
150152
cd test/build && ./test_random -r compact
151153

152154
test_json_monitors:
153155
cd test/build && $(CXX) $(CXXFLAGS_TEST) main.o $(ROOT_DIR)/test/test_json_monitors.cpp -o test_json_monitors $(INCLUDE_FLAGS) -L/home/ulus/anaconda3/lib -lcudd
154156
cd test/build && ./test_json_monitors -r compact
155157

158+
test_performance_discrete: test/timescales/discrete/multitime/*.txt
159+
for batchfile in $^ ; do \
160+
multitime -n 10 -b $${batchfile} >/dev/null; \
161+
done
162+
156163
# test_mtl_performance_discrete: test/timescales/discrete/multitime/*.txt
157164
# for batchfile in $^ ; do \
158165
# multitime -n 10 -b $${batchfile} ; \

apps/ryjson1/main.cpp

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
/*
2+
* |
3+
* __| _ \ _ \ | _` | | |
4+
* | __/ __/ | ( | | |
5+
* _| \___|\___|_|\__,_|\__, |
6+
* ____/ Copyright (c) 2019-2020 Dogan Ulus
7+
*
8+
* This Source Code Form is subject to the terms of the Mozilla Public
9+
* License, v. 2.0. If a copy of the MPL was not distributed with this
10+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
11+
*/
12+
#include <glob.h> // glob(), globfree()
13+
#include <string.h> // memset()
14+
15+
#include <fstream>
16+
#include <iostream>
17+
#include <memory>
18+
#include <stdexcept>
19+
#include <string>
20+
#include <vector>
21+
22+
#include "reelay/json.hpp"
23+
#include "reelay/monitors.hpp"
24+
25+
#include "third_party/simdjson/simdjson.h"
26+
#include "third_party/simdjson/simdjson.cpp"
27+
#include "third_party/taywee/args.hpp"
28+
29+
#include "simdjson_adapter.hpp"
30+
31+
namespace rycli {
32+
33+
std::vector<std::string> expand_glob(const std::string& glob_str) {
34+
35+
// glob struct resides on the stack
36+
glob_t glob_result;
37+
memset(&glob_result, 0, sizeof(glob_result));
38+
39+
// do the glob operation
40+
int return_value
41+
= glob(glob_str.c_str(), GLOB_TILDE, NULL, &glob_result);
42+
43+
// glob() error handling
44+
// Info: http://man7.org/linux/man-pages/man3/glob.3.html
45+
if (return_value == GLOB_ABORTED) {
46+
globfree(&glob_result);
47+
std::stringstream ss;
48+
ss << "glob() encountered a read error" << std::endl;
49+
throw std::runtime_error(ss.str());
50+
} else if (return_value == GLOB_NOSPACE) {
51+
globfree(&glob_result);
52+
std::stringstream ss;
53+
ss << "glob() running out of memory" << std::endl;
54+
throw std::runtime_error(ss.str());
55+
}
56+
57+
// collect all the filenames into a std::list<std::string>
58+
std::vector<std::string> filenames;
59+
for (size_t i = 0; i < glob_result.gl_pathc; ++i) {
60+
filenames.push_back(std::string(glob_result.gl_pathv[i]));
61+
}
62+
63+
// cleanup
64+
globfree(&glob_result);
65+
66+
// done
67+
return filenames;
68+
}
69+
70+
template <class MonitorT>
71+
inline void discrete_timed_process_json_file(MonitorT monitor, const std::string& filename) {
72+
int stdout_line_count = 0;
73+
simdjson::dom::parser reader;
74+
std::ofstream output_file(filename + ".ryl");
75+
std::cout << "Processing " + filename << std::endl;
76+
std::cout << "---" << std::endl;
77+
for (simdjson::dom::element doc : reader.load_many(filename)) {
78+
reelay::json result = monitor->update(doc);
79+
if (not result.empty()) {
80+
if (stdout_line_count < 5) {
81+
std::cout << result << std::endl;
82+
stdout_line_count++;
83+
} else if (stdout_line_count == 5) {
84+
std::cout << "..." << std::endl;
85+
stdout_line_count++;
86+
}
87+
output_file << result << std::endl;
88+
};
89+
}
90+
if (stdout_line_count < 5){
91+
std::cout << "---" << std::endl;
92+
}
93+
std::cout << "Full output written to " + filename + ".ryl" << std::endl;
94+
}
95+
96+
template <class MonitorT>
97+
inline void dense_timed_process_json_file(MonitorT monitor, const std::string& filename) {
98+
int stdout_line_count = 0;
99+
simdjson::dom::parser reader;
100+
std::ofstream output_file(filename + ".ryl");
101+
std::cout << "Processing " + filename << std::endl;
102+
std::cout << "---" << std::endl;
103+
for (simdjson::dom::element doc : reader.load_many(filename)) {
104+
reelay::json result = monitor->update(doc);
105+
if (not result.empty()) {
106+
for(const auto& item: result){
107+
if (stdout_line_count < 5) {
108+
std::cout << item << std::endl;
109+
stdout_line_count++;
110+
} else if (stdout_line_count == 5) {
111+
std::cout << "..." << std::endl;
112+
stdout_line_count++;
113+
}
114+
output_file << item << std::endl;
115+
}
116+
}
117+
}
118+
if (stdout_line_count < 5) {
119+
std::cout << "---" << std::endl;
120+
}
121+
std::cout << "Full output written to " + filename + ".ryl" << std::endl;
122+
}
123+
124+
} // namespace rycli
125+
126+
int main(int argc, char** argv) {
127+
128+
using namespace reelay;
129+
130+
args::ArgumentParser parser(
131+
"Reelay Command Line Interface",
132+
"Further information: https://github.com/doganulus/reelay");
133+
134+
args::Positional<std::string> spec(
135+
parser, "SPEC", "Specification in Rye Format", args::Options::Required);
136+
args::PositionalList<std::string> paths(
137+
parser, "FILE", "Log files to be checked against SPEC",
138+
args::Options::Required);
139+
140+
args::Group gsetting(parser, "Monitor Settings");
141+
142+
args::Group gmodel(gsetting, "Time model:", args::Group::Validators::Xor,
143+
args::Options::Global);
144+
args::Flag fdense(gmodel, "fv", "Use dense time model (default)",
145+
{'v', "dense"});
146+
args::Flag fdiscrete(gmodel, "fx", "Use discrete time model",
147+
{'x', "discrete"});
148+
149+
args::Group gdtype(gsetting, "Time datatype:", args::Group::Validators::Xor,
150+
args::Options::Global);
151+
args::Flag fint(gdtype, "fi", "Use int64 as time type (default)",
152+
{'i', "itime"});
153+
args::Flag ffloat(gdtype, "ff", "with -v, use float64 as time type",
154+
{'f', "ftime"});
155+
156+
args::Group gsemantics(gsetting, "Value model:", args::Group::Validators::Xor,
157+
args::Options::Global);
158+
args::Flag fboolean(
159+
gsemantics, "fb", "Use boolean semantics", {'b', "boolean"});
160+
args::Flag frobustness(
161+
gsemantics, "fr", "Use robustness semantics", {'r', "robustness"});
162+
163+
args::Group ginterp(gsetting, "Interpolation:", args::Group::Validators::Xor,
164+
args::Options::Global);
165+
args::Flag fconstant(ginterp, "fk",
166+
"with -v, use piecewise constant interpolation (default)",
167+
{'k', "pwc"});
168+
args::Flag flinear(ginterp, "fl", "with -vf, use piecewise linear interpolation",
169+
{'l', "pwl"});
170+
171+
args::ValueFlag<double> fperiod(
172+
gsetting, "NUM", "with -v, use NUM as the sampling period",
173+
{"period"});
174+
args::Flag fno_condense(gsetting, "fno-condense",
175+
"with -x, disable dense output", {'z', "no-condense"});
176+
177+
args::Group gioctrl(parser, "Input/Output Control");
178+
args::Group gformat(gioctrl,
179+
"Input File Format:", args::Group::Validators::Xor,
180+
args::Options::Global);
181+
182+
args::ValueFlag<std::string> t_name(
183+
gioctrl, "STRING", "Use STRING as the name of time field", {"tname"}, "time");
184+
args::ValueFlag<std::string> y_name(
185+
gioctrl, "STRING", "use STRING as the name of output field", {"yname"}, "value");
186+
187+
args::HelpFlag help(parser, "help", "Display this help menu", {'h', "help"});
188+
189+
args::CompletionFlag completion(parser, {"complete"});
190+
191+
try {
192+
parser.ParseCLI(argc, argv);
193+
} catch (const args::Completion& e) {
194+
std::cout << e.what();
195+
return 0;
196+
} catch (const args::Help&) {
197+
std::cout << parser;
198+
return 0;
199+
} catch (const args::ParseError& e) {
200+
std::cerr << e.what() << std::endl;
201+
std::cerr << parser;
202+
return 1;
203+
}
204+
205+
// Glob Expansion
206+
auto filenames = std::vector<std::string>();
207+
for (const auto& p : args::get(paths)) {
208+
std::vector<std::string> expanded = rycli::expand_glob(p);
209+
filenames.insert(filenames.end(), expanded.begin(), expanded.end());
210+
}
211+
212+
using input_t = simdjson::dom::element;
213+
214+
reelay::kwargs extra_args
215+
= {{"t_name", args::get(t_name)}, {"y_name", args::get(y_name)}};
216+
217+
if (fdiscrete) {
218+
std::shared_ptr<base_monitor<int64_t, input_t, json>> m;
219+
220+
if (frobustness and fno_condense) {
221+
m = discrete_timed<int64_t>::robustness<double>::monitor<input_t>::make(
222+
args::get(spec), extra_args);
223+
} else if (frobustness and not fno_condense) {
224+
m = condensing<int64_t>::robustness<double>::monitor<input_t>::make(
225+
args::get(spec), extra_args);
226+
} else if (not frobustness and fno_condense) {
227+
m = discrete_timed<int64_t>::monitor<input_t>::make(
228+
args::get(spec), extra_args);
229+
} else {
230+
m = condensing<int64_t>::monitor<input_t>::make(
231+
args::get(spec), extra_args);
232+
}
233+
234+
for (const auto& filename : filenames) {
235+
rycli::discrete_timed_process_json_file<decltype(m)>(m, filename);
236+
}
237+
} else if (ffloat) { // fdense and ffloat
238+
std::shared_ptr<base_monitor<double, input_t, std::vector<json>>> m;
239+
240+
if (frobustness and flinear) {
241+
throw std::invalid_argument(
242+
("Linear interpolation under robustness semantics not supported"));
243+
} else if (frobustness and not flinear) {
244+
m = reelay::dense_timed<double, piecewise::CONSTANT>::robustness<
245+
double>::monitor<input_t>::make(args::get(spec), extra_args);
246+
} else if (not frobustness and flinear) {
247+
m = reelay::dense_timed<double, piecewise::LINEAR>::monitor<
248+
input_t>::make(args::get(spec), extra_args);
249+
} else { // not frobustness and not flinear
250+
m = reelay::dense_timed<double, piecewise::CONSTANT>::monitor<
251+
input_t>::make(args::get(spec), extra_args);
252+
}
253+
254+
for (const auto& filename : filenames) {
255+
rycli::dense_timed_process_json_file<decltype(m)>(m, filename);
256+
}
257+
} else { // fdense and fint
258+
std::shared_ptr<base_monitor<int64_t, input_t, std::vector<json>>> m;
259+
260+
if (frobustness and flinear) {
261+
throw std::invalid_argument((
262+
"Integer time type and linear interpolation does not work together"));
263+
} else if (frobustness and not flinear) {
264+
m = reelay::dense_timed<int64_t, piecewise::CONSTANT>::robustness<
265+
double>::monitor<input_t>::make(args::get(spec), extra_args);
266+
} else if (not frobustness and flinear) {
267+
throw std::invalid_argument((
268+
"Integer time type and linear interpolation does not work together"));
269+
} else { // not frobustness and not flinear
270+
m = reelay::dense_timed<int64_t, piecewise::CONSTANT>::monitor<
271+
input_t>::make(args::get(spec), extra_args);
272+
}
273+
274+
for (const auto& filename : filenames) {
275+
rycli::dense_timed_process_json_file<decltype(m)>(m, filename);
276+
}
277+
}
278+
279+
return 0;
280+
}

0 commit comments

Comments
 (0)