It seems that Unigram is a class type? and also it isn't final?
To get the best possible performance out of swift the first step is what you seem to be doing already: measuring with tooling like Instruments. The next steps are to migrate types to where Swift shines: use structures where possible/makes-sense, if not a structure then make sure classes are final, make sure types that are high frequency hits are marked for inlining via @inlinable and @usableFromInline or even @frozen etc, and perhaps the biggest impact is make sure to only measure in release mode with optimizations enabled. Dictionary and OrderdDictionary are quite fast but if you have other things preventing them from being as fast as they could it will hinder your overall performance.
Hopefully that is helpful hints on where to start tackling the issue.
The thing that pops out on that profile to my eye is that you're hitting slowCompare when comparing Strings. I don't off the top of my head remember what the fast and slow paths in that method are, but that would be the place I started looking.
Perhaps your C++ code is not doing unicode-correct comparison, for example, in which case maybe you should store StringUTF8Views instead of Strings? Or perhaps your Strings are accidentally wrapped NSStrings rather than native ones?
Thanks for your suggestion. Using "struct" towards Unigram, Bigram, and the KeyValuePair (built-in in Megrez) made the unit test of Megrez much faster and responsive than before. Marking these 3 structs (previously "classes") as @frozen for now since I can feel further speed boost (not instrument-measured yet.) and I don't see compiling problems with this tag.
Case solved by only using Unigram as the format to store data in the language model.
I don't know why Lukhnos uses a new type to store the data in C++, but I don't need to do the same in Swift.
Type conversion and data-mapping across types could take time, plus unnecessary for loops.
Thanks to Mr. Hausler's idea of frozing structs. This new "unigramsFor" now responds blazing fast" (no stucking anymore):
open func unigramsFor(key: String) -> [Megrez.Unigram] {
if let matched = keyValueRateMap[key] {
return matched
} else {
return [Megrez.Unigram]()
}
}