mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 15:28:19 +00:00
ifcparse: parse instances in parallel
The DATA section is split into one chunk per thread and each worker runs the same per-instance reader as the serial parse over its own reader, storage, inverse records and simple-type list; the results are merged in file order, so instance order, GlobalId precedence and inverse records are identical to the serial parse. Reference resolution then splits over the same threads: each instance's slots are its own and the name table is complete and read-only by then. The default is one thread per core, capped at 16; IFCOPENSHELL_PARSE_THREADS or file::parse_threads() overrides it, and 1 parses as before. The instance headers are read by one loop, for_each_instance_header(), shared with the lazy index: it looks declarations up once per keyword, passes over a bypassed instance's attribute list and slides past a stray keyword the way the serial reader does (the lazy index therefore no longer falls back on one). Finding the split points is the one place that looks at raw bytes rather than tokens, because tokenizing the file serially first would leave nothing to parallelise. It applies three rules: a string starts and ends at a quote and cannot span a line, and a comment runs from /* to */; a split is a '#' that starts a line outside both. Getting a string's end wrong can only lose a candidate, never accept a wrong one, since no string contains a newline. The equality test puts a comment holding a fake instance and a string holding "/*" between the chunks. file_reader gains for_each_span(), which hands a byte range out span by span (one span for a buffer, one per page for the paged reader), and reopen(), a reader over the same file for another thread. TXG 58 MB / 210_King 147 MB / OKgate22 231 MB, 12 threads: 0.44 / 1.24 / 2.01 s against 1.07 / 2.75 / 5.12 s on one thread; memory after the parse within 1–4%, peak +5–4%. This commit was written by an AI coding tool and has not been verified by a human. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013wcN7XquTfUi4vsKQ4KchL
This commit is contained in:
@@ -454,6 +454,19 @@ namespace ifcopenshell {
|
||||
}
|
||||
|
||||
// Finalizes bulk loading. Subsequent add() calls go to the delta.
|
||||
// Takes over another index's records, e.g. one built by a parser
|
||||
// worker. Both must still be in bulk-load mode (no delta).
|
||||
void append(inverse_index&& other) {
|
||||
if (base_.empty()) {
|
||||
base_ = std::move(other.base_);
|
||||
} else {
|
||||
base_.insert(base_.end(), other.base_.begin(), other.base_.end());
|
||||
}
|
||||
sorted_ = false;
|
||||
other.clear();
|
||||
invalidate_materialized();
|
||||
}
|
||||
|
||||
void sort() const {
|
||||
if (!sorted_) {
|
||||
std::sort(base_.begin(), base_.end(), record_less);
|
||||
@@ -602,6 +615,18 @@ namespace ifcopenshell {
|
||||
std::vector<unsigned> lazy_bypassed_;
|
||||
std::vector<std::pair<uint32_t, uint64_t>> lazy_offsets_;
|
||||
bool index_lazily(const std::string& path, const ifcopenshell::schema_definition*& schema, unsigned int& max_id, const std::set<std::string>& types_to_bypass);
|
||||
|
||||
// Number of threads read_from_stream() may use to parse instances;
|
||||
// 1 parses serially. Set by file::initialize().
|
||||
unsigned parse_threads = 1;
|
||||
|
||||
// Parses the DATA section with `threads` workers, each running the
|
||||
// same per-instance reader over its own chunk, and merges the
|
||||
// results in file order. Returns false, without side effects, when
|
||||
// the file is too small to be worth it or no split points were
|
||||
// found; the caller then parses serially.
|
||||
template <typename Reader>
|
||||
bool read_instances_parallel(Reader* stream, const ifcopenshell::schema_definition* schema, const std::set<std::string>& types_to_bypass, unsigned int& max_id, unsigned threads, std::vector<unsigned>& bypassed, unresolved_references& mixed_references, std::vector<shared_pointer_type>& instances);
|
||||
void materialize(instance_data* data);
|
||||
|
||||
typedef std::map<const ifcopenshell::declaration*, std::vector<express::base>> entities_by_type;
|
||||
|
||||
Reference in New Issue
Block a user