Merge branch 'release/1.10.x'

This commit is contained in:
rdb 2022-12-12 17:19:10 +01:00
commit e1b4083d6d
15 changed files with 211 additions and 81 deletions

View File

@ -8,9 +8,8 @@ from direct.showbase.PythonUtil import itype, deeptype, fastRepr
from direct.showbase.Job import Job from direct.showbase.Job import Job
from direct.showbase.JobManagerGlobal import jobMgr from direct.showbase.JobManagerGlobal import jobMgr
from direct.showbase.MessengerGlobal import messenger from direct.showbase.MessengerGlobal import messenger
import direct.showbase.DConfig as config from panda3d.core import ConfigVariableBool
import gc import gc
import types
GarbageCycleCountAnnounceEvent = 'announceGarbageCycleDesc2num' GarbageCycleCountAnnounceEvent = 'announceGarbageCycleDesc2num'
@ -213,7 +212,7 @@ class GarbageReport(Job):
startIndex = 0 startIndex = 0
# + 1 to include a reference back to the first object # + 1 to include a reference back to the first object
endIndex = numObjs + 1 endIndex = numObjs + 1
if type(objs[-1]) is types.InstanceType and type(objs[0]) is dict: if type(objs[0]) is dict and hasattr(objs[-1], '__dict__'):
startIndex -= 1 startIndex -= 1
endIndex -= 1 endIndex -= 1
@ -222,7 +221,7 @@ class GarbageReport(Job):
numToSkip -= 1 numToSkip -= 1
continue continue
obj = objs[index] obj = objs[index]
if type(obj) is types.InstanceType: if hasattr(obj, '__dict__'):
if not objAlreadyRepresented: if not objAlreadyRepresented:
cycleBySyntax += '%s' % obj.__class__.__name__ cycleBySyntax += '%s' % obj.__class__.__name__
cycleBySyntax += '.' cycleBySyntax += '.'
@ -307,7 +306,7 @@ class GarbageReport(Job):
while n > 0: while n > 0:
yield None yield None
digits += 1 digits += 1
n /= 10 n = n // 10
digits = digits digits = digits
format = '%0' + '%s' % digits + 'i:%s \t%s' format = '%0' + '%s' % digits + 'i:%s \t%s'
@ -562,7 +561,7 @@ class _CFGLGlobals:
def checkForGarbageLeaks(): def checkForGarbageLeaks():
gc.collect() gc.collect()
numGarbage = len(gc.garbage) numGarbage = len(gc.garbage)
if numGarbage > 0 and config.GetBool('auto-garbage-logging', 0): if numGarbage > 0 and ConfigVariableBool('auto-garbage-logging', False):
if numGarbage != _CFGLGlobals.LastNumGarbage: if numGarbage != _CFGLGlobals.LastNumGarbage:
print("") print("")
gr = GarbageReport('found garbage', threaded=False, collect=False) gr = GarbageReport('found garbage', threaded=False, collect=False)
@ -572,7 +571,7 @@ def checkForGarbageLeaks():
messenger.send(GarbageCycleCountAnnounceEvent, [gr.getDesc2numDict()]) messenger.send(GarbageCycleCountAnnounceEvent, [gr.getDesc2numDict()])
gr.destroy() gr.destroy()
notify = directNotify.newCategory("GarbageDetect") notify = directNotify.newCategory("GarbageDetect")
if config.GetBool('allow-garbage-cycles', 1): if ConfigVariableBool('allow-garbage-cycles', True):
func = notify.warning func = notify.warning
else: else:
func = notify.error func = notify.error

View File

@ -76,6 +76,8 @@ endif()
set(P3PRC_IGATEEXT set(P3PRC_IGATEEXT
configVariable_ext.cxx configVariable_ext.cxx
configVariable_ext.h configVariable_ext.h
notify_ext.cxx
notify_ext.h
streamReader_ext.cxx streamReader_ext.cxx
streamReader_ext.h streamReader_ext.h
streamWriter_ext.cxx streamWriter_ext.cxx

View File

@ -0,0 +1,48 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file notify_ext.cxx
* @author rdb
* @date 2022-12-09
*/
#include "notify_ext.h"
#ifdef HAVE_PYTHON
/**
* Changes the ostream that all subsequent Notify messages will be written to.
* If the previous ostream was set with delete_later = true, this will delete
* the previous ostream. If ostream_ptr is None, this resets the default to
* cerr.
*/
void Extension<Notify>::
set_ostream_ptr(PyObject *ostream_ptr, bool delete_later) {
extern struct Dtool_PyTypedObject Dtool_std_ostream;
if (ostream_ptr == Py_None) {
_this->set_ostream_ptr(nullptr, false);
return;
}
std::ostream *ptr = (std::ostream *)DTOOL_Call_GetPointerThisClass(ostream_ptr, &Dtool_std_ostream, 1, "Notify.set_ostream_ptr", false, true);
if (ptr == nullptr) {
return;
}
// Since we now have a reference to this class on the C++ end, make sure
// that the ostream isn't being destructed when its Python wrapper expires.
// Note that this may cause a memory leak if delete_later is not set, but
// since these pointers are usually set once for the rest of time, this is
// considered less of a problem than having the Python object destroy the
// object while C++ is still using it. See GitHub #1371.
((Dtool_PyInstDef *)ostream_ptr)->_memory_rules = false;
_this->set_ostream_ptr(ptr, delete_later);
}
#endif // HAVE_PYTHON

View File

@ -0,0 +1,37 @@
/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file notify_ext.h
* @author rdb
* @date 2022-12-09
*/
#ifndef NOTIFY_EXT_H
#define NOTIFY_EXT_H
#include "dtoolbase.h"
#ifdef HAVE_PYTHON
#include "extension.h"
#include "pnotify.h"
#include "py_panda.h"
/**
* This class defines the extension methods for Notify, which are called
* instead of any C++ methods with the same prototype.
*/
template<>
class Extension<Notify> : public ExtensionBase<Notify> {
public:
void set_ostream_ptr(PyObject *ostream_ptr, bool delete_later);
};
#endif // HAVE_PYTHON
#endif // NOTIFY_EXT_H

View File

@ -1,3 +1,4 @@
#include "configVariable_ext.cxx" #include "configVariable_ext.cxx"
#include "notify_ext.cxx"
#include "streamReader_ext.cxx" #include "streamReader_ext.cxx"
#include "streamWriter_ext.cxx" #include "streamWriter_ext.cxx"

View File

@ -35,7 +35,11 @@ PUBLISHED:
Notify(); Notify();
~Notify(); ~Notify();
#if defined(CPPPARSER) && defined(HAVE_PYTHON)
EXTEND void set_ostream_ptr(PyObject *ostream_ptr, bool delete_later);
#else
void set_ostream_ptr(std::ostream *ostream_ptr, bool delete_later); void set_ostream_ptr(std::ostream *ostream_ptr, bool delete_later);
#endif
std::ostream *get_ostream_ptr() const; std::ostream *get_ostream_ptr() const;
typedef bool AssertHandler(const char *expression, int line, typedef bool AssertHandler(const char *expression, int line,

View File

@ -43,35 +43,12 @@
#import <OpenGL/OpenGL.h> #import <OpenGL/OpenGL.h>
#import <Carbon/Carbon.h> #import <Carbon/Carbon.h>
#include <sys/sysctl.h>
TypeHandle CocoaGraphicsWindow::_type_handle; TypeHandle CocoaGraphicsWindow::_type_handle;
#ifndef MAC_OS_X_VERSION_10_15 #ifndef MAC_OS_X_VERSION_10_15
#define NSAppKitVersionNumber10_14 1671 #define NSAppKitVersionNumber10_14 1671
#endif #endif
/**
* Returns true if this is an arm64-based mac.
*/
static int is_arm64_mac() {
#ifdef __aarch64__
return 1;
#elif defined(__x86_64__)
// Running in Rosetta 2?
static int ret = -1;
if (ret < 0) {
size_t size = sizeof(ret);
if (sysctlbyname("sysctl.proc_translated", &ret, &size, nullptr, 0) == -1) {
ret = 0;
}
}
return ret;
#else
return 0;
#endif
}
/** /**
* *
*/ */
@ -209,29 +186,17 @@ begin_frame(FrameMode mode, Thread *current_thread) {
cocoagsg->lock_context(); cocoagsg->lock_context();
// Set the drawable. // Set the drawable.
if (_properties.get_fullscreen() && !is_arm64_mac()) { // Although not recommended, it is technically possible to use the same
// Fullscreen. Note that this call doesn't work with the newer // context with multiple different-sized windows. If that happens, the
// Metal-based OpenGL drivers. // context needs to be updated accordingly.
CGLError err = CGLSetFullScreenOnDisplay((CGLContextObj) [cocoagsg->_context CGLContextObj], CGDisplayIDToOpenGLDisplayMask(_display)); if ([cocoagsg->_context view] != _view) {
if (err != kCGLNoError) { // XXX I'm not 100% sure that changing the view requires it to update.
cocoadisplay_cat.error() _context_needs_update = true;
<< "Failed call to CGLSetFullScreenOnDisplay with display mask " [cocoagsg->_context setView:_view];
<< CGDisplayIDToOpenGLDisplayMask(_display) << ": " << CGLErrorString(err) << "\n";
return false;
}
} else {
// Although not recommended, it is technically possible to use the same
// context with multiple different-sized windows. If that happens, the
// context needs to be updated accordingly.
if ([cocoagsg->_context view] != _view) {
// XXX I'm not 100% sure that changing the view requires it to update.
_context_needs_update = true;
[cocoagsg->_context setView:_view];
if (cocoadisplay_cat.is_spam()) { if (cocoadisplay_cat.is_spam()) {
cocoadisplay_cat.spam() cocoadisplay_cat.spam()
<< "Switching context to view " << _view << "\n"; << "Switching context to view " << _view << "\n";
}
} }
} }

View File

@ -113,8 +113,8 @@ pad_bytes(size_t size) {
// Now append the data. // Now append the data.
// It is very important that we *don't* do this reserve() operation. See // It is very important that we *don't* do this reserve() operation. See
// the further comments in append_data(), below. _data.reserve(_data.size() // the further comments in append_data(), below.
// + size); //_data.reserve(_data.size() + size);
while (size > 0) { while (size > 0) {
_data.push_back('\0'); _data.push_back('\0');
@ -146,7 +146,8 @@ append_data(const void *data, size_t size) {
// actually slows it down on Windows, which takes the reserve() request as a // actually slows it down on Windows, which takes the reserve() request as a
// fixed size the array should be set to (!) instead of as a minimum size to // fixed size the array should be set to (!) instead of as a minimum size to
// guarantee. This forces the array to reallocate itself with *every* call // guarantee. This forces the array to reallocate itself with *every* call
// to append_data! _data.reserve(_data.size() + size); // to append_data!
//_data.reserve(_data.size() + size);
_data.v().insert(_data.v().end(), (const unsigned char *)data, _data.v().insert(_data.v().end(), (const unsigned char *)data,
(const unsigned char *)data + size); (const unsigned char *)data + size);

View File

@ -287,7 +287,7 @@ PUBLISHED:
// bounding volumes. // bounding volumes.
void set_bounds_type(BoundingVolume::BoundsType bounds_type); void set_bounds_type(BoundingVolume::BoundsType bounds_type);
BoundingVolume::BoundsType get_bounds_type() const; BoundingVolume::BoundsType get_bounds_type() const;
MAKE_PROPERTY(bounds_type, get_bounds_type); MAKE_PROPERTY(bounds_type, get_bounds_type, set_bounds_type);
void set_bounds(const BoundingVolume *volume); void set_bounds(const BoundingVolume *volume);
INLINE void clear_bounds(); INLINE void clear_bounds();

View File

@ -33,7 +33,8 @@ ConfigVariableDouble pstats_max_rate
("pstats-max-rate", 1000.0, ("pstats-max-rate", 1000.0,
PRC_DESC("The maximum number of packets per second, per thread, to send " PRC_DESC("The maximum number of packets per second, per thread, to send "
"to the remote PStats server. A packet is defined as a single " "to the remote PStats server. A packet is defined as a single "
"UDP packet, or each 1024 bytes of a TCP message.")); "UDP packet, or each 1024 bytes of a TCP message. Set this to a "
"negative number to disable the limit."));
ConfigVariableBool pstats_threaded_write ConfigVariableBool pstats_threaded_write
("pstats-threaded-write", true, ("pstats-threaded-write", true,

View File

@ -61,6 +61,10 @@ encode(Datagram &datagram) const {
} }
break; break;
case T_expire_thread:
datagram.add_uint16(_first_thread_index);
break;
default: default:
pstats_cat.error() pstats_cat.error()
<< "Invalid PStatClientControlMessage::Type " << (int)_type << "\n"; << "Invalid PStatClientControlMessage::Type " << (int)_type << "\n";
@ -117,6 +121,10 @@ decode(const Datagram &datagram, PStatClientVersion *version) {
} }
break; break;
case T_expire_thread:
_first_thread_index = source.get_uint16();
break;
case T_datagram: case T_datagram:
// Not, strictly speaking, a control message. // Not, strictly speaking, a control message.
return false; return false;

View File

@ -39,6 +39,7 @@ public:
T_hello, T_hello,
T_define_collectors, T_define_collectors,
T_define_threads, T_define_threads,
T_expire_thread,
T_invalid T_invalid
}; };

View File

@ -34,7 +34,6 @@ sort_time() {
*/ */
bool PStatFrameData:: bool PStatFrameData::
write_datagram(Datagram &destination, PStatClient *client) const { write_datagram(Datagram &destination, PStatClient *client) const {
Data::const_iterator di;
if (_time_data.size() >= 65536 || _level_data.size() >= 65536) { if (_time_data.size() >= 65536 || _level_data.size() >= 65536) {
pstats_cat.info() pstats_cat.info()
<< "Dropping frame with " << _time_data.size() << "Dropping frame with " << _time_data.size()
@ -43,16 +42,62 @@ write_datagram(Datagram &destination, PStatClient *client) const {
return false; return false;
} }
#if !defined(WORDS_BIGENDIAN) || defined(__GNUC__)
// Hand-roll this, significantly more efficient for many data points
size_t size = (_time_data.size() + _level_data.size()) * 6 + 4;
PTA_uchar array = destination.modify_array();
size_t offset = array.size();
array.resize(offset + size);
unsigned char *data = &array[0] + offset;
uint16_t *ptr = (uint16_t *)data;
#ifdef WORDS_BIGENDIAN
*ptr++ = __builtin_bswap16(_time_data.size());
for (const DataPoint &dp : _time_data) {
*ptr++ = __builtin_bswap16(dp._index);
PN_float32 v = (PN_float32)dp._value;
*(uint32_t *)ptr = __builtin_bswap32(reinterpret_cast<uint32_t &>(v));
ptr += 2;
}
*ptr++ = __builtin_bswap16(_level_data.size());
for (const DataPoint &dp : _level_data) {
*ptr++ = __builtin_bswap16(dp._index);
PN_float32 v = (PN_float32)dp._value;
*(uint32_t *)ptr = __builtin_bswap32(reinterpret_cast<uint32_t &>(v));
ptr += 2;
}
#else
*ptr++ = _time_data.size();
for (const DataPoint &dp : _time_data) {
*ptr++ = dp._index;
*(PN_float32 *)ptr = dp._value;
ptr += 2;
}
*ptr++ = _level_data.size();
for (const DataPoint &dp : _level_data) {
*ptr++ = dp._index;
*(PN_float32 *)ptr = dp._value;
ptr += 2;
}
#endif
#else
destination.add_uint16(_time_data.size()); destination.add_uint16(_time_data.size());
for (di = _time_data.begin(); di != _time_data.end(); ++di) { for (const DataPoint &dp : _time_data) {
destination.add_uint16((*di)._index); destination.add_uint16(dp._index);
destination.add_float32((*di)._value); destination.add_float32(dp._value);
} }
destination.add_uint16(_level_data.size()); destination.add_uint16(_level_data.size());
for (di = _level_data.begin(); di != _level_data.end(); ++di) { for (const DataPoint &dp : _level_data) {
destination.add_uint16((*di)._index); destination.add_uint16(dp._index);
destination.add_float32((*di)._value); destination.add_float32(dp._value);
} }
#endif
return true; return true;
} }
@ -61,25 +106,38 @@ write_datagram(Datagram &destination, PStatClient *client) const {
* Extracts the FrameData definition from the datagram. * Extracts the FrameData definition from the datagram.
*/ */
void PStatFrameData:: void PStatFrameData::
read_datagram(DatagramIterator &source, PStatClientVersion *) { read_datagram(DatagramIterator &source, PStatClientVersion *version) {
clear(); clear();
int i; {
int time_size = source.get_uint16(); size_t time_size;
for (i = 0; i < time_size; i++) { if (version->is_at_least(3, 2)) {
nassertv(source.get_remaining_size() > 0); time_size = source.get_uint32();
DataPoint dp; } else {
dp._index = source.get_uint16(); time_size = source.get_uint16();
dp._value = source.get_float32(); }
_time_data.push_back(dp); _time_data.resize(time_size);
for (DataPoint &dp : _time_data) {
nassertv(source.get_remaining_size() > 0);
dp._index = source.get_uint16();
dp._value = source.get_float32();
}
} }
int level_size = source.get_uint16();
for (i = 0; i < level_size; i++) { {
nassertv(source.get_remaining_size() > 0); size_t level_size;
DataPoint dp; if (version->is_at_least(3, 2)) {
dp._index = source.get_uint16(); level_size = source.get_uint32();
dp._value = source.get_float32(); } else {
_level_data.push_back(dp); level_size = source.get_uint16();
}
_level_data.resize(level_size);
for (DataPoint &dp : _level_data) {
nassertv(source.get_remaining_size() > 0);
dp._index = source.get_uint16();
dp._value = source.get_float32();
}
} }
//nassertv(source.get_remaining_size() == 0); //nassertv(source.get_remaining_size() == 0);
} }

View File

@ -31,6 +31,7 @@ static const int current_pstat_minor_version = 0;
// Incremented to 2.1 on 5/21/01 to add support for TCP frame data. // Incremented to 2.1 on 5/21/01 to add support for TCP frame data.
// Incremented to 3.0 on 4/28/05 to bump TCP headers to 32 bits. // Incremented to 3.0 on 4/28/05 to bump TCP headers to 32 bits.
// Incremented to 3.1 on 11/29/22 to support nested start/stop pairs. // Incremented to 3.1 on 11/29/22 to support nested start/stop pairs.
// Incremented to 3.2 on 12/10/22 to use 32-bit data counts, T_expire_thread.
/** /**
* Returns the current major version number of the PStats protocol. This is * Returns the current major version number of the PStats protocol. This is

View File

@ -195,7 +195,7 @@ handle_client_control_message(const PStatClientControlMessage &message) {
if (message._major_version != server_major_version || if (message._major_version != server_major_version ||
(message._major_version == server_major_version && (message._major_version == server_major_version &&
message._minor_version > server_minor_version && message._minor_version > server_minor_version &&
(message._major_version != 3 || message._minor_version != 1))) { (message._major_version != 3 || message._minor_version > 2))) {
_monitor->bad_version(message._client_hostname, message._client_progname, _monitor->bad_version(message._client_hostname, message._client_progname,
message._client_pid, message._client_pid,
message._major_version, message._minor_version, message._major_version, message._minor_version,
@ -228,6 +228,10 @@ handle_client_control_message(const PStatClientControlMessage &message) {
} }
break; break;
case PStatClientControlMessage::T_expire_thread:
// Ignore for now.
break;
default: default:
nout << "Invalid control message received from client.\n"; nout << "Invalid control message received from client.\n";
} }