All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] Windows: improve performance by avoiding a static dependency on ws2_32.dll and advapi32.dll
@ 2010-01-28  8:15 Michael Lukashov
  2010-01-28  9:09 ` Johannes Sixt
  0 siblings, 1 reply; 6+ messages in thread
From: Michael Lukashov @ 2010-01-28  8:15 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Michael Lukashov

ws2_32.dll is used by limited subset of git commands, such as pull,
push, fetch, send-email, ... By looking up functions that we need
at runtime, we can avoid the startup costs of this DLL.
As a result, we can remove static dependency on advapi32.dll too.

A call to "git status" loaded

before:  8 DLL
after:   4 DLL

Signed-off-by: Michael Lukashov <michael.lukashov@gmail.com>
---
 Makefile       |    1 -
 compat/bswap.h |   30 +++++++++
 compat/mingw.c |  193 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 compat/mingw.h |   49 +++++++++++++-
 4 files changed, 265 insertions(+), 8 deletions(-)

diff --git a/Makefile b/Makefile
index af08c8f..4a79eaa 100644
--- a/Makefile
+++ b/Makefile
@@ -1041,7 +1041,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
 		compat/win32/pthread.o
-	EXTLIBS += -lws2_32
 	PTHREAD_LIBS =
 	X = .exe
 ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
diff --git a/compat/bswap.h b/compat/bswap.h
index f3b8c44..08aea39 100644
--- a/compat/bswap.h
+++ b/compat/bswap.h
@@ -1,3 +1,6 @@
+#ifndef BSWAP_H
+#define BSWAP_H
+
 /*
  * Let's make sure we always have a sane definition for ntohl()/htonl().
  * Some libraries define those as a function call, just to perform byte
@@ -17,6 +20,12 @@ static inline uint32_t default_swab32(uint32_t val)
 		((val & 0x000000ff) << 24));
 }
 
+static inline uint16_t default_swab16(uint16_t val)
+{
+	return (((val & 0xff00) >>  8) |
+		((val & 0x00ff) << 8));
+}
+
 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
 
 #define bswap32(x) ({ \
@@ -28,11 +37,21 @@ static inline uint32_t default_swab32(uint32_t val)
 	} \
 	__res; })
 
+#define bswap16(x) ({ \
+	uint16_t __res; \
+	if (__builtin_constant_p(x)) { \
+		__res = default_swab16(x); \
+	} else { \
+		__asm__("xchgb %b0, %h0" : "=q" (__res) : "0" ((uint16_t)(x))); \
+	} \
+	__res; })
+
 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
 
 #include <stdlib.h>
 
 #define bswap32(x) _byteswap_ulong(x)
+#define bswap16(x) _byteswap_ushort(x)
 
 #endif
 
@@ -44,3 +63,14 @@ static inline uint32_t default_swab32(uint32_t val)
 #define htonl(x) bswap32(x)
 
 #endif
+
+#ifdef bswap16
+
+#undef ntohs
+#undef htons
+#define ntohs(x) bswap16(x)
+#define htons(x) bswap16(x)
+
+#endif
+
+#endif
diff --git a/compat/mingw.c b/compat/mingw.c
index ab65f77..484cf7c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -891,6 +891,172 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
+static HMODULE ws2_32_dll = NULL;
+static LPFN_INET_NTOA ws2_32_inet_ntoa;
+static LPFN_CONNECT ws2_32_connect;
+static LPFN_SELECT ws2_32_select;
+static LPFN_CLOSESOCKET ws2_32_closesocket;
+static LPFN_GETSERVBYPORT ws2_32_getservbyport;
+static LPFN_GETSERVBYNAME ws2_32_getservbyname;
+static LPFN_GETHOSTBYADDR ws2_32_gethostbyaddr;
+static LPFN_GETHOSTNAME ws2_32_gethostname;
+static LPFN_GETHOSTBYNAME ws2_32_gethostbyname;
+static LPFN_WSASTARTUP ws2_32_WSAStartup;
+static LPFN_WSACLEANUP ws2_32_WSACleanup;
+static LPFN_WSAGETLASTERROR ws2_32_WSAGetLastError;
+static LPFN_WSASOCKETA ws2_32_WSASocketA;
+
+static void ws2_32_cleanup(void)
+{
+	if (ws2_32_dll)
+		FreeLibrary(ws2_32_dll);
+	ws2_32_dll = NULL;
+	ws2_32_inet_ntoa = NULL;
+	ws2_32_connect = NULL;
+	ws2_32_select = NULL;
+	ws2_32_closesocket = NULL;
+	ws2_32_getservbyport = NULL;
+	ws2_32_getservbyname = NULL;
+	ws2_32_gethostbyaddr = NULL;
+	ws2_32_gethostname = NULL;
+	ws2_32_gethostbyname = NULL;
+	ws2_32_WSAStartup = NULL;
+	ws2_32_WSACleanup = NULL;
+	ws2_32_WSAGetLastError = NULL;
+	ws2_32_WSASocketA = NULL;
+}
+
+static void ensure_ws2_32_initialization(void)
+{
+	static int ws2_32_initialized = 0;
+
+	if (ws2_32_initialized)
+		return;
+
+	ws2_32_dll = LoadLibrary("ws2_32.dll");
+	if (!ws2_32_dll)
+		die("cannot load ws2_32.dll");
+
+	ws2_32_inet_ntoa = (LPFN_INET_NTOA)
+		GetProcAddress(ws2_32_dll, "inet_ntoa");
+	ws2_32_connect = (LPFN_CONNECT)
+		GetProcAddress(ws2_32_dll, "connect");
+	ws2_32_select = (LPFN_SELECT)
+		GetProcAddress(ws2_32_dll, "select");
+	ws2_32_closesocket = (LPFN_CLOSESOCKET)
+		GetProcAddress(ws2_32_dll, "closesocket");
+	ws2_32_getservbyport = (LPFN_GETSERVBYPORT)
+		GetProcAddress(ws2_32_dll, "getservbyport");
+	ws2_32_getservbyname = (LPFN_GETSERVBYNAME)
+		GetProcAddress(ws2_32_dll, "getservbyname");
+	ws2_32_gethostbyaddr = (LPFN_GETHOSTBYADDR)
+		GetProcAddress(ws2_32_dll, "gethostbyaddr");
+	ws2_32_gethostname = (LPFN_GETHOSTNAME)
+		GetProcAddress(ws2_32_dll, "gethostname");
+	ws2_32_gethostbyname = (LPFN_GETHOSTBYNAME)
+		GetProcAddress(ws2_32_dll, "gethostbyname");
+	ws2_32_WSAStartup = (LPFN_WSASTARTUP)
+		GetProcAddress(ws2_32_dll, "WSAStartup");
+	ws2_32_WSACleanup = (LPFN_WSACLEANUP)
+		GetProcAddress(ws2_32_dll, "WSACleanup");
+	ws2_32_WSAGetLastError = (LPFN_WSAGETLASTERROR)
+		GetProcAddress(ws2_32_dll, "WSAGetLastError");
+	ws2_32_WSASocketA = (LPFN_WSASOCKETA)
+		GetProcAddress(ws2_32_dll, "WSASocketA");
+
+	if (!ws2_32_inet_ntoa || !ws2_32_connect || !ws2_32_select ||
+		!ws2_32_closesocket || !ws2_32_getservbyport || !ws2_32_getservbyname ||
+		!ws2_32_gethostbyaddr || !ws2_32_gethostname || !ws2_32_gethostbyname ||
+		!ws2_32_WSAStartup || !ws2_32_WSACleanup ||
+		!ws2_32_WSAGetLastError || !ws2_32_WSASocketA) {
+		FreeLibrary(ws2_32_dll);
+		ws2_32_dll = NULL;
+		die("cannot initialize ws2_32.dll");
+	}
+	atexit(ws2_32_cleanup);
+	ws2_32_initialized = 1;
+}
+
+char *mingw_inet_ntoa(struct in_addr in)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_inet_ntoa(in);
+}
+
+int mingw_closesocket(SOCKET s)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_closesocket(s);
+}
+
+int mingw_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+			const struct timeval *timeout)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_select(nfds, readfds, writefds, exceptfds, timeout);
+}
+
+struct servent *mingw_getservbyport(int port, const char *proto)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_getservbyport(port, proto);
+}
+
+struct hostent *mingw_gethostbyaddr(const char *addr, int len, int type)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_gethostbyaddr(addr, len, type);
+}
+
+int mingw_gethostname(char *name, int namelen)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_gethostname(name, namelen);
+}
+
+struct servent *mingw_getservbyname(const char *name, const char *proto)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_getservbyname(name, proto);
+}
+
+int mingw_WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_WSAStartup(wVersionRequested, lpWSAData);
+}
+
+int mingw_WSACleanup(void)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_WSACleanup();
+}
+
+int mingw_WSAGetLastError(void)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_WSAGetLastError();
+}
+
+SOCKET mingw_WSASocketA(int af, int type, int protocol,
+			LPWSAPROTOCOL_INFOA lpProtocolInfo,
+			GROUP g, DWORD dwFlags)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_WSASocketA(af, type, protocol, lpProtocolInfo, g, dwFlags);
+}
+
+static HMODULE advapi32_dll = NULL;
+static BOOL (WINAPI *advapi32_get_user_name)(char *, DWORD *);
+
+static void advapi32_cleanup(void)
+{
+	if (advapi32_dll)
+		FreeLibrary(advapi32_dll);
+	advapi32_dll = NULL;
+	advapi32_get_user_name = NULL;
+}
+
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it it is null. It
@@ -1057,11 +1223,13 @@ static void ensure_socket_initialization(void)
 struct hostent *mingw_gethostbyname(const char *host)
 {
 	ensure_socket_initialization();
-	return gethostbyname(host);
+	ensure_ws2_32_initialization();
+	return ws2_32_gethostbyname(host);
 }
 
 void mingw_freeaddrinfo(struct addrinfo *res)
 {
+	ensure_socket_initialization();
 	ipv6_freeaddrinfo(res);
 }
 
@@ -1110,7 +1278,8 @@ int mingw_socket(int domain, int type, int protocol)
 int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
 {
 	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
-	return connect(s, sa, sz);
+	ensure_ws2_32_initialization();
+	return ws2_32_connect(s, sa, sz);
 }
 
 #undef rename
@@ -1180,9 +1349,27 @@ struct passwd *getpwuid(int uid)
 {
 	static char user_name[100];
 	static struct passwd p;
+	static int advapi32_initialized = 0;
 
 	DWORD len = sizeof(user_name);
-	if (!GetUserName(user_name, &len))
+
+	if (!advapi32_initialized)
+	{
+		advapi32_dll = LoadLibrary("advapi32.dll");
+		if (!advapi32_dll)
+			die("cannot load advapi32.dll");
+		advapi32_get_user_name = (BOOL (WINAPI *)(char *, DWORD *))
+			GetProcAddress(advapi32_dll, "GetUserNameA");
+		if (!advapi32_get_user_name) {
+			FreeLibrary(advapi32_dll);
+			advapi32_dll = NULL;
+			die("cannot find GetUserNameA");
+		}
+		atexit(advapi32_cleanup);
+		advapi32_initialized = 1;
+	}
+
+	if (!advapi32_get_user_name(user_name, &len))
 		return NULL;
 	p.pw_name = user_name;
 	p.pw_gecos = "unknown";
diff --git a/compat/mingw.h b/compat/mingw.h
index e254fb4..466c473 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,5 +1,6 @@
 #include <winsock2.h>
 #include <ws2tcpip.h>
+#include "bswap.h"
 
 /*
  * things that are not available in header files
@@ -176,9 +177,53 @@ char *mingw_getcwd(char *pointer, int len);
 char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
 
+/*
+ * wrappers for functions dynamically loaded from ws2_32.dll
+ */
+
+char *mingw_inet_ntoa(struct in_addr in);
+#define inet_ntoa mingw_inet_ntoa
+
+int mingw_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+			const struct timeval *timeout);
+#define select mingw_select
+
+int mingw_closesocket(SOCKET s);
+#define closesocket mingw_closesocket
+
+struct servent *mingw_getservbyport(int port, const char *proto);
+#define getservbyport mingw_getservbyport
+
+struct servent *mingw_getservbyname(const char *name, const char *proto);
+#define getservbyname mingw_getservbyname
+
+struct hostent *mingw_gethostbyaddr(const char *addr, int len, int type);
+#define gethostbyaddr mingw_gethostbyaddr
+
+int mingw_gethostname(char *name, int namelen);
+#define gethostname mingw_gethostname
+
 struct hostent *mingw_gethostbyname(const char *host);
 #define gethostbyname mingw_gethostbyname
 
+int mingw_WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
+#define WSAStartup mingw_WSAStartup
+
+int mingw_WSACleanup(void);
+#define WSACleanup mingw_WSACleanup
+
+int mingw_WSAGetLastError(void);
+#define WSAGetLastError mingw_WSAGetLastError
+
+SOCKET mingw_WSASocketA(int af, int type, int protocol,
+			LPWSAPROTOCOL_INFOA lpProtocolInfo,
+			GROUP g, DWORD dwFlags);
+#define WSASocketA mingw_WSASocketA
+
+/*
+ * support for IPv6 on MinGW
+ */
+
 void mingw_freeaddrinfo(struct addrinfo *res);
 #define freeaddrinfo mingw_freeaddrinfo
 
@@ -227,10 +272,6 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 void mingw_execvp(const char *cmd, char *const *argv);
 #define execvp mingw_execvp
 
-static inline unsigned int git_ntohl(unsigned int x)
-{ return (unsigned int)ntohl(x); }
-#define ntohl git_ntohl
-
 sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 #define signal mingw_signal
 
-- 
1.7.0.rc0.1466.g79f2.dirty

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] Windows: improve performance by avoiding a static dependency on ws2_32.dll and advapi32.dll
  2010-01-28  8:15 [PATCH v2] Windows: improve performance by avoiding a static dependency on ws2_32.dll and advapi32.dll Michael Lukashov
@ 2010-01-28  9:09 ` Johannes Sixt
  2010-01-28 10:18   ` Michael Lukashov
  0 siblings, 1 reply; 6+ messages in thread
From: Johannes Sixt @ 2010-01-28  9:09 UTC (permalink / raw)
  To: Michael Lukashov; +Cc: git

Michael Lukashov schrieb:
> ws2_32.dll is used by limited subset of git commands, such as pull,
> push, fetch, send-email, ... By looking up functions that we need
> at runtime, we can avoid the startup costs of this DLL.
> As a result, we can remove static dependency on advapi32.dll too.
> 
> A call to "git status" loaded
> 
> before:  8 DLL
> after:   4 DLL

Thanks. Due to the size of the change, I would acknowledge it only if you
have a proof that the reduced startup costs are noticable, for example, by
running the test suite.

What's the deal with bswap? Isn't it an unrelated change? It needs some
better justification. It is unobvious because it is not straight-forward
"use pointer to function that was looked up instead of function".

Will the result not break the MSVC build?

-- Hannes

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] Windows: improve performance by avoiding a static  dependency on ws2_32.dll and advapi32.dll
  2010-01-28  9:09 ` Johannes Sixt
@ 2010-01-28 10:18   ` Michael Lukashov
  2010-01-28 10:38     ` Johannes Schindelin
  0 siblings, 1 reply; 6+ messages in thread
From: Michael Lukashov @ 2010-01-28 10:18 UTC (permalink / raw)
  To: Johannes Sixt; +Cc: git

> Thanks. Due to the size of the change, I would acknowledge it only if you
> have a proof that the reduced startup costs are noticable, for example, by
> running the test suite.
>
> What's the deal with bswap? Isn't it an unrelated change? It needs some
> better justification. It is unobvious because it is not straight-forward
> "use pointer to function that was looked up instead of function".
>
> Will the result not break the MSVC build?
>
> -- Hannes
>

"git status" calls ntohs function, which was loaded from ws2_32.dll
I've noticed that bswap.h contains implementation of ntohl htonl functions,
so I decided to add implementation of ntohs htons functions, which is
pretty trivial.
After that call to "git status" doesn't load ws2_32.dll

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] Windows: improve performance by avoiding a static  dependency on ws2_32.dll and advapi32.dll
  2010-01-28 10:18   ` Michael Lukashov
@ 2010-01-28 10:38     ` Johannes Schindelin
  2010-01-28 10:47       ` Michael Lukashov
  0 siblings, 1 reply; 6+ messages in thread
From: Johannes Schindelin @ 2010-01-28 10:38 UTC (permalink / raw)
  To: Michael Lukashov; +Cc: Johannes Sixt, git

Hi,

On Thu, 28 Jan 2010, Michael Lukashov wrote:

> > Thanks. Due to the size of the change, I would acknowledge it only if you
> > have a proof that the reduced startup costs are noticable, for example, by
> > running the test suite.
> >
> > What's the deal with bswap? Isn't it an unrelated change? It needs some
> > better justification. It is unobvious because it is not straight-forward
> > "use pointer to function that was looked up instead of function".
> >
> > Will the result not break the MSVC build?
> >
> > -- Hannes
> >
> 
> "git status" calls ntohs function, which was loaded from ws2_32.dll
> I've noticed that bswap.h contains implementation of ntohl htonl functions,
> so I decided to add implementation of ntohs htons functions, which is
> pretty trivial.
> After that call to "git status" doesn't load ws2_32.dll

I am still not convinced of that patch, because the timings are still 
missing.

Ciao,
Dscho

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] Windows: improve performance by avoiding a static  dependency on ws2_32.dll and advapi32.dll
  2010-01-28 10:38     ` Johannes Schindelin
@ 2010-01-28 10:47       ` Michael Lukashov
  2010-01-29  7:44         ` Johannes Sixt
  0 siblings, 1 reply; 6+ messages in thread
From: Michael Lukashov @ 2010-01-28 10:47 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Johannes Sixt, git

>> >
>>
>> "git status" calls ntohs function, which was loaded from ws2_32.dll
>> I've noticed that bswap.h contains implementation of ntohl htonl functions,
>> so I decided to add implementation of ntohs htons functions, which is
>> pretty trivial.
>> After that call to "git status" doesn't load ws2_32.dll
>
> I am still not convinced of that patch, because the timings are still
> missing.
>
> Ciao,
> Dscho
>
>

Oops, sorry for the noise (again).

"git status" calls ntohs function, which was loaded from ws2_32.dll
I've noticed that bswap.h contains implementation of ntohl htonl functions,
so I decided to add implementation of ntohs htons functions, which is
pretty trivial.
After that call to "git status" doesn't load ws2_32.dll

The following commands were run and timed, the
best of five results is shown:

for i in `seq 1 10`;
do
	git status
	git log -n2
	git diff
done

before:
real    0m30.024s
user    0m0.105s
sys     0m0.425s

after:
real    0m29.578s
user    0m0.105s
sys     0m0.318s

The runtime of 'make -j2 test' went down from 35:19min
to 32:39min on my machine.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] Windows: improve performance by avoiding a static dependency on ws2_32.dll and advapi32.dll
  2010-01-28 10:47       ` Michael Lukashov
@ 2010-01-29  7:44         ` Johannes Sixt
  0 siblings, 0 replies; 6+ messages in thread
From: Johannes Sixt @ 2010-01-29  7:44 UTC (permalink / raw)
  To: Michael Lukashov; +Cc: Johannes Schindelin, git

Michael Lukashov schrieb:
> The runtime of 'make -j2 test' went down from 35:19min
> to 32:39min on my machine.

Sorry, I can't back this claim. In my tests, 'make -j2 test' did not go
down. My timings were between 13:40min and 13:50min with and without the
patch, and I tried multiple times.

For the MinGW version, I'd rather not apply this patch. People interested
in optimizing the MSVC version could link with /delayload:ws_32.dll to
achieve the same effect without any change to the code.

-- Hannes

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-01-29  7:44 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-01-28  8:15 [PATCH v2] Windows: improve performance by avoiding a static dependency on ws2_32.dll and advapi32.dll Michael Lukashov
2010-01-28  9:09 ` Johannes Sixt
2010-01-28 10:18   ` Michael Lukashov
2010-01-28 10:38     ` Johannes Schindelin
2010-01-28 10:47       ` Michael Lukashov
2010-01-29  7:44         ` Johannes Sixt

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.