DLL functions not exported when build in release configuration - c++

In my C++ DLL project, when I build the project in Debug configuration, it works perfectly.
Functions are exported using a .def file:
LIBRARY "calc"
EXPORTS
findMaxFreqEXL = findMaxFreq
findMinSpeedEXL = calcMinSpeed
findMaxSpeedEXL = calcMaxSpeed
createProfileEXL = createProfile
arrayTestEXL = arrayTest
setLimitsEXL = setLimits
And those functions are all defined in my project as:
double _stdcall findMaxFreq(double &dCutLength, double &dCutTime, double &dSealTime, double &dCutSpeed, double &dDoughHeight, double* limitArray)
{
Calc *calcObj = new Calc();
calcObj->setLimits((int)limitArray[0], (int)limitArray[1], (int)limitArray[2], (int)limitArray[3], limitArray[4], limitArray[5], (int)limitArray[6], (int)limitArray[7], (int)limitArray[8], (int)limitArray[9], (int)limitArray[10]);
double maxFreq = calcObj->calcMaxFreq((float) dCutLength, (float) dCutTime, (float) dSealTime, (float) dCutSpeed, (float) dDoughHeight);
//delete calcObj;
return maxFreq;
}
And so on for the rest of the functions.
The generated DLL file is 192 kb in size, and according to dumpbin, these are the exported functions:
Dump of file C:\Redacted\Debug\calcDLL.dll
File Type: DLL
Section contains the following exports for calc.dll
00000000 characteristics
57B17EE6 time date stamp Mon Aug 15 10:35:50 2016
0.00 version
1 ordinal base
6 number of functions
6 number of names
ordinal hint RVA name
1 0 00013339 arrayTestEXL = #ILT+820(?arrayTest##YGHPAN#Z)
2 1 00013460 createProfileEXL = #ILT+1115(?createProfile##YGHAAN00000PAN11#Z)
3 2 000138E8 findMaxFreqEXL = #ILT+2275(?findMaxFreq##YGNAAN0000PAN#Z)
4 3 00013744 findMaxSpeedEXL = #ILT+1855(?calcMaxSpeed##YGNAAN00#Z)
5 4 00013500 findMinSpeedEXL = #ILT+1275(?calcMinSpeed##YGNAAN00#Z)
6 5 000134F6 setLimitsEXL = #ILT+1265(?setLimits#Calc##QAEXHHHHHHHHHHH#Z)
Summary
1000 .data
2000 .idata
5000 .rdata
2000 .reloc
1000 .rsrc
28000 .text
12000 .textbss
In Release configuration the file is only 10 kb and dumpbin says this:
Dump of file C:\Redacted\Release\calcDLL.dll
File Type: DLL
Summary
1000 .data
1000 .rdata
1000 .reloc
1000 .rsrc
2000 .text
I use Visual Studio Express 2013. Any idea on what I am missing?

Evertything you show is sort of ok, so my guess is you just forgot to set the exports file in the project settings for the release configuration. Go to project properties->Linker->Input and set the Module Definition File.
Also: you have a memory leak because you don't delete calcObj. But actually there's no reason to use the heap here, just use Calc calcObj; on the stack. Also know that casting double to int is truncating, and have you thought of what will happen if the number is > 2^31 ?

Related

Amount of time to count lines for sequence of files using Rcpp higher than expected

I have a process for cleaning files and then saving them into correctly formatted files that arrow can read at a later time. The files are tsv format and have around 30 columns, mixed data types -- mostly character, but a couple of numeric columns. There is a significant number of files that have only a header and no data content. I decided that prior to reading in the files for cleaning, I would check to ensure that they have content, rather than reading in the file as a data frame, and then checking for content. So, essentially, I just wanted to check that the number of lines in the file was >= 2. I am using a simple C++ method that I pulled into R using Rcpp:
Rcpp::cppFunction(
"
#include <fstream>
bool more_than_one_line(std::string filepath) {
std::ifstream input_file;
input_file.open(filepath);
std::string unused;
int numLines = 0;
while(std::getline(input_file, unused)) {
++numLines;
if (numLines >= 2) {
return true;
}
}
return false;
}
"
)
I take some timing measurements like so:
v <- vector(mode="numeric", length=1000)
ii = 0
for (file in listOfFiles[1:1000]) {
print(ii)
ii = ii + 1
t0 <- Sys.time()
more_than_one_line(file);
v[ii] <- difftime(Sys.time(), t0)
}
When I run this code, it takes about 1 second per file, if the files have never been read before; it's much, much faster if I run the code over files that have previously been processed. Yet, according to this SO answer, the fastest time for counting the lines in a 12M row file is 0.1 seconds (my files are max 500k rows), and the SO user who recommended that fastest strategy (which used Linux wc) also recommended that using C++ would be quite fast. I thought the C++ method I wrote would be equally as fast as the wc method, if not faster, at least due to the fact that I am only reading, at most, the first two lines.
Am I thinking about this wrong? Is my approach wrong?
In my answer to the question linked to by the OP I mention package fpeek, function peek_count_lines. This is a fast function coded in C++. With a directory of 82 CSV files ranging from 4.8K lines to 108K lines on my computer (1 year old 11th Gen Intel(R) Core(TM) i5-1135G7 # 2.40GHz running Windows 11) it gives me an average 0.03 secs per file to get the number of lines.
Then you can use these values and subset on the condition flsize >= 2.
#path <- "my/path/omited"
fls <- list.files(path, full.names = TRUE)
# how many files
length(fls)
#> [1] 82
# range of file sizes in MB
range(file.size(fls)) / 1024L / 1024L
#> [1] 0.766923 19.999812
# total file size in MB
sum(file.size(fls)) / 1024L / 1024L
#> [1] 485.6675
# this is the main problem
t0 <- system.time(
flsize <- sapply(fls, fpeek::peek_count_lines)
)
# the files have from 4.8K to 108K lines
range(flsize)
#> [1] 4882 108503
# how many files have more than just the header line
sum(flsize >= 2)
#> [1] 82
# timings
t0
#> user system elapsed
#> 0.28 1.12 2.30
# average timings per file
t0/length(flsize)
#> user system elapsed
#> 0.003414634 0.013658537 0.028048780
Created on 2023-02-04 with reprex v2.0.2

How do I convert s.st_dev to /sys/block/<name>

I want to determine whether a file is on an HDD or an SDD.
I found out that I could check the type of drive using the /sys/block info:
prompt$ cat /sys/block/sdc/queue/rotational
1
This has 1 if it is rotational or unknown. It is 0 when the disk is an SSD.
Now I have a file and what to know whether it is on an HDD or an SDD. I can stat() the file to get the device number:
struct stat s;
stat(filename, &s);
// what do I do with s.st_dev now?
I'd like to convert s.st_dev to a drive name as I have in my /sys/block directory, in C.
What functions do I have to use to get that info? Or is it available in some /proc file?
First of all for the input file we need to file on which partition the file exists
you can use the following command for that
df -P <file name> | tail -1 | cut -d ' ' -f 1
Which will give you output something like this : /dev/sda3
Now you can apply following command to determine HDD , SDD
cat /sys/block/sdc/queue/rotational
You can use popen in your program to get output of these system commands
Okay, I really found it!
So my first solution, reading the partitions, wouldn't work. It would give me sbc1 instead of sbc. I also found the /proc/mounts which includes some info about what's mounted where, but it would still not help me convert the value to sbc.
Instead, I found another solution, which is to look at the block devices and more specifically this softlink:
/sys/dev/block/<major>:<minor>
The <major> and <minor> numbers can be extracted using the functions of the same name in C (I use C++, but the basic functions are all in C):
#include <sys/types.h>
...
std::string dev_path("/sys/dev/block/");
dev_path += std::to_string(major(s.st_dev));
dev_path += ":";
dev_path += std::to_string(minor(s.st_dev));
That path is a soft link and I want to get the real path of the destination:
char device_path[PATH_MAX + 1];
if(realpath(dev_path.c_str(), device_path) == nullptr)
{
return true;
}
From that real path, I then break up the path in segments and search for a directory with a sub-directory named queue and a file named rotational.
advgetopt::string_list_t segments;
advgetopt::split_string(device_path, segments, { "/" });
while(segments.size() > 3)
{
std::string path("/"
+ boost::algorithm::join(segments, "/")
+ "/queue/rotational");
std::ifstream in;
in.open(path);
if(in.is_open())
{
char line[32];
in.getline(line, sizeof(line));
return std::atoi(line) != 0;
}
segments.pop_back();
}
The in.getline() is what reads the .../queue/rotational file. If the value is not 0 then I consider that this is an HDD. If something fails, I also consider that the drive is an HDD drive. The only way my function returns false is if the rotational file exists and is set to 0.
My function can be found here. The line number may change over time, search for tool::is_hdd.
Old "Solution"
The file /proc/partition includes the major & minor device numbers, a size, and a name. So I just have to parse that one and return the name I need. VoilĂ .
$ cat /proc/partitions
major minor #blocks name
8 16 1953514584 sdb
8 17 248832 sdb1
8 18 1 sdb2
8 21 1953263616 sdb5
8 0 1953514584 sda
8 1 248832 sda1
8 2 1 sda2
8 5 1953263616 sda5
11 0 1048575 sr0
8 32 976764928 sdc
8 33 976763904 sdc1
252 0 4096 dm-0
252 1 1936375808 dm-1
252 2 1936375808 dm-2
252 3 1936375808 dm-3
252 4 16744448 dm-4
As you can see in this example, the first two lines represent the column names and an empty.The Name column is what I was looking for.

Cachegring file very small

I am new to profiling. I am trying to profile my PHP with xdebug.
The cachegrind file is created but has no significant content
I have set xdebug.profiler_enable_trigger = 1
xdebug.profiler_output_name = cachegrind+%p+%H+%R.cg
I call my page with additional GET parameter ?XDEBUG_PROFILE=1
My cachegrind file is generated but has no significant content
Here is my output:
version: 1
creator: xdebug 2.7.0alpha1 (PHP 7.0.30-dev)
cmd: C:\WPNserver\www\DMResources\Classes\VendorClasses\PHPMySQLiDatabase\MysqliDb.php
part: 1
positions: line
events: Time Memory
fl=(1)
fn=(221) php::mysqli->close
1244 103 -14832
fl=(42)
fn=(222) MysqliDbExt->__destruct
1239 56 0
cfl=(1)
cfn=(221)
calls=1 0 0
1244 103 -14832
That's it - I must be missing something fundamental.
I think you hit this bug in xdebug.
As suggested by Derick in the issue tracker, you can workaround this by adding %r to the profiler output name. eg: xdebug.profiler_output_name = cachegrind+%p+%H+%R+%r.cg
(with %r adding a random number to the name)

Linking with Windows Projected File System DLL/LIB

I am trying to build the RegFS sample to better understand the Windows Projected File System. My code is building without a warning, but I am getting dynamic linking errors. Below is a sample error, with the code causing it right below.
"The procedure entry point PrjWritePlaceholderInfo could not be located in the dynamic link library."
HRESULT VirtualizationInstance::WritePlaceholderInfo(
LPCWSTR relativePath,
PRJ_PLACEHOLDER_INFO* placeholderInfo,
DWORD length
) {
return PrjWritePlaceholderInfo(
_instanceHandle,
relativePath,
placeholderInfo,
length);
}
I'm sure I did something wrong when I was linking. Under [Project Property Pages] > Linker > Input, I prepended "ProjectedFSlib.lib" to "Additional Dependencies."
This is my first time using Visual Studio with libraries not linked in by default, and I've been unable to find instructions on how to locate and link libraries within the Windows SDK.
Thanks for your help!
EDIT:
The DUMPBIN output is:
Dump of file ProjectedFSLib.lib
File Type: LIBRARY
Exports
ordinal name
PrjAllocateAlignedBuffer
PrjClearNegativePathCache
PrjCloseFile
PrjCommandCallbacksInit
PrjCompleteCommand
PrjConfigureVolume
PrjConvertDirectoryToPlaceholder
PrjCreatePlaceholderAsHardlink
PrjDeleteFile
PrjDetachDriver
PrjDoesNameContainWildCards
PrjFileNameCompare
PrjFileNameMatch
PrjFillDirEntryBuffer
PrjFreeAlignedBuffer
PrjGetOnDiskFileState
PrjGetVirtualizationInstanceIdFromHandle
PrjGetVirtualizationInstanceInfo
PrjMarkDirectoryAsPlaceholder
PrjOpenFile
PrjReadFile
PrjStartVirtualizationInstance
PrjStartVirtualizationInstanceEx
PrjStartVirtualizing
PrjStopVirtualizationInstance
PrjStopVirtualizing
PrjUpdateFileIfNeeded
PrjUpdatePlaceholderIfNeeded
PrjWriteFile
PrjWriteFileData
PrjWritePlaceholderInfo
PrjWritePlaceholderInformation
PrjpReadPrjReparsePointData
Summary
D8 .debug$S
14 .idata$2
14 .idata$3
8 .idata$4
8 .idata$5
14 .idata$6
A DUMPBIN of the executable imports results in:
Dump of file regfs.exe
File Type: EXECUTABLE IMAGE
Section contains the following imports:
PROJECTEDFSLIB.dll
14006D2A0 Import Address Table
14006D9E0 Import Name Table
0 time date stamp
0 Index of first forwarder reference
1E PrjWritePlaceholderInfo
1D PrjWriteFileData
19 PrjStopVirtualizing
17 PrjStartVirtualizing
C PrjFileNameMatch
D PrjFillDirEntryBuffer
E PrjFreeAlignedBuffer
0 PrjAllocateAlignedBuffer
11 PrjGetVirtualizationInstanceInfo
12 PrjMarkDirectoryAsPlaceholder
B PrjFileNameCompare
KERNEL32.dll
14006D098 Import Address Table
14006D7D8 Import Name Table
0 time date stamp
0 Index of first forwarder reference
389 IsProcessorFeaturePresent
382 IsDebuggerPresent
466 RaiseException
1B1 FreeLibrary
BA CreateDirectoryW
116 DeleteFileW
59A TerminateProcess
4BD RemoveDirectoryW
621 WriteFile
C2 CreateFile2
86 CloseHandle
267 GetLastError
3F2 MultiByteToWideChar
21D GetCurrentProcess
57B SetUnhandledExceptionFilter
5BC UnhandledExceptionFilter
4E1 RtlVirtualUnwind
4DA RtlLookupFunctionEntry
4D3 RtlCaptureContext
477 ReadFile
2B5 GetProcAddress
5DD VirtualQuery
2BB GetProcessHeap
60D WideCharToMultiByte
450 QueryPerformanceCounter
21E GetCurrentProcessId
2F0 GetSystemTimeAsFileTime
36C InitializeSListHead
352 HeapFree
34E HeapAlloc
27E GetModuleHandleW
2D7 GetStartupInfoW
222 GetCurrentThreadId
ADVAPI32.dll
14006D000 Import Address Table
14006D740 Import Name Table
0 time date stamp
0 Index of first forwarder reference
299 RegQueryValueExW
293 RegQueryInfoKeyW
28C RegOpenKeyExW
27D RegEnumValueW
27A RegEnumKeyExW
25B RegCloseKey
281 RegGetValueW
ole32.dll
14006D438 Import Address Table
14006DB78 Import Name Table
0 time date stamp
0 Index of first forwarder reference
2A CoCreateGuid
MSVCP140D.dll
14006D228 Import Address Table
14006D968 Import Name Table
0 time date stamp
0 Index of first forwarder reference
A5 ??1_Lockit#std##QEAA#XZ
6D ??0_Lockit#std##QEAA#H#Z
296 ?_Xlength_error#std##YAXPEBD#Z
297 ?_Xout_of_range#std##YAXPEBD#Z
VCRUNTIME140D.dll
14006D360 Import Address Table
14006DAA0 Import Name Table
0 time date stamp
0 Index of first forwarder reference
3C memcpy
3D memmove
1 _CxxThrowException
E __CxxFrameHandler3
36 _purecall
3B memcmp
21 __std_exception_copy
22 __std_exception_destroy
8 __C_specific_handler
9 __C_specific_handler_noexcept
25 __std_type_info_destroy_list
2E __vcrt_GetModuleFileNameW
2F __vcrt_GetModuleHandleW
31 __vcrt_LoadLibraryExW
ucrtbased.dll
14006D498 Import Address Table
14006DBD8 Import Name Table
0 time date stamp
0 Index of first forwarder reference
2B6 _register_thread_local_exe_atexit_callback
B5 _configthreadlocale
2CE _set_new_mode
4D __p__commode
11D _free_dbg
52C strcpy_s
528 strcat_s
68 __stdio_common_vsprintf_s
2C2 _seh_filter_dll
B6 _configure_narrow_argv
171 _initialize_narrow_environment
172 _initialize_onexit_table
9F _c_exit
E5 _execute_onexit_table
C2 _crt_atexit
C1 _crt_at_quick_exit
54B terminate
39C _wmakepath_s
3B8 _wsplitpath_s
564 wcscpy_s
A4 _cexit
48D getchar
60 __stdio_common_vfwprintf
35 __acrt_iob_func
4 _CrtDbgReport
567 wcslen
176 _invalid_parameter
4B __p___wargv
49 __p___argc
2CB _set_fmode
EA _exit
450 exit
175 _initterm_e
174 _initterm
13E _get_initial_wide_environment
173 _initialize_wide_environment
B7 _configure_wide_argv
5B __setusermatherr
2C6 _set_app_type
561 wcscmp
5 _CrtDbgReportW
4D8 malloc
2B5 _register_onexit_function
A1 _callnewh
2C3 _seh_filter_exe
Summary
1000 .00cfg
1000 .data
2000 .idata
1000 .msvcjmc
5000 .pdata
17000 .rdata
1000 .reloc
1000 .rsrc
37000 .text
18000 .textbss
As evident, it imports all the necessary functions from PROJECTEDFSLIB.dll
Either add ProjectedFSLib.lib to your libraries or add a:
#pragma comment(lib, "ProjectedFSLib.lib")
line in your code. Also, make sure you are using version 10.0.17763.0 of the SDK. If you are using mingw it would not surprise me if this library has not been made available yet.
The Projected FS is still an optional feature of Windows that requires manual installation to use. Go to Control Panel -> Programs and Features -> Turn Windows Features on or off. In that list of optional features, scroll down to "Windows Projected File System" and make sure that it is enabled there. Only after that is done will you have a ProjectedFSLib.dll show up in your system32 directory.
It's also probably worth noting that it looks like there's only an x64 version of this DLL, so if you're building an x86 program, that might be the reason why you're unable to dynamically link with that DLL.

memory_profiler display only function level results

I am using the memory_profiler for python as follows:
from memory_profiler import profile
#profile
def my_func():
...
And run it normally.
Output looks like this (taken from docs):
Line # Mem usage Increment Line Contents
==============================================
3 #profile
4 5.97 MB 0.00 MB def my_func():
5 13.61 MB 7.64 MB a = [1] * (10 ** 6)
6 166.20 MB 152.59 MB b = [2] * (2 * 10 ** 7)
7 13.61 MB -152.59 MB del b
8 13.61 MB 0.00 MB return a
Though I'd like it to be shortened to function level and look akin to this:
Line # Mem usage Increment Max Line Contents
==============================================================
4 13.61 MB 7.64 MB 166.20 MB my_func()
20 23.26 MB 9.65 MB 56.20 MB my_second_func()
Is this possible?
You can always define a third function
#profile
def my_third_func():
my_func()
my_second_func()
and profile this function. This should yield the output you are looking for.
Otherwise, if you are only interested in the maximum memory consumption of the different functions, mprof provides a handy visual plot for that.