2010-06-16 02:49:56 +04:00
|
|
|
/*
|
|
|
|
util.h - utility functions for interfacing with the various python APIs.
|
|
|
|
|
|
|
|
This software may be used and distributed according to the terms of
|
|
|
|
the GNU General Public License, incorporated herein by reference.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _HG_UTIL_H_
|
|
|
|
#define _HG_UTIL_H_
|
|
|
|
|
|
|
|
#if PY_MAJOR_VERSION >= 3
|
|
|
|
|
|
|
|
#define IS_PY3K
|
|
|
|
#define PyInt_FromLong PyLong_FromLong
|
2010-07-02 23:21:38 +04:00
|
|
|
#define PyInt_AsLong PyLong_AsLong
|
2010-06-16 02:49:56 +04:00
|
|
|
|
2010-07-02 23:21:40 +04:00
|
|
|
/*
|
|
|
|
Mapping of some of the python < 2.x PyString* functions to py3k's PyUnicode.
|
|
|
|
|
|
|
|
The commented names below represent those that are present in the PyBytes
|
|
|
|
definitions for python < 2.6 (below in this file) that don't have a direct
|
|
|
|
implementation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define PyStringObject PyUnicodeObject
|
|
|
|
#define PyString_Type PyUnicode_Type
|
|
|
|
|
|
|
|
#define PyString_Check PyUnicode_Check
|
|
|
|
#define PyString_CheckExact PyUnicode_CheckExact
|
|
|
|
#define PyString_CHECK_INTERNED PyUnicode_CHECK_INTERNED
|
|
|
|
#define PyString_AS_STRING PyUnicode_AsLatin1String
|
|
|
|
#define PyString_GET_SIZE PyUnicode_GET_SIZE
|
|
|
|
|
|
|
|
#define PyString_FromStringAndSize PyUnicode_FromStringAndSize
|
|
|
|
#define PyString_FromString PyUnicode_FromString
|
|
|
|
#define PyString_FromFormatV PyUnicode_FromFormatV
|
|
|
|
#define PyString_FromFormat PyUnicode_FromFormat
|
|
|
|
/* #define PyString_Size PyUnicode_GET_SIZE */
|
|
|
|
/* #define PyString_AsString */
|
|
|
|
/* #define PyString_Repr */
|
|
|
|
#define PyString_Concat PyUnicode_Concat
|
|
|
|
#define PyString_ConcatAndDel PyUnicode_AppendAndDel
|
|
|
|
#define _PyString_Resize PyUnicode_Resize
|
|
|
|
/* #define _PyString_Eq */
|
|
|
|
#define PyString_Format PyUnicode_Format
|
|
|
|
/* #define _PyString_FormatLong */
|
|
|
|
/* #define PyString_DecodeEscape */
|
|
|
|
#define _PyString_Join PyUnicode_Join
|
|
|
|
#define PyString_Decode PyUnicode_Decode
|
|
|
|
#define PyString_Encode PyUnicode_Encode
|
|
|
|
#define PyString_AsEncodedObject PyUnicode_AsEncodedObject
|
|
|
|
#define PyString_AsEncodedString PyUnicode_AsEncodedString
|
|
|
|
#define PyString_AsDecodedObject PyUnicode_AsDecodedObject
|
|
|
|
#define PyString_AsDecodedString PyUnicode_AsDecodedUnicode
|
|
|
|
/* #define PyString_AsStringAndSize */
|
|
|
|
#define _PyString_InsertThousandsGrouping _PyUnicode_InsertThousandsGrouping
|
|
|
|
|
2010-06-16 02:49:56 +04:00
|
|
|
#endif /* PY_MAJOR_VERSION */
|
|
|
|
|
2012-04-10 21:07:14 +04:00
|
|
|
#ifdef _WIN32
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
/* msvc 6.0 has problems */
|
|
|
|
#define inline __inline
|
2013-09-13 05:54:43 +04:00
|
|
|
typedef signed char int8_t;
|
|
|
|
typedef short int16_t;
|
|
|
|
typedef long int32_t;
|
|
|
|
typedef __int64 int64_t;
|
store: implement fncache basic path encoding in C
(This is not yet enabled; it will be turned on in a followup patch.)
The path encoding performed by fncache is complex and (perhaps
surprisingly) slow enough to negatively affect the overall performance
of Mercurial.
For a short path (< 120 bytes), the Python code can be reduced to a fairly
tractable state machine that either determines that nothing needs to be
done in a single pass, or performs the encoding in a second pass.
For longer paths, we avoid the more complicated hashed encoding scheme
for now, and fall back to Python.
Raw performance: I measured in a repo containing 150,000 files in its tip
manifest, with a median path name length of 57 bytes, and 95th percentile
of 96 bytes.
In this repo, the Python code takes 3.1 seconds to encode all path
names, while the hybrid C-and-Python code (called from Python) takes
0.21 seconds, for a speedup of about 14.
Across several other large repositories, I've measured the speedup from
the C code at between 26x and 40x.
For path names above 120 bytes where we must fall back to Python for
hashed encoding, the speedup is about 1.7x. Thus absolute performance
will depend strongly on the characteristics of a particular repository.
2012-09-19 02:42:19 +04:00
|
|
|
typedef unsigned char uint8_t;
|
2013-09-13 05:54:43 +04:00
|
|
|
typedef unsigned short uint16_t;
|
2012-04-10 21:07:14 +04:00
|
|
|
typedef unsigned long uint32_t;
|
|
|
|
typedef unsigned __int64 uint64_t;
|
|
|
|
#else
|
|
|
|
#include <stdint.h>
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
/* not windows */
|
|
|
|
#include <sys/types.h>
|
|
|
|
#if defined __BEOS__ && !defined __HAIKU__
|
|
|
|
#include <ByteOrder.h>
|
|
|
|
#else
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#endif
|
|
|
|
#include <inttypes.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined __hpux || defined __SUNPRO_C || defined _AIX
|
|
|
|
#define inline
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __linux
|
|
|
|
#define inline __inline
|
|
|
|
#endif
|
|
|
|
|
parsers: inline fields of dirstate values in C version
Previously, while unpacking the dirstate we'd create 3-4 new CPython objects
for most dirstate values:
- the state is a single character string, which is pooled by CPython
- the mode is a new object if it isn't 0 due to being in the lookup set
- the size is a new object if it is greater than 255
- the mtime is a new object if it isn't -1 due to being in the lookup set
- the tuple to contain them all
In some cases such as regular hg status, we actually look at all the objects.
In other cases like hg add, hg status for a subdirectory, or hg status with the
third-party hgwatchman enabled, we look at almost none of the objects.
This patch eliminates most object creation in these cases by defining a custom
C struct that is exposed to Python with an interface similar to a tuple. Only
when tuple elements are actually requested are the respective objects created.
The gains, where they're expected, are significant. The following tests are run
against a working copy with over 270,000 files.
parse_dirstate becomes significantly faster:
$ hg perfdirstate
before: wall 0.186437 comb 0.180000 user 0.160000 sys 0.020000 (best of 35)
after: wall 0.093158 comb 0.100000 user 0.090000 sys 0.010000 (best of 95)
and as a result, several commands benefit:
$ time hg status # with hgwatchman enabled
before: 0.42s user 0.14s system 99% cpu 0.563 total
after: 0.34s user 0.12s system 99% cpu 0.471 total
$ time hg add new-file
before: 0.85s user 0.18s system 99% cpu 1.033 total
after: 0.76s user 0.17s system 99% cpu 0.931 total
There is a slight regression in regular status performance, but this is fixed
in an upcoming patch.
2014-05-28 01:27:41 +04:00
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD
|
|
|
|
char state;
|
|
|
|
int mode;
|
|
|
|
int size;
|
|
|
|
int mtime;
|
|
|
|
} dirstateTupleObject;
|
|
|
|
|
2014-07-03 21:05:04 +04:00
|
|
|
extern PyTypeObject dirstateTupleType;
|
parsers: inline fields of dirstate values in C version
Previously, while unpacking the dirstate we'd create 3-4 new CPython objects
for most dirstate values:
- the state is a single character string, which is pooled by CPython
- the mode is a new object if it isn't 0 due to being in the lookup set
- the size is a new object if it is greater than 255
- the mtime is a new object if it isn't -1 due to being in the lookup set
- the tuple to contain them all
In some cases such as regular hg status, we actually look at all the objects.
In other cases like hg add, hg status for a subdirectory, or hg status with the
third-party hgwatchman enabled, we look at almost none of the objects.
This patch eliminates most object creation in these cases by defining a custom
C struct that is exposed to Python with an interface similar to a tuple. Only
when tuple elements are actually requested are the respective objects created.
The gains, where they're expected, are significant. The following tests are run
against a working copy with over 270,000 files.
parse_dirstate becomes significantly faster:
$ hg perfdirstate
before: wall 0.186437 comb 0.180000 user 0.160000 sys 0.020000 (best of 35)
after: wall 0.093158 comb 0.100000 user 0.090000 sys 0.010000 (best of 95)
and as a result, several commands benefit:
$ time hg status # with hgwatchman enabled
before: 0.42s user 0.14s system 99% cpu 0.563 total
after: 0.34s user 0.12s system 99% cpu 0.471 total
$ time hg add new-file
before: 0.85s user 0.18s system 99% cpu 1.033 total
after: 0.76s user 0.17s system 99% cpu 0.931 total
There is a slight regression in regular status performance, but this is fixed
in an upcoming patch.
2014-05-28 01:27:41 +04:00
|
|
|
#define dirstate_tuple_check(op) (Py_TYPE(op) == &dirstateTupleType)
|
|
|
|
|
2012-04-16 20:26:00 +04:00
|
|
|
static inline uint32_t getbe32(const char *c)
|
|
|
|
{
|
|
|
|
const unsigned char *d = (const unsigned char *)c;
|
|
|
|
|
|
|
|
return ((d[0] << 24) |
|
|
|
|
(d[1] << 16) |
|
|
|
|
(d[2] << 8) |
|
|
|
|
(d[3]));
|
|
|
|
}
|
|
|
|
|
2015-01-20 22:09:57 +03:00
|
|
|
static inline int16_t getbeint16(const char *c)
|
|
|
|
{
|
|
|
|
const unsigned char *d = (const unsigned char *)c;
|
|
|
|
|
|
|
|
return ((d[0] << 8) |
|
|
|
|
(d[1]));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint16_t getbeuint16(const char *c)
|
|
|
|
{
|
|
|
|
const unsigned char *d = (const unsigned char *)c;
|
|
|
|
|
|
|
|
return ((d[0] << 8) |
|
|
|
|
(d[1]));
|
|
|
|
}
|
|
|
|
|
2012-04-16 20:26:00 +04:00
|
|
|
static inline void putbe32(uint32_t x, char *c)
|
|
|
|
{
|
|
|
|
c[0] = (x >> 24) & 0xff;
|
|
|
|
c[1] = (x >> 16) & 0xff;
|
|
|
|
c[2] = (x >> 8) & 0xff;
|
|
|
|
c[3] = (x) & 0xff;
|
|
|
|
}
|
|
|
|
|
2015-02-03 21:17:21 +03:00
|
|
|
static inline double getbefloat64(const char *c)
|
|
|
|
{
|
|
|
|
const unsigned char *d = (const unsigned char *)c;
|
|
|
|
double ret;
|
|
|
|
int i;
|
|
|
|
uint64_t t = 0;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
t = (t<<8) + d[i];
|
|
|
|
}
|
|
|
|
memcpy(&ret, &t, sizeof(t));
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-04-03 05:17:32 +03:00
|
|
|
/* This should be kept in sync with normcasespecs in encoding.py. */
|
|
|
|
enum normcase_spec {
|
|
|
|
NORMCASE_LOWER = -1,
|
|
|
|
NORMCASE_UPPER = 1,
|
|
|
|
NORMCASE_OTHER = 0
|
|
|
|
};
|
|
|
|
|
2015-03-24 21:00:09 +03:00
|
|
|
#define MIN(a, b) (((a)<(b))?(a):(b))
|
2015-03-25 22:16:10 +03:00
|
|
|
/* VC9 doesn't include bool and lacks stdbool.h based on my searching */
|
2015-04-21 06:21:57 +03:00
|
|
|
#if defined(_MSC_VER) || __STDC_VERSION__ < 199901L
|
2015-03-25 22:16:10 +03:00
|
|
|
#define true 1
|
|
|
|
#define false 0
|
|
|
|
typedef unsigned char bool;
|
|
|
|
#else
|
|
|
|
#include <stdbool.h>
|
|
|
|
#endif
|
|
|
|
|
2010-06-16 02:49:56 +04:00
|
|
|
#endif /* _HG_UTIL_H_ */
|