[Cbe-oss-dev] [PATCH] spufs: Avoid restarting MFC in context saving

Kazunori Asayama asayama at sm.sony.co.jp
Wed Jul 4 17:41:01 EST 2007


Kazunori Asayama <asayama at sm.sony.co.jp> wrote:
> Jeremy Kerr <jk at ozlabs.org> wrote:

> > Do you have a testcase that I can use to confirm the fix?
> 
> Yes, I have. I'll submit it to this ML later.

Attached is the test. Run it as following:

    gcc dma_context_save_test.c -o dma_context_save_test.elf -lspe2
    spu-gcc spu_dma_stop.c -o spu_dma_stop.elf
    ./dma_context_save_test.elf

It will take several seconds on Cell Blade to complete the test, and
more on PS3 (it depends on # of available SPEs). The test silently
returns zero as its exit code if passed, otherwise it returns non-zero
value, crashes or hangs.

--
(ASAYAMA Kazunori
  (asayama at sm.sony.co.jp))
t
-------------- next part --------------
/*
 *  dma_context_save_test - A testcase for SPUFS 
 *
 *  Copyright (C) 2007 Sony Computer Entertainment Inc.
 *  Copyright 2007 Sony Corp.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *  
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>

#include <libspe2.h>

#define NUM_SPES 17

#define COUNT 10000
#define DMA_SIZE 0x4000
#define MFC_COMMAND_QUEUE_DEPTH 16
#define BUFFER_SIZE (DMA_SIZE * MFC_COMMAND_QUEUE_DEPTH)

#define SPE_ELF "spu_dma_stop.elf"

static char dma_data[BUFFER_SIZE] __attribute__((aligned(16)));

spe_program_handle_t *spe_prog;

static void *spu_thread_proc(void *arg)
{
  spe_context_ptr_t spe = (spe_context_ptr_t)arg;
  unsigned int entry = SPE_DEFAULT_ENTRY;
  int ret;
  spe_stop_info_t stop_info;

  if (spe_program_load(spe, spe_prog)) {
    perror("spe_program_load");
    exit(1);
  }

  for ( ; ; ) {
    ret = spe_context_run(spe, &entry, 0, (void*)COUNT, dma_data, &stop_info);
    if (ret == 0) {
      /* Normal exit */
      if (stop_info.result.spe_exit_code) {
	fprintf(stderr, "DMA data mismatch.\n");
	exit(1);
      }
      break;
    }
    else if (ret == 1) {
      /* Do nothing here. */
    }
    else if (ret > 0) {
      fprintf(stderr, "Unexpected stop and signal (0x%x).\n", ret);
      exit(1);
    }
    else {
      perror("spe_context_run");
      exit(1);
    }
  }

  return NULL;
}

static void data_generate(void *data, size_t size)
{
  unsigned char *ptr = data;
  unsigned char *end = ptr + size;
  unsigned char value = 0;
  
  while (ptr < end) {
    *ptr++ = value++;
  }
}

int main(int argc, char **argv)
{
  int i;
  int ret;
  spe_context_ptr_t spe[NUM_SPES];
  pthread_t tid[NUM_SPES];

  data_generate(dma_data, BUFFER_SIZE);

  spe_prog = spe_image_open(SPE_ELF);
  if (!spe_prog) {
    perror("spe_image_open");
    return 1;
  }

  for (i = 0; i < NUM_SPES; i++) {
    spe[i] = spe_context_create(0, 0);
    if (!spe[i]) {
      perror("spe_context_create");
      return 1;
    }
    if (pthread_create(&tid[i], NULL, spu_thread_proc, spe[i])) {
      perror("pthread_create");
      return 1;
    }
  }

  for (i = 0; i < NUM_SPES; i++) {
    pthread_join(tid[i], NULL);
    ret = spe_context_destroy(spe[i]);
    if (ret) {
      perror("spe_context_destroy");
      return 1;
    }
  }

  spe_image_close(spe_prog);

  return 0;
}
-------------- next part --------------
/*
 *  dma_context_save_test - A testcase for SPUFS 
 *
 *  Copyright (C) 2007 Sony Computer Entertainment Inc.
 *  Copyright 2007 Sony Corp.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *  
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *  
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <spu_mfcio.h>
#include <string.h>

#define DMA_SIZE 0x4000
#define MFC_COMMAND_QUEUE_DEPTH 16
#define TAG 1

static unsigned char buf[DMA_SIZE] __attribute__((aligned(16)));

static inline int data_check(unsigned char *p, int size)
{
  vector unsigned char *pv = (vector unsigned char *)p;
  vector unsigned char *pv_end = pv + (size >> 4);
  vector unsigned char v1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, };

  while (pv < pv_end) {
    if (spu_extract(spu_gather(spu_cmpeq(v1, *pv)), 0) != 0xffff) {
      return 0;
    }
    v1 += spu_splats((unsigned char)16);
    pv++;
  }
  return 1;
}

int main(unsigned long long spe,
	 unsigned long long argp /* loop */,
	 unsigned long long envp /* EA */ )
{
  unsigned long long i;

  for (i = 0; i < argp; i++) {
    unsigned long long ea = envp;
    int j;

    /* issue DMA */
    for (j = 0; j < MFC_COMMAND_QUEUE_DEPTH; j++) {
      spu_mfcdma64(buf, mfc_ea2h(ea), mfc_ea2l(ea), DMA_SIZE, TAG, MFC_GETF_CMD);
      ea += DMA_SIZE;
    }

    /* stop here to increase probability of context saving with
       outstanding DMAs. */
    spu_stop(1);

    /* wait for completion */
    mfc_write_tag_mask(1 << TAG);
    mfc_read_tag_status_all();

    /* check the result */
    if (!data_check(buf, DMA_SIZE)) {
      /* data mismatch */
      return 1;
    }

    memset(buf, 0, sizeof(buf));
  }

  return 0;
}


More information about the cbe-oss-dev mailing list