(breaking the thread since we're far from valarrays now).

I've played with this idea and came with the attached interface change.
Aside from low-level backend changes, everything was very easy to implement.

Let's take an example. I modified lstopo to add some userdata to the
root object and define the following export callback:

static void export(void *reserved, hwloc_topology_t topo, hwloc_obj_t obj)
{
  /* we export random stuff instead of the actual userdata content */
  hwloc_export_obj_userdata(reserved, topo, obj, NULL, "coincoin", 8); /* no 
name */
  hwloc_export_obj_userdata(reserved, topo, obj, "MyName", "foobar", 6);
  hwloc_export_obj_userdata(reserved, topo, obj, "MyValue", "foobarbarbar", 
10); /* truncated to 10 chars */
}


This callback is only called for the root object since others have
userdata=NULL. It exports three lines to XML:

    <userdata length="8">coincoin</userdata>
    <userdata name="MyName" length="6">foobar</userdata>
    <userdata name="MyValue" length="10">foobarbarb</userdata>


The idea behind multiple userdata lines per object is that it helps the
application structure its userdata without having to create a single
contigous buffer.

When you import this with an import() callback, you get three
invocations of the callback:

##### name (null) value coincoin length 8
##### name MyName value foobar length 6
##### name MyValue value foobarbarb length 10


The optional "name" attribute lets the application recognize things (but
they always looked in-order in my testing).

My user that wants valarrays would likely export:
* the number of elements in his arrays as a first line
* the content of his latency array as a second line
* the content of his bandwidth array as a third line

We set import() and export() callbacks with two different function
because it makes the doc much more clear and the requirements are
different (import() must be set before load(), export() must use
export_userdata()).

I am satisfied with all this, I don't have any concern with the
genericity of the interface anymore.


Now, I still think we should offer some optional basic encoding
capability since many users have no clue about XDR or base64. For
instance, add export_userdata_encoded() on the side of
export_userdata(). On the import side, we could let the application
decode with a dedicated hwloc function. But I think I would rather mark
the XML line as "encoded" so that hwloc transparently decodes before
passing the data to the import() callback.

Brice

diff --git a/include/hwloc.h b/include/hwloc.h
index a1cb836..b6b1f7e 100644
--- a/include/hwloc.h
+++ b/include/hwloc.h
@@ -371,7 +371,10 @@ struct hwloc_obj {
   struct hwloc_obj *last_child;		/**< \brief Last child */

   /* misc */
-  void *userdata;			/**< \brief Application-given private data pointer, initialized to \c NULL, use it as you wish */
+  void *userdata;			/**< \brief Application-given private data pointer,
+					 * initialized to \c NULL, use it as you wish.
+					 * See hwloc_topology_set_userdata_export_callback()
+					 * if you wish to export this field to XML. */

   /* cpusets and nodesets */
   hwloc_cpuset_t cpuset;		/**< \brief CPUs covered by this object
@@ -825,6 +828,9 @@ HWLOC_DECLSPEC int hwloc_topology_set_synthetic(hwloc_topology_t __hwloc_restric
  *
  * \return -1 with errno set to EINVAL on failure to read the XML file.
  *
+ * \note See also hwloc_topology_set_userdata_import_callback()
+ * for importing application-specific userdata.
+ *
  * \note For convenience, this backend provides empty binding hooks which just
  * return success.  To have hwloc still actually call OS-specific hooks, the
  * HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM has to be set to assert that the loaded
@@ -848,6 +854,9 @@ HWLOC_DECLSPEC int hwloc_topology_set_xml(hwloc_topology_t __hwloc_restrict topo
  *
  * \return -1 with errno set to EINVAL on failure to read the XML buffer.
  *
+ * \note See also hwloc_topology_set_userdata_import_callback()
+ * for importing application-specific userdata.
+ *
  * \note For convenience, this backend provides empty binding hooks which just
  * return success.  To have hwloc still actually call OS-specific hooks, the
  * HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM has to be set to assert that the loaded
@@ -985,6 +994,9 @@ HWLOC_DECLSPEC const struct hwloc_topology_support *hwloc_topology_get_support(h
  *
  * \return -1 if a failure occured.
  *
+ * \note See also hwloc_topology_set_userdata_export_callback()
+ * for exporting application-specific userdata.
+ *
  * \note Only printable characters may be exported to XML string attributes.
  * Any other character, especially any non-ASCII character, will be silently
  * dropped.
@@ -1000,6 +1012,9 @@ HWLOC_DECLSPEC int hwloc_topology_export_xml(hwloc_topology_t topology, const ch
  *
  * \return -1 if a failure occured.
  *
+ * \note See also hwloc_topology_set_userdata_export_callback()
+ * for exporting application-specific userdata.
+ *
  * \note Only printable characters may be exported to XML string attributes.
  * Any other character, especially any non-ASCII character, will be silently
  * dropped.
@@ -1009,6 +1024,59 @@ HWLOC_DECLSPEC int hwloc_topology_export_xmlbuffer(hwloc_topology_t topology, ch
 /** \brief Free a buffer allocated by hwloc_topology_export_xmlbuffer() */
 HWLOC_DECLSPEC void hwloc_free_xmlbuffer(hwloc_topology_t topology, char *xmlbuffer);

+/** \brief Set the application-specific callback for exporting userdata
+ *
+ * The object userdata pointer is not exported to XML by default because hwloc
+ * does not know what it contains.
+ *
+ * This function lets applications set \p export to a callback function
+ * that converts this opaque userdata into an exportable string.
+ * The callback will be invoked during XML export for each object
+ * whose \p userdata pointer is not \c NULL.
+ * The callback should use hwloc_export_obj_userdata() to actually export
+ * something to XML (possibly multiple times per object).
+ *
+ * \p export may be set to \c NULL if userdata should not be exported to XML.
+ */
+HWLOC_DECLSPEC void hwloc_topology_set_userdata_export_callback(hwloc_topology_t topology,
+								void (*export)(void *reserved, hwloc_topology_t topology, hwloc_obj_t obj));
+
+/** \brief Export some object userdata to XML
+ *
+ * This function may only be called from within the export() callback passed
+ * to hwloc_topology_set_userdata_export_callback().
+ * It may be invoked one of multiple times to export some userdata to XML.
+ * The \p buffer content of length \p length is stored with optional name
+ * \p name.
+ *
+ * When importing this XML file, the import() callback (if set) will be
+ * called exactly as many times as hwloc_export_obj_userdata() was called
+ * during export(). It will receive the corresponding \p name, \p buffer
+ * and \p length arguments.
+ *
+ * \note Only printable characters may be exported to XML string attributes.
+ * Any other character, especially any non-ASCII character, will be silently
+ * dropped.
+ *
+ */
+HWLOC_DECLSPEC void hwloc_export_obj_userdata(void *reserved, hwloc_topology_t topology, hwloc_obj_t obj, const char *name, const void *buffer, size_t length);
+
+/** \brief Set the application-specific callback for importing userdata
+ *
+ * On XML import, userdata is ignored by default because hwloc does not know
+ * how to store it in memory.
+ *
+ * This function lets applications set \p import to a callback function
+ * that will get the XML-stored userdata and store it in the object as expected
+ * by the application.
+ *
+ * \p import may be \c NULL if userdata should be ignored during import.
+ *
+ * \note This function should be called before hwloc_topology_load().
+ */
+HWLOC_DECLSPEC void hwloc_topology_set_userdata_import_callback(hwloc_topology_t topology,
+								void (*import)(hwloc_topology_t topology, hwloc_obj_t obj, const char *name, const void *buffer, size_t length));
+
 /** @} */


Reply via email to