summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKellen Renshaw <kellen.renshaw@canonical.com>2021-10-27 22:32:20 +0000
committerKellen Renshaw <kellen.renshaw@canonical.com>2022-01-07 20:39:08 +0000
commitd9aa77225d5813dd1dd9adec16b22064d7b999aa (patch)
treefec6dc6ad09727b5a8efdd88b6b3dc708160e1c0
parent819ecf7b8160e4eac6131e710871397233f8a8b6 (diff)
downloadceph-d9aa77225d5813dd1dd9adec16b22064d7b999aa.tar.gz
test/allocator_replay_test: Add replay_alloc option
New replay_alloc option added to ceph_test_alloc_replay binary that permits the loading of a dump produced by "ceph daemon osd.<id> bluestore allocator dump block" and replaying a list of allocation requests against the loaded allocator state an arbitrary number of times (default, 100). Once the allocator dump is loaded, the fragmentation state and free space information are printed. Then the list of allocation requests is replayed against that state. Output consists of the time in ns that the allocator took to return the requested allocation, along with the request. If an allocation request fails or the list of allocation requests is completed, the error info, if any, and the fragementation and free space information is printed. The list of allocations is formatted as a file with one allocation request per line, with space separated values for "want", "unit", "max", and "hint". Values can be any integer format supported by std::scanf()'s %u formatter. The allocation request line format: <want> <unit> [max] [hint] Example request lines: 0x4000 0x4000 0x4000 0x0 0x18000 0x4000 0x18000 0x0 The "want" and "unit" values are required. Optional request values are 0 if not present in the request. Fixes: https://tracker.ceph.com/issues/53571 Signed-off-by: Kellen Renshaw <kellen.renshaw@canonical.com>
-rw-r--r--src/test/objectstore/allocator_replay_test.cc104
1 files changed, 102 insertions, 2 deletions
diff --git a/src/test/objectstore/allocator_replay_test.cc b/src/test/objectstore/allocator_replay_test.cc
index 811cc92cdea..401eaa42703 100644
--- a/src/test/objectstore/allocator_replay_test.cc
+++ b/src/test/objectstore/allocator_replay_test.cc
@@ -18,8 +18,14 @@
using namespace std;
void usage(const string &name) {
- cerr << "Usage: " << name << " <log_to_replay> <raw_duplicate|free_dump|try_alloc count want alloc_unit>"
- << std::endl;
+ cerr << "Usage: " << name << " <log_to_replay> <raw_duplicate|free_dump|try_alloc count want alloc_unit|replay_alloc alloc_list_file>" << std::endl;
+}
+
+void usage_replay_alloc(const string &name) {
+ cerr << "Detailed replay_alloc usage: " << name << " <allocator_dump_JSON> replay_alloc <alloc_list_file> [number of replays]" << std::endl;
+ cerr << "The number of replays defaults to 1." << std::endl;
+ cerr << "The \"alloc_list_file\" parameter should be a file with allocation requests, one per line." << std::endl;
+ cerr << "Allocation request format (space separated, optional parameters are 0 if not given): want unit [max] [hint]" << std::endl;
}
int replay_and_check_for_duplicate(char* fname)
@@ -389,5 +395,99 @@ int main(int argc, char **argv)
<< ", unit:" << alloc_unit << std::endl;
return 0;
});
+ } else if (strcmp(argv[2], "replay_alloc") == 0) {
+ if (argc < 4) {
+ std::cerr << "Error: insufficient arguments for \"replay_alloc\" option."
+ << std::endl;
+ usage_replay_alloc(argv[0]);
+ return 1;
+ }
+ return replay_free_dump_and_apply(argv[1],
+ [&](Allocator *a, const string &aname) {
+ ceph_assert(a);
+ std::cout << "Fragmentation:" << a->get_fragmentation()
+ << std::endl;
+ std::cout << "Fragmentation score:" << a->get_fragmentation_score()
+ << std::endl;
+ std::cout << "Free:" << std::hex << a->get_free() << std::dec
+ << std::endl;
+ {
+ /* replay a set of allocation requests */
+ char s[4096];
+
+ FILE *f_alloc_list = fopen(argv[3], "r");
+ if (!f_alloc_list) {
+ std::cerr << "error: unable to open " << argv[3] << std::endl;
+ return -1;
+ }
+
+ /* Replay user specified number of times to simulate extended activity
+ * Defaults to 1 replay.
+ */
+ auto replay_count = 1;
+ if (argc == 5) {
+ replay_count = atoi(argv[4]);
+ }
+
+ for (auto i = 0; i < replay_count; ++i) {
+ while (fgets(s, sizeof(s), f_alloc_list) != nullptr) {
+ /* parse allocation request */
+ uint64_t want = 0, unit = 0, max = 0, hint = 0;
+
+ if (std::sscanf(s, "%ji %ji %ji %ji", &want, &unit, &max, &hint) < 2)
+ {
+ cerr << "Error: malformed allocation request:" << std::endl;
+ cerr << s << std::endl;
+ /* do not attempt to allocate a malformed request */
+ continue;
+ }
+
+ /* timestamp for allocation start */
+ auto t0 = ceph::mono_clock::now();
+
+ /* allocate */
+ PExtentVector extents;
+ auto r = a->allocate(want, unit, max, hint, &extents);
+ if (r < 0) {
+ /* blind replays of allocations may run out of space, provide info for easy confirmation */
+ std::cerr << "Error: allocation failure code: " << r
+ << " requested want/unit/max/hint (hex): " << std::hex
+ << want << "/" << unit << "/" << max << "/" << hint
+ << std::dec << std::endl;
+ std::cerr << "Fragmentation:" << a->get_fragmentation()
+ << std::endl;
+ std::cerr << "Fragmentation score:" << a->get_fragmentation_score()
+ << std::endl;
+ std::cerr << "Free:" << std::hex << a->get_free() << std::dec
+ << std::endl;
+ /* return 0 if the allocator ran out of space */
+ if (r == -ENOSPC) {
+ return 0;
+ }
+ return -1;
+ }
+
+ /* Outputs the allocation's duration in nanoseconds and the allocation request parameters */
+ std::cout << "Duration (ns): " << (ceph::mono_clock::now() - t0).count()
+ << " want/unit/max/hint (hex): " << std::hex
+ << want << "/" << unit << "/" << max << "/" << hint
+ << std::dec << std::endl;
+
+ /* Do not release. */
+ //alloc->release(extents);
+ extents.clear();
+ }
+ fseek(f_alloc_list, 0, SEEK_SET);
+ }
+ fclose(f_alloc_list);
+ std::cout << "Fragmentation:" << a->get_fragmentation()
+ << std::endl;
+ std::cout << "Fragmentation score:" << a->get_fragmentation_score()
+ << std::endl;
+ std::cout << "Free:" << std::hex << a->get_free() << std::dec
+ << std::endl;
+ }
+ return 0;
+ });
}
}