1+ // Copyright (C) 2018-2024 - DevSH GrapMonoAssetManagerAndBuiltinResourceApplicationhics Programming Sp. z O.O.
2+ // This file is part of the "Nabla Engine".
3+ // For conditions of distribution and use, see copyright notice in nabla.h
4+ #include " nbl/application_templates/MonoAssetManagerAndBuiltinResourceApplication.hpp"
5+
6+ #include < future>
7+
8+ #include " nlohmann/json.hpp"
9+ #include " argparse/argparse.hpp"
10+
11+ using json = nlohmann::json;
12+
13+ using namespace nbl ;
14+ using namespace core ;
15+ using namespace hlsl ;
16+ using namespace system ;
17+ using namespace asset ;
18+ using namespace ui ;
19+ using namespace video ;
20+
21+ class ThreadPool
22+ {
23+ using task_t = std::function<void ()>;
24+ public:
25+ ThreadPool (size_t workers = std::thread::hardware_concurrency())
26+ {
27+ for (size_t i = 0 ; i < workers; i++)
28+ {
29+ m_workers.emplace_back ([this ] {
30+ task_t task;
31+
32+ while (1 )
33+ {
34+ {
35+ std::unique_lock<std::mutex> lock (m_queueLock);
36+ m_taskAvailable.wait (lock, [this ] { return !m_tasks.empty () || m_shouldStop; });
37+
38+ if (m_shouldStop && m_tasks.empty ()) {
39+ return ;
40+ }
41+
42+ task = std::move (m_tasks.front ());
43+ m_tasks.pop ();
44+ }
45+
46+ task ();
47+ }
48+ });
49+ }
50+ }
51+
52+ ~ThreadPool ()
53+ {
54+ m_shouldStop = true ;
55+ m_taskAvailable.notify_all ();
56+
57+ for (auto & worker : m_workers)
58+ {
59+ worker.join ();
60+ }
61+ }
62+
63+ void enqueue (task_t task)
64+ {
65+ {
66+ std::lock_guard<std::mutex> lock (m_queueLock);
67+ m_tasks.emplace (std::move (task));
68+ }
69+ m_taskAvailable.notify_one ();
70+ }
71+ private:
72+ std::mutex m_queueLock;
73+ std::condition_variable m_taskAvailable;
74+ std::vector<std::thread> m_workers;
75+ std::queue<task_t > m_tasks;
76+ std::atomic<bool > m_shouldStop = false ;
77+ };
78+
79+ class JpegLoaderApp final : public application_templates::MonoAssetManagerAndBuiltinResourceApplication
80+ {
81+ using clock_t = std::chrono::steady_clock;
82+ using clock_resolution_t = std::chrono::milliseconds;
83+ using base_t = application_templates::MonoAssetManagerAndBuiltinResourceApplication;
84+ public:
85+ using base_t ::base_t ;
86+
87+ inline bool onAppInitialized (smart_refctd_ptr<ISystem>&& system) override
88+ {
89+ argparse::ArgumentParser program (" Color Space" );
90+
91+ program.add_argument <std::string>(" --directory" )
92+ .required ()
93+ .help (" Path to a directory where all JPEG files are stored (not recursive)" );
94+
95+ program.add_argument <std::string>(" --output" )
96+ .default_value (" output.json" )
97+ .help (" Path to the file where the benchmark result will be stored" );
98+
99+ try
100+ {
101+ program.parse_args ({ argv.data (), argv.data () + argv.size () });
102+ }
103+ catch (const std::exception& err)
104+ {
105+ std::cerr << err.what () << std::endl << program; // NOTE: std::cerr because logger isn't initialized yet
106+ return false ;
107+ }
108+
109+ if (!base_t::onAppInitialized (std::move (system)))
110+ return false ;
111+
112+ options.directory = program.get <std::string>(" --directory" );
113+ options.outputFile = program.get <std::string>(" --output" );
114+
115+ // check if directory exists
116+ if (!std::filesystem::exists (options.directory ))
117+ {
118+ logFail (" Provided directory doesn't exist" );
119+ return false ;
120+ }
121+
122+ auto start = clock_t::now ();
123+ std::vector<std::string> files;
124+
125+ {
126+ ThreadPool tp;
127+
128+ constexpr auto cachingFlags = static_cast <IAssetLoader::E_CACHING_FLAGS>(IAssetLoader::ECF_DONT_CACHE_REFERENCES & IAssetLoader::ECF_DONT_CACHE_TOP_LEVEL);
129+ const IAssetLoader::SAssetLoadParams loadParams (0ull , nullptr , cachingFlags, IAssetLoader::ELPF_NONE, m_logger.get ());
130+
131+ for (auto & item : std::filesystem::directory_iterator (options.directory ))
132+ {
133+ auto & path = item.path ();
134+ if (path.has_extension () && path.extension () == " .jpg" )
135+ {
136+ files.emplace_back (std::move (path.generic_string ()));
137+
138+ ISystem::future_t <smart_refctd_ptr<system::IFile>> future;
139+ m_system->createFile (future, path, IFile::ECF_READ | IFile::ECF_MAPPABLE);
140+
141+ if (auto pFile = future.acquire (); pFile && pFile->get ())
142+ {
143+ auto & file = *pFile;
144+ tp.enqueue ([=] {
145+ m_logger->log (" Loading %S" , ILogger::ELL_INFO, path.c_str ());
146+ m_assetMgr->getAsset (file.get (), path.generic_string (), loadParams);
147+ });
148+ }
149+ }
150+ }
151+ }
152+
153+ auto stop = clock_t::now ();
154+ auto time = std::chrono::duration_cast<clock_resolution_t >(stop - start).count ();
155+
156+ m_logger->log (" Process took %llu ms" , ILogger::ELL_INFO, time);
157+
158+ // Dump data to JSON
159+ json j;
160+ j[" loaded_files" ] = files;
161+ j[" duration_ms" ] = time;
162+
163+ std::ofstream output (options.outputFile );
164+ if (!output.good ())
165+ {
166+ logFail (" Failed to open %S" , options.outputFile );
167+ return false ;
168+ }
169+
170+ output << j;
171+
172+ return true ;
173+ }
174+
175+ inline bool keepRunning () override
176+ {
177+ return false ;
178+ }
179+
180+ inline void workLoopBody () override
181+ {
182+
183+ }
184+
185+ private:
186+ struct NBL_APP_OPTIONS
187+ {
188+ std::string directory;
189+ std::string outputFile;
190+ } options;
191+ };
192+
193+ NBL_MAIN_FUNC (JpegLoaderApp)
0 commit comments