This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: socket.sendto(SOCK_DGRAM) very slow on OSX!
Type: Stage:
Components: Library (Lib) Versions:
process
Status: closed Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: jackjansen, loewis, mkangas
Priority: normal Keywords:

Created on 2003-06-01 06:21 by mkangas, last changed 2022-04-10 16:08 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
build_notes.txt mkangas, 2003-06-14 22:21
Messages (6)
msg16216 - (view) Author: Matt Kangas (mkangas) Date: 2003-06-01 06:21
I'm trying to send UDP packets using socket.sendto().
With Python 2.2 on Linux, this works like a champ. On
Mac OS X, something's terribly wrong.

Time to send 100 UDP packets using test code + Python
2.2.1:
- Linux 2.4.18 (RedHat 8): 0.009 sec
- MacOS X 10.2.6: > 1 sec, sometimes > 2 sec.

I've tried the following Python builds on OS X, all
with the same results:
- Stock 2.2 build that comes with OS X 10.2
- 2.2.1 provided by Fink
- built-from-scratch 2.2.3: "./configure; make"

provided are sample programs in Python and C.
ktrace/kdump seem to indicate that both programs make
the same sequence of syscalls. the C program runs
blazingly fast on OS X, while the Python one seems to
stall on every call to socket.sendto().

why does socket.sendto() perform so poorly on OS X?

----------------- python sample ----------------
 
#
# UDP socket test: how fast can we write?
# (5/2003 kangas)
#
# time to run with python 2.2.1:
# - Linux 2.4.18:     0.009 sec
# - Mac OS x 10.2.6:  1.272 sec (!!!)

import socket, time, sys

PORT = 9999
DEST_ADDR = ("192.168.1.60", PORT)

def run():
    maxcount = 100
    data = "pingme pingme pingme pingme pingme..."
    dest = DEST_ADDR

    print "opening socket"
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    
    print "Sending %i packets" % maxcount
    t0 = time.time()
    for i in xrange(0, maxcount):
        s.sendto(data, dest)
    t1 = time.time() - t0
    print "%0.4f secs elapsed" % t1

    s.close()

if __name__=="__main__":
    run()
    

----------------- C sample ----------------

/*
 * UDP socket test: how fast can we write?
 * (5/2003 kangas)
 *
 * Tested on Mac OS X 10.2.6 and Linux 2.4
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>

static const int MAXCOUNT = 100;
static const char DATA[] = "pingme pingme pingme pingme
pingme...";
    
int main(void) {
    int s, i, err;
    struct sockaddr_in serverAddr;

    bzero(&serverAddr, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(9999);
    
    inet_pton(AF_INET, "192.168.1.60",
&serverAddr.sin_addr);
    
    printf("opening socket\n");
    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
	perror("socket");
	exit(1);
    }

    printf("sending %i packets\n", MAXCOUNT);
    for (i=0; i<MAXCOUNT; i++) {
	err = sendto(s, DATA, strlen(DATA), 0,
		     (struct sockaddr *)&serverAddr, sizeof(serverAddr));
	if (err < 0) {
	    perror("sendto");
	    break;
	}
	printf(".");
     };
    printf("\n");

    printf("closing...\n");
    close(s);
    printf("done!\n");
    return 0;
}
msg16217 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2003-06-14 06:55
Logged In: YES 
user_id=21627

Can you try to link your C program with the same libraries
that python is linked with, and compile it with the same
command line options that socketmodule is compiled with?

My first guess is that enabling pthreads may have an effect.
msg16218 - (view) Author: Matt Kangas (mkangas) Date: 2003-06-14 22:21
Logged In: YES 
user_id=234623

"otool -L" (similar to Linux's ldd) shows the following for
my freshly-built Python 2.2.3 interpreter:

drinkycrow:Python-2.2.3$ otool -L python.exe
python.exe:
        /usr/lib/libSystem.B.dylib (compatibility version
1.0.0, current version 63.0.0)
       
/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices
(compatibility version 1.0.0, current version 14.0.0)
       
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation
(compatibility version 300.0.0, current version 462.0.0)
drinkycrow:Python-2.2.3$ ./python.exe
Python 2.2.3 (#2, Jun 14 2003, 17:58:35)
[GCC 3.1 20020420 (prerelease)] on darwin

--------------------------------------

I added the following CFLAGS line to my makefile:

CFLAGS = -DNDEBUG -g -O3 -Wall -Wstrict-prototypes
-no-cpp-precomp -framework System -framework CoreServices
-framework Foundation

These are, AFAIK, all of the relevant options used when
building _socket.so and python.exe. (See attached
"build_notes.txt" for full details)

------------------------------------------

How does the C test-case perform now? Slower than before,
but still an order of magnitude faster than the Python code!

drinkycrow:udp_test_py$ make clean; make
rm socktest
gcc -DNDEBUG -g -O3 -Wall -Wstrict-prototypes
-no-cpp-precomp -framework System-framework CoreServices
-framework Foundation    socktest.c   -o socktest
socktest.c: In function `main':
socktest.c:21: warning: implicit declaration of function `bzero'
socktest.c:25: warning: implicit declaration of function
`inet_pton'
socktest.c:30: warning: implicit declaration of function `exit'
socktest.c:35: warning: implicit declaration of function
`strlen'
socktest.c:46: warning: implicit declaration of function `close'
drinkycrow:udp_test_py$ time ./socktest
opening socket
sending 100 packets
....................................................................................................
closing...
done!

real    0m0.164s
user    0m0.030s
sys     0m0.040s

drinkycrow:udp_test_py$ otool -L socktest
socktest:
        /usr/lib/libSystem.B.dylib (compatibility version
1.0.0, current version 63.0.0)
       
/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices
(compatibility version 1.0.0, current version 14.0.0)
       
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation
(compatibility version 300.0.0, current version 462.0.0)
msg16219 - (view) Author: Jack Jansen (jackjansen) * (Python committer) Date: 2003-06-16 13:12
Logged In: YES 
user_id=45365

Hmm. It looks like something that is fixed in 2.3.

When running the example with Apple's /usr/bin/python 2.2 I 
get "0.6942 secs elapsed". When I run it with 2.3b2 from CVS I 
get "0.0069 secs elapsed".

Could this be an effect of the gethostbyname() mods that were 
done for numeric addresses? Yes, it seems it could be. 1000 calls 
to gethostbyname("192.168.1.60") cost 7.4 seconds in Python 
2.2, while 2.3b2 needs only 0.02 seconds.

I don't know whether these fixes can be backported to 2.2, 
though (nor even exactly what they are:-)
msg16220 - (view) Author: Matt Kangas (mkangas) Date: 2003-07-27 19:16
Logged In: YES 
user_id=234623

Confirmed that it is fixed in 2.3c2. My python testcase now runs in 0.096 secs.

Would anyone happen to know what exactly changed for gethostbyname() calls on OSX btw. 2.2 and 2.3? I ask because PHP 4.3.2 seems to suffer from the very same problem!
msg16221 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2003-07-27 21:34
Logged In: YES 
user_id=21627

In 2.3, Python now uses the C library's getaddrinfo, instead
of an emulated one that uses gethostbyname.

Interestingly enough, this change has been attributed to a
slowdown in 2.3 over 2.2 also.
History
Date User Action Args
2022-04-10 16:08:59adminsetgithub: 38574
2003-06-01 06:21:59mkangascreate