Skip to content

Commit 37c3b90

Browse files
authored
Improve ap startup on linux (o3de#17526)
* Improves the startup time of AP on linux. Note that this could also potentially improve it on mac and windows, as well as metafile processing in general. Most of this change is just moving the initialization of the catalog until the file cache is warmed up and then using the file cache to fix path cases on case sensitive file systems. The rest of it is fixing the unit tests to account for this - the mock for the file system wasn't sufficient to actually use this new code as it would do things like always answer false for "is directory". With this change, all unit tests pass in debug on linux, with no unexpected assertions and no failures. In addition, AP starts and idles very quickly without any long freezes during startup. Signed-off-by: Nicholas Lawson <[email protected]> * Fixes a warning I'm not sure I created During Createjobs, Asset Processor Manager does this: ```cpp Q_EMIT CreateJobsDurationChanged(sourceAsset.RelativePath().c_str(), sourceAsset.ScanFolderId()); ``` However, scan folder ID of type AZ::s64 which hasn't been registered to Qt serializer's meta object system, so it does not know how to convert it to a byte array to emit messages across threads. This causes warnings and probably causes that message not to be emitted. * Fixes for windows Most of the problems were in oversights in existing tests. For example the asset catalog tests use a virtual file system but were using CreateDummyFile which makes real files. Likewise, the asset catalog was using SystemFile instead of FileIO which was the mock file IO. So it would be making mock files in memory but then checking real files on disk, etc. Note that the Pass-thru file cache is only used in unit tests, or when specifically asked for by a command line parameter, which is not used in any of the test scripts. Signed-off-by: Nicholas Lawson <[email protected]>
1 parent c8e2330 commit 37c3b90

28 files changed

+1185
-793
lines changed

Code/Framework/AzCore/AzCore/IO/FileIO.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ namespace AZ
3333
/// like "*.bat" or "blah??.pak" or "test*.exe" and such.
3434
bool NameMatchesFilter(AZStd::string_view name, AZStd::string_view filter);
3535

36+
//! Converts the operating-specific values returned by AZ::IO::FileIO API
37+
//! to independent units representing the milliseconds since 1/1/1970 0:00 UTC
38+
AZ::u64 FileTimeToMSecsSincePosixEpoch(AZ::u64 fileTime);
39+
3640
using HandleType = AZ::u32;
3741
static const HandleType InvalidHandle = 0;
3842

Code/Framework/AzCore/Platform/Android/platform_android_files.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ set(FILES
3535
../Common/Default/AzCore/IO/Streamer/StreamerContext_Default.cpp
3636
../Common/Default/AzCore/IO/Streamer/StreamerContext_Default.h
3737
../Common/UnixLike/AzCore/IO/AnsiTerminalUtils_UnixLike.cpp
38+
../Common/UnixLike/AzCore/IO/FileIO_UnixLike.cpp
3839
../Common/UnixLike/AzCore/IO/SystemFile_UnixLike.cpp
3940
../Common/UnixLike/AzCore/IO/Internal/SystemFileUtils_UnixLike.h
4041
../Common/UnixLike/AzCore/IO/Internal/SystemFileUtils_UnixLike.cpp
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright (c) Contributors to the Open 3D Engine Project.
3+
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
4+
*
5+
* SPDX-License-Identifier: Apache-2.0 OR MIT
6+
*
7+
*/
8+
9+
#include <AzCore/IO/FileIO.h>
10+
11+
namespace AZ::IO
12+
{
13+
// On posix compatible systems, file times are in time_t, that is,
14+
// number of seconds since posix epoch. Converting this just means converting from
15+
// seconds to milliseconds
16+
AZ::u64 FileTimeToMSecsSincePosixEpoch(AZ::u64 fileTime)
17+
{
18+
return fileTime * 1000;
19+
}
20+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) Contributors to the Open 3D Engine Project.
3+
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
4+
*
5+
* SPDX-License-Identifier: Apache-2.0 OR MIT
6+
*
7+
*/
8+
9+
#include <AzCore/IO/FileIO.h>
10+
11+
namespace AZ::IO
12+
{
13+
// There are no leap seconds from the start of the win32 file epoch
14+
// which begins Jan 1 1601, until the posix epoch begins. So to convert
15+
// it can just be offset.
16+
// see Code\Legacy\CrySystem\LocalizedStringManager.cpp for example of where these constants
17+
// came from.
18+
// it represents the number of 100-nanosecond intervals between the two epocs.
19+
// since win32 file time is in 100-nanosecond intervals.
20+
AZ::u64 FileTimeToMSecsSincePosixEpoch(AZ::u64 fileTime)
21+
{
22+
static constexpr const AZ::u64 differenceBetweenEpochs = 116444736000000000;
23+
if (fileTime <= differenceBetweenEpochs)
24+
{
25+
return 0; // before the epoch
26+
}
27+
28+
fileTime = fileTime - differenceBetweenEpochs;
29+
// convert second to millisecond = * 1,000
30+
// convert millisecond to millisecond = * 1
31+
// convert microsecond to millisecond = / 1,000
32+
// convert nanosecond to millisecond = / 1,000,000 , therefore
33+
// convert 100 nanosec to millisecond = / 10,000 (1,000,000 / 100)
34+
fileTime = fileTime / 10000; // convert from 100-nanosecond interval to seconds
35+
return fileTime;
36+
}
37+
}

Code/Framework/AzCore/Platform/Linux/platform_linux_files.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ set(FILES
3636
../Common/Default/AzCore/IO/Streamer/StreamerContext_Default.cpp
3737
../Common/Default/AzCore/IO/Streamer/StreamerContext_Default.h
3838
../Common/UnixLike/AzCore/IO/AnsiTerminalUtils_UnixLike.cpp
39+
../Common/UnixLike/AzCore/IO/FileIO_UnixLike.cpp
3940
../Common/UnixLike/AzCore/IO/SystemFile_UnixLike.cpp
4041
../Common/UnixLike/AzCore/IO/SystemFile_UnixLike.h
4142
../Common/UnixLike/AzCore/IO/Internal/SystemFileUtils_UnixLike.h

Code/Framework/AzCore/Platform/Mac/platform_mac_files.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ set(FILES
3737
../Common/Default/AzCore/IO/Streamer/StreamerContext_Default.cpp
3838
../Common/Default/AzCore/IO/Streamer/StreamerContext_Default.h
3939
../Common/UnixLike/AzCore/IO/AnsiTerminalUtils_UnixLike.cpp
40+
../Common/UnixLike/AzCore/IO/FileIO_UnixLike.cpp
4041
../Common/UnixLike/AzCore/IO/SystemFile_UnixLike.cpp
4142
../Common/UnixLike/AzCore/IO/Internal/SystemFileUtils_UnixLike.h
4243
../Common/UnixLike/AzCore/IO/Internal/SystemFileUtils_UnixLike.cpp

Code/Framework/AzCore/Platform/Windows/platform_windows_files.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ set(FILES
3535
AzCore/Debug/StackTracer_Windows.cpp
3636
../Common/WinAPI/AzCore/Debug/Trace_WinAPI.cpp
3737
../Common/WinAPI/AzCore/IO/AnsiTerminalUtils_WinAPI.cpp
38+
../Common/WinAPI/AzCore/IO/FileIO_WinAPI.cpp
3839
../Common/WinAPI/AzCore/IO/Streamer/StreamerContext_WinAPI.cpp
3940
../Common/WinAPI/AzCore/IO/Streamer/StreamerContext_WinAPI.h
4041
../Common/WinAPI/AzCore/IO/SystemFile_WinAPI.cpp

Code/Framework/AzCore/Platform/iOS/platform_ios_files.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ set(FILES
3737
../Common/Apple/AzCore/IO/SystemFile_Apple.cpp
3838
../Common/Apple/AzCore/IO/SystemFile_Apple.h
3939
../Common/UnixLike/AzCore/IO/AnsiTerminalUtils_UnixLike.cpp
40+
../Common/UnixLike/AzCore/IO/FileIO_UnixLike.cpp
4041
../Common/UnixLike/AzCore/IO/SystemFile_UnixLike.cpp
4142
../Common/UnixLike/AzCore/IO/Internal/SystemFileUtils_UnixLike.h
4243
../Common/UnixLike/AzCore/IO/Internal/SystemFileUtils_UnixLike.cpp

Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,8 +241,24 @@ namespace AzToolsFramework::AssetUtils
241241
return configFiles;
242242
}
243243

244-
bool UpdateFilePathToCorrectCase(AZStd::string_view rootPath, AZStd::string& relPathFromRoot)
244+
bool UpdateFilePathToCorrectCase(AZStd::string_view rootPath, AZStd::string& relPathFromRoot, bool checkEntirePath /* = true */)
245245
{
246+
// The reason this is so expensive is that it could also be the case that the DIRECTORY path is the wrong case.
247+
// For example, the actual path might be /SomeFolder/textures/whatever/texture.dat
248+
// but the real file on disk is actually /SomeFolder/Textures/Whatever/texture.dat
249+
// Note the case difference of the directories. If you were to ask the operating system just to list all of
250+
// the files in the input folder (/SomeFolder/textures/whatever/*) it would not find any since the directory
251+
// does not itself exist. Not only that, but many operating system calls on case-insensitive file systems
252+
// actually use the input given in their return - that is, if you ask a WINAPI call to construct an absolute path
253+
// to a file and give it the wrong case as input, the output absolute path will also be the wrong case.
254+
// Thus, to actually correct a path it has to start at the bottom and whenever it encounters
255+
// a path segment, it has to do a read of the actual directory information to see which files exist in that
256+
// directory, and whether a file or directory exists with the correct name but with different case.
257+
258+
// if checkEntirePath is false, we only check the file name, and nothing else. This is for the case where
259+
// the path is known to be good except for the file name, such as when the relPathFromRoot comes from just
260+
// taking an existing, known-good file and replacing its extension only.
261+
246262
AZ::StringFunc::Path::Normalize(relPathFromRoot);
247263
AZStd::vector<AZStd::string> tokens;
248264
AZ::StringFunc::Tokenize(relPathFromRoot.c_str(), tokens, AZ_CORRECT_FILESYSTEM_SEPARATOR_STRING);
@@ -261,6 +277,15 @@ namespace AzToolsFramework::AssetUtils
261277

262278
for (int idx = 0; idx < tokens.size(); idx++)
263279
{
280+
if (!checkEntirePath)
281+
{
282+
if (idx != tokens.size() - 1)
283+
{
284+
// only the last token is potentially incorrect, we can skip filenames before that
285+
validatedPath /= tokens[idx]; // go one step deeper.
286+
continue;
287+
}
288+
}
264289
AZStd::string element = tokens[idx];
265290
bool foundAMatch = false;
266291
AZ::IO::FileIOBase::GetInstance()->FindFiles(validatedPath.c_str(), "*", [&](const char* file)

Code/Framework/AzToolsFramework/AzToolsFramework/Asset/AssetUtils.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ namespace AzToolsFramework::AssetUtils
4949
//! @param root a trusted already-case-correct path (will not be case corrected). If empty it will be set to appRoot.
5050
//! @param relativePathFromRoot a non-trusted (may be incorrect case) path relative to rootPath,
5151
//! which will be normalized and updated to be correct casing.
52+
//! @param checkEntirePath Optimization - set this to false if the caller is absolutely sure the path
53+
//! is correct and only the last element (file name or extension) is potentially incorrect, this can happen
54+
//! when for example taking a real file found from a real file directory that is already correct and
55+
//! replacing the file extension or file name only.
5256
//! @return if such a file does NOT exist, it returns FALSE, else returns TRUE.
5357
//! @note A very expensive function! Call sparingly.
54-
bool UpdateFilePathToCorrectCase(AZStd::string_view root, AZStd::string& relativePathFromRoot);
58+
bool UpdateFilePathToCorrectCase(AZStd::string_view root, AZStd::string& relativePathFromRoot, bool checkEntirePath = true);
5559
} //namespace AzToolsFramework::AssetUtils

0 commit comments

Comments
 (0)