diff --git a/build/VStudio/testing/fsbench.vcxproj b/build/VStudio/testing/fsbench.vcxproj
new file mode 100755
index 00000000..49bb6fb6
--- /dev/null
+++ b/build/VStudio/testing/fsbench.vcxproj
@@ -0,0 +1,187 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}
+ Win32Proj
+ fsbench
+ 8.1
+
+
+
+ Application
+ true
+ v140
+ Unicode
+
+
+ Application
+ false
+ v140
+ true
+ Unicode
+
+
+ Application
+ true
+ v140
+ Unicode
+
+
+ Application
+ false
+ v140
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ $(SolutionDir)build\$(Configuration)\
+ $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\
+ $(ProjectName)-$(PlatformTarget)
+
+
+ true
+ $(SolutionDir)build\$(Configuration)\
+ $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\
+ $(ProjectName)-$(PlatformTarget)
+
+
+ false
+ $(SolutionDir)build\$(Configuration)\
+ $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\
+ $(ProjectName)-$(PlatformTarget)
+
+
+ false
+ $(SolutionDir)build\$(Configuration)\
+ $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\
+ $(ProjectName)-$(PlatformTarget)
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ ..\..\..\ext
+
+
+ Console
+ true
+
+
+
+
+
+
+ Level3
+ Disabled
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ ..\..\..\ext
+
+
+ Console
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ ..\..\..\ext
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ ..\..\..\ext
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ TurnOffAllWarnings
+ false
+ TurnOffAllWarnings
+ false
+ TurnOffAllWarnings
+ false
+ TurnOffAllWarnings
+ false
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/VStudio/testing/fsbench.vcxproj.filters b/build/VStudio/testing/fsbench.vcxproj.filters
new file mode 100755
index 00000000..fe811f89
--- /dev/null
+++ b/build/VStudio/testing/fsbench.vcxproj.filters
@@ -0,0 +1,25 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {d76fc01e-0f8d-4596-bdef-c2a5d3fede2e}
+
+
+
+
+ Source
+
+
+ Source\tlib
+
+
+
+
+ Source\tlib
+
+
+
\ No newline at end of file
diff --git a/build/VStudio/winfsp.sln b/build/VStudio/winfsp.sln
index 79b70563..fcc072ca 100644
--- a/build/VStudio/winfsp.sln
+++ b/build/VStudio/winfsp.sln
@@ -51,6 +51,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fscrash", "testing\fscrash.
{C85C26BA-8C22-4D30-83DA-46C3548E6332} = {C85C26BA-8C22-4D30-83DA-46C3548E6332}
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fsbench", "testing\fsbench.vcxproj", "{C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -175,6 +177,22 @@ Global
{10757011-749D-4954-873B-AE38D8145472}.Release|x64.Build.0 = Release|x64
{10757011-749D-4954-873B-AE38D8145472}.Release|x86.ActiveCfg = Release|Win32
{10757011-749D-4954-873B-AE38D8145472}.Release|x86.Build.0 = Release|Win32
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x64.ActiveCfg = Debug|x64
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x64.Build.0 = Debug|x64
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x86.ActiveCfg = Debug|Win32
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Debug|x86.Build.0 = Debug|Win32
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x64.ActiveCfg = Debug|x64
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x64.Build.0 = Debug|x64
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x86.ActiveCfg = Debug|Win32
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Debug|x86.Build.0 = Debug|Win32
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x64.ActiveCfg = Release|x64
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x64.Build.0 = Release|x64
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x86.ActiveCfg = Release|Win32
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Installer.Release|x86.Build.0 = Release|Win32
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x64.ActiveCfg = Release|x64
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x64.Build.0 = Release|x64
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x86.ActiveCfg = Release|Win32
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -187,5 +205,6 @@ Global
{A5EFD487-0140-4184-8C54-FFAEC2F85E35} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
{73EAAEDA-557B-48D5-A137-328934720FB4} = {FD28A504-431E-49B9-BB8C-DCA0E7019F66}
{10757011-749D-4954-873B-AE38D8145472} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
+ {C4E1E9E5-0959-488E-8C6A-C327CC81BEFB} = {69439FD1-C07D-4BF1-98DC-3CCFECE53A49}
EndGlobalSection
EndGlobal
diff --git a/ext/tlib/testsuite.c b/ext/tlib/testsuite.c
index 9be2b5cf..5dd3fae2 100644
--- a/ext/tlib/testsuite.c
+++ b/ext/tlib/testsuite.c
@@ -54,10 +54,19 @@ static char assert_buf[256];
static void test_printf(const char *fmt, ...);
static double run_test(struct test *test)
{
+#if defined(_WIN64) || defined(_WIN32)
+ #pragma comment(lib, "winmm.lib")
+ unsigned long __stdcall timeGetTime(void);
+ unsigned long t0 = timeGetTime();
+ test->fn();
+ unsigned long t1 = timeGetTime();
+ return (t1 - t0) / 1000.0;
+#else
time_t t0 = time(0);
test->fn();
time_t t1 = time(0);
return difftime(t1, t0);
+#endif
}
static void do_test_default(struct test *test, int testno)
{
@@ -73,7 +82,7 @@ static void do_test_default(struct test *test, int testno)
dispname[sizeof dispname - 1] = '\0';
test_printf("%s ", dispname);
double d = run_test(test);
- test_printf("OK %.0fs\n", d);
+ test_printf("OK %.2fs\n", d);
}
else
test_printf("--- COMPLETE ---\n");
diff --git a/tools/deploy.bat b/tools/deploy.bat
index 4c992ef0..a21d0c55 100755
--- a/tools/deploy.bat
+++ b/tools/deploy.bat
@@ -10,7 +10,7 @@ set TARGET=\\%TARGET_MACHINE%%TARGET_ACCOUNT%
cd %~dp0..
mkdir %TARGET% 2>nul
-for %%f in (winfsp-%SUFFIX%.sys winfsp-%SUFFIX%.dll winfsp-tests-%SUFFIX%.exe fscrash-%SUFFIX%.exe memfs-%SUFFIX%.exe) do (
+for %%f in (winfsp-%SUFFIX%.sys winfsp-%SUFFIX%.dll winfsp-tests-%SUFFIX%.exe fsbench-%SUFFIX%.exe fscrash-%SUFFIX%.exe memfs-%SUFFIX%.exe) do (
copy build\VStudio\build\%CONFIG%\%%f %TARGET% >nul
)
echo sc create WinFsp type=filesys binPath=%%~dp0%DRIVER% >%TARGET%sc-create.bat
diff --git a/tst/fsbench/fsbench.c b/tst/fsbench/fsbench.c
new file mode 100644
index 00000000..bb356c26
--- /dev/null
+++ b/tst/fsbench/fsbench.c
@@ -0,0 +1,204 @@
+/**
+ * @file fsbench.c
+ *
+ * @copyright 2015-2016 Bill Zissimopoulos
+ */
+/*
+ * This file is part of WinFsp.
+ *
+ * You can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 3 as published by the Free Software
+ * Foundation.
+ *
+ * Licensees holding a valid commercial license may use this file in
+ * accordance with the commercial license agreement provided with the
+ * software.
+ */
+
+#include
+#include
+#include
+
+ULONG OptFiles = 1000;
+ULONG OptDirs = 1000;
+ULONG OptRdwr = 10000;
+
+static void file_create_test(void)
+{
+ HANDLE Handle;
+ BOOL Success;
+ WCHAR FileName[MAX_PATH];
+
+ for (ULONG Index = 0; OptFiles > Index; Index++)
+ {
+ StringCbPrintfW(FileName, sizeof FileName, L"fsbench-file%lu", Index);
+ Handle = CreateFileW(FileName,
+ GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0,
+ CREATE_NEW, FILE_ATTRIBUTE_NORMAL,
+ 0);
+ ASSERT(INVALID_HANDLE_VALUE != Handle);
+ Success = CloseHandle(Handle);
+ ASSERT(Success);
+ }
+}
+static void file_delete_test(void)
+{
+ BOOL Success;
+ WCHAR FileName[MAX_PATH];
+
+ for (ULONG Index = 0; OptFiles > Index; Index++)
+ {
+ StringCbPrintfW(FileName, sizeof FileName, L"fsbench-file%lu", Index);
+ Success = DeleteFileW(FileName);
+ ASSERT(Success);
+ }
+}
+static void file_tests(void)
+{
+ TEST(file_create_test);
+ TEST(file_delete_test);
+}
+
+static void dir_mkdir_test(void)
+{
+ BOOL Success;
+ WCHAR FileName[MAX_PATH];
+
+ for (ULONG Index = 0; OptDirs > Index; Index++)
+ {
+ StringCbPrintfW(FileName, sizeof FileName, L"fsbench-dir%lu", Index);
+ Success = CreateDirectoryW(FileName, 0);
+ ASSERT(Success);
+ }
+}
+static void dir_rmdir_test(void)
+{
+ BOOL Success;
+ WCHAR FileName[MAX_PATH];
+
+ for (ULONG Index = 0; OptDirs > Index; Index++)
+ {
+ StringCbPrintfW(FileName, sizeof FileName, L"fsbench-dir%lu", Index);
+ Success = RemoveDirectoryW(FileName);
+ ASSERT(Success);
+ }
+}
+static void dir_tests(void)
+{
+ TEST(dir_mkdir_test);
+ TEST(dir_rmdir_test);
+}
+
+static void rdwr_dotest(ULONG CreateDisposition, ULONG CreateFlags)
+{
+ SYSTEM_INFO SystemInfo;
+ PVOID Buffer;
+ HANDLE Handle;
+ BOOL Success;
+ DWORD BytesTransferred;
+ WCHAR FileName[MAX_PATH];
+
+ GetSystemInfo(&SystemInfo);
+ Buffer = _aligned_malloc(SystemInfo.dwPageSize, SystemInfo.dwPageSize);
+ ASSERT(0 != Buffer);
+ memset(Buffer, 0, SystemInfo.dwPageSize);
+
+ StringCbPrintfW(FileName, sizeof FileName, L"fsbench-file");
+ Handle = CreateFileW(FileName,
+ GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0,
+ CreateDisposition,
+ FILE_ATTRIBUTE_NORMAL | CreateFlags,
+ 0);
+ ASSERT(INVALID_HANDLE_VALUE != Handle);
+
+ for (ULONG Index = 0; OptRdwr > Index; Index++)
+ {
+ if (CREATE_NEW == CreateDisposition)
+ Success = WriteFile(Handle, Buffer, SystemInfo.dwPageSize, &BytesTransferred, 0);
+ else
+ Success = ReadFile(Handle, Buffer, SystemInfo.dwPageSize, &BytesTransferred, 0);
+ ASSERT(Success);
+ ASSERT(SystemInfo.dwPageSize == BytesTransferred);
+ }
+
+ Success = CloseHandle(Handle);
+ ASSERT(Success);
+
+ _aligned_free(Buffer);
+}
+static void rdwr_cached_write_test(void)
+{
+ rdwr_dotest(CREATE_NEW, 0);
+}
+static void rdwr_cached_read_test(void)
+{
+ rdwr_dotest(OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE);
+}
+static void rdwr_noncached_write_test(void)
+{
+ rdwr_dotest(CREATE_NEW, 0 | FILE_FLAG_NO_BUFFERING);
+}
+static void rdwr_noncached_read_test(void)
+{
+ rdwr_dotest(OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_NO_BUFFERING);
+}
+static void rdwr_tests(void)
+{
+ TEST(rdwr_cached_write_test);
+ TEST(rdwr_cached_read_test);
+ TEST(rdwr_noncached_write_test);
+ TEST(rdwr_noncached_read_test);
+}
+
+static void mmap_cached_test(void)
+{
+}
+static void mmap_noncached_test(void)
+{
+}
+static void mmap_tests(void)
+{
+ TEST(mmap_cached_test);
+ TEST(mmap_noncached_test);
+}
+
+#define rmarg(argv, argc, argi) \
+ argc--, \
+ memmove(argv + argi, argv + argi + 1, (argc - argi) * sizeof(char *)),\
+ argi--, \
+ argv[argc] = 0
+int main(int argc, char *argv[])
+{
+ TESTSUITE(file_tests);
+ TESTSUITE(dir_tests);
+ TESTSUITE(rdwr_tests);
+ TESTSUITE(mmap_tests);
+
+ for (int argi = 1; argc > argi; argi++)
+ {
+ const char *a = argv[argi];
+ if ('-' == a[0])
+ {
+ if (0 == strncmp("--files=", a, sizeof "--files=" - 1))
+ {
+ OptFiles = strtoul(a + sizeof "--files=" - 1, 0, 10);
+ rmarg(argv, argc, argi);
+ }
+ else if (0 == strncmp("--dirs=", a, sizeof "--dirs=" - 1))
+ {
+ OptDirs = strtoul(a + sizeof "--dirs=" - 1, 0, 10);
+ rmarg(argv, argc, argi);
+ }
+ else if (0 == strncmp("--rdwr=", a, sizeof "--rdwr=" - 1))
+ {
+ OptRdwr = strtoul(a + sizeof "--rdwr=" - 1, 0, 10);
+ rmarg(argv, argc, argi);
+ }
+ }
+ }
+
+ tlib_run_tests(argc, argv);
+ return 0;
+}