Exemplo n.º 1
0
        // Burst/thread safe
        internal static unsafe void *MarkerGetOrCreate(ushort categoryId, byte *name, int nameBytes, ushort flags)
        {
            if (nameBytes <= 0)
            {
                return(null);
            }

            MarkerBucketNode *marker = null;
            int bucket = (((nameBytes << 5) + (nameBytes >> 2)) ^ name[0]) & 255;

            if (markerHashTableHead != null)
            {
                // No need for locking yet - read operations on hash table are thread safe as long as we are careful about
                // modification during write and only allow one thread to write at a time.
                if (MarkerBucketNode.SearchFor(&markerHashTableHead->MarkersBuffer[bucket], name, nameBytes, ref marker))
                {
                    return(marker);
                }
            }

            // The marker didn't exist in hash table. Need to lock so only one thread can modify at a time.
            // This path will usually only be taken during startup - after which markers should be found in the
            // above loop instead of needing to be created. Even this is a worse-case scenario because correct ProfilerMarker
            // usage will create/get them once, and they will exist as an instance which only calls MarkerBegin() and MarkerEnd()
            // when needed.
            PlayerConnectionMt_LockProfilerHashTables();

            if (marker == null)
            {
                if (markerHashTableHead == null)
                {
                    markerHashTableHead = FastHashTableBufferNode.Allocate(sizeof(MarkerBucketNode));
                    markerHashTableTail = markerHashTableHead;
                }

                marker = &markerHashTableHead->MarkersBuffer[bucket];
            }

            // In case this bucket was added to while another thread had the lock, the end-of-bucket
            // pointer needs to be increased. Also, it's possible the same exact name appears now.
            if (MarkerBucketNode.SearchFor(marker, name, nameBytes, ref marker))
            {
                PlayerConnectionMt_UnlockProfilerHashTables();
                return(marker);
            }

            MarkerBucketNode *oldMarker = null;

            if (marker->nameBytes > 0)
            {
                // There is already a valid marker here at the end of the linked list - add a new one
                markerHashTableTail = markerHashTableTail->ExtendPoolIfFull(sizeof(MarkerBucketNode));

                MarkerBucketNode *newMarker = &markerHashTableTail->MarkersBuffer[markerHashTableTail->size];
                markerHashTableTail->size++;
                oldMarker = marker;
                marker    = newMarker;
            }

            marker->init       = false;
            marker->categoryId = categoryId;
            marker->flags      = flags;
            marker->markerId   = nextMarkerId++;
            marker->nameBytes  = nameBytes;

            // Todo: When Burst printing works we should warn the user if a name is too long and will be truncated
            UnsafeUtility.MemCpy(marker->nameUtf8, name, Math.Min(nameBytes, k_MaxMarkerNameLength));

            // Do this last so if we find the node before locking, we don't have access to it unless it is otherwise fully assigned
            if (oldMarker != null)
            {
                oldMarker->next = marker;
            }

            PlayerConnectionMt_UnlockProfilerHashTables();

            NeedsUpdate = true;

            return(marker);
        }
Exemplo n.º 2
0
        // NOT Burst safe due to string usage
        // Thread safe
        internal static unsafe void ThreadSetInfo(ulong threadId, ulong sysTicksStart, bool frameIndependent, string threadGroup, string threadName)
        {
            ThreadBucketNode *thread = null;
            int bucket = (int)threadId & 255;

            if (threadHashTableHead != null)
            {
                // No need for locking yet - read operations on hash table are thread safe as long as we are careful about
                // modification during write and only allow one thread to write at a time.
                if (ThreadBucketNode.SearchFor(&threadHashTableHead->ThreadsBuffer[bucket], threadId, ref thread))
                {
                    return;
                }
            }

            // The thread info didn't exist in hash table. Need to lock so only one thread can modify at a time.
            // This path will usually only be taken during startup when creating threads - after which thread info
            // should be found in the above loop instead of needing to be created.
            PlayerConnectionMt_LockProfilerHashTables();

            if (thread == null)
            {
                if (threadHashTableHead == null)
                {
                    threadHashTableHead = FastHashTableBufferNode.Allocate(sizeof(ThreadBucketNode));
                    threadHashTableTail = threadHashTableHead;
                }

                thread = &threadHashTableHead->ThreadsBuffer[bucket];
            }

            // In case this bucket was added to while another thread had the lock, the end-of-bucket
            // pointer needs to be increased. Also, it's possible the same exact name appears now.
            if (ThreadBucketNode.SearchFor(thread, threadId, ref thread))
            {
                PlayerConnectionMt_UnlockProfilerHashTables();
                return;
            }

            ThreadBucketNode *oldThread = null;

            if (thread->nameBytes > 0 || thread->groupBytes > 0)
            {
                // There is already a valid thread here at the end of the linked list - add a new one
                threadHashTableTail = threadHashTableTail->ExtendPoolIfFull(sizeof(ThreadBucketNode));

                ThreadBucketNode *newThread = &threadHashTableTail->ThreadsBuffer[threadHashTableTail->size];
                threadHashTableTail->size++;
                oldThread = thread;
                thread    = newThread;
            }

            thread->init = false;
            Assert.IsTrue(thread->nameBytes <= k_MaxThreadNameLength);
            Assert.IsTrue(thread->groupBytes <= k_MaxThreadNameLength);

            fixed(char *c = threadGroup)
            thread->groupBytes = UTF8.GetBytes(c, threadGroup.Length, thread->groupUtf8, k_MaxThreadNameLength);

            fixed(char *c = threadName)
            thread->nameBytes = UTF8.GetBytes(c, threadName.Length, thread->nameUtf8, k_MaxThreadNameLength);

            thread->frameIndependent = frameIndependent;
            thread->sysTicksStart    = sysTicksStart;
            thread->threadId         = threadId;

            // Do this last so if we find the node before locking, we don't have access to it unless it is otherwise fully assigned
            if (oldThread != null)
            {
                oldThread->next = thread;
            }

            PlayerConnectionMt_UnlockProfilerHashTables();

            NeedsUpdate = true;
        }