LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
segmentation_impl.cpp
Go to the documentation of this file.
1// Copyright 2002-2023 CEA LIST
2// SPDX-FileCopyrightText: 2023 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
7
9
12 m_decoder(SegmentationClassifier::get_output(), m_char_len),
13 m_current_slot_timepoints(0),
14 m_current_slot_no(-1),
15 m_last_completed_slot(-1),
16 m_buff_set(SegmentationClassifier::get_num_threads() * 2, SegmentationClassifier::get_slot_size() * 4),
17 m_curr_buff_idx(0)
18{}
19
20// SegmentationImpl::SegmentationImpl(
21// const std::vector<ngram_descr_t>& ngram_descr,
22// size_t threads,
23// size_t buffer_size_per_thread
24// )
25// : SegmentationClassifier(
26// ngram_descr.size() * 2, 4, threads * 2, buffer_size_per_thread, threads),
27// m_input_encoder(ngram_descr),
28// m_decoder(SegmentationClassifier::get_output(), m_char_len),
29// m_current_timepoint(SegmentationClassifier::get_start_timepoint()),
30// m_buff_set(SegmentationClassifier::get_num_threads() * 2, SegmentationClassifier::get_slot_size() * 4)
31// {
32// m_char_len.resize(SegmentationClassifier::size());
33// }
34
35void SegmentationImpl::load(const std::string& fn)
36{
37 try
38 {
40 }
41 catch (std::runtime_error& e)
42 {
43 std::cerr << "SegmentationImpl exception while trying to load model " << fn << ":" << std::endl
44 << e.what();
45 throw;
46 }
47 m_input_encoder.init(SegmentationClassifier::get_ngram_descr());
48}
49
50void SegmentationImpl::init(size_t threads, size_t buffer_size_per_thread)
51{
52 SegmentationClassifier::set_dicts(SegmentationClassifier::get_dicts()); // This line needs refactoring.
53 SegmentationClassifier::init(SegmentationClassifier::get_ngram_descr().size(),
54 4, threads * 2 + 2, buffer_size_per_thread, threads);
55 m_char_len.resize(SegmentationClassifier::size());
59}
60
62{
63 // std::cerr << "SegmentationImpl::parse_from_stream" << std::endl;
64 size_t n = 0;
65 bool just_started = true;
66 bool continue_reading = true;
67 uint64_t counter = 0;
68 reset(); // reset internal slots for (re)use
72
73 do
74 {
76
77 while (buff.locked())
78 {
80 }
81
82 int32_t bytes_read = 0;
83 continue_reading = fn(buff.m_data, bytes_read, m_buff_set.max_buff_size());
84 if (0 == bytes_read)
85 {
86 break;
87 }
88 counter += bytes_read;
89 // std::cerr << "SegmentationImpl::parse_from_stream Reading callback: "
90 // << bytes_read << " bytes, continue_reading="
91 // << continue_reading << " counter=" << counter << std::endl;
92 buff.m_char_aligned_data = (const char*)(buff.m_data);
93 buff.m_len = bytes_read;
94 // std::cerr << "SegmentationImpl::parse_from_stream locking (m_buff_set) buff "
95 // << n << std::endl;
96 buff.lock();
97
98 int32_t pos = 0;
99 uint8_t* p = buff.m_data;
100 if (!just_started && 0 == n)
101 {
102 memcpy(p - 8,
105 8);
106 }
107
108 // Warming up is required in the beginning of the text
110 {
111 m_input_encoder.warmup(p, &pos, bytes_read);
112 }
113
114 uint32_t lookbehind = 0;
115 if (0 == pos)
116 {
117 // parse_start can handle bytes remaining from the previous buffer
118 if ((lookbehind = m_input_encoder.parse_start(p, &pos, bytes_read)) > 0)
119 {
120 assert(lookbehind <= 6);
122 }
123 }
124
125 while (pos < bytes_read)
126 {
127 if (m_input_encoder.parse(p, &pos, bytes_read) > 0)
128 {
130 }
131 }
132
133 n = m_buff_set.next(n);
134 just_started = false;
135 } while (continue_reading);
136
137 char final_spaces[] = " ";
138 for (size_t i = 0; i < m_input_encoder.get_lookahead(); i++)
139 {
140 int32_t pos = 0;
141 if (m_input_encoder.parse((uint8_t*)final_spaces, &pos, 1) > 0)
142 {
144 }
145 else
146 {
147 throw std::runtime_error("Something wrong.");
148 }
149 }
150
151 no_more_data();
152
153 for (size_t i = 0; i < m_buff_set.size(); i++)
154 {
155 locked_buffer_t& buff = m_buff_set.get(n);
156
157 while (buff.locked())
158 {
160 }
161
162 // m_buff_set.pretty_print();
163 // SegmentationClassifier::pretty_print();
164
165 n = m_buff_set.next(n);
166 }
167}
168
173
175{
176 for (size_t i = 0; i < m_input_encoder.size(); i++)
177 {
178 SegmentationClassifier::set(timepoint, i, m_input_encoder.get_feat(i));
179 }
180
182}
183
190
191void SegmentationImpl::send_results(int32_t slot_idx)
192{
193 uint64_t from = SegmentationClassifier::get_slot_begin(slot_idx);
194 const uint64_t to = SegmentationClassifier::get_slot_end(slot_idx);
195
196 while (from < to)
197 {
200
201 if (0 == max || nullptr == pch)
202 {
203 break;
204 }
205
206 from = m_decoder.decode(&pch, max, from, to);
207 assert(nullptr != pch);
208
209 for (size_t i = m_curr_buff_idx; i < m_buff_set.size(); i++)
210 {
211 uint8_t* buff_end = m_buff_set.get(i).end();
212 if (nullptr == buff_end)
213 {
214 break;
215 }
216 if ((uint8_t*)pch >= buff_end)
217 {
218 m_buff_set.get(i).unlock();
220 }
221 else
222 {
224 m_curr_buff_idx = i;
225 break;
226 }
227 }
228 }
229
230 assert(from == SegmentationClassifier::get_slot_end(slot_idx));
231
233 m_last_completed_slot = slot_idx;
234}
235
237{
238 int32_t slot_idx = m_last_completed_slot;
239 if (-1 == slot_idx)
240 {
241 slot_idx = 0;
242 }
243 else
244 {
245 slot_idx = SegmentationClassifier::next_slot(slot_idx);
246 }
247
248 // We are in send_next_results
249 // Note, use get_lock_count from
250 // using SegmentationClassifier = RnnSequenceClassifier<eigen_impl::Model, eigen_impl::EmbdVectorizer, uint8_t> ;
251 // This one accesses its m_slots[idx].m_lock_count (std::vector<slot_t> member of RnnSequenceClassifier)
252 // while send_results (above but called below) do m_buff_set.get(i).unlock() (a
253 // locked_buffer_set_t), a member of SegmentationImpl
254 // Should we use SegmentationClassifier::decrement_lock_count in send_results too?
255
256 uint8_t lock_count = SegmentationClassifier::get_lock_count(slot_idx);
257
258 while (lock_count > 1)
259 {
260 // Worker still uses this slot. Waiting...
261 // std::cerr << "SegmentationImpl::send_next_results: waiting for slot " << slot_idx+1
262 // << " (lock_count==" << int(lock_count) << ")\n";
263 // m_buff_set.pretty_print();
264 // SegmentationClassifier::pretty_print();
266 lock_count = SegmentationClassifier::get_lock_count(slot_idx);
267 }
268 if (1 == lock_count)
269 {
270 // Data is ready. We can return it to caller
271 send_results(slot_idx);
272 }
273}
274
276{
278 {
280 // std::cerr << "SegmentationImpl::acquire_slot: got " << m_current_slot_no
281 // << " for timepoint " << m_current_timepoint << std::endl;
283
284 while (lock_count > 1)
285 {
286 // Worker still uses this slot. Waiting...
287 // std::cerr << "SegmentationImpl::acquire_slot, waiting for slot "
288 // << m_current_slot_no << " / " << lock_count << std::endl;
291 }
292 if (1 == lock_count)
293 {
294 // Data is ready. We can return it to caller
296 }
297
300 }
301}
302
304{
305 // std::cerr << "SegmentationImpl::handle_timepoint " << std::endl;
306 acquire_slot();
307
310
313 {
315 // std::cerr << "Slot " << m_current_slot_no << " sent to inference engine (segmentation)" << std::endl;
316 acquire_slot();
317 }
318}
319
328
330{
331 // std::cerr << "SegmentationImpl::finalize" << std::endl;
332
334 m_char_len.resize(SegmentationClassifier::size());
336 // no_more_data();
337 //
338 // for (size_t i = 0; i < m_buff_set.size(); i++)
339 // {
340 // locked_buffer_t& buff = m_buff_set.get(i);
341 // while (buff.locked())
342 // {
343 // send_next_results();
344 // // buff.unlock();
345 // }
346 // }
347 // for (auto i=0; i < SegmentationClassifier::get_num_slots(); i++)
348 // {
349 // while (SegmentationClassifier::get_lock_count(i) > 0)
350 // {
351 // SegmentationClassifier::decrement_lock_count(i);
352 // }
353 // }
354}
355
356} // namespace impl
357 // namespace lemmatization
358 // namespace deeplima
359
Handles multithreading.
int32_t next_slot(uint32_t idx)
uint64_t get_slot_end(uint32_t idx) const
virtual void init(uint32_t max_feat, uint32_t overlap, uint32_t num_slots, uint32_t slot_len, uint32_t num_threads, bool precomputed_input=false)
void load(const std::string &fn)
void increment_timepoint(uint64_t &timepoint)
uint8_t get_lock_count(uint32_t idx) const
void set_slot_end(uint32_t idx, uint64_t slot_end)
void increment_lock_count(uint32_t idx, uint8_t v=1)
void decrement_lock_count(uint32_t idx)
int32_t get_slot_idx(uint64_t timepoint) const
uint64_t get_slot_begin(uint32_t idx) const
void start_job(uint32_t idx, bool no_more_data=false)
virtual void reset()
Need to be called to be able to reuse this classifier on several sequences.
std::function< bool(uint8_t *buffer, int32_t &read, int32_t max) > read_callback_t
void init(const std::vector< ngram_descr_t > &ngram_descr)
uint8_t warmup(const uint8_t *str, int32_t *pos, int32_t len)
uint64_t decode(const char **pch, uint32_t max, uint64_t from, uint64_t to)
void register_handler(const segmentation_callback_t fn)
virtual void parse_from_stream(const read_callback_t fn) override
virtual void register_handler(const segmentation_callback_t fn) override
virtual void finalize() override
Cleanup all remaining locks if any.
void init(size_t threads, size_t buffer_size_per_thread)
virtual void load(const std::string &fn)
std::function< void(const std::vector< token_pos > &tokens, uint32_t len) > segmentation_callback_t
void init(size_t n, uint32_t buffer_size)
uint32_t bytes_available(size_t n)
size_t next(size_t n) const
locked_buffer_t & get(size_t n)
uint32_t max_buff_size() const
size_t size() const
locketd_buffer_t is the character-level buffer shared between the source file reader and the tokenize...
const char * m_char_aligned_data
bool locked() const
void set_read_start(const char *new_start)
uint8_t * end() const