Skip to content

Commit 52bce48

Browse files
committed
Use a vector instead of a map to store fingerprints and reserve its space.
Use a vector so the map doesn't have to be converted to a vector for each iteration (since __gnu_parallel::for_each doesn't work on non-random-access iterators). Before (gcc7): around 2.9~3 seconds per iteration (30000 songs/second) After (gcc8): around 2.4 seconds per iteration (36600 songs/second)
1 parent 046da19 commit 52bce48

2 files changed

Lines changed: 38 additions & 9 deletions

File tree

bard/bard.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,7 @@ def findAudioDuplicates2(self, from_song_id=None):
898898
speeds = []
899899
songs_processed = 0
900900
totalSongsCount = MusicDatabase.getSongsCount()
901+
fpm.setExpectedSize(totalSongsCount+5)
901902
sql = ('SELECT id, fingerprint, sha256sum, audio_sha256sum, path, '
902903
'completeness FROM fingerprints, songs, checksums, '
903904
'properties where songs.id=fingerprints.song_id and '

bard/bard_ext.cpp

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ class FingerprintManager
5757
void setMaxOffset(int maxoffset);
5858
int maxOffset() const;
5959

60+
void setExpectedSize(int expectedSize);
61+
int size() const;
62+
6063
void addSong(long songID, boost::python::list &fingerprint);
6164
boost::python::list addSongAndCompare(long songID, boost::python::list &fingerprint, double cancelThreshold=0.55);
6265
std::pair<int, double> compareSongs(long songID1, long songID2, double cancelThreshold=0.55);
@@ -65,9 +68,12 @@ class FingerprintManager
6568
std::pair<int, double> compareChromaprintFingerprintsAndOffset(const std::vector<int> &fp1, const std::vector<int> &fp2, double cancelThreshold) const;
6669
boost::python::list compareChromaprintFingerprintsAndOffsetVerbose(std::vector<int> fp1, std::vector<int> fp2) const;
6770

71+
protected:
72+
std::vector<int> songFingerprint(int songID);
73+
6874
private:
6975
int m_maxoffset;
70-
std::map<int, std::vector<int>> m_fingerprints;
76+
std::vector<std::pair<int,std::vector<int>>> m_fingerprints;
7177
};
7278

7379
FingerprintManager::FingerprintManager(): m_maxoffset(50)
@@ -85,11 +91,33 @@ int FingerprintManager::maxOffset() const
8591
return m_maxoffset;
8692
}
8793

94+
void FingerprintManager::setExpectedSize(int expectedSize)
95+
{
96+
m_fingerprints.reserve(expectedSize);
97+
}
98+
99+
int FingerprintManager::size() const
100+
{
101+
return m_fingerprints.size();
102+
}
103+
104+
std::vector<int> FingerprintManager::songFingerprint(int songID)
105+
{
106+
auto it = std::lower_bound( m_fingerprints.begin(), m_fingerprints.end(), songID,
107+
[](auto x, auto y)
108+
{ return x.first < y;
109+
});
110+
if (it == m_fingerprints.end())
111+
return std::vector<int>();
112+
else
113+
return it->second;
114+
}
115+
88116
void FingerprintManager::addSong(long songID, boost::python::list &fingerprint)
89117
{
90118
auto v = to_std_vector<int>(fingerprint);
91119
v.insert(v.begin(), m_maxoffset, 0);
92-
m_fingerprints[songID]=v;
120+
m_fingerprints.emplace_back(std::make_pair(songID, v));
93121
}
94122

95123
boost::python::list FingerprintManager::addSongAndCompare(long songID, boost::python::list &fingerprint, double cancelThreshold)
@@ -99,9 +127,7 @@ boost::python::list FingerprintManager::addSongAndCompare(long songID, boost::py
99127
auto v = to_std_vector<int>(fingerprint);
100128
v.insert(v.begin(), m_maxoffset, 0);
101129

102-
auto vectorizedFP = std::vector<std::pair<int,std::vector<int>>>(m_fingerprints.begin(), m_fingerprints.end());
103-
104-
__gnu_parallel::for_each(vectorizedFP.begin(), vectorizedFP.end(),
130+
__gnu_parallel::for_each(m_fingerprints.begin(), m_fingerprints.end(),
105131
[&](const auto &itSong)
106132
{
107133
auto & [itSongID, itFingerprint] = itSong;
@@ -113,7 +139,7 @@ boost::python::list FingerprintManager::addSongAndCompare(long songID, boost::py
113139
result_mutex.unlock();
114140
}
115141
}, __gnu_parallel::parallel_balanced);
116-
m_fingerprints[songID]=v;
142+
m_fingerprints.emplace_back(std::make_pair(songID, v));
117143
return result;
118144
}
119145

@@ -238,12 +264,12 @@ boost::python::list FingerprintManager::compareChromaprintFingerprintsAndOffsetV
238264

239265
std::pair<int, double> FingerprintManager::compareSongs(long songID1, long songID2, double cancelThreshold)
240266
{
241-
return compareChromaprintFingerprintsAndOffset(m_fingerprints[songID1], m_fingerprints[songID2], cancelThreshold);
267+
return compareChromaprintFingerprintsAndOffset(songFingerprint(songID1), songFingerprint(songID2), cancelThreshold);
242268
}
243269

244270
boost::python::list FingerprintManager::compareSongsVerbose(long songID1, long songID2)
245271
{
246-
return compareChromaprintFingerprintsAndOffsetVerbose(m_fingerprints[songID1], m_fingerprints[songID2]);
272+
return compareChromaprintFingerprintsAndOffsetVerbose(songFingerprint(songID1), songFingerprint(songID2));
247273
}
248274

249275
BOOST_PYTHON_MODULE(bard_ext)
@@ -257,7 +283,9 @@ BOOST_PYTHON_MODULE(bard_ext)
257283
.def("compareSongs", &FingerprintManager::compareSongs)
258284
.def("compareSongsVerbose", &FingerprintManager::compareSongsVerbose)
259285
.def("setMaxOffset", &FingerprintManager::setMaxOffset)
260-
.def("maxOffset", &FingerprintManager::maxOffset);
286+
.def("maxOffset", &FingerprintManager::maxOffset)
287+
.def("setExpectedSize", &FingerprintManager::setExpectedSize)
288+
.def("size", &FingerprintManager::size);
261289
}
262290

263291

0 commit comments

Comments
 (0)