unsigned int init_pci(unsigned char bus, const unsigned char forcemem) { int ret = pci_system_init(); if (ret) die(_("Failed to init pciaccess")); struct pci_id_match match; match.vendor_id = 0x1002; match.device_id = PCI_MATCH_ANY; match.subvendor_id = PCI_MATCH_ANY; match.subdevice_id = PCI_MATCH_ANY; match.device_class = 0; match.device_class_mask = 0; match.match_data = 0; struct pci_device_iterator *iter = pci_id_match_iterator_create(&match); struct pci_device *dev = NULL; char busid[32]; while ((dev = pci_device_next(iter))) { pci_device_probe(dev); if ((dev->device_class & 0x00ffff00) != 0x00030000 && (dev->device_class & 0x00ffff00) != 0x00038000) continue; snprintf(busid, sizeof(busid), "pci:%04x:%02x:%02x.%u", dev->domain, dev->bus, dev->dev, dev->func); if (!bus || bus == dev->bus) break; } pci_iterator_destroy(iter); if (!dev) die(_("Can't find Radeon cards")); const unsigned int device_id = dev->device_id; int reg = 2; if (getfamily(device_id) >= BONAIRE) reg = 5; if (!dev->regions[reg].size) die(_("Can't get the register area size")); // printf("Found area %p, size %lu\n", area, dev->regions[reg].size); // DRM support for VRAM drm_fd = drmOpen(NULL, busid); if (drm_fd >= 0) { drmVersionPtr ver = drmGetVersion(drm_fd); if (strcmp(ver->name, "radeon") != 0 && strcmp(ver->name, "amdgpu") != 0) { close(drm_fd); drm_fd = -1; } strcpy(drm_name, ver->name); drmFreeVersion(ver); } if (drm_fd < 0 && access("/dev/ati/card0", F_OK) == 0) // fglrx path drm_fd = open("/dev/ati/card0", O_RDWR); use_ioctl = 0; if (drm_fd >= 0) { authenticate_drm(drm_fd); uint32_t rreg = 0x8010; use_ioctl = get_drm_value(drm_fd, RADEON_INFO_READ_REG, &rreg); } if (forcemem) { printf(_("Forcing the /dev/mem path.\n")); use_ioctl = 0; } if (!use_ioctl) { int mem = open("/dev/mem", O_RDONLY); if (mem < 0) die(_("Cannot access GPU registers, are you root?")); area = mmap(NULL, MMAP_SIZE, PROT_READ, MAP_PRIVATE, mem, dev->regions[reg].base_addr + 0x8000); if (area == MAP_FAILED) die(_("mmap failed")); } bits.vram = 0; if (drm_fd < 0) { printf(_("Failed to open DRM node, no VRAM support.\n")); } else { drmDropMaster(drm_fd); drmVersionPtr ver = drmGetVersion(drm_fd); /* printf("Version %u.%u.%u, name %s\n", ver->version_major, ver->version_minor, ver->version_patchlevel, ver->name);*/ if (ver->version_major < 2 || (ver->version_major == 2 && ver->version_minor < 36)) { printf(_("Kernel too old for VRAM reporting.\n")); drmFreeVersion(ver); goto out; } drmFreeVersion(ver); // No version indicator, so we need to test once // We use different codepaths for radeon and amdgpu // We store vram_size and check below if the ret value is sane if (strcmp(drm_name, "radeon") == 0) { struct drm_radeon_gem_info gem; ret = drmCommandWriteRead(drm_fd, DRM_RADEON_GEM_INFO, &gem, sizeof(gem)); vramsize = gem.vram_size; } else if (strcmp(drm_name, "amdgpu") == 0) { #ifdef ENABLE_AMDGPU struct drm_amdgpu_info_vram_gtt vram_gtt = {}; struct drm_amdgpu_info request; memset(&request, 0, sizeof(request)); request.return_pointer = (unsigned long) &vram_gtt; request.return_size = sizeof(vram_gtt); request.query = AMDGPU_INFO_VRAM_GTT; ret = drmCommandWrite(drm_fd, DRM_AMDGPU_INFO, &request, sizeof(request)); vramsize = vram_gtt.vram_size; #else printf(_("amdgpu DRM driver is used, but amdgpu VRAM size reporting is not enabled\n")); #endif } if (ret) { printf(_("Failed to get VRAM size, error %d\n"), ret); goto out; } ret = getvram(); if (ret == 0) { if (strcmp(drm_name, "amdgpu") == 0) { #ifndef ENABLE_AMDGPU printf(_("amdgpu DRM driver is used, but amdgpu VRAM usage reporting is not enabled\n")); #endif } printf(_("Failed to get VRAM usage, kernel likely too old\n")); goto out; } bits.vram = 1; } out: pci_system_cleanup(); return device_id; }
static void *collector(void *arg) { struct collector_args_t *args = (struct collector_args_t *) arg; const unsigned int ticks = args->ticks; const unsigned int dumpinterval = args->dumpinterval; struct bits_t res[2]; // Save one second's worth of history struct bits_t *history = calloc(ticks * dumpinterval, sizeof(struct bits_t)); unsigned int cur = 0, curres = 0; const useconds_t sleeptime = 1e6 / ticks; while (1) { unsigned int stat = readgrbm(); memset(&history[cur], 0, sizeof(struct bits_t)); if (stat & bits.ee) history[cur].ee = 1; if (stat & bits.vgt) history[cur].vgt = 1; if (stat & bits.gui) history[cur].gui = 1; if (stat & bits.ta) history[cur].ta = 1; if (stat & bits.tc) history[cur].tc = 1; if (stat & bits.sx) history[cur].sx = 1; if (stat & bits.sh) history[cur].sh = 1; if (stat & bits.spi) history[cur].spi = 1; if (stat & bits.smx) history[cur].smx = 1; if (stat & bits.sc) history[cur].sc = 1; if (stat & bits.pa) history[cur].pa = 1; if (stat & bits.db) history[cur].db = 1; if (stat & bits.cr) history[cur].cr = 1; if (stat & bits.cb) history[cur].cb = 1; history[cur].mclk = getmclk(); history[cur].sclk = getsclk(); usleep(sleeptime); cur++; cur %= ticks * dumpinterval; // One second has passed, we have one sec's worth of data if (cur == 0) { unsigned int i; memset(&res[curres], 0, sizeof(struct bits_t)); for (i = 0; i < ticks * dumpinterval; i++) { res[curres].ee += history[i].ee; res[curres].vgt += history[i].vgt; res[curres].gui += history[i].gui; res[curres].ta += history[i].ta; res[curres].tc += history[i].tc; res[curres].sx += history[i].sx; res[curres].sh += history[i].sh; res[curres].spi += history[i].spi; res[curres].smx += history[i].smx; res[curres].sc += history[i].sc; res[curres].pa += history[i].pa; res[curres].db += history[i].db; res[curres].cb += history[i].cb; res[curres].cr += history[i].cr; res[curres].mclk += history[i].mclk; res[curres].sclk += history[i].sclk; } res[curres].vram = getvram(); res[curres].gtt = getgtt(); // Atomically write it to the pointer __sync_bool_compare_and_swap(&results, results, &res[curres]); curres++; curres %= 2; } } return NULL; }