| // Copyright (C) 2020 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| #include "stackify_start_stop.h" |
| |
| #include "hash_table.h" |
| #include "npyiter.h" |
| #include "pyobj.h" |
| #include "pyparsetuple.h" |
| #include "pyparsetuplenpy.h" |
| #include "result_buffer.h" |
| #include "span.h" |
| |
| namespace dctv { |
| |
| // TODO(dancol): XXX: remove these typedefs |
| |
| using Token = int64_t; |
| using StackId = Partition; |
| using TaskId = Partition; |
| using Depth = int64_t; |
| |
| static |
| unique_pyref |
| stackify_start_stop(PyObject*, PyObject* py_args) |
| { |
| auto args = PARSEPYARGS_V( |
| (pyref, chunk_iter) |
| (pyref, history_cb) |
| (pyref, stack_content_cb) |
| (QueryExecution*, qe) |
| )(py_args); |
| |
| using Stack = Vector<Token>; |
| struct StackHasher final { |
| using result_type = size_t; |
| using argument_type = Stack; |
| size_t operator()(const Stack& stack) const noexcept { |
| HashSponge sponge; |
| for (const auto& value : stack) |
| sponge.absorb(value); |
| return sponge.squeeze(); |
| } |
| }; |
| |
| StackId next_stack_id = 0; |
| HashTable<Stack, StackId, StackHasher> known_stacks; |
| HashTable<TaskId, Stack> current_stack_by_task; |
| |
| auto stack_history = |
| ResultBuffer<TimeStamp, TaskId, StackId>( |
| addref(args.history_cb), |
| args.qe); |
| auto stack_content = |
| ResultBuffer<TaskId, Depth, Token>( |
| addref(args.stack_content_cb), |
| args.qe); |
| |
| auto intern_stack = [&](const Stack& stack) -> StackId { |
| StackId stack_id; |
| auto it = known_stacks.find(stack); |
| if (it == known_stacks.end()) { |
| stack_id = next_stack_id++; |
| known_stacks[stack] = stack_id; |
| int depth = 0; |
| for (const auto& token : stack) |
| stack_content.add(stack_id, depth++, token); |
| } else { |
| stack_id = it->second; |
| } |
| return stack_id; |
| }; |
| |
| intern_stack(Stack()); // For side effect |
| for (PythonChunkIterator<TaskId, TimeStamp, Token, bool> |
| iter(addref(args.chunk_iter)); |
| !iter.is_at_eof(); |
| iter.advance()) { |
| auto [task_id, ts, token, end_flag] = iter.get(); |
| Stack& stack = current_stack_by_task[task_id]; |
| if (end_flag) { |
| if (!stack.empty()) |
| stack.pop_back(); |
| } else { |
| stack.push_back(token); |
| } |
| StackId stack_id = intern_stack(stack); |
| stack_history.add(ts, task_id, stack_id); |
| } |
| |
| stack_content.flush(); |
| stack_history.flush(); |
| return addref(Py_None); |
| } |
| |
| |
| |
| static PyMethodDef functions[] = { |
| make_methoddef("stackify_start_stop_qqqq", |
| wraperr<stackify_start_stop>(), |
| METH_VARARGS, |
| "Transform start and stop history into interned stacks"), |
| { 0 } |
| }; |
| |
| void |
| init_stackify_start_stop(pyref m) |
| { |
| register_functions(m, functions); |
| } |
| |
| |
| } // namespace dctv |