示例#1
0
 def sendMessage(self, data):
     pyprofile.incr('vnc_client.data.sent.messages')
     pyprofile.incr('vnc_client.data.sent.bytes',
                    len(data),
                    unit=pyprofile.BYTES)
     if self.transport:
         self.transport.write(data)
示例#2
0
 def parse_rectangle(cls, client, x, y, width, height, data):
     decompressed = client.zlib_decompressor.decompress(data)
     logger.debug('[zlib] Decompressed from %s bytes -> %s bytes', len(data), len(decompressed))
     pyprofile.incr('vncdriver.recv_rectangle.zlib_encoding.decompressed_bytes', len(decompressed), unit=pyprofile.BYTES)
     data = np.frombuffer(decompressed, np.uint8).reshape((height, width, 4))[:, :, [0, 1, 2]]
     encoding = cls(data)
     return Rectangle(x, y, width, height, encoding)
示例#3
0
    def dataReceived(self, data):
        pyprofile.incr('vnc_proxy_server.data.sent.messages')
        pyprofile.incr('vnc_proxy_server.data.sent.bytes', len(data))

        self.buf.append(data)
        self.buf_len += len(data)
        self.flush()
示例#4
0
    def __call__(self, img, available_at):
        # Choose the return value
        if len(self.deque) > 0 and self.deque[0].ready():
            last = self.deque.popleft()
            res = last.get()
            if res is not None:
                pyprofile.timing('vnc_env.diagnostics.async_decode.latency', time.time() - res['available_at'])
        else:
            res = False

        pyprofile.gauge('vnc_env.diagnostics.async_decode.queue_depth', len(self.deque))

        # Just grayscale it by keeping only one component. Should be
        # good enough as this region is black and white anyway.
        grayscale = img[self.y:self.y+self.height, self.x:self.x+self.width, 0]

        # Apply processing if needed
        match = np.array_equal(self._last_img, grayscale)
        if not match:
            pyprofile.incr('vnc_env.diagnostics.async_decode.schedule')
            # sneakily copy if numpy hasn't, so it can be cached
            self._last_img = np.ascontiguousarray(grayscale)
            async = self.qr_pool.apply_async(self.method, (self._last_img, time.time(), available_at))
            self.deque.append(async)
        else:
            pyprofile.incr('vnc_env.diagnostics.async_decode.cache_hit')

        return res
示例#5
0
    def send_env_reward(self, reward, done, info, episode_id):
        pyprofile.incr('agent_conn.reward', reward)
        if done:
            pyprofile.incr('agent_conn.done')

        reactor.callFromThread(self._send_env_reward, reward, done, info,
                               episode_id)
示例#6
0
    def __call__(self, img, available_at):
        # Choose the return value
        if len(self.deque) > 0 and self.deque[0].ready():
            last = self.deque.popleft()
            res = last.get()
            if res is not None:
                pyprofile.timing('vnc_env.diagnostics.async_decode.latency',
                                 time.time() - res['available_at'])
        else:
            res = False

        pyprofile.gauge('vnc_env.diagnostics.async_decode.queue_depth',
                        len(self.deque))

        # Just grayscale it by keeping only one component. Should be
        # good enough as this region is black and white anyway.
        grayscale = img[self.y:self.y + self.height,
                        self.x:self.x + self.width, 0]

        # Apply processing if needed
        match = np.array_equal(self._last_img, grayscale)
        if not match:
            pyprofile.incr('vnc_env.diagnostics.async_decode.schedule')
            # sneakily copy if numpy hasn't, so it can be cached
            self._last_img = np.ascontiguousarray(grayscale)
            async = self.qr_pool.apply_async(
                self.method, (self._last_img, time.time(), available_at))
            self.deque.append(async)
        else:
            pyprofile.incr('vnc_env.diagnostics.async_decode.cache_hit')

        return res
示例#7
0
 def update_rectangle(self, x, y, width, height, data):
     bytes = data.tobytes()
     pyprofile.incr('vncdriver.pyglet_screen.blit')
     pyprofile.incr('vncdriver.pyglet_screen.blit.bytes', len(bytes), unit=pyprofile.BYTES)
     import pyglet
     image = pyglet.image.ImageData(width, height, 'RGB', bytes, pitch=width * -3)
     self.texture.blit_into(image, x, self._height-height-y, 0)
     self._is_updated = True
示例#8
0
 def recv_DecodeZlib_value(self, block, x, y, width, height):
     pyprofile.incr('vncdriver.recv_rectangle.zlib_encoding.bytes',
                    len(block),
                    unit=pyprofile.BYTES)
     rectangle = server_messages.ZlibEncoding.parse_rectangle(
         self, x, y, width, height, block)
     self._rectangles.append(rectangle)
     self._process_rectangles()
示例#9
0
    def recv_DecodeZlib(self, block, x, y, width, height):
        pyprofile.incr('vncdriver.recv_rectangle.zlib_encoding')
        pyprofile.incr('vncdriver.recv_rectangle.zlib_encoding.bytes',
                       len(block),
                       unit=pyprofile.BYTES)

        (length, ) = struct.unpack('!I', block)
        self.expect(self.recv_DecodeZlib_value, length, x, y, width, height)
示例#10
0
    def dataReceived(self, data):
        pyprofile.incr('vnc_client.data.received.messages')
        pyprofile.incr('vnc_client.data.received.bytes', len(data), unit=pyprofile.BYTES)

        self.buf.append(data)
        self.buf_len += len(data)
        logger.debug('Received data: %s bytes (brings us to %s total)', len(data), self.buf_len)

        self.flush()
示例#11
0
    def recv_FramebufferUpdate(self, block):
        (number_of_rectangles, ) = struct.unpack('!xH', block)
        logger.debug('Receiving %d rectangles', number_of_rectangles)
        pyprofile.incr('vncdriver.framebuffer_update')
        pyprofile.incr('vncdriver.framebuffer_update.number_of_rectangles', number_of_rectangles)
        self._remaining_rectangles = number_of_rectangles
        self._rectangles = []

        self._process_rectangles()
示例#12
0
    def get(self, cropped):
        if self._last_img is None:
            return

        match = np.array_equal(self._last_img, cropped)
        if match:
            pyprofile.incr('score.crop_cache.hit.{}'.format(self.name))
            return self._last_value
        else:
            self._last_img = None
示例#13
0
    def reward(self):
        info = {}

        if self.env is None:
            return 0, False, info

        screen, _, done, observation_info = self.env.step([])

        # Copy over the staleness of the observation and the number of
        # VNC updates in the last frame. This gets sent to the client.
        lag = observation_info.get('diagnostics.lag.observation')
        if lag is not None:
            info['rewarder.lag.observation'] = lag[0]
            info['rewarder.lag.observation.timestamp'] = time.time() - lag[0]
        info['rewarder.vnc.updates.n'] = updates_n = observation_info.get(
            'vnc.updates.n')
        info['rewarder.vnc.updates.pixels'] = observation_info.get(
            'vnc.updates.pixels')
        info['rewarder.vnc.updates.bytes'] = observation_info.get(
            'vnc.updates.bytes')

        if updates_n is not None:
            pyprofile.incr('reward.vnc.updates.n', updates_n)

        now = time.time()
        if self._has_initial_reward and info[
                'rewarder.vnc.updates.n'] == 0:  # Nothing new!
            # Timeout after 100 seconds without VNC updates.
            # This means nothing on the screen has changed, which is probably very bad.
            # We log the error and end the episode, hopefully it will recover nicely.
            if now > self._vnc_last_update + 100:
                logger.error('No vnc updates since {}'.format(
                    self._vnc_last_update))
                done = True
            return 0, done, info
        elif self.reward_parser is None:
            return 0, done, info
        self._vnc_last_update = now
        self._has_initial_reward = True

        reward, done, reward_info = self.reward_parser.reward(screen)
        if (self.env_id == 'flashgames.NeonRace2-v0' and reward > 20000) or \
           (self.env_id == 'flashgames.CoasterRacer-v0' and reward > 20000) or \
           (self.env_id == 'internet.SlitherIO-v0' and reward > 1000):
            import tempfile
            f = tempfile.NamedTemporaryFile()
            path = f.name + '.png'
            f.close()

            logger.info(
                '[%s] Abnormally large reward of %s received! This may indicate a bug in the OCR. Saving a screenshot to %s for investigation.',
                utils.thread_name(), reward, path)
            Image.fromarray(screen).save(path)
        return reward, done, info
示例#14
0
    def dataReceived(self, data):
        if self.expected is None:
            # We're in direct proxy mode
            self.proxyData(data)
            return

        pyprofile.incr('vnc_proxy_server.data.sent.messages')
        pyprofile.incr('vnc_proxy_server.data.sent.bytes', len(data))

        self.buf.append(data)
        self.buf_len += len(data)
        self.flush()
示例#15
0
 def parse_rectangle(cls, client, x, y, width, height, data):
     decompressed = client.zlib_decompressor.decompress(data)
     logger.debug('[zlib] Decompressed from %s bytes -> %s bytes',
                  len(data), len(decompressed))
     pyprofile.incr(
         'vncdriver.recv_rectangle.zlib_encoding.decompressed_bytes',
         len(decompressed),
         unit=pyprofile.BYTES)
     data = np.frombuffer(decompressed, np.uint8).reshape(
         (height, width, 4))[:, :, [0, 1, 2]]
     encoding = cls(data)
     return Rectangle(x, y, width, height, encoding)
示例#16
0
 def update_rectangle(self, x, y, width, height, data):
     bytes = data.tobytes()
     pyprofile.incr('vncdriver.pyglet_screen.blit')
     pyprofile.incr('vncdriver.pyglet_screen.blit.bytes',
                    len(bytes),
                    unit=pyprofile.BYTES)
     import pyglet
     image = pyglet.image.ImageData(width,
                                    height,
                                    'RGB',
                                    bytes,
                                    pitch=width * -3)
     self.texture.blit_into(image, x, self._height - height - y, 0)
     self._is_updated = True
示例#17
0
    def parse_rectangle(cls, client, x, y, width, height, data):
        decompressed = client.zlib_decompressor.decompress(data)
        logger.debug('[zrle] Decompressed from %s bytes -> %s bytes', len(data), len(decompressed))
        pyprofile.incr('vncdriver.recv_rectangle.zrle_encoding.decompressed_bytes', len(decompressed), unit=pyprofile.BYTES)

        if client.framebuffer.bpp > 24:
            bytes_per_pixel = 3
        else:
            bytes_per_pixel = client.framebuffer.bypp

        buf = BytesIO(decompressed)
        data = cls._read(x, y, width, height, buf, bytes_per_pixel)
        encoding = cls(data)
        return Rectangle(x, y, width, height, encoding)
示例#18
0
    def parse_rectangle(cls, client, x, y, width, height, data):
        decompressed = client.zlib_decompressor.decompress(data)
        logger.debug('[zrle] Decompressed from %s bytes -> %s bytes',
                     len(data), len(decompressed))
        pyprofile.incr(
            'vncdriver.recv_rectangle.zrle_encoding.decompressed_bytes',
            len(decompressed),
            unit=pyprofile.BYTES)

        if client.framebuffer.bpp > 24:
            bytes_per_pixel = 3
        else:
            bytes_per_pixel = client.framebuffer.bypp

        buf = BytesIO(decompressed)
        data = cls._read(x, y, width, height, buf, bytes_per_pixel)
        encoding = cls(data)
        return Rectangle(x, y, width, height, encoding)
示例#19
0
    def reward(self, img):
        score, done = self.score(img)
        now = time.time()

        # See how long we're running without score, and error out if too long
        if done:
            logger.info('RESET CAUSE: gameover state reached')
        elif score is None:
            # If the scorer can't find anything and the episode isn't over,
            # we're probably stuck in some kind of weird or stale state.
            # It's been more than 100 seconds, we're done here.
            #
            # If no vexpect is provided, then we assume the user
            # is testing vexpect and will handle resets on their
            # own.
            if now > self._last_score_time + 70 and self.vexpect != None and self.scorer != None:
                pyprofile.incr('rewarder.reset.unable_to_parse_score_parse')
                logger.error(
                    'RESET CAUSE: Rewarder has been unable to parse a score since %.2f (%.2fs ago)',
                    self._last_score_time, now - self._last_score_time)
                done = True
        else:
            # We got a good score, reset our timeout
            self._last_score_time = time.time()

        if score is None:
            # TODO: could return negative score here...
            return 0, done, self.UNKNOWN_SCORE

        reward_to_return, info = self.reward_from_score.reward(
            score, time.time())
        if reward_to_return == 0:
            if self.nonzero_reward_timeout is not None and \
               now - self._last_nonzero_reward_time > self.nonzero_reward_timeout:
                logger.error(
                    'RESET CAUSE: No non-zero rewards were generated since %.2f (%.2fs ago), which exceeds the configured timeout of %.2fs',
                    self._last_nonzero_reward_time,
                    now - self._last_nonzero_reward_time,
                    self.nonzero_reward_timeout)
                done = True
        else:
            self._last_nonzero_reward_time = time.time()

        return reward_to_return, done, info
示例#20
0
    def onMessage(self, payload, isBinary):
        if not self.factory.agent_conn.check_message(self):
            return

        assert not isBinary, "Binary websocket not supported"
        payload = ujson.loads(payload)

        context = {
            'start': time.time(),
            'conn': self,
        }
        latency = context['start'] - payload['headers']['sent_at']
        pyprofile.incr('rewarder_protocol.messages')
        pyprofile.incr('rewarder_protocol.messages.{}'.format(payload['method']))

        pyprofile.timing('rewarder_protocol.latency.rtt.skew_unadjusted', 2*latency)
        if latency < 0:
            pyprofile.incr('rewarder_protocol.latency.rtt.skew_unadjusted.negative')

        if payload['method'] == 'v0.env.reset':
            logger.info('Received reset message: %s', payload)
            self.factory.agent_conn.control_buffer.recv_rpc(context, payload)
        elif payload['method'] == 'v0.control.ping':
            logger.debug('Received ping message: %s', payload)
            parent_message_id = payload['headers']['message_id']
            headers = {'parent_message_id': parent_message_id}
            self.send_message('v0.reply.control.ping', {}, headers)
        else:
            logger.warn('Received unsupported message: %s', payload)
示例#21
0
    def onMessage(self, payload, isBinary):
        extra_logger.debug('[%s] Received payload: %s', self.factory.label,
                           payload)
        assert not isBinary
        payload = ujson.loads(payload)

        context = self._make_context()
        latency = context['start'] - payload['headers']['sent_at']
        pyprofile.incr('rewarder_protocol.messages')
        pyprofile.incr('rewarder_protocol.messages.{}'.format(
            payload['method']))

        # Double latency to model RTT
        pyprofile.timing('rewarder_protocol.latency.rtt.skew_unadjusted',
                         2 * latency)
        if latency < 0:
            pyprofile.incr(
                'rewarder_protocol.latency.rtt.skew_unadjusted.negative')

        self.recv(context, payload)
示例#22
0
    def recv_DecodeZlib(self, block, x, y, width, height):
        pyprofile.incr('vncdriver.recv_rectangle.zlib_encoding')
        pyprofile.incr('vncdriver.recv_rectangle.zlib_encoding.bytes', len(block), unit=pyprofile.BYTES)

        (length,) = struct.unpack('!I', block)
        self.expect(self.recv_DecodeZlib_value, length, x, y, width, height)
示例#23
0
 def recv_DecodeZlib_value(self, block, x, y, width, height):
     pyprofile.incr('vncdriver.recv_rectangle.zlib_encoding.bytes', len(block), unit=pyprofile.BYTES)
     rectangle = server_messages.ZlibEncoding.parse_rectangle(self, x, y, width, height, block)
     self._rectangles.append(rectangle)
     self._process_rectangles()
示例#24
0
    def recv(self, context, response):
        method = response['method']
        body = response['body']
        headers = response['headers']

        remote_time = headers['sent_at']
        local_time = context['start']

        episode_id = headers.get('episode_id')
        if episode_id is not None:
            self.reward_buffer.push_time(episode_id, remote_time, local_time)

        # Gets called by RewarderClient
        if method == 'v0.env.reward':
            episode_id = headers['episode_id']
            reward = body['reward']
            done = body['done']
            info = body['info']
            extra_logger.debug(
                '[%s] Received %s: reward=%s done=%s info=%s episode_id=%s',
                self.factory.label, method, reward, done, info, episode_id)
            pyprofile.incr('rewarder_client.reward', reward)
            if done:
                pyprofile.incr('rewarder_client.done')
            self.reward_buffer.push(episode_id, reward, done, info)
        elif method == 'v0.env.text':
            episode_id = headers['episode_id']
            text = body['text']
            extra_logger.debug('[%s] Received %s: text=%s episode_id=%s',
                               self.factory.label, method, text, episode_id)
            self.reward_buffer.push_text(episode_id, text)
        elif method == 'v0.env.observation':
            episode_id = headers['episode_id']
            jsonable = body['observation']
            extra_logger.debug(
                '[%s] Received %s: observation=%s episode_id=%s',
                self.factory.label, method, jsonable, episode_id)
            self.reward_buffer.set_observation(episode_id=episode_id,
                                               observation=jsonable)
        elif method == 'v0.env.describe':
            episode_id = headers['episode_id']
            env_id = body['env_id']
            env_state = body['env_state']
            fps = body['fps']
            extra_logger.info(
                '[%s] Received %s: env_id=%s env_state=%s episode_id=%s',
                self.factory.label, method, env_id, env_state, episode_id)
            self.reward_buffer.set_env_info(env_state,
                                            env_id=env_id,
                                            episode_id=episode_id,
                                            fps=fps)
        elif method == 'v0.reply.env.reset':
            episode_id = headers['episode_id']
            self._finish_reset(episode_id)
        elif method in ['v0.reply.error', 'v0.reply.control.ping']:
            assert headers.get('parent_message_id') is not None
        elif method == 'v0.connection.close':
            assert headers.get('parent_message_id') is None
            logger.debug('Server hanging up: %s', body['message'])

            self._close_message = body['message']
            e = error.Error(body['message'])
            self.factory.record_error(e)
        else:
            logger.error(
                'Unrecognized websocket method: method=%s body=%s headers=%s (consider adding to rewarder_state.py)',
                method, body, headers)
            return

        parent_id = headers.get('parent_message_id')
        if parent_id is not None:
            try:
                spec = self._requests.pop(parent_id)
            except KeyError:
                logger.error(
                    '[%s] Received extra reply to %d; ignoring: method=%s body=%s headers=%s ',
                    self.factory.label, parent_id, method, body, headers)
            else:
                request, d = spec
                if method != 'v0.reply.error':
                    d.callback((context, request, response))
                else:
                    e = RemoteError('[{}] Remote error: {}'.format(
                        self.factory.label, body['message']))
                    d.errback(e)
示例#25
0
 def sendMessage(self, data):
     pyprofile.incr('vnc_client.data.sent.messages')
     pyprofile.incr('vnc_client.data.sent.bytes', len(data), unit=pyprofile.BYTES)
     if self.transport:
         self.transport.write(data)
示例#26
0
    def process_rpc(self, context, message):
        if message['method'] == 'v0.env.reset':
            env_info = self.env_status.env_info()
            env_id = message['body']['env_id']
            fps = message['body']['fps']
            if fps < 0 or fps > 60:
                logger.warn('[%s] Ignoring request for bad fps=%s', fps)
                fps = None

            changing_id = env_id != env_info['env_id']
            changing_fps = fps != env_info['fps']

            if changing_id:
                # Validate the env ID before altering any state
                try:
                    gym_controlplane.spec(env_id)
                except error.UserError as e:
                    self.agent_conn.send_reply_error(
                        e.user_message,
                        parent_message_id=message['headers']['message_id'],
                        parent_context=context)
                    pyprofile.incr('control.env_id_change.user_error')
                    return

            episode_id = message['headers']['episode_id']
            if not changing_id and not changing_fps and \
               rewarder.compare_ids(episode_id, env_info['episode_id']) < 0 and \
               self._sweep_id == self._last_reset_sweep_id:
                # The user hasn't requested any changes, and our
                # current episode_id is ahead of the requested one,
                # and we're in the middle of resetting -- they may as
                # well just piggyback on our current reset.
                logger.info(
                    '[%s] SKIPPING RESET: user requested reset, but already reset in this sweep and no changes requested: request: env_id=%s fps=%s episode_id=%s current: episode_id=%s. Short circuiting by just using the current reset.',
                    utils.thread_name(), env_id, fps, episode_id,
                    env_info['episode_id'])
                short_circuit = True
            else:
                logger.debug(
                    'Change requested: changing_id=%s changing_fps=%s compare_ids=%s state=%s sweep_id=%s last_reset_sweep_id=%s',
                    changing_id, changing_fps,
                    rewarder.compare_ids(episode_id, env_info['episode_id']),
                    env_info['env_state'], self._sweep_id,
                    self._last_reset_sweep_id)
                # Make sure we're resetting before changing the env_id
                env_info = self.env_status.set_env_info('resetting',
                                                        env_id=env_id,
                                                        bump_past=episode_id)
                short_circuit = False
            if not short_circuit:
                if changing_id:
                    self.load_env(env_id)

                    pyprofile.incr('control.env_id_change')
                    pyprofile.incr('control.env_id_change.{}'.format(env_id))
                    logger.info(
                        '[%s] RESET CAUSE: changing out environments due to v0.env.reset (with episode_id=%s): %s -> %s (new episode_id=%s fps=%s)',
                        utils.thread_name(), episode_id, env_info['env_id'],
                        env_id, env_info['episode_id'], fps)
                else:

                    logger.info(
                        '[%s] RESET CAUSE: Resetting environment due to v0.env.reset (with episode_id=%s), keeping same env_id=%s: new episode_id=%s fps=%s',
                        utils.thread_name(), episode_id, env_id,
                        env_info['episode_id'], fps)

                self.reset()
            # We let the agent know the new episode_id to care
            # about. (In theory, we could do this before the reset
            # completes, but the aggregation case would then behave
            # differently.)
            self.agent_conn.send_reply_env_reset(
                episode_id=env_info['episode_id'],
                parent_message_id=message['headers']['message_id'],
                parent_context=context,
            )
        else:
            logger.warn('Ignoring unsupported message: %s', message)