Skip to content

Commit a039343

Browse files
authored
Merge pull request #44 from atom-ide-community/performance
2 parents a2bb051 + 513e9d3 commit a039343

File tree

7 files changed

+134
-106
lines changed

7 files changed

+134
-106
lines changed

binding.gyp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
'configurations': {
1212
# Release Settings
1313
'Release': {
14-
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ],
15-
"cflags": [ "-fno-exceptions", "-O3" ],
16-
"cflags_cc": [ "-fno-exceptions", "-O3", "-std=c++2a" ],
14+
'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS', 'NDEBUG' ],
15+
"cflags": [ "-fno-exceptions", "-Ofast" ],
16+
"cflags_cc": [ "-fno-exceptions", "-Ofast", "-std=c++2a" ],
1717
"xcode_settings": {
1818
'GCC_OPTIMIZATION_LEVEL': '3', # stop gyp from defaulting to -Os
1919
"CLANG_CXX_LIBRARY": "libc++",
@@ -28,6 +28,11 @@
2828
"AdditionalOptions": [
2929
# C++ standard
3030
"/std:c++latest",
31+
"/O2", # optimizations
32+
"/Ob3", # agressive inline
33+
"/Oi", # intrinsic functions
34+
"/Ot", # favor speed
35+
"/DNDEBUG" # turn off asserts
3136
],
3237
'EnableFunctionLevelLinking': 'true',
3338
'EnableIntrinsicFunctions': 'true',
@@ -41,7 +46,7 @@
4146
},
4247
# Debug Settings
4348
'Debug': {
44-
'defines': [ 'DEBUG', 'NAPI_CPP_EXCEPTIONS', 'ENABLE_DEBUG' ],
49+
'defines': [ 'DEBUG', 'NAPI_CPP_EXCEPTIONS' ],
4550
'cflags': [ '-g', '-O0' ],
4651
"cflags_cc": [
4752
'-fexceptions', # enable exceptions

src/common.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <cstring>
1010
#include <iostream>
1111
#include <utility>
12+
#include <cassert>
1213

1314
#include <napi.h>
1415

@@ -17,6 +18,7 @@ using namespace std;
1718
constexpr size_t kMaxThreads = 16;
1819

1920
#ifdef ENABLE_DEBUG
21+
// TODO does not work anymore because we added explicit to constructors
2022
// Safe string class that logs error when index is accessed outside the string.
2123
class SafeString : public std::string {
2224
public:
@@ -75,9 +77,9 @@ struct Options {
7577
struct AcronymResult {
7678
Score score;
7779
float pos;
78-
int count;
80+
size_t count;
7981

80-
explicit AcronymResult(Score s, float p, int c) noexcept : score(s), pos(p), count(c) {}
82+
explicit AcronymResult(Score s, float p, size_t c) noexcept : score(s), pos(p), count(c) {}
8183
};
8284

8385
extern Element ToLower(const Element &s);

src/filter.cc

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ void filter_internal(const std::vector<CandidateString> &candidates,
2424
const Options &options,
2525
size_t max_results,
2626
CandidateScorePriorityQueue &results) {
27+
const auto scoreProvider = options.usePathScoring ? path_scorer_score : scorer_score;
2728
for (size_t i = 0, len = candidates.size(); i < len; i++) {
2829
const auto &candidate = candidates[i];
2930
if (candidate.empty()) {
3031
continue;
3132
}
32-
const auto scoreProvider = options.usePathScoring ? path_scorer_score : scorer_score;
3333
auto score = scoreProvider(candidate, query, options);
3434
if (score > 0) {
3535
results.emplace(score, start_index + i);
@@ -40,20 +40,14 @@ void filter_internal(const std::vector<CandidateString> &candidates,
4040
}
4141
}
4242

43-
void thread_worker_filter(const std::vector<CandidateString> &candidates,
44-
size_t start_index,
45-
const Element &query,
46-
const Options &options,
47-
size_t max_results,
48-
CandidateScorePriorityQueue &results) {
49-
filter_internal(candidates, start_index, query, options, max_results, results);
50-
}
51-
5243
std::vector<CandidateIndex> sort_priority_queue(CandidateScorePriorityQueue &&candidates) {
5344
vector<CandidateScore> sorted;
5445
std::vector<CandidateIndex> ret;
55-
sorted.reserve(candidates.size());
56-
ret.reserve(candidates.size());
46+
47+
const auto initial_candidates_size = candidates.size();
48+
sorted.reserve(initial_candidates_size);
49+
ret.reserve(initial_candidates_size);
50+
5751
while (!candidates.empty()) {
5852
sorted.emplace_back(candidates.top());
5953
candidates.pop();
@@ -66,6 +60,10 @@ std::vector<CandidateIndex> sort_priority_queue(CandidateScorePriorityQueue &&ca
6660
}
6761

6862
std::vector<CandidateIndex> filter(const vector<std::vector<CandidateString>> &candidates, const Element &query, const Options &options) {
63+
const auto candidates_size = candidates.size();
64+
65+
assert(1 <= candidates_size);// TODO handled outside
66+
6967
CandidateScorePriorityQueue top_k;
7068
auto max_results = options.max_results;
7169
if (max_results == 0u) {
@@ -74,17 +72,24 @@ std::vector<CandidateIndex> filter(const vector<std::vector<CandidateString>> &c
7472

7573
// Split the dataset and pass down to multiple threads.
7674
vector<thread> threads;
77-
vector<CandidateScorePriorityQueue> results(candidates.size());
75+
threads.reserve(candidates.size());
76+
77+
auto results = vector<CandidateScorePriorityQueue>(candidates.size());
78+
7879
size_t start_index = 0;
79-
for (size_t i = 1, len = candidates.size(); i < len; i++) {
80-
start_index += candidates[i - 1].size();
81-
threads.emplace_back(thread_worker_filter, ref(candidates[i]), start_index, ref(query), ref(options), max_results, ref(results[i]));
80+
for (size_t i = 1; i < candidates_size; i++) {
81+
assert(1 < i && i < candidates.size() && i < results.size());
82+
start_index += candidates[i - 1].size();//inbounds
83+
threads.emplace_back(filter_internal, ref(candidates[i]), start_index, ref(query), ref(options), max_results, ref(results[i]));// inbounds
8284
}
85+
86+
assert(threads.size() == candidates.size() && results.size() == candidates.size());
87+
8388
// Do the work for first thread.
84-
filter_internal(candidates[0], 0, query, options, max_results, top_k);
85-
// Wait for threads to complete and merge the restuls.
86-
for (size_t i = 1, len = candidates.size(); i < len; i++) {
87-
threads[i - 1].join();
89+
filter_internal(candidates[0], 0, query, options, max_results, top_k);//inbounds (candidate_size >= 1)
90+
// Wait for threads to complete and merge the results.
91+
for (size_t i = 1; i < candidates_size; i++) {
92+
threads[i - 1].join();//inbounds
8893
while (!results[i].empty()) {
8994
top_k.emplace(results[i].top());
9095
results[i].pop();

src/matcher.cc

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,16 @@ std::vector<size_t> computeMatch(const CandidateString &subject, const Candidate
2020
const auto &query_lw = preparedQuery.query_lw;
2121

2222
// TODO making these two auto breaks the code. There are a lot of narrowing conversions in this file
23-
const int m = subject.size();
24-
const int n = query.size();
23+
const int subject_size = subject.size();
24+
const int query_size = query.size();
2525

2626
// this is like the consecutive bonus, but for camelCase / snake_case initials
2727
const auto acro = scoreAcronyms(subject, subject_lw, query, query_lw);
2828
const auto acro_score = acro.score;
2929

3030
// Init
31-
vector<Score> score_row(n, 0);
32-
vector<Score> csc_row(n, 0);
31+
vector<Score> score_row(query_size, 0);
32+
vector<Score> csc_row(query_size, 0);
3333

3434
// Directions constants
3535
enum class Direction {
@@ -40,18 +40,18 @@ std::vector<size_t> computeMatch(const CandidateString &subject, const Candidate
4040
};
4141

4242
// Traceback matrix
43-
std::vector<Direction> trace(m * n, Direction::STOP);
43+
std::vector<Direction> trace(subject_size * query_size, Direction::STOP);
4444
auto pos = -1;
4545

4646
auto i = -1;
47-
while (++i < m) {//foreach char is of subject
47+
while (++i < subject_size) {//foreach char is of subject
4848
Score score = 0;
4949
Score score_up = 0;
5050
Score csc_diag = 0;
5151
const auto si_lw = subject_lw[i];
5252

5353
auto j = -1;//0..n-1
54-
while (++j < n) {//foreach char qj of query
54+
while (++j < query_size) {//foreach char qj of query
5555
// reset score
5656
Score csc_score = 0;
5757
Score align = 0;
@@ -100,17 +100,17 @@ std::vector<size_t> computeMatch(const CandidateString &subject, const Candidate
100100
// Go back in the trace matrix
101101
// and collect matches (diagonals)
102102

103-
i = m - 1;
104-
auto j = n - 1;
105-
pos = i * n + j;
103+
i = subject_size - 1;
104+
auto j = query_size - 1;
105+
pos = i * query_size + j;
106106
auto backtrack = true;
107107
std::vector<size_t> matches;
108108

109109
while (backtrack && i >= 0 && j >= 0) {
110110
switch (trace[pos]) {
111111
case Direction::UP:
112112
i--;
113-
pos -= n;
113+
pos -= query_size;
114114
break;
115115
case Direction::LEFT:
116116
j--;
@@ -120,7 +120,7 @@ std::vector<size_t> computeMatch(const CandidateString &subject, const Candidate
120120
matches.emplace_back(i + offset);
121121
j--;
122122
i--;
123-
pos -= n + 1;
123+
pos -= query_size + 1;
124124
break;
125125
default:
126126
backtrack = false;
@@ -172,13 +172,13 @@ std::vector<size_t> basenameMatch(const CandidateString &subject, const Candidat
172172
// (Assume sequences are sorted, matches are sorted by construction.)
173173
//
174174
std::vector<size_t> mergeMatches(const std::vector<size_t> &a, const std::vector<size_t> &b) {
175-
const auto m = a.size();
176-
const auto n = b.size();
175+
const auto a_size = a.size();
176+
const auto b_size = b.size();
177177

178-
if (n == 0) {
178+
if (b_size == 0) {
179179
return a;
180180
}
181-
if (m == 0) {
181+
if (a_size == 0) {
182182
return b;
183183
}
184184

@@ -187,18 +187,18 @@ std::vector<size_t> mergeMatches(const std::vector<size_t> &a, const std::vector
187187
auto bj = b[j];
188188
std::vector<size_t> out;
189189

190-
while (++i < m) {
190+
while (++i < a_size) {
191191
auto ai = a[i];
192192

193-
while (bj <= ai && ++j < n) {
193+
while (bj <= ai && ++j < b_size) {
194194
if (bj < ai) {
195195
out.emplace_back(bj);
196196
}
197197
bj = b[j];
198198
}
199199
out.emplace_back(ai);
200200
}
201-
while (j < n) {
201+
while (j < b_size) {
202202
out.emplace_back(b[j++]);
203203
}
204204
return out;

src/path_scorer.cc

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ Score scorePath(const CandidateString &subject, const CandidateString &subject_l
5151
// {preparedQuery, useExtensionBonus, pathSeparator} = options
5252

5353
// Skip trailing slashes
54-
auto end = subject.size() - 1;
54+
int end = subject.size() - 1;
5555
while (subject[end] == options.pathSeparator) {
5656
end--;
5757
}
@@ -110,17 +110,19 @@ int countDir(const CandidateString &path, const size_t end, const char pathSepar
110110

111111
//skip slash at the start so `foo/bar` and `/foo/bar` have the same depth.
112112
while ((i < end) && (path[i] == pathSeparator)) {//inbounds
113-
// assert(i>=0); fuzz: if end==0, it does not enter while and i==0
113+
assert(0 <= i);// fuzz: if end==0, it does not enter while and i==0
114114
++i;
115115
}
116+
assert(0 <= i);
116117

117118
while (++i < end) {
118-
// assert(i>=0); fuzz: if end==0, it does not enter while and i==0
119+
assert(0 <= i && i < path.size());// fuzz: if end==0, it does not enter while and i==0
119120
if (path[i] == pathSeparator) {//inbounds
120121
count++;//record first slash, but then skip consecutive ones
121122
while ((++i < end) && (path[i] == pathSeparator)) {}
122123
}
123124
}
125+
assert(0 <= i && i < path.size());
124126

125127
return count;
126128
}
@@ -146,31 +148,32 @@ Score getExtensionScore(const CandidateString &candidate, const CandidateString
146148

147149
// Check that (a) extension exist, (b) it is after the start of the basename
148150
int pos = candidate.rfind('.', endPos);
149-
// assert(pos >= 0u);
151+
assert(pos >= 0u);
150152
if (pos <= startPos) {
151153
return 0;// (note that startPos >= -1)
152154
}
153155

154-
int n = ext.size();
156+
int ext_size = ext.size();
155157
auto m = endPos - pos;
156158

157159
// n contain the smallest of both extension length, m the largest.
158-
if (m < n) {
159-
n = m;
160+
if (m < ext_size) {
161+
ext_size = m;
160162
m = ext.size();
161163
}
162164

163165
//place cursor after dot & count number of matching characters in extension
164166
pos++;
165-
// assert(pos >= 1u);
167+
assert(pos >= 1u);
166168
auto matched = 0;
167-
while (matched < n) {
168-
// assert(matched >=0); // fuzz: if n==0, does not enter while and matched==0
169+
while (matched < ext_size) {
170+
assert(matched >= 0);// fuzz: if n==0, does not enter while and matched==0
169171
if (candidate[pos + matched] != ext[matched]) {// TODO candidate upper bound
170172
break;
171173
}
172174
++matched;
173175
}
176+
assert(matched >= 0);
174177

175178
// if nothing found, try deeper for multiple extensions, with some penalty for depth
176179
if (matched == 0u && maxDepth > 0) {

src/query.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ std::set<char> getCharCodes(const Element &str) {
2828

2929
// create map
3030
while (i < len) {
31-
// assert(i>=0); // fuzz: if len==0, does not enter while and i==0
31+
assert(0 <= i && i < str.size());// fuzz: if len==0, does not enter while and i==0
3232
charCodes.insert(str[i]);//inbounds
3333
++i;
3434
}
35+
assert(0 <= i && i < str.size());
3536
return charCodes;
3637
}

0 commit comments

Comments
 (0)