<commit_before>/*
 * Copyright © 2009 CNRS, INRIA, Université Bordeaux 1
 * See COPYING in top-level directory.
 */

#include <private/config.h>
#include <hwloc.h>
#include <hwloc/helper.h>
#include <private/private.h>
#include <private/debug.h>

#ifdef HWLOC_HAVE_LIBPCI

#include <pci/pci.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>
#ifdef HWLOC_LINUX_SYS
#include <dirent.h>
#include <sys/types.h>
#endif

#define CONFIG_SPACE_CACHESIZE 64

static void
hwloc_pci_traverse_print_cb(struct hwloc_obj *pcidev, int depth __hwloc_attribute_unused)
{
  char busid[14];
  snprintf(busid, sizeof(busid), "%04x:%02x:%02x.%01x",
           pcidev->attr->pcidev.domain, pcidev->attr->pcidev.bus, pcidev->attr->pcidev.dev, pcidev->attr->pcidev.func);

  if (pcidev->type == HWLOC_OBJ_BRIDGE) {
    if (pcidev->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_HOST)
      hwloc_debug("%*s HostBridge", depth, "");
    else
      hwloc_debug("%*s %s Bridge [%04x:%04x]", depth, "", busid,
		  pcidev->attr->pcidev.vendor_id, pcidev->attr->pcidev.device_id);
    hwloc_debug(" to %04x:[%02x:%02x]\n",
		pcidev->attr->bridge.downstream.pci.domain, pcidev->attr->bridge.downstream.pci.secondary_bus, pcidev->attr->bridge.downstream.pci.subordinate_bus);
  } else
    hwloc_debug("%*s %s Device [%04x:%04x (%04x:%04x) rev=%02x class=%04x]\n", depth, "", busid,
		pcidev->attr->pcidev.vendor_id, pcidev->attr->pcidev.device_id,
		pcidev->attr->pcidev.subvendor_id, pcidev->attr->pcidev.subdevice_id,
		pcidev->attr->pcidev.revision, pcidev->attr->pcidev.class_id);
}

static void
hwloc_pci_traverse_setbridgedepth_cb(struct hwloc_obj *pcidev, int depth)
{
  if (pcidev->type == HWLOC_OBJ_BRIDGE)
    pcidev->attr->bridge.depth = depth;
}

#ifdef HWLOC_LINUX_SYS
static void
hwloc_linux_add_os_device(struct hwloc_obj *pcidev, const char *name)
{
  struct hwloc_obj *obj = hwloc_alloc_setup_object(HWLOC_OBJ_OS_DEVICE, -1);
  obj->name = strdup(name);
  obj->cpuset = hwloc_cpuset_alloc();
  obj->logical_index = -1;

  if (pcidev->last_child) {
    pcidev->last_child->next_sibling = obj;
    obj->prev_sibling = pcidev->last_child;
  } else {
    pcidev->first_child = obj;
  }
  pcidev->last_child = obj;
}

/* look for objects of the given class below a sysfs directory */
static void
hwloc_linux_class_readdir(struct hwloc_obj *pcidev, const char *devicepath, const char *classname)
{
  size_t classnamelen = strlen(classname);
  char path[256];
  DIR *dir;
  struct dirent *dirent;

  snprintf(path, sizeof(path), "%s/%s", devicepath, classname);
  dir = opendir(path);
  if (dir) {
    /* modern sysfs: <device>/<class>/<name> */
    while ((dirent = readdir(dir)) != NULL) {
      if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, ".."))
	continue;
      hwloc_linux_add_os_device(pcidev, dirent->d_name);
    }
    closedir(dir);
  } else {
    /* deprecated sysfs: <device>/<class>:<name> */
    dir = opendir(devicepath);
    if (dir) {
      while ((dirent = readdir(dir)) != NULL) {
	if (strncmp(dirent->d_name, classname, classnamelen) || dirent->d_name[classnamelen] != ':')
	  continue;
	hwloc_linux_add_os_device(pcidev, dirent->d_name + classnamelen+1);
      }
    }
    closedir(dir);
  }
}

/* net and infiniband class objects are immediately below pci devices */
static void
hwloc_linux_lookup_net_class(struct hwloc_obj *pcidev, const char *pcidevpath)
{
  hwloc_linux_class_readdir(pcidev, pcidevpath, "net");
}
static void
hwloc_linux_lookup_infiniband_class(struct hwloc_obj *pcidev, const char *pcidevpath)
{
  hwloc_linux_class_readdir(pcidev, pcidevpath, "infiniband");
}

/* block class objects are in host%d/target%d:%d:%d/%d:%d:%d/ below pci devices */
static void
hwloc_linux_lookup_block_class(struct hwloc_obj *pcidev, const char *pcidevpath)
{
  size_t pathlen;
  DIR *devicedir, *hostdir, *targetdir;
  struct dirent *devicedirent, *hostdirent, *targetdirent;
  char path[256];
  int dummy;

  strcpy(path, pcidevpath);
  pathlen = strlen(path);

  devicedir = opendir(pcidevpath);
  if (!devicedir)
    return;
  while ((devicedirent = readdir(devicedir)) != NULL) {
    if (sscanf(devicedirent->d_name, "host%d", &dummy) != 1)
      continue;
    /* found for host%d */
    path[pathlen] = '/';
    strcpy(&path[pathlen+1], devicedirent->d_name);
    pathlen += 1+strlen(devicedirent->d_name);
    hostdir = opendir(path);
    if (!hostdir)
      continue;
    while ((hostdirent = readdir(hostdir)) != NULL) {
      if (sscanf(hostdirent->d_name, "target%d:%d:%d", &dummy, &dummy, &dummy) != 3)
	continue;
      /* found host%d/target%d:%d:%d */
      path[pathlen] = '/';
      strcpy(&path[pathlen+1], hostdirent->d_name);
      pathlen += 1+strlen(hostdirent->d_name);
      targetdir = opendir(path);
      if (!targetdir)
	continue;
      while ((targetdirent = readdir(targetdir)) != NULL) {
	if (sscanf(targetdirent->d_name, "%d:%d:%d:%d", &dummy, &dummy, &dummy, &dummy) != 4)
	  continue;
	/* found host%d/target%d:%d:%d/%d:%d:%d:%d */
	path[pathlen] = '/';
	strcpy(&path[pathlen+1], targetdirent->d_name);
	pathlen += 1+strlen(targetdirent->d_name);
	/* lookup block class for real */
	hwloc_linux_class_readdir(pcidev, path, "block");
	/* restore parent path */
	pathlen -= 1+strlen(targetdirent->d_name);
	path[pathlen] = '\0';
      }
      closedir(targetdir);
      /* restore parent path */
      pathlen -= 1+strlen(hostdirent->d_name);
      path[pathlen] = '\0';
    }
    closedir(hostdir);
    /* restore parent path */
    pathlen -= 1+strlen(devicedirent->d_name);
    path[pathlen] = '\0';
  }
  closedir(devicedir);
}
#endif /* HWLOC_LINUX_SYS */

static void
hwloc_pci_traverse_lookuposdevices_cb(struct hwloc_obj *pcidev, int depth __hwloc_attribute_unused)
{
  if (pcidev->type == HWLOC_OBJ_BRIDGE)
    return;

#ifdef HWLOC_LINUX_SYS
  char pcidevpath[256];

  snprintf(pcidevpath, sizeof(pcidevpath), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
	   pcidev->attr->pcidev.domain, pcidev->attr->pcidev.bus,
	   pcidev->attr->pcidev.dev, pcidev->attr->pcidev.func);

  hwloc_linux_lookup_net_class(pcidev, pcidevpath);
  hwloc_linux_lookup_infiniband_class(pcidev, pcidevpath);
  hwloc_linux_lookup_block_class(pcidev, pcidevpath);

#endif /* HWLOC_LINUX_SYS */
}

static void
hwloc_pci__traverse(struct hwloc_obj *root, void (*cb)(struct hwloc_obj *, int depth), int depth)
{
  struct hwloc_obj *child = root->first_child;
  while (child) {
    cb(child, depth);
    if (child->type == HWLOC_OBJ_BRIDGE)
      hwloc_pci__traverse(child, cb, depth+1);
    child = child->next_sibling;
  }
}

static void
hwloc_pci_traverse(struct hwloc_obj *root, void (*cb)(struct hwloc_obj *, int depth))
{
  hwloc_pci__traverse(root, cb, 0);
}<commit_msg>Lookup dmaengine devices too<commit_after>/*
 * Copyright © 2009 CNRS, INRIA, Université Bordeaux 1
 * See COPYING in top-level directory.
 */

#include <private/config.h>
#include <hwloc.h>
#include <hwloc/helper.h>
#include <private/private.h>
#include <private/debug.h>

#ifdef HWLOC_HAVE_LIBPCI

#include <pci/pci.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <assert.h>
#ifdef HWLOC_LINUX_SYS
#include <dirent.h>
#include <sys/types.h>
#endif

#define CONFIG_SPACE_CACHESIZE 64

static void
hwloc_pci_traverse_print_cb(struct hwloc_obj *pcidev, int depth __hwloc_attribute_unused)
{
  char busid[14];
  snprintf(busid, sizeof(busid), "%04x:%02x:%02x.%01x",
           pcidev->attr->pcidev.domain, pcidev->attr->pcidev.bus, pcidev->attr->pcidev.dev, pcidev->attr->pcidev.func);

  if (pcidev->type == HWLOC_OBJ_BRIDGE) {
    if (pcidev->attr->bridge.upstream_type == HWLOC_OBJ_BRIDGE_HOST)
      hwloc_debug("%*s HostBridge", depth, "");
    else
      hwloc_debug("%*s %s Bridge [%04x:%04x]", depth, "", busid,
		  pcidev->attr->pcidev.vendor_id, pcidev->attr->pcidev.device_id);
    hwloc_debug(" to %04x:[%02x:%02x]\n",
		pcidev->attr->bridge.downstream.pci.domain, pcidev->attr->bridge.downstream.pci.secondary_bus, pcidev->attr->bridge.downstream.pci.subordinate_bus);
  } else
    hwloc_debug("%*s %s Device [%04x:%04x (%04x:%04x) rev=%02x class=%04x]\n", depth, "", busid,
		pcidev->attr->pcidev.vendor_id, pcidev->attr->pcidev.device_id,
		pcidev->attr->pcidev.subvendor_id, pcidev->attr->pcidev.subdevice_id,
		pcidev->attr->pcidev.revision, pcidev->attr->pcidev.class_id);
}

static void
hwloc_pci_traverse_setbridgedepth_cb(struct hwloc_obj *pcidev, int depth)
{
  if (pcidev->type == HWLOC_OBJ_BRIDGE)
    pcidev->attr->bridge.depth = depth;
}

#ifdef HWLOC_LINUX_SYS
static void
hwloc_linux_add_os_device(struct hwloc_obj *pcidev, const char *name)
{
  struct hwloc_obj *obj = hwloc_alloc_setup_object(HWLOC_OBJ_OS_DEVICE, -1);
  obj->name = strdup(name);
  obj->cpuset = hwloc_cpuset_alloc();
  obj->logical_index = -1;

  if (pcidev->last_child) {
    pcidev->last_child->next_sibling = obj;
    obj->prev_sibling = pcidev->last_child;
  } else {
    pcidev->first_child = obj;
  }
  pcidev->last_child = obj;
}

/* look for objects of the given class below a sysfs directory */
static void
hwloc_linux_class_readdir(struct hwloc_obj *pcidev, const char *devicepath, const char *classname)
{
  size_t classnamelen = strlen(classname);
  char path[256];
  DIR *dir;
  struct dirent *dirent;

  snprintf(path, sizeof(path), "%s/%s", devicepath, classname);
  dir = opendir(path);
  if (dir) {
    /* modern sysfs: <device>/<class>/<name> */
    while ((dirent = readdir(dir)) != NULL) {
      if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, ".."))
	continue;
      hwloc_linux_add_os_device(pcidev, dirent->d_name);
    }
    closedir(dir);
  } else {
    /* deprecated sysfs: <device>/<class>:<name> */
    dir = opendir(devicepath);
    if (dir) {
      while ((dirent = readdir(dir)) != NULL) {
	if (strncmp(dirent->d_name, classname, classnamelen) || dirent->d_name[classnamelen] != ':')
	  continue;
	hwloc_linux_add_os_device(pcidev, dirent->d_name + classnamelen+1);
      }
    }
    closedir(dir);
  }
}

/* class objects that are immediately below pci devices */
static void
hwloc_linux_lookup_net_class(struct hwloc_obj *pcidev, const char *pcidevpath)
{
  hwloc_linux_class_readdir(pcidev, pcidevpath, "net");
}
static void
hwloc_linux_lookup_infiniband_class(struct hwloc_obj *pcidev, const char *pcidevpath)
{
  hwloc_linux_class_readdir(pcidev, pcidevpath, "infiniband");
}
static void
hwloc_linux_lookup_dma_class(struct hwloc_obj *pcidev, const char *pcidevpath)
{
  hwloc_linux_class_readdir(pcidev, pcidevpath, "dma");
}

/* block class objects are in host%d/target%d:%d:%d/%d:%d:%d/ below pci devices */
static void
hwloc_linux_lookup_block_class(struct hwloc_obj *pcidev, const char *pcidevpath)
{
  size_t pathlen;
  DIR *devicedir, *hostdir, *targetdir;
  struct dirent *devicedirent, *hostdirent, *targetdirent;
  char path[256];
  int dummy;

  strcpy(path, pcidevpath);
  pathlen = strlen(path);

  devicedir = opendir(pcidevpath);
  if (!devicedir)
    return;
  while ((devicedirent = readdir(devicedir)) != NULL) {
    if (sscanf(devicedirent->d_name, "host%d", &dummy) != 1)
      continue;
    /* found for host%d */
    path[pathlen] = '/';
    strcpy(&path[pathlen+1], devicedirent->d_name);
    pathlen += 1+strlen(devicedirent->d_name);
    hostdir = opendir(path);
    if (!hostdir)
      continue;
    while ((hostdirent = readdir(hostdir)) != NULL) {
      if (sscanf(hostdirent->d_name, "target%d:%d:%d", &dummy, &dummy, &dummy) != 3)
	continue;
      /* found host%d/target%d:%d:%d */
      path[pathlen] = '/';
      strcpy(&path[pathlen+1], hostdirent->d_name);
      pathlen += 1+strlen(hostdirent->d_name);
      targetdir = opendir(path);
      if (!targetdir)
	continue;
      while ((targetdirent = readdir(targetdir)) != NULL) {
	if (sscanf(targetdirent->d_name, "%d:%d:%d:%d", &dummy, &dummy, &dummy, &dummy) != 4)
	  continue;
	/* found host%d/target%d:%d:%d/%d:%d:%d:%d */
	path[pathlen] = '/';
	strcpy(&path[pathlen+1], targetdirent->d_name);
	pathlen += 1+strlen(targetdirent->d_name);
	/* lookup block class for real */
	hwloc_linux_class_readdir(pcidev, path, "block");
	/* restore parent path */
	pathlen -= 1+strlen(targetdirent->d_name);
	path[pathlen] = '\0';
      }
      closedir(targetdir);
      /* restore parent path */
      pathlen -= 1+strlen(hostdirent->d_name);
      path[pathlen] = '\0';
    }
    closedir(hostdir);
    /* restore parent path */
    pathlen -= 1+strlen(devicedirent->d_name);
    path[pathlen] = '\0';
  }
  closedir(devicedir);
}
#endif /* HWLOC_LINUX_SYS */

static void
hwloc_pci_traverse_lookuposdevices_cb(struct hwloc_obj *pcidev, int depth __hwloc_attribute_unused)
{
  if (pcidev->type == HWLOC_OBJ_BRIDGE)
    return;

#ifdef HWLOC_LINUX_SYS
  char pcidevpath[256];

  snprintf(pcidevpath, sizeof(pcidevpath), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/",
	   pcidev->attr->pcidev.domain, pcidev->attr->pcidev.bus,
	   pcidev->attr->pcidev.dev, pcidev->attr->pcidev.func);

  hwloc_linux_lookup_net_class(pcidev, pcidevpath);
  hwloc_linux_lookup_infiniband_class(pcidev, pcidevpath);
  hwloc_linux_lookup_dma_class(pcidev, pcidevpath);
  hwloc_linux_lookup_block_class(pcidev, pcidevpath);
  /* FIXME: what about gpus? could try class "drm", but proprietary drivers won't appear there */

#endif /* HWLOC_LINUX_SYS */
}

static void
hwloc_pci__traverse(struct hwloc_obj *root, void (*cb)(struct hwloc_obj *, int depth), int depth)
{
  struct hwloc_obj *child = root->first_child;
  while (child) {
    cb(child, depth);
    if (child->type == HWLOC_OBJ_BRIDGE)
      hwloc_pci__traverse(child, cb, depth+1);
    child = child->next_sibling;
  }
}

static void
hwloc_pci_traverse(struct hwloc_obj *root, void (*cb)(struct hwloc_obj *, int depth))
{
  hwloc_pci__traverse(root, cb, 0);
}
{'fraction_non_alphanumeric': 0.15652678960360097, 'fraction_numerical': 0.011035283868157398, 'mean_word_length': 4.485862206292314, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 191, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '474658', 'n_tokens_mistral': 5557, 'n_tokens_neox': 5400, 'n_words': 968}