
{"id":2227,"date":"2015-09-15T10:39:01","date_gmt":"2015-09-15T10:39:01","guid":{"rendered":"http:\/\/www.codergears.com\/Blog\/?p=2227"},"modified":"2015-09-15T10:43:40","modified_gmt":"2015-09-15T10:43:40","slug":"a-look-inside-the-resource-manager-of-the-crt-concurrency-runtime","status":"publish","type":"post","link":"https:\/\/codergears.com\/Blog\/?p=2227","title":{"rendered":"A look inside the Resource Manager of the CRT Concurrency Runtime"},"content":{"rendered":"<article style=\"color: #000000;\">Each Visual C++ version \u00a0comes with interesting new features and enhancements to simplify more native programming. The Concurrency Runtime is an added framework to simplify parallel programming and helps you write robust, scalable, and responsive parallel applications.The Concurrency Runtime raises the level of abstraction so that you do not have to manage the infrastructure details that are related to concurrency. The Concurrency Runtime also enables you to specify scheduling policies that meet the quality of service demands of your applications.Here&#8217;s the architecture of Concurrent Runtime Framework:<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt10.png\"><img decoding=\"async\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt10.png?w=296\" alt=\"\" border=\"0\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>And to have more information&#8217;s about this framework, here&#8217;s a good\u00a0<a href=\"http:\/\/blogs.msdn.com\/b\/nativeconcurrency\/archive\/2009\/01\/12\/an-introduction-to-native-concurrency-in-visual-studio-2010.aspx\">introduction\u00a0<\/a>about it.<\/p>\n<p>In this article we will discuss the Resource Manager layer, and try to discover how it works internally.For that\u00a0<a href=\"http:\/\/www.cppdepend.com\/\">CppDepend<\/a>\u00a0is used to analyse CRT Concurrency Runtime code source.<\/p>\n<p>Before reading this article it&#8217;s better to take a look at these interesting articles about ResourceManager:<\/p>\n<ul>\n<li><a href=\"http:\/\/blogs.msdn.com\/b\/nativeconcurrency\/archive\/2009\/03\/10\/resource-management-in-the-concurrency-runtime-part-1.aspx\">Resource Management in Concurrency Runtime &#8211; Part 1<\/a><\/li>\n<li><a href=\"http:\/\/blogs.msdn.com\/b\/nativeconcurrency\/archive\/2009\/07\/21\/resource-management-in-concurrency-runtime-part-2.aspx\">Resource Management in Concurrency Runtime &#8211; Part 2<\/a><\/li>\n<li><a href=\"http:\/\/blogs.msdn.com\/b\/nativeconcurrency\/archive\/2009\/11\/13\/resource-management-in-concurrency-runtime-part-3.aspx\">Resource Management in Concurrency Runtime &#8211; Part 3<\/a><\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: bold; color: #3366ff;\">ResourceManager Design<\/span><\/p>\n<p><span style=\"font-style: italic; color: #3366ff;\">Which classes are used by the ResourceManager to achieve its responsibility?<\/span><\/p>\n<p><span style=\"color: #3333ff;\">SELECT TYPES WHERE<\/span>\u00a0IsDirectlyUsedBy &#8220;<span style=\"color: #ff0000;\">Concurrency.details.ResourceManager<\/span>&#8221;<\/p>\n<p><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt110.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-389\" title=\"crt1\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt110.png\" alt=\"\" width=\"600\" height=\"377\" \/><\/a><\/p>\n<p>The first remark about this design is that it enforces the:<\/p>\n<p>&#8211; High Cohesion: Many classes and structs are used by resource manager, each one has a specific responsability, it makes the design very clear.<span style=\"color: #000000;\">The single responsibility principle states that a class should have more than one reason to change. Such a class is said to be cohesive.<\/span><span style=\"color: #000000;\">\u00a0A high LCOM value generally pinpoints a poorly cohesive class. There are several LCOM metrics. The LCOM takes its values in the range [0-1]. The LCOMHS (HS stands for Henderson-Sellers) takes its values in the range [0-2]. Note that the LCOMHS metric is often considered as more efficient to detect non-cohesive types.<\/span><\/p>\n<p>LCOMHS value higher than 1 should be considered alarming.<\/p>\n<p><span style=\"color: #3333ff;\">WARN IF<\/span>\u00a0Count &gt; 0\u00a0<span style=\"color: #3333ff;\">IN SELECT<\/span>\u00a0TYPES\u00a0<span style=\"color: #3333ff;\">WHERE\u00a0<\/span>LCOMHS &gt; 1\u00a0<span style=\"color: #3333ff;\">AND\u00a0<\/span>NbFields &gt; 10\u00a0<span style=\"color: #3333ff;\">AND\u00a0<\/span>NbMethods &gt;10\u00a0<span style=\"color: #3333ff;\">AND<\/span>!IsGlobal\u00a0<span style=\"color: #3333ff;\">ORDER BY\u00a0<\/span>LCOMHS DESC<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt141.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-391\" title=\"crt14\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt141.png\" alt=\"\" width=\"482\" height=\"132\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>So among classes used by ResourceManager, only UMS is considered as class with a poor cohesion.<\/p>\n<p>&#8211; Low Coupling:Many interfaces and proxies are used to isolate ResourceManager from other components. The Scheduler communicate with ResourceManager but there&#8217;s no direct link between Two components, so how the scheduler communicate with ResourceManager?<\/p>\n<p>To answer to this question let&#8217;s discover classes using ResourceManager:<\/p>\n<p><span style=\"color: #3366ff;\">SELECT TYPES WHERE<\/span>\u00a0IsDirectlyUsing &#8220;<span style=\"color: #ff0000;\">Concurrency.details.ResourceManager<\/span>&#8221;<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt71.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-392\" title=\"crt7\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt71.png\" alt=\"\" width=\"600\" height=\"216\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>Only these classes use the ResourceManager, and the Scheduler doesnt know the ResourceManager directly , so how it interact with it? let&#8217;s add to dependency graph the scheduler and interfaces used by it.<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt81.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-393\" title=\"crt8\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt81.png\" alt=\"\" width=\"600\" height=\"272\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>As shown in the dependency graph the Scheduler communicate with the ResourceManager using the interfaces IResourceManager,ISchedulere and ISchedulerProxy.<\/p>\n<p><span style=\"font-style: italic; color: #3366ff;\">Where the ResourceManager is created?<\/span><br \/>\n<span style=\"color: #3366ff;\">SELECT METHODS WHERE<\/span>\u00a0DepthOfCreateA &#8220;<span style=\"color: #ff0000;\">Concurrency.details.ResourceManager<\/span>&#8221; == 1<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt162.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-395\" title=\"crt16\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt162.png\" alt=\"\" width=\"362\" height=\"140\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>Only ResourceManager create an instance, and it&#8217;s a singleton so only one ResourceManager exist for the whole process.<\/p>\n<p><span style=\"font-weight: bold; color: #3366ff;\">Workflow of resource allocation:<\/span><\/p>\n<p><span style=\"font-style: italic; color: #3366ff;\">Step 1: Get resources data\u00a0from system<\/span><br \/>\nThe Resource manager need all physical information&#8217;s concerning processors and cores to use them when allocating resources for schedulers. Let&#8217;s discover all data manipulated by this component.<\/p>\n<p><span style=\"color: #3366ff;\">SELECT FIELDS WHERE<\/span>\u00a0IsDirectlyUsedBy &#8220;<span style=\"color: #ff0000;\">Concurrency.details.ResourceManager<\/span>&#8221;<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt23.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-396\" title=\"crt2\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt23.png\" alt=\"\" width=\"360\" height=\"378\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>These structs represent all data needed by ResourceManager, the basic ones are ProcessorCore and ProcessorNode representing information&#8217;s about physical resources.<\/p>\n<p>Other structs contains some scheduler data needed for the allocation algorithm.<\/p>\n<p>The good news is that ResourceManager didnt directly access to fields of other logical classes used by it.<\/p>\n<p>Let&#8217;s search where Resourcemanager get basic information&#8217;s about physical resources, for that we can search for methods using GetLogicalProcessorInformation.<\/p>\n<p><span style=\"color: #3366ff;\">SELECT METHODS WHERE<\/span>\u00a0IsDirectlyUsing &#8220;<span style=\"color: #ff0000;\">WindowsAPIGlobalMembers.GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION,PDWORD)<\/span>&#8221;<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt41.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-397\" title=\"crt4\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt41.png\" alt=\"\" width=\"336\" height=\"147\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>Only ResourceManager::InitializeSystemInformation use this method, to get information&#8217;s from system, but it&#8217;s this method responsible of populating ProcessorCore and ProcessorNode?<\/p>\n<p>For that we can search for methods assigning a fields of ProcessorCore:\u00a0<span style=\"color: #3366ff;\">SELECT METHODS WHERE<\/span>IsDirectlyWritingField &#8220;<span style=\"color: #ff0000;\">Concurrency.details.ProcessorCore.m_processorNumber<\/span>&#8221;<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt31.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-398\" title=\"crt3\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt31.png\" alt=\"\" width=\"340\" height=\"169\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>So \u00a0the ResourceManager invokes the DetermineTopology method to populate data into structs.<br \/>\nAnd here&#8217;s a dependency graph showing the methods concerned by getting nodes and cores information&#8217;s.<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt151.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-399\" title=\"crt15\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt151.png\" alt=\"\" width=\"592\" height=\"388\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p><span style=\"font-style: italic; color: #3366ff;\">Step2: Scheduler ask for resource allocation<\/span><br \/>\nAfter the ResourceManager get all data needed for allocation algorithm, a scheduler can ask it to allocate ressources.<\/p>\n<p>When the Scheduler is created it ask for a ResourceManager and invokes CreateResourceManager to get the singleton, after that it invokes IResourceManager::RegisterScheduler to register it self with the resource manager, and get a pointer to ISchedulerProxy, and with this interface the Scheduler will interact with the resource manager.<br \/>\nAfter that the Scheduler is ready to ask for resources allocation by invocking RequestInitialVirtualProcessors.<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt171.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-400\" title=\"crt17\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt171.png\" alt=\"\" width=\"525\" height=\"240\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>And as explained before the Scheduler communicate with resource manager using IScheduleProxy interface to enforces low coupling, and the concrete implemenatation of this interface invoke ResourceManager::RequestInitialVirtualprocessors.<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt181.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-401\" title=\"crt18\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt181.png\" alt=\"\" width=\"401\" height=\"127\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p><span style=\"font-style: italic; color: #3366ff;\">Step3: Resources allocation<\/span><br \/>\nThe resource Manager have to give resources to schedulers when schedulers are created.It will do the allocation depending on the policies and taking into account the other schedulers in the process. Eventually the resources will be provided to the scheduler in need.<\/p>\n<p>The entry point of allocating request is RequestInitialVirtualProcessors, and here&#8217;s a dependency graph showing methods used to acheive allocation.<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt61.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-402\" title=\"crt6\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt61.png\" alt=\"\" width=\"600\" height=\"619\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>PerformAllocation method implements the allocation logic, it ask for Scheduler policies from SchedulerProxy, and invoke AllocateCores method to perform allocation.<\/p>\n<p>Here&#8217;s some characteristics of PerformAllocation and AllocateCores:<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt121.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-403\" title=\"crt12\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt121.png\" alt=\"\" width=\"355\" height=\"145\" \/><\/a><\/div>\n<p><span class=\"body\"><span class=\"body\"><br \/>\n<\/span><\/span><\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt111.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-404\" title=\"crt11\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt111.png\" alt=\"\" width=\"352\" height=\"153\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>Thoses methods are very well documented and the cyclomatic complexity is not high, and it&#8217;s a good indicator that the algorithm of initial allocation is not very complicated.<\/p>\n<p><span style=\"font-style: italic; color: #3366ff;\">Step4: giving resources to Scheduler<\/span><br \/>\nAfter ResourceManager allocate Resources , the scheduler is notified with resources allocated, for that the resource manager invoke GrantAllocation method.<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt131.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-405\" title=\"crt13\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt131.png\" alt=\"\" width=\"600\" height=\"323\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p><span style=\"font-style: italic; color: #3333ff;\">What resources the ResourceManager have to give to Scheduler?<\/span><br \/>\nAs described in msdn articles mentioned below related to resource manager, the resource is a virtual processor associated to a specific thread and runing in a specific core.<br \/>\nBut as shown in the dependency graph the resource manager dont give VirtualProcessors to SchedulerProxy but an array of SchedulerNodes, the SchedulerProxy create VirtualProcessorRoot classes, VirtualProcessorRoot represent an abstraction for a hardware thread on which a thread proxy can execute.<\/p>\n<p><span style=\"font-style: italic; color: #3366ff;\">Who is creating VirtualProcessor?<\/span><br \/>\nBefore answering to this question let&#8217;s search for classes that represent a Virtual Processor, so let&#8217;s search for classes inheriting from this one.<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt191.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-406\" title=\"crt19\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt191.png\" alt=\"\" width=\"418\" height=\"136\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>So VirtualProcessor could concern a simple thread or an UMS Thread.<br \/>\nUser-mode scheduling (UMS) is a light-weight mechanism introduced in Windows7 and Windows server 2008 R2, that applications can use to schedule their own threads. For more information, see\u00a0<a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/dd627187%28v=VS.85%29.aspx\">User-Mode Scheduling<\/a>.<\/p>\n<p>Let&#8217;s search for methods creating ThreadVirtualProcessor.<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt201.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-407\" title=\"crt20\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt201.png\" alt=\"\" width=\"384\" height=\"140\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>So the Scheduler is the responsible of creating VirtualProcessors, and all information&#8217;s needed to create it are given by manager.<\/p>\n<p><span style=\"font-style: italic; color: #3366ff;\">Step5:Dynamic managing resources<\/span><br \/>\nAfter the initial allocation of resources, the second main responsability of resource manager is to Constantly monitoring utilization of resources by schedulers, and dynamically migrating resources between schedulers.<\/p>\n<p>And as shown in the following graph the resource manager create DynamicRM Thread,This worker thread wakes up at fixed intervals and load balances resources among schedulers.<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt211.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-408\" title=\"crt21\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt211.png\" alt=\"\" width=\"600\" height=\"94\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>And here&#8217;s the dependency graph of DynamicResourceManager:<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt102.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-410\" title=\"crt10\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt102.png\" alt=\"\" width=\"588\" height=\"574\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: bold; color: #3333ff;\">Is ResourceManager customizable?<\/span><br \/>\nResourceManager is well designed and is decoupled from other Concurrency Runtime framework by using interfaces, but it&#8217;s possible to customize the allocation behavior of resource manager.<\/p>\n<p>For that let&#8217;s search for ResourceManager virtual methods:<\/p>\n<p><span style=\"color: #3366ff;\">SELECT METHODS FROM TYPES<\/span>\u00a0&#8220;<span style=\"color: #ff0000;\">Concurrency.details.ResourceManager<\/span>&#8221;\u00a0<span style=\"color: #3366ff;\">WHERE<\/span>\u00a0IsVirtual<\/p>\n<p>&nbsp;<\/p>\n<div><a href=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt221.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-409\" title=\"crt22\" src=\"http:\/\/cppdepend.files.wordpress.com\/2010\/09\/crt221.png\" alt=\"\" width=\"364\" height=\"158\" \/><\/a><\/div>\n<p>&nbsp;<\/p>\n<p>Only these methods are virtual and they implements the IResourceManager methods,so it&#8217;s not possible to overload the allocation resource manager logic and customize it.<\/p>\n<\/article>\n<p><!--more--><\/p>\n<p><!--more--><\/p>\n<p><span class=\"body\">\u00a0<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Each Visual C++ version \u00a0comes with interesting new features and enhancements to simplify more native programming. The Concurrency Runtime is an added framework to simplify parallel programming and helps you write robust, scalable, and responsive parallel applications.The Concurrency Runtime raises the level of abstraction so that you do not have to manage the infrastructure details &hellip; <a href=\"https:\/\/codergears.com\/Blog\/?p=2227\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;A look inside the Resource Manager of the CRT Concurrency Runtime&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-2227","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=\/wp\/v2\/posts\/2227","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2227"}],"version-history":[{"count":6,"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=\/wp\/v2\/posts\/2227\/revisions"}],"predecessor-version":[{"id":2233,"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=\/wp\/v2\/posts\/2227\/revisions\/2233"}],"wp:attachment":[{"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2227"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2227"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/codergears.com\/Blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2227"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}