1
0
mirror of https://github.com/solemnwarning/ipxwrapper synced 2024-12-30 16:45:37 +01:00

Merge branch 'profiling'

This commit is contained in:
Daniel Collins 2023-12-10 12:59:39 +00:00
commit bbe0dbd4e1
22 changed files with 882 additions and 227 deletions

View File

@ -86,62 +86,62 @@ dist: all
IPXWRAPPER_OBJS := src/ipxwrapper.o src/winsock.o src/ipxwrapper_stubs.o src/log.o src/common.o \ IPXWRAPPER_OBJS := src/ipxwrapper.o src/winsock.o src/ipxwrapper_stubs.o src/log.o src/common.o \
src/interface.o src/interface2.o src/router.o src/ipxwrapper.def src/addrcache.o src/config.o src/addr.o \ src/interface.o src/interface2.o src/router.o src/ipxwrapper.def src/addrcache.o src/config.o src/addr.o \
src/firewall.o src/wpcap_stubs.o src/ethernet.o src/firewall.o src/ethernet.o src/funcprof.o
ipxwrapper.dll: $(IPXWRAPPER_OBJS) ipxwrapper.dll: $(IPXWRAPPER_OBJS)
echo 'const char *version_string = "$(VERSION)", *compile_time = "'`date`'";' | $(CC) -c -x c -o version.o - echo 'const char *version_string = "$(VERSION)", *compile_time = "'`date`'";' | $(CC) -c -x c -o version.o -
$(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^ version.o -liphlpapi -lversion -lole32 -loleaut32 $(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^ version.o -liphlpapi -lversion -lole32 -loleaut32
src/ipxwrapper_stubs.s: src/ipxwrapper_stubs.txt src/ipxwrapper_stubs.s: src/ipxwrapper_stubs.txt
perl mkstubs.pl src/ipxwrapper_stubs.txt src/ipxwrapper_stubs.s 0 perl mkstubs.pl src/ipxwrapper_stubs.txt src/ipxwrapper_stubs.s ipxwrapper.dll
# #
# WSOCK32.DLL # WSOCK32.DLL
# #
wsock32.dll: src/stubdll.o src/wsock32_stubs.o src/log.o src/common.o src/config.o src/addr.o src/wsock32.def wsock32.dll: src/stubdll.o src/wsock32_stubs.o src/log.o src/common.o src/config.o src/addr.o src/funcprof.o src/wsock32.def
$(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^ $(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^
src/wsock32_stubs.s: src/wsock32_stubs.txt src/wsock32_stubs.s: src/wsock32_stubs.txt
perl mkstubs.pl src/wsock32_stubs.txt src/wsock32_stubs.s 1 perl mkstubs.pl src/wsock32_stubs.txt src/wsock32_stubs.s wsock32.dll
# #
# MSWSOCK.DLL # MSWSOCK.DLL
# #
mswsock.dll: src/stubdll.o src/mswsock_stubs.o src/log.o src/common.o src/config.o src/addr.o src/mswsock.def mswsock.dll: src/stubdll.o src/mswsock_stubs.o src/log.o src/common.o src/config.o src/addr.o src/funcprof.o src/mswsock.def
$(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^ $(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^
src/mswsock_stubs.s: src/mswsock_stubs.txt src/mswsock_stubs.s: src/mswsock_stubs.txt
perl mkstubs.pl src/mswsock_stubs.txt src/mswsock_stubs.s 2 perl mkstubs.pl src/mswsock_stubs.txt src/mswsock_stubs.s mswsock.dll
# #
# DPWSOCKX.DLL # DPWSOCKX.DLL
# #
dpwsockx.dll: src/directplay.o src/log.o src/dpwsockx_stubs.o src/common.o src/config.o src/addr.o src/dpwsockx.def dpwsockx.dll: src/directplay.o src/log.o src/dpwsockx_stubs.o src/common.o src/config.o src/addr.o src/funcprof.o src/dpwsockx.def
$(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^ -lwsock32 $(CC) $(CFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -shared -o $@ $^ -lwsock32
src/dpwsockx_stubs.s: src/dpwsockx_stubs.txt src/dpwsockx_stubs.s: src/dpwsockx_stubs.txt
perl mkstubs.pl src/dpwsockx_stubs.txt src/dpwsockx_stubs.s 3 perl mkstubs.pl src/dpwsockx_stubs.txt src/dpwsockx_stubs.s dpwsockx.dll
# #
# IPXCONFIG.EXE # IPXCONFIG.EXE
# #
IPXCONFIG_OBJS := src/ipxconfig.o icons/ipxconfig.o src/addr.o src/interface2.o src/common.o \ IPXCONFIG_OBJS := src/ipxconfig.o icons/ipxconfig.o src/addr.o src/interface2.o src/common.o \
src/config.o src/wpcap_stubs.o src/config.o src/ipxconfig_stubs.o src/funcprof.o
ipxconfig.exe: $(IPXCONFIG_OBJS) ipxconfig.exe: $(IPXCONFIG_OBJS)
$(CXX) $(CXXFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -static-libstdc++ -mwindows -o $@ $^ -liphlpapi -lcomctl32 -lws2_32 $(CXX) $(CXXFLAGS) -Wl,--enable-stdcall-fixup -static-libgcc -static-libstdc++ -mwindows -o $@ $^ -liphlpapi -lcomctl32 -lws2_32
src/ipxconfig_stubs.s: src/ipxwrapper_stubs.txt
perl mkstubs.pl src/ipxconfig_stubs.txt src/ipxconfig_stubs.s ipxconfig.exe
# #
# SHARED TARGETS # SHARED TARGETS
# #
src/wpcap_stubs.s: src/wpcap_stubs.txt
perl mkstubs.pl src/wpcap_stubs.txt src/wpcap_stubs.s 5
icons/%.o: icons/%.rc icons/%.ico icons/%.o: icons/%.rc icons/%.ico
$(WINDRES) $< -O coff -o $@ $(WINDRES) $< -O coff -o $@

View File

@ -1,5 +1,5 @@
# IPXWrapper - Generate assembly stub functions # IPXWrapper - Generate assembly stub functions
# Copyright (C) 2008-2011 Daniel Collins <solemnwarning@solemnwarning.net> # Copyright (C) 2008-2023 Daniel Collins <solemnwarning@solemnwarning.net>
# #
# This program is free software; you can redistribute it and/or modify it # This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 as published by # under the terms of the GNU General Public License version 2 as published by
@ -18,74 +18,268 @@ use strict;
use warnings; use warnings;
if(@ARGV != 3) { if(@ARGV != 3) {
print STDERR "Usage: mkdll.pl <function list> <output file> <dll number>\n"; print STDERR "Usage: mkdll.pl <stub definitions file> <asm output file> <dll name>\n";
exit(1); exit(1);
} }
my $stub_file = $ARGV[0]; # Must be kept in sync with dll_names in common.c!
my $asm_file = $ARGV[1]; my %DLL_INDICES = (
my $dllnum = $ARGV[2]; "ipxwrapper.dll" => 0,
my $do_logging = ($dllnum != 0); "wsock32.dll" => 1,
"mswsock.dll" => 2,
"dpwsockx.dll" => 3,
"ws2_32.dll" => 4,
"wpcap.dll" => 5,
"ipxconfig.exe" => 6,
);
my ($stub_file, $asm_file, $dll_name) = @ARGV;
my $dll_index = $DLL_INDICES{$dll_name}
// die "Unknown DLL name: $dll_name";
open(STUBS, "<$stub_file") or die("Cannot open $stub_file: $!"); open(STUBS, "<$stub_file") or die("Cannot open $stub_file: $!");
open(CODE, ">$asm_file") or die("Cannot open $asm_file: $!"); open(CODE, ">$asm_file") or die("Cannot open $asm_file: $!");
my @stubs = (); my @stubs = ();
my @stubs_dll = ();
foreach my $line(<STUBS>) { # Skip over header
(scalar <STUBS>);
(scalar <STUBS>);
# Read in stub definitions
foreach my $line(<STUBS>)
{
$line =~ s/[\r\n]//g; $line =~ s/[\r\n]//g;
if($line ne "") { if($line ne "") {
my ($func, $dn) = split(/:/, $line); my ($name, $target_dll, $target_func, $params) = split(/\s+/, $line);
$dn = $dllnum if(!defined($dn));
my $sym = $func; my $target_dll_index = $DLL_INDICES{$target_dll}
$sym =~ s/^r_//; // die "Unknown DLL: $target_dll\n";
push(@stubs, {"name" => $func, "sym" => $sym, "dllnum" => $dn}); push(@stubs, {
name => $name,
target_dll => $target_dll,
target_dll_index => $target_dll_index,
target_func => $target_func,
params => $params,
});
} }
} }
print CODE "section .rdata:\n"; print CODE <<"END";
extern _QueryPerformanceCounter\@4
foreach my $func(@stubs) { extern _find_sym
print CODE "\t".$func->{"name"}."_sym:\tdb\t'".$func->{"sym"}."', 0\n"; extern _log_call
extern _fprof_record_timed
extern _fprof_record_untimed
struc FuncStats
.func_name: resd 1
.min_time: resd 1
.max_time: resd 1
.total_time: resd 1
.n_calls: resd 1
.cs: resb 24
endstruc
END
print CODE <<"END";
section .rdata
END
foreach my $func(@stubs)
{
print CODE <<"END";
$func->{name}_name: db '$func->{name}', 0
$func->{name}_target_func: db '$func->{target_func}', 0
END
} }
print CODE "\nsection .data\n"; my $num_funcs = (scalar @stubs);
foreach my $func(@stubs) { print CODE <<"END";
print CODE "\t".$func->{"name"}."_addr:\tdd\t0\n"; global _NUM_STUBS
_NUM_STUBS: dd $num_funcs
DLL_NAME: db '$dll_name', 0
global _STUBS_DLL_NAME
_STUBS_DLL_NAME: dd DLL_NAME
END
print CODE <<"END";
section .data
global _stubs_enable_profile
_stubs_enable_profile: db 0
END
foreach my $func(@stubs)
{
print CODE <<"END";
$func->{name}_addr: dd 0
END
} }
print CODE "\nsection .text\n"; print CODE <<"END";
print CODE "\textern\t_find_sym\n"; global _stub_fstats
print CODE "\textern\t_log_call\n" if($do_logging); _stub_fstats:
END
foreach my $func(@stubs) { foreach my $func(@stubs)
my $f_name = $func->{"name"}; {
print CODE <<"END";
print CODE "\nglobal\t_$f_name\n"; $func->{name}_fstats:
print CODE "_$f_name:\n"; istruc FuncStats
at FuncStats.func_name, dd $func->{name}_name
if($do_logging) { iend
print CODE "\tpush\tdword ".$func->{"dllnum"}."\n"; END
print CODE "\tpush\t$f_name\_sym\n"; }
print CODE "\tpush\tdword $dllnum\n";
print CODE "\tcall\t_log_call\n"; print CODE <<"END";
section .text
END
foreach my $func(@stubs)
{
if(defined $func->{params})
{
my $to_copy = $func->{params};
print CODE <<"END";
global _$func->{name}
_$func->{name}:
; Log the call
push dword $func->{target_dll_index}
push $func->{name}_target_func
push dword $dll_index
call _log_call
; Check if we have address cached
cmp dword [$func->{name}_addr], 0
jne $func->{name}_go
; Fetch target function address
push $func->{name}_target_func
push dword $func->{target_dll_index}
call _find_sym
mov dword [$func->{name}_addr], eax
$func->{name}_go:
; Bypass the profiling code and jump straight into the taget
; function when not profiling.
cmp byte [_stubs_enable_profile], 0
je $func->{name}_skip
push ebp
mov ebp, esp
; Push tick count onto stack (ebp - 8)
sub esp, 8
push esp
call _QueryPerformanceCounter\@4
; Copy original arguments ($to_copy bytes)
END
for(; $to_copy >= 4;)
{
$to_copy -= 4;
print CODE <<"END";
push dword [ebp + 4 + 4 + $to_copy]
END
}
for(; $to_copy >= 2;)
{
$to_copy -= 2;
print CODE <<"END";
push word [ebp + 4 + 4 + $to_copy]
END
}
for(; $to_copy >= 1;)
{
$to_copy -= 1;
print CODE <<"END";
push byte [ebp + 4 + 4 + $to_copy]
END
}
print CODE <<"END";
; Call target function
call [$func->{name}_addr]
; Push target function return value onto stack (ebp - 12)
push eax
; Push tick count onto stack (ebp - 20)
sub esp, 8
push esp
call _QueryPerformanceCounter\@4
; End tick parameter to _fprof_record_timed
push dword ebp
sub dword [esp], 20
; Start tick parameter to _fprof_record_timed
push dword ebp
sub dword [esp], 8
; FuncStats parameter to _fprof_record_timed
push dword $func->{name}_fstats
; Record profiling data
call _fprof_record_timed
add esp, 8 ; Pop end tick count
pop eax ; Pop return value
add esp, 8 ; Pop start tick count
pop ebp ; Restore caller's ebp
ret $func->{params}
$func->{name}_skip:
jmp [$func->{name}_addr]
END
}
else{
print CODE <<"END";
global _$func->{name}
_$func->{name}:
; Log the call
push dword $func->{target_dll_index}
push $func->{name}_target_func
push dword $dll_index
call _log_call
; Check if we have address cached
cmp dword [$func->{name}_addr], 0
jne $func->{name}_go
; Fetch target function address
push $func->{name}_target_func
push dword $func->{target_dll_index}
call _find_sym
mov dword [$func->{name}_addr], eax
$func->{name}_go:
; Record that we were called
push dword $func->{name}_fstats
call _fprof_record_untimed
; Jump into target function. We have left the stack as we found it
; so it can take over our frame.
jmp [$func->{name}_addr]
END
} }
print CODE "\tcmp\tdword [$f_name\_addr], 0\n";
print CODE "\tjne\t$f_name\_jmp\n";
print CODE "\tpush\t$f_name\_sym\n";
print CODE "\tpush\tdword ".$func->{"dllnum"}."\n";
print CODE "\tcall\t_find_sym\n";
print CODE "\tmov\t[$f_name\_addr], eax\n";
print CODE "\t$f_name\_jmp:\n";
print CODE "\tjmp\t[$f_name\_addr]\n";
} }
close(CODE); close(CODE);

View File

@ -1,5 +1,5 @@
/* IPXWrapper - Common functions /* IPXWrapper - Common functions
* Copyright (C) 2011-2021 Daniel Collins <solemnwarning@solemnwarning.net> * Copyright (C) 2011-2023 Daniel Collins <solemnwarning@solemnwarning.net>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by * under the terms of the GNU General Public License version 2 as published by
@ -23,6 +23,7 @@
enum ipx_log_level min_log_level = LOG_INFO; enum ipx_log_level min_log_level = LOG_INFO;
/* Must be kept in sync with DLL_INDICES in mkstubs.pl! */
static const char *dll_names[] = { static const char *dll_names[] = {
"ipxwrapper.dll", "ipxwrapper.dll",
"wsock32.dll", "wsock32.dll",
@ -30,6 +31,7 @@ static const char *dll_names[] = {
"dpwsockx.dll", "dpwsockx.dll",
"ws2_32.dll", "ws2_32.dll",
"wpcap.dll", "wpcap.dll",
"ipxconfig.exe",
NULL NULL
}; };

View File

@ -24,6 +24,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "addr.h" #include "addr.h"
#include "funcprof.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -39,6 +40,12 @@ enum ipx_log_level {
extern enum ipx_log_level min_log_level; extern enum ipx_log_level min_log_level;
/* Defined by stubs */
extern struct FuncStats stub_fstats[];
extern const unsigned int NUM_STUBS;
extern const char *STUBS_DLL_NAME;
extern unsigned char stubs_enable_profile;
const char *w32_error(DWORD errnum); const char *w32_error(DWORD errnum);
HKEY reg_open_main(bool readwrite); HKEY reg_open_main(bool readwrite);

View File

@ -33,6 +33,7 @@ main_config_t get_main_config(void)
config.encap_type = ENCAP_TYPE_IPXWRAPPER; config.encap_type = ENCAP_TYPE_IPXWRAPPER;
config.frame_type = FRAME_TYPE_ETH_II; config.frame_type = FRAME_TYPE_ETH_II;
config.log_level = LOG_INFO; config.log_level = LOG_INFO;
config.profile = false;
config.dosbox_server_addr = NULL; config.dosbox_server_addr = NULL;
config.dosbox_server_port = 213; config.dosbox_server_port = 213;
@ -59,6 +60,7 @@ main_config_t get_main_config(void)
config.encap_type = reg_get_dword(reg, "use_pcap", config.encap_type); config.encap_type = reg_get_dword(reg, "use_pcap", config.encap_type);
config.frame_type = reg_get_dword(reg, "frame_type", config.frame_type); config.frame_type = reg_get_dword(reg, "frame_type", config.frame_type);
config.log_level = reg_get_dword(reg, "log_level", config.log_level); config.log_level = reg_get_dword(reg, "log_level", config.log_level);
config.profile = reg_get_dword(reg, "profile", config.profile);
config.dosbox_server_addr = reg_get_string(reg, "dosbox_server_addr", ""); config.dosbox_server_addr = reg_get_string(reg, "dosbox_server_addr", "");
config.dosbox_server_port = reg_get_dword(reg, "dosbox_server_port", config.dosbox_server_port); config.dosbox_server_port = reg_get_dword(reg, "dosbox_server_port", config.dosbox_server_port);
@ -91,6 +93,7 @@ bool set_main_config(const main_config_t *config)
&& reg_set_dword(reg, "use_pcap", config->encap_type) && reg_set_dword(reg, "use_pcap", config->encap_type)
&& reg_set_dword(reg, "frame_type", config->frame_type) && reg_set_dword(reg, "frame_type", config->frame_type)
&& reg_set_dword(reg, "log_level", config->log_level) && reg_set_dword(reg, "log_level", config->log_level)
&& reg_set_dword(reg, "profile", config->profile)
&& reg_set_string(reg, "dosbox_server_addr", config->dosbox_server_addr) && reg_set_string(reg, "dosbox_server_addr", config->dosbox_server_addr)
&& reg_set_dword(reg, "dosbox_server_port", config->dosbox_server_port); && reg_set_dword(reg, "dosbox_server_port", config->dosbox_server_port);

View File

@ -52,6 +52,7 @@ typedef struct main_config {
uint16_t dosbox_server_port; uint16_t dosbox_server_port;
enum ipx_log_level log_level; enum ipx_log_level log_level;
bool profile;
} main_config_t; } main_config_t;
struct v1_global_config { struct v1_global_config {

View File

@ -1,5 +1,5 @@
/* ipxwrapper - DirectPlay service provider /* ipxwrapper - DirectPlay service provider
* Copyright (C) 2011 Daniel Collins <solemnwarning@solemnwarning.net> * Copyright (C) 2011-2019 Daniel Collins <solemnwarning@solemnwarning.net>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by * under the terms of the GNU General Public License version 2 as published by
@ -725,6 +725,8 @@ HRESULT WINAPI SPInit(LPSPINITDATA data) {
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
if(fdwReason == DLL_PROCESS_ATTACH) if(fdwReason == DLL_PROCESS_ATTACH)
{ {
fprof_init(stub_fstats, NUM_STUBS);
log_open("ipxwrapper.log"); log_open("ipxwrapper.log");
min_log_level = get_main_config().log_level; min_log_level = get_main_config().log_level;
@ -743,6 +745,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
unload_dlls(); unload_dlls();
log_close(); log_close();
fprof_cleanup(stub_fstats, NUM_STUBS);
} }
return TRUE; return TRUE;

View File

@ -1,9 +1,10 @@
r_SPInit Function name Target DLL Target function
DPWS_GetEnumPort ------------------------------------------------------------
DPWS_BuildIPMessageHeader r_SPInit dpwsockx.dll SPInit
DPWS_GetEnumPort dpwsockx.dll DPWS_GetEnumPort
WSACreateEvent:4 DPWS_BuildIPMessageHeader dpwsockx.dll DPWS_BuildIPMessageHeader
WSACloseEvent:4 WSACreateEvent ws2_32.dll WSACreateEvent
WSAEventSelect:4 WSACloseEvent ws2_32.dll WSACloseEvent
WSAResetEvent:4 WSAEventSelect ws2_32.dll WSAEventSelect
WSASetEvent:4 WSAResetEvent ws2_32.dll WSAResetEvent
WSASetEvent ws2_32.dll WSASetEvent

129
src/funcprof.c Normal file
View File

@ -0,0 +1,129 @@
/* IPXWrapper - Function profiling functions
* Copyright (C) 2019 Daniel Collins <solemnwarning@solemnwarning.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <windows.h>
#include "common.h"
#include "funcprof.h"
void fprof_init(struct FuncStats *fstats, size_t n_fstats)
{
for(size_t i = 0; i < n_fstats; ++i)
{
fstats[i].min_time = 0.0;
fstats[i].max_time = 0.0;
fstats[i].total_time = 0.0;
fstats[i].n_calls = 0;
InitializeCriticalSectionAndSpinCount(&(fstats[i].cs), 0x80000000);
}
}
void fprof_cleanup(struct FuncStats *fstats, size_t n_fstats)
{
for(size_t i = 0; i < n_fstats; ++i)
{
DeleteCriticalSection(&(fstats[i].cs));
}
}
__stdcall void fprof_record_timed(struct FuncStats *fstats, const LARGE_INTEGER *start, const LARGE_INTEGER *end)
{
EnterCriticalSection(&(fstats->cs));
float this_time = end->QuadPart - start->QuadPart;
if(fstats->n_calls == 0)
{
fstats->min_time = this_time;
fstats->max_time = this_time;
fstats->total_time = this_time;
}
else{
if(fstats->min_time > this_time)
{
fstats->min_time = this_time;
}
if(fstats->max_time < this_time)
{
fstats->max_time = this_time;
}
fstats->total_time += this_time;
}
++(fstats->n_calls);
LeaveCriticalSection(&(fstats->cs));
}
__stdcall void fprof_record_untimed(struct FuncStats *fstats)
{
EnterCriticalSection(&(fstats->cs));
++(fstats->n_calls);
LeaveCriticalSection(&(fstats->cs));
}
void fprof_report(const char *dll_name, struct FuncStats *fstats, size_t n_fstats)
{
LARGE_INTEGER freq; /* TODO: Cache somewhere */
QueryPerformanceFrequency(&freq);
const float TICKS_PER_USEC = freq.QuadPart / 1000000.0;
for(size_t i = 0; i < n_fstats; ++i)
{
EnterCriticalSection(&(fstats[i].cs));
float min_time = fstats[i].min_time;
float max_time = fstats[i].max_time;
float total_time = fstats[i].total_time;
unsigned int n_calls = fstats[i].n_calls;
fstats[i].n_calls = 0;
LeaveCriticalSection(&(fstats[i].cs));
if(n_calls > 0)
{
if(total_time > 0.0)
{
log_printf(LOG_INFO,
"%s:%s was called %u times duration total %fus min %fus max %fus avg %fus",
dll_name,
fstats[i].func_name,
n_calls,
(total_time / TICKS_PER_USEC),
(min_time / TICKS_PER_USEC),
(max_time / TICKS_PER_USEC),
((total_time / (float)(n_calls)) / TICKS_PER_USEC));
}
else{
log_printf(LOG_INFO,
"%s:%s was called %u times",
dll_name,
fstats[i].func_name,
n_calls);
}
}
}
}

64
src/funcprof.h Normal file
View File

@ -0,0 +1,64 @@
/* IPXWrapper - Function profiling functions
* Copyright (C) 2019 Daniel Collins <solemnwarning@solemnwarning.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef IPXWRAPPER_FUNCPROF_H
#define IPXWRAPPER_FUNCPROF_H
#include <windows.h>
#ifdef __cplusplus
extern "C" {
#endif
struct FuncStats
{
const char *func_name;
float min_time, max_time, total_time;
unsigned int n_calls;
CRITICAL_SECTION cs;
};
void fprof_init(struct FuncStats *fstats, size_t n_fstats);
void fprof_cleanup(struct FuncStats *fstats, size_t n_fstats);
__stdcall void fprof_record_timed(struct FuncStats *fstats, const LARGE_INTEGER *start, const LARGE_INTEGER *end);
__stdcall void fprof_record_untimed(struct FuncStats *fstats);
void fprof_report(const char *dll_name, struct FuncStats *fstats, size_t n_fstats);
#define FPROF_RECORD_SCOPE(fstats) \
__attribute__((cleanup (_fprof_record_scope_exit))) struct _fprof_record_scope_ctx fstats_scoped_ctx = { fstats }; \
QueryPerformanceCounter(&(fstats_scoped_ctx.enter_time));
struct _fprof_record_scope_ctx {
struct FuncStats *fstats;
LARGE_INTEGER enter_time;
};
static inline void _fprof_record_scope_exit(struct _fprof_record_scope_ctx *ctx)
{
LARGE_INTEGER leave_time;
QueryPerformanceCounter(&leave_time);
fprof_record_timed(ctx->fstats, &(ctx->enter_time), &leave_time);
}
#ifdef __cplusplus
}
#endif
#endif /* !IPXWRAPPER_FUNCPROF_H */

View File

@ -1,5 +1,5 @@
/* IPXWrapper - Configuration tool /* IPXWrapper - Configuration tool
* Copyright (C) 2011-2022 Daniel Collins <solemnwarning@solemnwarning.net> * Copyright (C) 2011-2023 Daniel Collins <solemnwarning@solemnwarning.net>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by * under the terms of the GNU General Public License version 2 as published by
@ -41,6 +41,7 @@ enum {
ID_OPT_W95 = 22, ID_OPT_W95 = 22,
ID_OPT_LOG_DEBUG = 25, ID_OPT_LOG_DEBUG = 25,
ID_OPT_LOG_TRACE = 26, ID_OPT_LOG_TRACE = 26,
ID_OPT_PROFILE = 27,
ID_OK = 31, ID_OK = 31,
ID_CANCEL = 32, ID_CANCEL = 32,
@ -142,6 +143,7 @@ static struct {
HWND opt_w95; HWND opt_w95;
HWND opt_log_debug; HWND opt_log_debug;
HWND opt_log_trace; HWND opt_log_trace;
HWND opt_profile;
HWND ok_btn; HWND ok_btn;
HWND can_btn; HWND can_btn;
@ -257,6 +259,8 @@ static LRESULT CALLBACK groupbox_wproc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp
int main() int main()
{ {
fprof_init(stub_fstats, NUM_STUBS);
INITCOMMONCONTROLSEX common_controls; INITCOMMONCONTROLSEX common_controls;
common_controls.dwSize = sizeof(common_controls); common_controls.dwSize = sizeof(common_controls);
common_controls.dwICC = ICC_LISTVIEW_CLASSES; common_controls.dwICC = ICC_LISTVIEW_CLASSES;
@ -316,6 +320,8 @@ int main()
} }
} }
fprof_cleanup(stub_fstats, NUM_STUBS);
return msg.wParam; return msg.wParam;
} }
@ -584,6 +590,8 @@ static bool save_config()
} }
} }
main_config.profile = get_checkbox(wh.opt_profile);
if(main_config.encap_type == ENCAP_TYPE_IPXWRAPPER || main_config.encap_type == ENCAP_TYPE_PCAP) if(main_config.encap_type == ENCAP_TYPE_IPXWRAPPER || main_config.encap_type == ENCAP_TYPE_PCAP)
{ {
for(auto i = nics.begin(); i != nics.end(); i++) for(auto i = nics.begin(); i != nics.end(); i++)
@ -792,6 +800,7 @@ static void main_window_init()
* | Enable Windows 95 SO_BROADCAST bug | * | Enable Windows 95 SO_BROADCAST bug |
* | Log debugging messages | * | Log debugging messages |
* | Log WinSock API calls | * | Log WinSock API calls |
* | Log profiling counters |
* +---------------------------------------------------------+ * +---------------------------------------------------------+
*/ */
@ -801,10 +810,12 @@ static void main_window_init()
wh.opt_w95 = create_checkbox(wh.box_options, "Enable Windows 95 SO_BROADCAST bug", ID_OPT_W95); wh.opt_w95 = create_checkbox(wh.box_options, "Enable Windows 95 SO_BROADCAST bug", ID_OPT_W95);
wh.opt_log_debug = create_checkbox(wh.box_options, "Log debugging messages", ID_OPT_LOG_DEBUG); wh.opt_log_debug = create_checkbox(wh.box_options, "Log debugging messages", ID_OPT_LOG_DEBUG);
wh.opt_log_trace = create_checkbox(wh.box_options, "Log WinSock API calls", ID_OPT_LOG_TRACE); wh.opt_log_trace = create_checkbox(wh.box_options, "Log WinSock API calls", ID_OPT_LOG_TRACE);
wh.opt_profile = create_checkbox(wh.box_options, "Log profiling counters", ID_OPT_PROFILE);
set_checkbox(wh.opt_w95, main_config.w95_bug); set_checkbox(wh.opt_w95, main_config.w95_bug);
set_checkbox(wh.opt_log_debug, main_config.log_level <= LOG_DEBUG); set_checkbox(wh.opt_log_debug, main_config.log_level <= LOG_DEBUG);
set_checkbox(wh.opt_log_trace, main_config.log_level <= LOG_CALL); set_checkbox(wh.opt_log_trace, main_config.log_level <= LOG_CALL);
set_checkbox(wh.opt_profile, main_config.profile);
} }
wh.ok_btn = create_child(wh.main, "BUTTON", "OK", BS_PUSHBUTTON | WS_TABSTOP, 0, ID_OK); wh.ok_btn = create_child(wh.main, "BUTTON", "OK", BS_PUSHBUTTON | WS_TABSTOP, 0, ID_OK);
@ -978,6 +989,9 @@ static void main_window_init()
MoveWindow(wh.opt_log_trace, BOX_SIDE_PAD, box_options_y, BOX_INNER_WIDTH, text_h, TRUE); MoveWindow(wh.opt_log_trace, BOX_SIDE_PAD, box_options_y, BOX_INNER_WIDTH, text_h, TRUE);
box_options_y += text_h + 2; box_options_y += text_h + 2;
MoveWindow(wh.opt_profile, BOX_SIDE_PAD, box_options_y, BOX_INNER_WIDTH, text_h, TRUE);
box_options_y += text_h + 2;
int box_options_h = box_options_y + BOX_BOTTOM_PAD; int box_options_h = box_options_y + BOX_BOTTOM_PAD;
MoveWindow(wh.box_options, BOX_SIDE_MARGIN, 0, BOX_WIDTH, box_options_h, TRUE); MoveWindow(wh.box_options, BOX_SIDE_MARGIN, 0, BOX_WIDTH, box_options_h, TRUE);

10
src/ipxconfig_stubs.txt Normal file
View File

@ -0,0 +1,10 @@
Function name Target DLL Target function Parameters (bytes)
-----------------------------------------------------------------------------
pcap_open wpcap.dll pcap_open
pcap_close wpcap.dll pcap_close
pcap_findalldevs_ex wpcap.dll pcap_findalldevs_ex
pcap_freealldevs wpcap.dll pcap_freealldevs
pcap_getevent wpcap.dll pcap_getevent
pcap_dispatch wpcap.dll pcap_dispatch
pcap_geterr wpcap.dll pcap_geterr
pcap_sendpacket wpcap.dll pcap_sendpacket

View File

@ -30,6 +30,7 @@
#include "ipxwrapper.h" #include "ipxwrapper.h"
#include "common.h" #include "common.h"
#include "funcprof.h"
#include "interface.h" #include "interface.h"
#include "router.h" #include "router.h"
#include "addrcache.h" #include "addrcache.h"
@ -50,6 +51,17 @@ static CRITICAL_SECTION sockets_cs;
typedef ULONGLONG WINAPI (*GetTickCount64_t)(void); typedef ULONGLONG WINAPI (*GetTickCount64_t)(void);
static HMODULE kernel32 = NULL; static HMODULE kernel32 = NULL;
struct FuncStats ipxwrapper_fstats[] = {
#define FPROF_DECL(func) { #func },
#include "ipxwrapper_prof_defs.h"
#undef FPROF_DECL
};
const unsigned int ipxwrapper_fstats_size = sizeof(ipxwrapper_fstats) / sizeof(*ipxwrapper_fstats);
unsigned int send_packets = 0, send_bytes = 0; /* Sent from emulated socket */
unsigned int recv_packets = 0, recv_bytes = 0; /* Forwarded to emulated socket */
static void init_cs(CRITICAL_SECTION *cs) static void init_cs(CRITICAL_SECTION *cs)
{ {
if(!InitializeCriticalSectionAndSpinCount(cs, 0x80000000)) if(!InitializeCriticalSectionAndSpinCount(cs, 0x80000000))
@ -59,10 +71,42 @@ static void init_cs(CRITICAL_SECTION *cs)
} }
} }
static HANDLE prof_thread_handle = NULL;
static HANDLE prof_thread_exit = NULL;
static void report_packet_stats(void)
{
unsigned int my_send_packets = __atomic_exchange_n(&send_packets, 0, __ATOMIC_RELAXED);
unsigned int my_send_bytes = __atomic_exchange_n(&send_bytes, 0, __ATOMIC_RELAXED);
unsigned int my_recv_packets = __atomic_exchange_n(&recv_packets, 0, __ATOMIC_RELAXED);
unsigned int my_recv_bytes = __atomic_exchange_n(&recv_bytes, 0, __ATOMIC_RELAXED);
log_printf(LOG_INFO, "IPX sockets sent %u packets (%u bytes)", my_send_packets, my_send_bytes);
log_printf(LOG_INFO, "IPX sockets received %u packets (%u bytes)", my_recv_packets, my_recv_bytes);
}
static DWORD WINAPI prof_thread_main(LPVOID lpParameter)
{
static const int PROF_INTERVAL_MS = 10000;
while(WaitForSingleObject(prof_thread_exit, PROF_INTERVAL_MS) == WAIT_TIMEOUT)
{
fprof_report(STUBS_DLL_NAME, stub_fstats, NUM_STUBS);
fprof_report("ipxwrapper.dll", ipxwrapper_fstats, ipxwrapper_fstats_size);
report_packet_stats();
}
return 0;
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{ {
if(fdwReason == DLL_PROCESS_ATTACH) if(fdwReason == DLL_PROCESS_ATTACH)
{ {
fprof_init(stub_fstats, NUM_STUBS);
fprof_init(ipxwrapper_fstats, ipxwrapper_fstats_size);
log_open("ipxwrapper.log"); log_open("ipxwrapper.log");
log_printf(LOG_INFO, "IPXWrapper %s", version_string); log_printf(LOG_INFO, "IPXWrapper %s", version_string);
@ -104,6 +148,35 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
} }
router_init(); router_init();
if(main_config.profile)
{
stubs_enable_profile = true;
prof_thread_exit = CreateEvent(NULL, FALSE, FALSE, NULL);
if(prof_thread_exit != NULL)
{
prof_thread_handle = CreateThread(
NULL, /* lpThreadAttributes */
0, /* dwStackSize */
&prof_thread_main, /* lpStartAddress */
NULL, /* lpParameter */
0, /* dwCreationFlags */
NULL); /* lpThreadId */
if(prof_thread_handle == NULL)
{
log_printf(LOG_ERROR,
"Unable to create prof_thread_main thread: %s",
w32_error(GetLastError()));
}
}
else{
log_printf(LOG_ERROR,
"Unable to create prof_thread_exit event object: %s",
w32_error(GetLastError()));
}
}
} }
else if(fdwReason == DLL_PROCESS_DETACH) else if(fdwReason == DLL_PROCESS_DETACH)
{ {
@ -117,6 +190,22 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
return TRUE; return TRUE;
} }
if(prof_thread_exit != NULL)
{
SetEvent(prof_thread_exit);
if(prof_thread_handle != NULL)
{
WaitForSingleObject(prof_thread_handle, INFINITE);
CloseHandle(prof_thread_handle);
prof_thread_handle = NULL;
}
CloseHandle(prof_thread_exit);
prof_thread_exit = NULL;
}
router_cleanup(); router_cleanup();
WSACleanup(); WSACleanup();
@ -129,6 +218,14 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
unload_dlls(); unload_dlls();
if(main_config.profile)
{
fprof_report(STUBS_DLL_NAME, stub_fstats, NUM_STUBS);
fprof_report("ipxwrapper.dll", ipxwrapper_fstats, ipxwrapper_fstats_size);
report_packet_stats();
}
log_close(); log_close();
if(kernel32) if(kernel32)
@ -136,6 +233,9 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
FreeLibrary(kernel32); FreeLibrary(kernel32);
kernel32 = NULL; kernel32 = NULL;
} }
fprof_cleanup(ipxwrapper_fstats, ipxwrapper_fstats_size);
fprof_cleanup(stub_fstats, NUM_STUBS);
} }
return TRUE; return TRUE;
@ -181,6 +281,7 @@ ipx_socket *get_socket_wait_for_ready(SOCKET sockfd, int timeout_ms)
/* Lock the mutex */ /* Lock the mutex */
void lock_sockets(void) void lock_sockets(void)
{ {
FPROF_RECORD_SCOPE(&(ipxwrapper_fstats[IPXWRAPPER_FSTATS_lock_sockets]));
EnterCriticalSection(&sockets_cs); EnterCriticalSection(&sockets_cs);
} }

View File

@ -27,6 +27,7 @@
#include <uthash.h> #include <uthash.h>
#include "config.h" #include "config.h"
#include "funcprof.h"
#include "router.h" #include "router.h"
/* The standard Windows driver (in XP) only allows 1467 bytes anyway */ /* The standard Windows driver (in XP) only allows 1467 bytes anyway */
@ -188,6 +189,17 @@ struct spxinit
extern ipx_socket *sockets; extern ipx_socket *sockets;
extern main_config_t main_config; extern main_config_t main_config;
extern struct FuncStats ipxwrapper_fstats[];
enum {
#define FPROF_DECL(func) IPXWRAPPER_FSTATS_ ## func,
#include "ipxwrapper_prof_defs.h"
#undef FPROF_DECL
};
extern unsigned int send_packets, send_bytes; /* Sent from emulated socket */
extern unsigned int recv_packets, recv_bytes; /* Forwarded to emulated socket */
ipx_socket *get_socket(SOCKET sockfd); ipx_socket *get_socket(SOCKET sockfd);
ipx_socket *get_socket_wait_for_ready(SOCKET sockfd, int timeout_ms); ipx_socket *get_socket_wait_for_ready(SOCKET sockfd, int timeout_ms);
void lock_sockets(void); void lock_sockets(void);

View File

@ -0,0 +1,5 @@
FPROF_DECL(_deliver_packet)
FPROF_DECL(_handle_udp_recv)
FPROF_DECL(_handle_dosbox_recv)
FPROF_DECL(_handle_pcap_frame)
FPROF_DECL(lock_sockets)

View File

@ -1,38 +1,49 @@
inet_addr:4 Function name Target DLL Target function Parameters (bytes)
WSAStartup:4 -------------------------------------------------------------------------------
WSACleanup:4 inet_addr ws2_32.dll inet_addr 4
WSASetLastError:4 WSAStartup ws2_32.dll WSAStartup 8
WSAGetLastError:4 WSACleanup ws2_32.dll WSACleanup 0
htonl:4 WSASetLastError ws2_32.dll WSASetLastError 4
ntohl:4 WSAGetLastError ws2_32.dll WSAGetLastError 0
htons:4 htonl ws2_32.dll htonl 4
ntohs:4 ntohl ws2_32.dll ntohl 4
r_select:4 htons ws2_32.dll htons 4
r_listen:4 ntohs ws2_32.dll ntohs 4
r_accept:4 r_select ws2_32.dll select 20
WSACreateEvent:4 r_listen ws2_32.dll listen 8
WSAEventSelect:4 r_accept ws2_32.dll accept 12
WSACloseEvent:4 WSACreateEvent ws2_32.dll WSACreateEvent 0
WSAResetEvent:4 WSAEventSelect ws2_32.dll WSAEventSelect 12
WSASetEvent:4 WSACloseEvent ws2_32.dll WSACloseEvent 4
r_EnumProtocolsA:2 WSAResetEvent ws2_32.dll WSAResetEvent 4
r_EnumProtocolsW:2 WSASetEvent ws2_32.dll WSASetEvent 4
r_WSARecvEx:2 r_EnumProtocolsA mswsock.dll EnumProtocolsA 12
r_bind:4 r_EnumProtocolsW mswsock.dll EnumProtocolsW 12
r_closesocket:4 r_WSARecvEx mswsock.dll WSARecvEx 16
r_getsockname:4 r_bind ws2_32.dll bind 12
r_getsockopt:4 r_closesocket ws2_32.dll closesocket 4
r_recv:4 r_getsockname ws2_32.dll getsockname 12
r_recvfrom:4 r_getsockopt ws2_32.dll getsockopt 20
r_sendto:4 r_recv ws2_32.dll recv 16
r_setsockopt:4 r_recvfrom ws2_32.dll recvfrom 24
r_shutdown:4 r_sendto ws2_32.dll sendto 24
r_socket:4 r_setsockopt ws2_32.dll setsockopt 20
r_ioctlsocket:4 r_shutdown ws2_32.dll shutdown 8
r_connect:4 r_socket ws2_32.dll socket 12
r_send:4 r_ioctlsocket ws2_32.dll ioctlsocket 12
r_getpeername:4 r_connect ws2_32.dll connect 12
inet_ntoa:4 r_send ws2_32.dll send 16
__WSAFDIsSet:4 r_getpeername ws2_32.dll getpeername 12
r_WSAAsyncSelect:4 inet_ntoa ws2_32.dll inet_ntoa 4
gethostbyname:4 __WSAFDIsSet ws2_32.dll __WSAFDIsSet 8
r_WSAAsyncSelect ws2_32.dll WSAAsyncSelect 16
gethostbyname ws2_32.dll gethostbyname 4
pcap_open wpcap.dll pcap_open
pcap_close wpcap.dll pcap_close
pcap_findalldevs_ex wpcap.dll pcap_findalldevs_ex
pcap_freealldevs wpcap.dll pcap_freealldevs
pcap_getevent wpcap.dll pcap_getevent
pcap_dispatch wpcap.dll pcap_dispatch
pcap_geterr wpcap.dll pcap_geterr
pcap_sendpacket wpcap.dll pcap_sendpacket

View File

@ -1,35 +1,37 @@
ServiceMain Function name Target DLL Target function Parameters (bytes)
SvchostPushServiceGlobals --------------------------------------------------------------------------------------------------
AcceptEx ServiceMain mswsock.dll ServiceMain
EnumProtocolsA:0 SvchostPushServiceGlobals mswsock.dll SvchostPushServiceGlobals
EnumProtocolsW:0 AcceptEx mswsock.dll AcceptEx 32
GetAcceptExSockaddrs EnumProtocolsA ipxwrapper.dll EnumProtocolsA 12
GetAddressByNameA EnumProtocolsW ipxwrapper.dll EnumProtocolsW 12
GetAddressByNameW GetAcceptExSockaddrs mswsock.dll GetAcceptExSockaddrs 32
GetNameByTypeA GetAddressByNameA mswsock.dll GetAddressByNameA 40
GetNameByTypeW GetAddressByNameW mswsock.dll GetAddressByNameW 40
GetServiceA GetNameByTypeA mswsock.dll GetNameByTypeA 12
GetServiceW GetNameByTypeW mswsock.dll GetNameByTypeW 12
GetTypeByNameA GetServiceA mswsock.dll GetServiceA 28
GetTypeByNameW GetServiceW mswsock.dll GetServiceW 28
MigrateWinsockConfiguration GetTypeByNameA mswsock.dll GetTypeByNameA 8
NPLoadNameSpaces GetTypeByNameW mswsock.dll GetTypeByNameW 8
NSPStartup MigrateWinsockConfiguration mswsock.dll MigrateWinsockConfiguration
SetServiceA NPLoadNameSpaces mswsock.dll NPLoadNameSpaces
SetServiceW NSPStartup mswsock.dll NSPStartup 8
StartWsdpService SetServiceA mswsock.dll SetServiceA 24
StopWsdpService SetServiceW mswsock.dll SetServiceW 24
TransmitFile StartWsdpService mswsock.dll StartWsdpService
WSARecvEx:0 StopWsdpService mswsock.dll StopWsdpService
WSPStartup TransmitFile mswsock.dll TransmitFile 28
dn_expand WSARecvEx ipxwrapper.dll WSARecvEx 16
getnetbyname WSPStartup mswsock.dll WSPStartup 76
inet_network dn_expand mswsock.dll dn_expand
rcmd getnetbyname mswsock.dll getnetbyname
rexec inet_network mswsock.dll inet_network
rresvport rcmd mswsock.dll rcmd
s_perror rexec mswsock.dll rexec
sethostname rresvport mswsock.dll rresvport
inet_addr s_perror mswsock.dll s_perror
WSHEnumProtocols:0 sethostname mswsock.dll sethostname
ntohs:1 inet_addr mswsock.dll inet_addr 4
WSHEnumProtocols ipxwrapper.dll WSHEnumProtocols 16
ntohs wsock32.dll ntohs 4

View File

@ -26,6 +26,7 @@
#include "router.h" #include "router.h"
#include "common.h" #include "common.h"
#include "funcprof.h"
#include "ipxwrapper.h" #include "ipxwrapper.h"
#include "interface.h" #include "interface.h"
#include "addrcache.h" #include "addrcache.h"
@ -230,6 +231,8 @@ static void _deliver_packet(
const void *data, const void *data,
size_t data_size) size_t data_size)
{ {
FPROF_RECORD_SCOPE(&(ipxwrapper_fstats[IPXWRAPPER_FSTATS__deliver_packet]));
{ {
IPX_STRING_ADDR(src_addr, src_net, src_node, src_socket); IPX_STRING_ADDR(src_addr, src_net, src_node, src_socket);
IPX_STRING_ADDR(dest_addr, dest_net, dest_node, dest_socket); IPX_STRING_ADDR(dest_addr, dest_net, dest_node, dest_socket);
@ -344,6 +347,10 @@ static void _deliver_packet(
{ {
log_printf(LOG_ERROR, "Error relaying packet: %s", w32_error(WSAGetLastError())); log_printf(LOG_ERROR, "Error relaying packet: %s", w32_error(WSAGetLastError()));
} }
else{
__atomic_add_fetch(&recv_packets, 1, __ATOMIC_RELAXED);
__atomic_add_fetch(&recv_bytes, data_size, __ATOMIC_RELAXED);
}
free(packet); free(packet);
} }
@ -353,6 +360,8 @@ static void _deliver_packet(
static void _handle_udp_recv(ipx_packet *packet, size_t packet_size, struct sockaddr_in src_ip) static void _handle_udp_recv(ipx_packet *packet, size_t packet_size, struct sockaddr_in src_ip)
{ {
FPROF_RECORD_SCOPE(&(ipxwrapper_fstats[IPXWRAPPER_FSTATS__handle_udp_recv]));
size_t data_size = ntohs(packet->size); size_t data_size = ntohs(packet->size);
if(packet_size < sizeof(ipx_packet) - 1 || data_size > MAX_DATA_SIZE || data_size + sizeof(ipx_packet) - 1 != packet_size) if(packet_size < sizeof(ipx_packet) - 1 || data_size > MAX_DATA_SIZE || data_size + sizeof(ipx_packet) - 1 != packet_size)
@ -536,6 +545,8 @@ static void _handle_dosbox_registration_response(novell_ipx_packet *packet, size
static void _handle_dosbox_recv(novell_ipx_packet *packet, size_t packet_size) static void _handle_dosbox_recv(novell_ipx_packet *packet, size_t packet_size)
{ {
FPROF_RECORD_SCOPE(&(ipxwrapper_fstats[IPXWRAPPER_FSTATS__handle_dosbox_recv]));
if(packet_size < sizeof(novell_ipx_packet) || ntohs(packet->length) != packet_size) if(packet_size < sizeof(novell_ipx_packet) || ntohs(packet->length) != packet_size)
{ {
/* Doesn't look valid. */ /* Doesn't look valid. */
@ -617,6 +628,8 @@ static bool _do_udp_recv(int fd)
static void _handle_pcap_frame(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data) static void _handle_pcap_frame(u_char *user, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data)
{ {
FPROF_RECORD_SCOPE(&(ipxwrapper_fstats[IPXWRAPPER_FSTATS__handle_pcap_frame]));
ipx_interface_t *iface = (ipx_interface_t*)(user); ipx_interface_t *iface = (ipx_interface_t*)(user);
const novell_ipx_packet *ipx; const novell_ipx_packet *ipx;

View File

@ -1,5 +1,5 @@
/* IPXWrapper - Stub DLL functions /* IPXWrapper - Stub DLL functions
* Copyright (C) 2008-2011 Daniel Collins <solemnwarning@solemnwarning.net> * Copyright (C) 2008-2023 Daniel Collins <solemnwarning@solemnwarning.net>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by * under the terms of the GNU General Public License version 2 as published by
@ -21,13 +21,52 @@
#include "common.h" #include "common.h"
#include "config.h" #include "config.h"
#include "funcprof.h"
static DWORD WINAPI prof_thread_main(LPVOID lpParameter);
static HANDLE prof_thread_handle = NULL;
static HANDLE prof_thread_exit = NULL;
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
if(fdwReason == DLL_PROCESS_ATTACH) if(fdwReason == DLL_PROCESS_ATTACH)
{ {
fprof_init(stub_fstats, NUM_STUBS);
log_open("ipxwrapper.log"); log_open("ipxwrapper.log");
min_log_level = get_main_config().log_level; main_config_t config = get_main_config();
min_log_level = config.log_level;
if(config.profile)
{
stubs_enable_profile = true;
prof_thread_exit = CreateEvent(NULL, FALSE, FALSE, NULL);
if(prof_thread_exit != NULL)
{
prof_thread_handle = CreateThread(
NULL, /* lpThreadAttributes */
0, /* dwStackSize */
&prof_thread_main, /* lpStartAddress */
NULL, /* lpParameter */
0, /* dwCreationFlags */
NULL); /* lpThreadId */
if(prof_thread_handle == NULL)
{
log_printf(LOG_ERROR,
"Unable to create prof_thread_main thread: %s",
w32_error(GetLastError()));
}
}
else{
log_printf(LOG_ERROR,
"Unable to create prof_thread_exit event object: %s",
w32_error(GetLastError()));
}
}
} }
else if(fdwReason == DLL_PROCESS_DETACH) else if(fdwReason == DLL_PROCESS_DETACH)
{ {
@ -41,9 +80,45 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
return TRUE; return TRUE;
} }
if(prof_thread_exit != NULL)
{
SetEvent(prof_thread_exit);
if(prof_thread_handle != NULL)
{
WaitForSingleObject(prof_thread_handle, INFINITE);
CloseHandle(prof_thread_handle);
prof_thread_handle = NULL;
}
CloseHandle(prof_thread_exit);
prof_thread_exit = NULL;
}
unload_dlls(); unload_dlls();
if(stubs_enable_profile)
{
fprof_report(STUBS_DLL_NAME, stub_fstats, NUM_STUBS);
}
log_close(); log_close();
fprof_cleanup(stub_fstats, NUM_STUBS);
} }
return TRUE; return TRUE;
} }
static DWORD WINAPI prof_thread_main(LPVOID lpParameter)
{
static const int PROF_INTERVAL_MS = 10000;
while(WaitForSingleObject(prof_thread_exit, PROF_INTERVAL_MS) == WAIT_TIMEOUT)
{
fprof_report(STUBS_DLL_NAME, stub_fstats, NUM_STUBS);
}
return 0;
}

View File

@ -1475,6 +1475,9 @@ static DWORD ipx_send_packet(
if(pcap_sendpacket(iface->pcap, (void*)(frame), frame_size) == 0) if(pcap_sendpacket(iface->pcap, (void*)(frame), frame_size) == 0)
{ {
__atomic_add_fetch(&send_packets, 1, __ATOMIC_RELAXED);
__atomic_add_fetch(&send_bytes, data_size, __ATOMIC_RELAXED);
free(frame); free(frame);
return ERROR_SUCCESS; return ERROR_SUCCESS;
} }
@ -1531,6 +1534,10 @@ static DWORD ipx_send_packet(
error = WSAGetLastError(); error = WSAGetLastError();
log_printf(LOG_ERROR, "Error sending DOSBox IPX packet: %s", w32_error(error)); log_printf(LOG_ERROR, "Error sending DOSBox IPX packet: %s", w32_error(error));
} }
else{
__atomic_add_fetch(&send_packets, 1, __ATOMIC_RELAXED);
__atomic_add_fetch(&send_bytes, data_size, __ATOMIC_RELAXED);
}
free(packet); free(packet);
@ -1635,6 +1642,12 @@ static DWORD ipx_send_packet(
free(packet); free(packet);
if(send_ok)
{
__atomic_add_fetch(&send_packets, 1, __ATOMIC_RELAXED);
__atomic_add_fetch(&send_bytes, data_size, __ATOMIC_RELAXED);
}
return send_ok return send_ok
? ERROR_SUCCESS ? ERROR_SUCCESS
: send_error; : send_error;

View File

@ -1,8 +0,0 @@
pcap_open
pcap_close
pcap_findalldevs_ex
pcap_freealldevs
pcap_getevent
pcap_dispatch
pcap_geterr
pcap_sendpacket

View File

@ -1,76 +1,78 @@
accept:0 Function name Target DLL Target function Parameters (bytes)
bind:0 --------------------------------------------------------------------------------------------------
closesocket:0 accept ipxwrapper.dll accept 12
connect:0 bind ipxwrapper.dll bind 12
getpeername:0 closesocket ipxwrapper.dll closesocket 4
getsockname:0 connect ipxwrapper.dll connect 12
getsockopt:0 getpeername ipxwrapper.dll getpeername 12
htonl getsockname ipxwrapper.dll getsockname 12
htons getsockopt ipxwrapper.dll getsockopt 20
inet_addr htonl wsock32.dll htonl 4
inet_ntoa htons wsock32.dll htons 4
ioctlsocket:0 inet_addr wsock32.dll inet_addr 4
listen:0 inet_ntoa wsock32.dll inet_ntoa 4
ntohl ioctlsocket ipxwrapper.dll ioctlsocket 12
ntohs listen ipxwrapper.dll listen 8
recv:0 ntohl wsock32.dll ntohl 4
recvfrom:0 ntohs wsock32.dll ntohs 4
select:0 recv ipxwrapper.dll recv 16
send:0 recvfrom ipxwrapper.dll recvfrom 24
sendto:0 select ipxwrapper.dll select 20
setsockopt:0 send ipxwrapper.dll send 16
shutdown:0 sendto ipxwrapper.dll sendto 24
socket:0 setsockopt ipxwrapper.dll setsockopt 20
MigrateWinsockConfiguration shutdown ipxwrapper.dll shutdown 8
gethostbyaddr socket ipxwrapper.dll socket 12
gethostbyname MigrateWinsockConfiguration wsock32.dll MigrateWinsockConfiguration
getprotobyname gethostbyaddr wsock32.dll gethostbyaddr 12
getprotobynumber gethostbyname wsock32.dll gethostbyname 4
getservbyname getprotobyname wsock32.dll getprotobyname 4
getservbyport getprotobynumber wsock32.dll getprotobynumber 4
gethostname getservbyname wsock32.dll getservbyname 8
WSAAsyncSelect:0 getservbyport wsock32.dll getservbyport 8
WSAAsyncGetHostByAddr gethostname wsock32.dll gethostname 8
WSAAsyncGetHostByName WSAAsyncSelect ipxwrapper.dll WSAAsyncSelect 16
WSAAsyncGetProtoByNumber WSAAsyncGetHostByAddr wsock32.dll WSAAsyncGetHostByAddr 28
WSAAsyncGetProtoByName WSAAsyncGetHostByName wsock32.dll WSAAsyncGetHostByName 20
WSAAsyncGetServByPort WSAAsyncGetProtoByNumber wsock32.dll WSAAsyncGetProtoByNumber 20
WSAAsyncGetServByName WSAAsyncGetProtoByName wsock32.dll WSAAsyncGetProtoByName 20
WSACancelAsyncRequest WSAAsyncGetServByPort wsock32.dll WSAAsyncGetServByPort 24
WSASetBlockingHook WSAAsyncGetServByName wsock32.dll WSAAsyncGetServByName 24
WSAUnhookBlockingHook WSACancelAsyncRequest wsock32.dll WSACancelAsyncRequest 4
WSAGetLastError WSASetBlockingHook wsock32.dll WSASetBlockingHook 4
WSASetLastError WSAUnhookBlockingHook wsock32.dll WSAUnhookBlockingHook 0
WSACancelBlockingCall WSAGetLastError wsock32.dll WSAGetLastError 0
WSAIsBlocking WSASetLastError wsock32.dll WSASetLastError 4
WSAStartup WSACancelBlockingCall wsock32.dll WSACancelBlockingCall 0
WSACleanup WSAIsBlocking wsock32.dll WSAIsBlocking 0
__WSAFDIsSet WSAStartup wsock32.dll WSAStartup 8
WEP WSACleanup wsock32.dll WSACleanup 0
WSApSetPostRoutine __WSAFDIsSet wsock32.dll __WSAFDIsSet 8
inet_network WEP wsock32.dll WEP
getnetbyname WSApSetPostRoutine wsock32.dll WSApSetPostRoutine
rcmd inet_network wsock32.dll inet_network
rexec getnetbyname wsock32.dll getnetbyname
rresvport rcmd wsock32.dll rcmd
sethostname rexec wsock32.dll rexec
dn_expand rresvport wsock32.dll rresvport
WSARecvEx:0 sethostname wsock32.dll sethostname
s_perror dn_expand wsock32.dll dn_expand
GetAddressByNameA WSARecvEx ipxwrapper.dll WSARecvEx 16
GetAddressByNameW s_perror wsock32.dll s_perror
EnumProtocolsA:0 GetAddressByNameA wsock32.dll GetAddressByNameA 40
EnumProtocolsW:0 GetAddressByNameW wsock32.dll GetAddressByNameW 40
GetTypeByNameA EnumProtocolsA ipxwrapper.dll EnumProtocolsA 12
GetTypeByNameW EnumProtocolsW ipxwrapper.dll EnumProtocolsW 12
GetNameByTypeA GetTypeByNameA wsock32.dll GetTypeByNameA 8
GetNameByTypeW GetTypeByNameW wsock32.dll GetTypeByNameW 8
SetServiceA GetNameByTypeA wsock32.dll GetNameByTypeA 12
SetServiceW GetNameByTypeW wsock32.dll GetNameByTypeW 12
GetServiceA SetServiceA wsock32.dll SetServiceA 24
GetServiceW SetServiceW wsock32.dll SetServiceW 24
NPLoadNameSpaces GetServiceA wsock32.dll GetServiceA 28
TransmitFile GetServiceW wsock32.dll GetServiceW 28
AcceptEx NPLoadNameSpaces wsock32.dll NPLoadNameSpaces
GetAcceptExSockaddrs TransmitFile wsock32.dll TransmitFile 28
WSHEnumProtocols:0 AcceptEx wsock32.dll AcceptEx 32
GetAcceptExSockaddrs wsock32.dll GetAcceptExSockaddrs 32
WSHEnumProtocols ipxwrapper.dll WSHEnumProtocols 16