11// =============================================================================
2- // Copyright (c) 2019-2021 Advanced Micro Devices, Inc. All rights reserved.
2+ // Copyright (c) 2019-2022 Advanced Micro Devices, Inc. All rights reserved.
33// / @author AMD Developer Tools Team
44// / @file
55// / @brief Implementation of functions for working with a data set.
66// =============================================================================
77
88#include < map>
9- #include < set >
9+ #include < unordered_set >
1010#include < stdlib.h> // for malloc() / free()
1111#include < string>
1212#include < string.h> // for memcpy()
@@ -102,7 +102,10 @@ static std::map<RmtCorrelationIdentifier, RmtResourceNameData> resource_name_loo
102102static std::map<RmtResourceIdentifier, RmtResourceIdentifier> unique_resource_id_lookup_map;
103103
104104// A list of implicit resources to be removed from a snapshot.
105- static std::set<RmtResourceIdentifier> implicit_resource_list;
105+ static std::unordered_set<RmtResourceIdentifier> implicit_resource_list;
106+
107+ // The set of created resources at any point in time.
108+ static std::unordered_set<RmtResourceIdentifier> created_resources;
106109
107110// A flag used to indicate that the list of implicit resources has been created.
108111// This list is created when the trace is first parsed and the timeline is built.
@@ -407,6 +410,22 @@ static RmtErrorCode ParseChunks(RmtDataSet* data_set)
407410 return kRmtOk ;
408411}
409412
413+ // Check for SAM (Smart access memory) support.
414+ //
415+ // Without SAM support, the local memory size is 256MB. If SAM is enabled, the local memory
416+ // will be the total GPU memory. In addition, the invisible memory available will be 0 bytes.
417+ static void CheckForSAMSupport (RmtDataSet* data_set)
418+ {
419+ if (data_set->segment_info [kRmtHeapTypeInvisible ].size == 0 )
420+ {
421+ data_set->sam_enabled = true ;
422+ }
423+ else
424+ {
425+ data_set->sam_enabled = false ;
426+ }
427+ }
428+
410429static void BuildDataProfileParseUserdata (RmtDataSet* data_set, const RmtToken* current_token)
411430{
412431 RMT_ASSERT (current_token->type == kRmtTokenTypeUserdata );
@@ -459,10 +478,13 @@ static void BuildDataProfileParseResourceCreate(RmtDataSet* data_set, const RmtT
459478{
460479 RMT_ASSERT (current_token->type == kRmtTokenTypeResourceCreate );
461480
481+ // Add this resource to the list of created resources, and keep track of the maximum number of concurrent resources.
482+ created_resources.insert (current_token->resource_create_token .resource_identifier );
483+ data_set->data_profile .max_concurrent_resources =
484+ RMT_MAXIMUM (data_set->data_profile .max_concurrent_resources , static_cast <int32_t >(created_resources.size ()));
485+
462486 data_set->data_profile .current_resource_count ++;
463487 data_set->data_profile .total_resource_count ++;
464- data_set->data_profile .max_concurrent_resources =
465- RMT_MAXIMUM (data_set->data_profile .max_concurrent_resources , data_set->data_profile .current_resource_count );
466488
467489 // Add one to the allocation count if the resource being created is a shareable image, since we might need to create a dummy allocation token
468490 // if we don't see one in the token stream.
@@ -480,6 +502,11 @@ static void BuildDataProfileParseResourceDestroy(RmtDataSet* data_set, const Rmt
480502{
481503 RMT_ASSERT (current_token->type == kRmtTokenTypeResourceDestroy );
482504
505+ // Only remove the resource from list of created resources if it has previously been created.
506+ if (created_resources.find (current_token->resource_create_token .resource_identifier ) != created_resources.end ())
507+ {
508+ created_resources.erase (current_token->resource_create_token .resource_identifier );
509+ }
483510 data_set->data_profile .current_resource_count --;
484511}
485512
@@ -499,6 +526,8 @@ static RmtErrorCode BuildDataProfile(RmtDataSet* data_set)
499526 RmtProcessMapAddProcess (&data_set->process_map , data_set->process_start_info [current_process_start_index].process_id );
500527 }
501528
529+ created_resources.clear ();
530+
502531 // if the heap has something there, then add it.
503532 while (!RmtStreamMergerIsEmpty (&data_set->stream_merger ))
504533 {
@@ -542,6 +571,8 @@ static RmtErrorCode BuildDataProfile(RmtDataSet* data_set)
542571 }
543572 }
544573
574+ created_resources.clear ();
575+
545576 data_set->cpu_frequency = data_set->streams [0 ].cpu_frequency ;
546577
547578 // Create an allocator for the token heap to use for generating unique resource IDs
@@ -587,7 +618,7 @@ static RmtErrorCode AllocateMemoryForSnapshot(RmtDataSet* data_set, RmtDataSnaps
587618
588619 // Initialize the virtual allocation list.
589620 const size_t virtual_allocation_buffer_size =
590- RmtVirtualAllocationListGetBufferSize (data_set->data_profile .total_virtual_allocation_count , data_set->data_profile .max_concurrent_resources + 200 );
621+ RmtVirtualAllocationListGetBufferSize (data_set->data_profile .total_virtual_allocation_count , data_set->data_profile .max_concurrent_resources );
591622 if (virtual_allocation_buffer_size > 0 )
592623 {
593624 out_snapshot->virtual_allocation_buffer = PerformAllocation (data_set, virtual_allocation_buffer_size, sizeof (uint32_t ));
@@ -597,14 +628,14 @@ static RmtErrorCode AllocateMemoryForSnapshot(RmtDataSet* data_set, RmtDataSnaps
597628 out_snapshot->virtual_allocation_buffer ,
598629 virtual_allocation_buffer_size,
599630 data_set->data_profile .max_virtual_allocation_count ,
600- data_set->data_profile .max_concurrent_resources + 200 ,
631+ data_set->data_profile .max_concurrent_resources ,
601632 data_set->data_profile .total_virtual_allocation_count );
602633 RMT_ASSERT (error_code == kRmtOk );
603634 RMT_RETURN_ON_ERROR (error_code == kRmtOk , error_code);
604635 }
605636
606637 // create the resource list.
607- const size_t resource_list_buffer_size = RmtResourceListGetBufferSize (data_set->data_profile .max_concurrent_resources + 200 );
638+ const size_t resource_list_buffer_size = RmtResourceListGetBufferSize (data_set->data_profile .max_concurrent_resources );
608639 if (resource_list_buffer_size > 0 )
609640 {
610641 out_snapshot->resource_list_buffer = PerformAllocation (data_set, resource_list_buffer_size, sizeof (uint32_t ));
@@ -614,7 +645,7 @@ static RmtErrorCode AllocateMemoryForSnapshot(RmtDataSet* data_set, RmtDataSnaps
614645 out_snapshot->resource_list_buffer ,
615646 resource_list_buffer_size,
616647 &out_snapshot->virtual_allocation_list ,
617- data_set->data_profile .max_concurrent_resources + 200 );
648+ data_set->data_profile .max_concurrent_resources );
618649 RMT_ASSERT (error_code == kRmtOk );
619650 RMT_RETURN_ON_ERROR (error_code == kRmtOk , error_code);
620651 }
@@ -793,12 +824,15 @@ static RmtErrorCode ProcessTokenForSnapshot(RmtDataSet* data_set, RmtToken* curr
793824 current_token->resource_bind_token .virtual_address ,
794825 (int32_t )(current_token->resource_bind_token .size_in_bytes >> 12 ),
795826 kDummyHeapPref ,
796- RmtOwnerType::kRmtOwnerTypeClientDriver );
827+ RmtOwnerType::kRmtOwnerTypeClientDriver ,
828+ data_set->sam_enabled );
797829 }
798830 else if (error_code == kRmtErrorResourceAlreadyBound )
799831 {
800- // duplicate the command allocator resource we have at this resource ID this is because command allocators are
801- // bound to multiple chunks of virtual address space simultaneously.
832+ // Handle the case where the resource is already bound to a virtual memory allocation.
833+ // This can occur for command allocators which can be bound to multiple chunks of virtual
834+ // address space simultaneously or buffer resources already bound to an allocation. These
835+ // resources are implicitly destroyed, created again and bound to a different allocation.
802836 const RmtResource* matching_resource = NULL ;
803837 error_code = RmtResourceListGetResourceByResourceId (
804838 &out_snapshot->resource_list , current_token->resource_bind_token .resource_identifier , &matching_resource);
@@ -809,24 +843,40 @@ static RmtErrorCode ProcessTokenForSnapshot(RmtDataSet* data_set, RmtToken* curr
809843 resource_create_token.resource_identifier = matching_resource->identifier ;
810844 resource_create_token.owner_type = matching_resource->owner_type ;
811845 resource_create_token.commit_type = matching_resource->commit_type ;
812- resource_create_token.resource_type = kRmtResourceTypeCommandAllocator ;
846+ resource_create_token.resource_type = matching_resource-> resource_type ;
813847 memcpy (&resource_create_token.common , ¤t_token->common , sizeof (RmtTokenCommon));
814- memcpy (&resource_create_token.command_allocator , &matching_resource->command_allocator , sizeof (RmtResourceDescriptionCommandAllocator));
815848
816- // Create the resource.
849+ switch (matching_resource->resource_type )
850+ {
851+ case kRmtResourceTypeCommandAllocator :
852+ memcpy (&resource_create_token.command_allocator , &matching_resource->command_allocator , sizeof (RmtResourceDescriptionCommandAllocator));
853+ break ;
854+
855+ case kRmtResourceTypeBuffer :
856+ memcpy (&resource_create_token.buffer , &matching_resource->buffer , sizeof (RmtResourceDescriptionBuffer));
857+ break ;
858+
859+ default :
860+ // Unexpected resource type.
861+ RMT_ASSERT_FAIL (" Re-binding is only supported for buffer and command allocator resource types" );
862+ break ;
863+ }
864+
865+ // Create the resource. Since the resource already exists, the Create operation will implicitly destroy it first.
817866 error_code = RmtResourceListAddResourceCreate (&out_snapshot->resource_list , &resource_create_token);
818867 RMT_ASSERT (error_code == kRmtOk );
819868
820869 if (!(current_token->resource_bind_token .is_system_memory && current_token->resource_bind_token .virtual_address == 0 ))
821870 {
871+ // Re-bind the resource to its new virtual memory allocation.
822872 error_code = RmtResourceListAddResourceBind (&out_snapshot->resource_list , ¤t_token->resource_bind_token );
823873 RMT_ASSERT (error_code == kRmtOk );
824874 }
825875 }
826876 }
827877
828878 RMT_ASSERT (error_code == kRmtOk );
829- // RMT_RETURN_ON_ERROR(error_code == kRmtOk, error_code);
879+ // RMT_RETURN_ON_ERROR(error_code == kRmtOk, error_code);
830880 }
831881 break ;
832882
@@ -877,13 +927,13 @@ static RmtErrorCode ProcessTokenForSnapshot(RmtDataSet* data_set, RmtToken* curr
877927 current_token->virtual_allocate_token .virtual_address ,
878928 current_token->virtual_allocate_token .size_in_bytes );
879929#endif
880-
881930 error_code = RmtVirtualAllocationListAddAllocation (&out_snapshot->virtual_allocation_list ,
882931 current_token->common .timestamp ,
883932 current_token->virtual_allocate_token .virtual_address ,
884933 (int32_t )(current_token->virtual_allocate_token .size_in_bytes >> 12 ),
885934 current_token->virtual_allocate_token .preference ,
886- current_token->virtual_allocate_token .owner_type );
935+ current_token->virtual_allocate_token .owner_type ,
936+ data_set->sam_enabled );
887937 RMT_ASSERT (error_code == kRmtOk );
888938 RMT_RETURN_ON_ERROR (error_code == kRmtOk , error_code);
889939 }
@@ -1064,6 +1114,8 @@ RmtErrorCode RmtDataSetInitialize(const char* path, RmtDataSet* data_set)
10641114 RMT_ASSERT (error_code == kRmtOk );
10651115 RMT_RETURN_ON_ERROR (error_code == kRmtOk , error_code);
10661116
1117+ CheckForSAMSupport (data_set);
1118+
10671119 // construct the data profile for subsequent data parsing.
10681120 error_code = BuildDataProfile (data_set);
10691121 RMT_ASSERT (error_code == kRmtOk );
0 commit comments