stdlib: Add Vector2d to PyStats
Change-Id: Icb2f691abf88ef4bac8d277e421329edb000209b
This commit is contained in:
@@ -142,6 +142,64 @@ class Vector(Statistic):
|
|||||||
return sum(float(self.value[key]) for key in self.values)
|
return sum(float(self.value[key]) for key in self.values)
|
||||||
|
|
||||||
|
|
||||||
|
class Vector2d(Statistic):
|
||||||
|
"""
|
||||||
|
A 2D vector of scalar values.
|
||||||
|
"""
|
||||||
|
|
||||||
|
value: Dict[Union[str, int, float], Vector]
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
value: Dict[Union[str, int, float], Vector],
|
||||||
|
type: Optional[str] = None,
|
||||||
|
description: Optional[str] = None,
|
||||||
|
):
|
||||||
|
assert (
|
||||||
|
len({vector.size() for vector in value.values()}) == 1
|
||||||
|
), "All the Vectors in the 2d Vector are not of equal length."
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
value=value,
|
||||||
|
type=type,
|
||||||
|
description=description,
|
||||||
|
)
|
||||||
|
|
||||||
|
def x_size(self) -> int:
|
||||||
|
"""Returns the number of elements in the x dimension."""
|
||||||
|
assert self.value is not None
|
||||||
|
return len(self.value)
|
||||||
|
|
||||||
|
def y_size(self) -> int:
|
||||||
|
"""Returns the number of elements in the y dimension."""
|
||||||
|
assert self.value is not None
|
||||||
|
return len(self.value[0])
|
||||||
|
|
||||||
|
def size(self) -> int:
|
||||||
|
"""Returns the total number of elements."""
|
||||||
|
return self.x_size() * self.y_size()
|
||||||
|
|
||||||
|
def total(self) -> int:
|
||||||
|
"""The total (sum) of all the entries in the 2d vector/"""
|
||||||
|
assert self.value is not None
|
||||||
|
total = 0
|
||||||
|
for vector in self.value.values():
|
||||||
|
for scalar in vector.values():
|
||||||
|
total += scalar.value
|
||||||
|
return total
|
||||||
|
|
||||||
|
def __getitem__(self, index: Union[str, int, float]) -> Vector:
|
||||||
|
assert self.value is not None
|
||||||
|
# In the case of string, we cast strings to integers of floats if they
|
||||||
|
# are numeric. This avoids users having to cast strings to integers.
|
||||||
|
if isinstance(index, str):
|
||||||
|
if index.isindex():
|
||||||
|
index = int(index)
|
||||||
|
elif index.isnumeric():
|
||||||
|
index = float(index)
|
||||||
|
return self.value[index]
|
||||||
|
|
||||||
|
|
||||||
class Distribution(Vector):
|
class Distribution(Vector):
|
||||||
"""
|
"""
|
||||||
A statistic type that stores information relating to distributions. Each
|
A statistic type that stores information relating to distributions. Each
|
||||||
|
|||||||
@@ -138,6 +138,8 @@ def __get_statistic(statistic: _m5.stats.Info) -> Optional[Statistic]:
|
|||||||
pass
|
pass
|
||||||
elif isinstance(statistic, _m5.stats.VectorInfo):
|
elif isinstance(statistic, _m5.stats.VectorInfo):
|
||||||
return __get_vector(statistic)
|
return __get_vector(statistic)
|
||||||
|
elif isinstance(statistic, _m5.stats.Vector2dInfo):
|
||||||
|
return __get_vector2d(statistic)
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -193,7 +195,6 @@ def __get_distribution(statistic: _m5.stats.DistInfo) -> Distribution:
|
|||||||
def __get_vector(statistic: _m5.stats.VectorInfo) -> Vector:
|
def __get_vector(statistic: _m5.stats.VectorInfo) -> Vector:
|
||||||
vec: Dict[Union[str, int, float], Scalar] = {}
|
vec: Dict[Union[str, int, float], Scalar] = {}
|
||||||
|
|
||||||
|
|
||||||
for index in range(statistic.size):
|
for index in range(statistic.size):
|
||||||
# All the values in a Vector are Scalar values
|
# All the values in a Vector are Scalar values
|
||||||
value = statistic.value[index]
|
value = statistic.value[index]
|
||||||
@@ -231,6 +232,42 @@ def __get_vector(statistic: _m5.stats.VectorInfo) -> Vector:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def __get_vector2d(statistic: _m5.stats.Vector2dInfo) -> Vector2d:
|
||||||
|
# All the values in a 2D Vector are Scalar values
|
||||||
|
description = statistic.desc
|
||||||
|
x_size = statistic.x_size
|
||||||
|
y_size = statistic.y_size
|
||||||
|
|
||||||
|
vector_rep: Dict[Union[str, int, float], Vector] = {}
|
||||||
|
for x_index in range(x_size):
|
||||||
|
x_index_string = x_index
|
||||||
|
if x_index in statistic.subnames:
|
||||||
|
x_index_string = str(statistic.subnames[x_index])
|
||||||
|
|
||||||
|
x_desc = description
|
||||||
|
if x_index in statistic.subdescs:
|
||||||
|
x_desc = str(statistic.subdescs[x_index])
|
||||||
|
x_vec: Dict[str, Scalar] = {}
|
||||||
|
for y_index in range(y_size):
|
||||||
|
y_index_val = y_index
|
||||||
|
if y_index in statistic.ysubnames:
|
||||||
|
y_index_val = str(statistic.subnames[y_index])
|
||||||
|
|
||||||
|
x_vec[y_index_val] = Scalar(
|
||||||
|
value=statistic.value[x_index * y_size + y_index],
|
||||||
|
unit=statistic.unit,
|
||||||
|
datatype=StorageType["f64"],
|
||||||
|
)
|
||||||
|
|
||||||
|
vector_rep[x_index_string] = Vector(
|
||||||
|
x_vec,
|
||||||
|
type="Vector",
|
||||||
|
description=x_desc,
|
||||||
|
)
|
||||||
|
|
||||||
|
return Vector2d(value=vector_rep, type="Vector2d", description=description)
|
||||||
|
|
||||||
|
|
||||||
def _prepare_stats(group: _m5.stats.Group):
|
def _prepare_stats(group: _m5.stats.Group):
|
||||||
"""
|
"""
|
||||||
Prepares the statistics for dumping.
|
Prepares the statistics for dumping.
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ cast_stat_info(const statistics::Info *info)
|
|||||||
*/
|
*/
|
||||||
TRY_CAST(statistics::FormulaInfo);
|
TRY_CAST(statistics::FormulaInfo);
|
||||||
TRY_CAST(statistics::VectorInfo);
|
TRY_CAST(statistics::VectorInfo);
|
||||||
|
TRY_CAST(statistics::Vector2dInfo);
|
||||||
TRY_CAST(statistics::DistInfo);
|
TRY_CAST(statistics::DistInfo);
|
||||||
|
|
||||||
return py::cast(info);
|
return py::cast(info);
|
||||||
@@ -183,6 +184,17 @@ pybind_init_stats(py::module_ &m_native)
|
|||||||
[](const statistics::VectorInfo &info) { return info.total(); })
|
[](const statistics::VectorInfo &info) { return info.total(); })
|
||||||
;
|
;
|
||||||
|
|
||||||
|
py::class_<statistics::Vector2dInfo, statistics::Info,
|
||||||
|
std::unique_ptr<statistics::Vector2dInfo, py::nodelete>>(
|
||||||
|
m, "Vector2dInfo")
|
||||||
|
.def_readonly("x_size", &statistics::Vector2dInfo::x)
|
||||||
|
.def_readonly("y_size", &statistics::Vector2dInfo::y)
|
||||||
|
.def_readonly("subnames", &statistics::Vector2dInfo::subnames)
|
||||||
|
.def_readonly("subdescs", &statistics::Vector2dInfo::subdescs)
|
||||||
|
.def_readonly("ysubnames", &statistics::Vector2dInfo::y_subnames)
|
||||||
|
.def_readonly("value", &statistics::Vector2dInfo::cvec)
|
||||||
|
;
|
||||||
|
|
||||||
py::class_<statistics::FormulaInfo, statistics::VectorInfo,
|
py::class_<statistics::FormulaInfo, statistics::VectorInfo,
|
||||||
std::unique_ptr<statistics::FormulaInfo, py::nodelete>>(
|
std::unique_ptr<statistics::FormulaInfo, py::nodelete>>(
|
||||||
m, "FormulaInfo")
|
m, "FormulaInfo")
|
||||||
|
|||||||
@@ -31,5 +31,6 @@ if env['CONF']['USE_TEST_OBJECTS']:
|
|||||||
'StatTester',
|
'StatTester',
|
||||||
'ScalarStatTester',
|
'ScalarStatTester',
|
||||||
'VectorStatTester',
|
'VectorStatTester',
|
||||||
|
'Vector2dStatTester',
|
||||||
])
|
])
|
||||||
Source('stat_tester.cc')
|
Source('stat_tester.cc')
|
||||||
|
|||||||
@@ -62,3 +62,28 @@ class VectorStatTester(StatTester):
|
|||||||
"The vector stat's subdescriptions. If empty, the subdescriptions "
|
"The vector stat's subdescriptions. If empty, the subdescriptions "
|
||||||
"are not used.",
|
"are not used.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Vector2dStatTester(StatTester):
|
||||||
|
type = "Vector2dStatTester"
|
||||||
|
cxx_header = "test_objects/stat_tester.hh"
|
||||||
|
cxx_class = "gem5::Vector2dStatTester"
|
||||||
|
|
||||||
|
x_size = Param.Int("The number of elements in the x dimension.")
|
||||||
|
y_size = Param.Int("The number of elements in the y dimension.")
|
||||||
|
|
||||||
|
values = VectorParam.Float("The vector stat's values, flattened.")
|
||||||
|
subnames = VectorParam.String(
|
||||||
|
[],
|
||||||
|
"The vector stat's subnames. If position is empty, index int is "
|
||||||
|
"used instead.",
|
||||||
|
)
|
||||||
|
subdescs = VectorParam.String(
|
||||||
|
[],
|
||||||
|
"The vector stat's subdescriptions. If empty, the subdescriptions "
|
||||||
|
"are not used.",
|
||||||
|
)
|
||||||
|
ysubnames = VectorParam.String(
|
||||||
|
[],
|
||||||
|
"The vector stat's y subdescriptions. If empty, the subdescriptions ",
|
||||||
|
)
|
||||||
|
|||||||
@@ -84,4 +84,53 @@ VectorStatTester::VectorStatTesterStats::VectorStatTesterStats(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Vector2dStatTester::setStats()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < params.x_size; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < params.y_size; j++)
|
||||||
|
{
|
||||||
|
stats.vector2d[i][j] = (params.values[j + i * params.y_size]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2dStatTester::Vector2dStatTesterStats::Vector2dStatTesterStats(
|
||||||
|
statistics::Group *parent,
|
||||||
|
const Vector2dStatTesterParams ¶ms
|
||||||
|
) : statistics::Group(parent),
|
||||||
|
vector2d(this,
|
||||||
|
params.name.c_str(),
|
||||||
|
statistics::units::Count::get(),
|
||||||
|
params.description.c_str()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
vector2d.init(params.x_size, params.y_size);
|
||||||
|
|
||||||
|
assert(params.x_size * params.y_size == params.values.size());
|
||||||
|
|
||||||
|
for (int i = 0; i < params.x_size; i++)
|
||||||
|
{
|
||||||
|
if (params.subnames.size() > i) {
|
||||||
|
vector2d.subname(i, params.subnames[i]);
|
||||||
|
} else {
|
||||||
|
vector2d.subname(i, std::to_string(i));
|
||||||
|
}
|
||||||
|
if (params.subdescs.size() > i) {
|
||||||
|
vector2d.subdesc(i, params.subdescs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int j = 0; j < params.y_size; j++)
|
||||||
|
{
|
||||||
|
if (params.ysubnames.size() > j) {
|
||||||
|
vector2d.ysubname(j, params.ysubnames[j]);
|
||||||
|
} else {
|
||||||
|
vector2d.ysubname(j, std::to_string(j));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace gem5
|
} // namespace gem5
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "base/statistics.hh"
|
#include "base/statistics.hh"
|
||||||
#include "params/ScalarStatTester.hh"
|
#include "params/ScalarStatTester.hh"
|
||||||
#include "params/StatTester.hh"
|
#include "params/StatTester.hh"
|
||||||
|
#include "params/Vector2dStatTester.hh"
|
||||||
#include "params/VectorStatTester.hh"
|
#include "params/VectorStatTester.hh"
|
||||||
#include "sim/sim_object.hh"
|
#include "sim/sim_object.hh"
|
||||||
|
|
||||||
@@ -136,6 +137,28 @@ class VectorStatTester : public StatTester
|
|||||||
} stats;
|
} stats;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Vector2dStatTester : public StatTester
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
Vector2dStatTesterParams params;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Vector2dStatTester(const Vector2dStatTesterParams &p) :
|
||||||
|
StatTester(p), params(p), stats(this, p) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setStats() override;
|
||||||
|
struct Vector2dStatTesterStats : public statistics::Group
|
||||||
|
{
|
||||||
|
Vector2dStatTesterStats(
|
||||||
|
statistics::Group *parent,
|
||||||
|
const Vector2dStatTesterParams ¶ms
|
||||||
|
);
|
||||||
|
statistics::Vector2d vector2d;
|
||||||
|
} stats;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
} // namespace gem5
|
} // namespace gem5
|
||||||
|
|
||||||
#endif // __STAT_TESTER_HH__
|
#endif // __STAT_TESTER_HH__
|
||||||
|
|||||||
172
tests/gem5/stats/configs/pystat_vector2d_check.py
Normal file
172
tests/gem5/stats/configs/pystat_vector2d_check.py
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
# Copyright (c) 2024 The Regents of the University of California
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are
|
||||||
|
# met: redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer;
|
||||||
|
# redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution;
|
||||||
|
# neither the name of the copyright holders nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import m5
|
||||||
|
from m5.objects import (
|
||||||
|
Root,
|
||||||
|
Vector2dStatTester,
|
||||||
|
)
|
||||||
|
from m5.stats.gem5stats import get_simstat
|
||||||
|
|
||||||
|
"""This script is used for checking that Vector2d statistics set in the
|
||||||
|
simulation are correctly parsed through to the python Pystats.
|
||||||
|
"""
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Tests the output of a Vector2D Pystat."
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"value",
|
||||||
|
help="Comma delimited list representing the 2d vector in a flattened "
|
||||||
|
"state.",
|
||||||
|
type=lambda s: [float(item) for item in s.split(",")],
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"num_vectors",
|
||||||
|
help="The number of vectors in the vector of vectors",
|
||||||
|
type=int,
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--name",
|
||||||
|
type=str,
|
||||||
|
default="vector2d",
|
||||||
|
required=False,
|
||||||
|
help="Name of the vector statistic.",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--description",
|
||||||
|
type=str,
|
||||||
|
default="",
|
||||||
|
required=False,
|
||||||
|
help="Description of the vector statistic.",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--subnames",
|
||||||
|
help="delimited list representing the vector subnames",
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--subdescs",
|
||||||
|
help="delimited list representing the vector subdescs",
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"--ysubnames",
|
||||||
|
help="delimited list representing the vector ysubnames",
|
||||||
|
type=str,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
expected_output = None
|
||||||
|
stat_tester = None
|
||||||
|
|
||||||
|
stat_tester = Vector2dStatTester()
|
||||||
|
stat_tester.name = args.name
|
||||||
|
stat_tester.description = args.description
|
||||||
|
stat_tester.subnames = []
|
||||||
|
if args.subnames:
|
||||||
|
stat_tester.subnames = [str(item) for item in args.subnames.split(",")]
|
||||||
|
|
||||||
|
stat_tester.subdescs = []
|
||||||
|
if args.subdescs:
|
||||||
|
stat_tester.subdescs = [str(item) for item in args.subdescs.split(",")]
|
||||||
|
|
||||||
|
stat_tester.ysubnames = []
|
||||||
|
if args.ysubnames:
|
||||||
|
stat_tester.ysubnames = [str(item) for item in args.ysubnames.split(",")]
|
||||||
|
|
||||||
|
assert (
|
||||||
|
len(args.value) % args.num_vectors == 0
|
||||||
|
), "The number of values is not divisable by the number of vectors."
|
||||||
|
|
||||||
|
stat_tester.x_size = args.num_vectors
|
||||||
|
stat_tester.y_size = len(args.value) / args.num_vectors
|
||||||
|
stat_tester.values = args.value
|
||||||
|
|
||||||
|
vectors = {} # The representation we expect output.
|
||||||
|
for x in range(args.num_vectors):
|
||||||
|
x_index = x if x not in stat_tester.subnames else stat_tester.subnames[x]
|
||||||
|
|
||||||
|
vector = {}
|
||||||
|
for y in range(stat_tester.y_size):
|
||||||
|
to_add = args.value[
|
||||||
|
int(y + (x * (len(args.value) / args.num_vectors)))
|
||||||
|
]
|
||||||
|
vector[y] = {
|
||||||
|
"value": to_add,
|
||||||
|
"type": "Scalar",
|
||||||
|
"unit": "Count",
|
||||||
|
"description": None,
|
||||||
|
"datatype": "f64",
|
||||||
|
}
|
||||||
|
|
||||||
|
vectors[x_index] = {
|
||||||
|
"type": "Vector",
|
||||||
|
"description": stat_tester.subdescs[x]
|
||||||
|
if x in stat_tester.subdescs
|
||||||
|
else stat_tester.description,
|
||||||
|
"value": vector,
|
||||||
|
}
|
||||||
|
|
||||||
|
expected_output = {
|
||||||
|
"type": "Group",
|
||||||
|
"time_conversion": None,
|
||||||
|
args.name: {
|
||||||
|
"type": "Vector2d",
|
||||||
|
"value": vectors,
|
||||||
|
"description": args.description,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
root = Root(full_system=False, system=stat_tester)
|
||||||
|
|
||||||
|
m5.instantiate()
|
||||||
|
m5.simulate()
|
||||||
|
|
||||||
|
simstats = get_simstat(stat_tester)
|
||||||
|
output = simstats.to_json()["system"]
|
||||||
|
|
||||||
|
if output != expected_output:
|
||||||
|
print("Output statistics do not match expected:", file=sys.stderr)
|
||||||
|
print("", file=sys.stderr)
|
||||||
|
print("Expected:", file=sys.stderr)
|
||||||
|
print(expected_output, file=sys.stderr)
|
||||||
|
print("", file=sys.stderr)
|
||||||
|
print("Actual:", file=sys.stderr)
|
||||||
|
print(output, file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
@@ -182,3 +182,33 @@ gem5_verify_config(
|
|||||||
valid_isas=(constants.all_compiled_tag,),
|
valid_isas=(constants.all_compiled_tag,),
|
||||||
length=constants.quick_tag,
|
length=constants.quick_tag,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
gem5_verify_config(
|
||||||
|
name="pystat_vector2d_test",
|
||||||
|
fixtures=(),
|
||||||
|
verifiers=[],
|
||||||
|
config=joinpath(
|
||||||
|
config.base_dir,
|
||||||
|
"tests",
|
||||||
|
"gem5",
|
||||||
|
"stats",
|
||||||
|
"configs",
|
||||||
|
"pystat_vector2d_check.py",
|
||||||
|
),
|
||||||
|
config_args=[
|
||||||
|
"2.4,4.3,3.7,-1.4,-2,4,0,0",
|
||||||
|
2,
|
||||||
|
"--name",
|
||||||
|
"vector2d_stat",
|
||||||
|
"--description",
|
||||||
|
"A 2d vector statistic with",
|
||||||
|
"--subnames",
|
||||||
|
"decimals,integers",
|
||||||
|
"--subdescs",
|
||||||
|
"A random collection of decimals,A random collection of integers",
|
||||||
|
"--ysubnames",
|
||||||
|
"first,second,third,fourth",
|
||||||
|
],
|
||||||
|
valid_isas=(constants.all_compiled_tag,),
|
||||||
|
length=constants.quick_tag,
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user