Skip to content

Commit 70d46be

Browse files
authored
Improve cali-query --help (LLNL#566)
* Add CalQL help in cali-query * Remove csv formatter alias * Simplify print_caliquery_help * Proper namespacing in query_common.cpp * Update cali-query --help service and config lists
1 parent f696f27 commit 70d46be

File tree

7 files changed

+199
-16
lines changed

7 files changed

+199
-16
lines changed

include/caliper/ConfigManager.h

+4
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,10 @@ class ConfigManager
495495
std::vector<std::string>
496496
available_config_specs() const;
497497

498+
/// \brief Return short description for the given config spec.
499+
std::string
500+
get_description_for_spec(const char* name) const;
501+
498502
/// \brief Return description and options for the given config spec.
499503
std::string
500504
get_documentation_for_spec(const char* name) const;

src/caliper/ConfigManager.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -1185,6 +1185,12 @@ struct ConfigManager::ConfigManagerImpl
11851185
return !m_error;
11861186
}
11871187

1188+
std::string
1189+
get_description_for_spec(const char* name) const {
1190+
auto it = m_spec.find(name);
1191+
return it != m_spec.end() ? it->second->description : std::string();
1192+
}
1193+
11881194
std::string
11891195
get_documentation_for_spec(const char* name) const {
11901196
std::ostringstream out;
@@ -1394,10 +1400,16 @@ ConfigManager::available_config_specs() const
13941400
}
13951401

13961402
std::string
1397-
ConfigManager::get_documentation_for_spec(const char* name) const
1403+
ConfigManager::get_description_for_spec(const char* name) const
13981404
{
13991405
mP->import_builtin_config_specs();
1406+
return mP->get_description_for_spec(name);
1407+
}
14001408

1409+
std::string
1410+
ConfigManager::get_documentation_for_spec(const char* name) const
1411+
{
1412+
mP->import_builtin_config_specs();
14011413
return mP->get_documentation_for_spec(name);
14021414
}
14031415

src/reader/FormatProcessor.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ enum FormatterID {
3737

3838
const QuerySpec::FunctionSignature formatters[] = {
3939
{ FormatterID::Cali, "cali", 0, 0, nullptr },
40-
{ FormatterID::Cali, "csv", 0, 0, nullptr }, // keep old "csv" name for backwards compatibility
4140
{ FormatterID::Json, "json", 0, 6, json_kernel_args },
4241
{ FormatterID::Expand, "expand", 0, 0, nullptr },
4342
{ FormatterID::Format, "format", 1, 2, format_kernel_args },

src/services/Services.cpp

+17-3
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,16 @@ class ServicesManager {
7171
m_services[get_name_from_spec(s->name_or_spec)] = *s;
7272
}
7373

74-
std::ostream& print_service_description(std::ostream& os, const std::string& name) {
74+
std::string get_service_description(const std::string& name) {
75+
auto service_itr = m_services.find(name);
76+
if (service_itr == m_services.end())
77+
return std::string();
78+
auto dict = StringConverter(service_itr->second.name_or_spec).rec_dict();
79+
auto spec_itr = dict.find("description");
80+
return spec_itr != dict.end() ? spec_itr->second.to_string() : std::string();
81+
}
82+
83+
std::ostream& print_service_documentation(std::ostream& os, const std::string& name) {
7584
auto service_itr = m_services.find(name);
7685
if (service_itr == m_services.end())
7786
return os;
@@ -171,9 +180,14 @@ std::vector<std::string> get_available_services()
171180
return ServicesManager::instance()->get_available_services();
172181
}
173182

174-
std::ostream& print_service_description(std::ostream& os, const char* name)
183+
std::ostream& print_service_documentation(std::ostream& os, const std::string& name)
184+
{
185+
return ServicesManager::instance()->print_service_documentation(os, name);
186+
}
187+
188+
std::string get_service_description(const std::string& name)
175189
{
176-
return ServicesManager::instance()->print_service_description(os, name);
190+
return ServicesManager::instance()->get_service_description(name);
177191
}
178192

179193
ConfigSet init_config_from_spec(RuntimeConfig config, const char* spec)

src/services/Services.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,13 @@ void register_configured_services(Caliper* c, Channel* chn);
3737
/// \brief Read and initialize runtime config set from given JSON spec
3838
ConfigSet init_config_from_spec(RuntimeConfig cfg, const char* spec);
3939

40-
/// \brief Find and print service description
41-
std::ostream& print_service_description(std::ostream& os, const char* name);
40+
/// \brief Find and print service documentation (description and options)
41+
std::ostream&
42+
print_service_documentation(std::ostream& os, const std::string& name);
43+
44+
/// \brief Get description string for service
45+
std::string
46+
get_service_description(const std::string& name);
4247

4348
/// \brief Get all currently available service names.
4449
std::vector<std::string> get_available_services();

src/tools/cali-query/query_common.cpp

+157-8
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
#include "caliper/reader/Aggregator.h"
77
#include "caliper/reader/CalQLParser.h"
88
#include "caliper/reader/FormatProcessor.h"
9+
#include "caliper/reader/Preprocessor.h"
910
#include "caliper/reader/RecordSelector.h"
1011

1112
#include "caliper/tools-util/Args.h"
1213

1314
#include "caliper/common/Log.h"
1415

1516
#include "../../common/util/parse_util.h"
17+
#include "../../common/util/format_util.h"
1618
#include "../../common/util/split.hpp"
1719

1820
#include "../../services/Services.h"
@@ -98,6 +100,113 @@ parse_functioncall(std::istream& is, const QuerySpec::FunctionSignature* defs)
98100
return std::make_pair(retid, std::move(args));
99101
}
100102

103+
const char* s_calql_helpstr = R"helpstr(
104+
The Caliper Query Language (CalQL) is used to to filter, aggregate, and create
105+
reports from Caliper .cali data with cali-query.
106+
107+
The general structure of a query is:
108+
109+
LET
110+
<list of pre-processing operations>
111+
SELECT
112+
<list of output attributes and aggregations>
113+
GROUP BY
114+
<list of aggregation key attributes>
115+
WHERE
116+
<list of conditions>
117+
FORMAT
118+
<report/output formatter>
119+
ORDER BY
120+
<list of sort attributes>
121+
122+
All of the statements are optional; by default cali-query will pass the input
123+
records through as-is, without any aggregations, and output .cali data.
124+
statements are case-insensitive and can be provided in any order.
125+
126+
Run "--help [let, select, groupby, where, format]" for more information about
127+
each CalQL statement.
128+
)helpstr";
129+
130+
const char* s_calql_let_helpstr = R"helpstr(
131+
The LET statement defines operations to be applied on input records before
132+
further processing. The general structure of the LET statement is
133+
134+
LET result = op(arguments) [ IF condition ] [, ... ]
135+
136+
This adds a new attribute "result" with the result of operation "op" to
137+
the record. Results are only added if the operation was successful
138+
(e.g., all required input operands were present in the record). If an
139+
optional IF condition is given, the operation is only applied if the
140+
condition is true.
141+
142+
Available LET operators:
143+
144+
)helpstr";
145+
146+
const char* s_calql_select_helpstr = R"helpstr(
147+
The SELECT statement selects the attributes and aggregations in the output.
148+
The general structure is
149+
150+
SELECT attribute | op(arguments) [ AS alias ] [ UNIT unit ] [, ...]
151+
152+
The aggregations in the SELECT statement specify how attributes are
153+
aggregated. Use the GROUP BY statement to specify the output set. Use AS
154+
to specify an optional custom label/header.
155+
156+
Available aggregation operations:
157+
158+
)helpstr";
159+
160+
const char* s_calql_groupby_helpstr = R"helpstr(
161+
The GROUP BY statement selects the attributes that define the output set. For
162+
example, when grouping by "mpi.rank", the output set has one record for each
163+
mpi.rank value encountered in the input. Input records with the same mpi.rank
164+
value will be aggregated as specified by the SELECT statement. The general
165+
structure is
166+
167+
GROUP BY path | attribute name [, ...]
168+
169+
The "path" value selects all region name attributes for grouping.
170+
)helpstr";
171+
172+
const char* s_calql_where_helpstr = R"helpstr(
173+
Use the WHERE statement to filter input records. The filter is applied after
174+
pre-processing (see LET) and before aggregating. The general structure is
175+
176+
WHERE [NOT] condition [, ...]
177+
178+
NOT negates the condition. Available conditions are:
179+
180+
attribute (matches if any entry for "attribute" is in the record)
181+
attribute = value
182+
attribute > value
183+
attribute < value
184+
)helpstr";
185+
186+
const char* s_calql_format_helpstr = R"helpstr(
187+
The FORMAT statement selects and configures the output formatter. The general
188+
structure is
189+
190+
FORMAT formatter [(arguments)] [ORDER BY attribute [ASC | DESC] [,...]]
191+
192+
The ORDER BY statement specifies a list of attributes to sort the output
193+
records by. It can be used with the "table" and "tree" formatters.
194+
195+
Available formatters:
196+
197+
)helpstr";
198+
199+
std::ostream& print_function_signature(std::ostream& os, const QuerySpec::FunctionSignature& s)
200+
{
201+
os << " " << s.name << "(";
202+
for (int i = 0; i < s.min_args; ++i)
203+
os << (i > 0 ? ", " : "") << s.args[i];
204+
for (int i = s.min_args; i < s.max_args; ++i)
205+
os << (i > 0 ? ", " : "") << s.args[i] << "*";
206+
os << ")";
207+
return os;
208+
}
209+
101210
}
102211

103212
namespace cali
@@ -262,17 +371,50 @@ void print_caliquery_help(const Args& args, const char* usage, const ConfigManag
262371
{
263372
std::string helpopt = args.get("help");
264373

265-
if (helpopt == "configs") {
374+
if (helpopt == "configs" || helpopt == "recipes") {
375+
std::cout << "Available config recipes:\n";
266376
auto list = mgr.available_config_specs();
377+
size_t len = 0;
267378
for (const auto &s : list)
268-
std::cout << mgr.get_documentation_for_spec(s.c_str()) << "\n";
379+
len = std::max(len, s.size());
380+
for (const auto &s : list) {
381+
std::string descr = mgr.get_description_for_spec(s.c_str());
382+
util::pad_right(std::cout << " ", s, len) << descr << "\n";
383+
}
269384
} else if (helpopt == "services") {
385+
std::cout << "Available services:\n";
270386
services::add_default_service_specs();
271-
272-
int i = 0;
273-
for (const auto& s : services::get_available_services())
274-
std::cout << (i++ > 0 ? "," : "") << s;
275-
std::cout << std::endl;
387+
auto list = services::get_available_services();
388+
size_t len = 0;
389+
for (const auto &s : list)
390+
len = std::max(len, s.size());
391+
for (const auto &s : list) {
392+
std::string descr = services::get_service_description(s);
393+
util::pad_right(std::cout << " ", s, len) << descr << "\n";
394+
}
395+
} else if (helpopt == "calql") {
396+
std::cout << s_calql_helpstr;
397+
} else if (helpopt == "let") {
398+
std::cout << s_calql_let_helpstr;
399+
const QuerySpec::FunctionSignature* ops = Preprocessor::preprocess_defs();
400+
for (const auto* p = ops; p && p->name; ++p)
401+
print_function_signature(std::cout, *p) << "\n";
402+
} else if (helpopt == "select") {
403+
std::cout << s_calql_select_helpstr;
404+
const QuerySpec::FunctionSignature* ops = Aggregator::aggregation_defs();
405+
for (const auto* p = ops; p && p->name; ++p) {
406+
print_function_signature(std::cout, *p) << " -> ";
407+
std::vector<std::string> args(p->args, p->args+p->max_args);
408+
const QuerySpec::AggregationOp op(*p, args);
409+
std::cout << Aggregator::get_aggregation_attribute_name(op) << "\n";
410+
}
411+
} else if (helpopt == "where") {
412+
std::cout << s_calql_where_helpstr;
413+
} else if (helpopt == "format") {
414+
std::cout << s_calql_format_helpstr;
415+
const QuerySpec::FunctionSignature* ops = FormatProcessor::formatter_defs();
416+
for (const auto* p = ops; p && p->name; ++p)
417+
print_function_signature(std::cout, *p) << "\n";
276418
} else if (!helpopt.empty()) {
277419
{
278420
auto cfgs = mgr.available_config_specs();
@@ -288,7 +430,7 @@ void print_caliquery_help(const Args& args, const char* usage, const ConfigManag
288430
auto srvs = services::get_available_services();
289431
auto it = std::find(srvs.begin(), srvs.end(), helpopt);
290432
if (it != srvs.end()) {
291-
services::print_service_description(std::cout << *it << " service:\n", helpopt.c_str());
433+
services::print_service_documentation(std::cout << *it << " service:\n", helpopt);
292434
return;
293435
}
294436
}
@@ -302,6 +444,13 @@ void print_caliquery_help(const Args& args, const char* usage, const ConfigManag
302444
} else {
303445
std::cout << usage << "\n\n";
304446
args.print_available_options(std::cout);
447+
std::cout <<
448+
"\n Use \"--help configs\" to list all config recipes."
449+
"\n Use \"--help services\" to list all available services."
450+
"\n Use \"--help [recipe name]\" to get help for a config recipe."
451+
"\n Use \"--help [service name]\" to get help for a service."
452+
"\n Use \"--help calql\" to get help for the CalQL query language."
453+
"\n Use \"--help [let,select,where,groupby,format]\" to get help for CalQL statements.\n";
305454
}
306455
}
307456

test/ci_app_tests/test_caliquery.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def test_caliquery_list_services(self):
3636
]
3737

3838
report_out,_ = cat.run_test(target_cmd, env)
39-
res = report_out.decode().split(',')
39+
res = report_out.decode().split()
4040

4141
for target in service_targets:
4242
if not target in res:

0 commit comments

Comments
 (0)